blonk is a radar for your web, where you follow vibes for cool blips on the radar

more docs, abandon typescript fully, move elixir in

Changed files
+11122 -1029
assets
config
elixir_blonk
lib
priv
test
+7 -7
.gitignore
··· 1 1 node_modules/ 2 - /elixir_blonk/_build 2 + /_build 3 3 dist/ 4 4 .env 5 5 .DS_Store ··· 11 11 /_build/ 12 12 13 13 # If you run "mix test --cover", coverage assets end up here. 14 - /elixir_blonk/cover/ 14 + /cover/ 15 15 16 16 # The directory Mix downloads your dependencies sources to. 17 - /elixir_blonk/deps/ 17 + /deps/ 18 18 19 19 # Where 3rd-party dependencies like ExDoc output generated docs. 20 - /elixir_blonk/doc/ 20 + /doc/ 21 21 22 22 # Ignore .fetch files in case you like to edit your project deps locally. 23 - elixir_blonk/.fetch 23 + .fetch 24 24 25 25 # If the VM crashes, it generates a dump, let's ignore it too. 26 26 erl_crash.dump ··· 35 35 elixir_blonk-*.tar 36 36 37 37 # Ignore assets that are produced by build tools. 38 - elixir_blonk/priv/static/assets/ 38 + priv/static/assets/ 39 39 40 40 # Ignore digested assets cache. 41 - elixir_blonk/priv/static/cache_manifest.json 41 + priv/static/cache_manifest.json 42 42 43 43 # In case you use Node.js/npm, you want to ignore these. 44 44 npm-debug.log
+192 -87
README.md
··· 1 - # Blonk 1 + # Blonk 🎯 2 2 3 - ## What is Blonk? 4 - ATProto reddit. 5 - But it will be different, thats just a thing to say to make people place a vibe in their head. 3 + **A place to find blips on the radar of your web, with a focus on vibes.** 6 4 7 - Blonk doesn't have subreddits like a forum. It has loose groups of vibes. 5 + Blonk is a community-driven content discovery platform built on ATProto that enables organic topic communities to form around "vibes" - interest-based feeds where users submit "blips" (content) to get "grooves" (community engagement). 8 6 9 - Maybe they will just be subscribers, but maybe a vibe isnt just users it identifies but users who label themselves into it or something. 7 + ## 🌟 Core Concepts 10 8 11 - We will need to build this in a way where it is consumable on its own website. 12 - It should have some mechanism where it creates its own lexicon or something for the links? 9 + ### The Blonk Ecosystem 13 10 14 - I dont know, we are going to walk through this together. 11 + **🎯 Radar** - The frontpage that surfaces trending content across all vibes 12 + **🌊 Vibes** - Topic-based communities created by community action (#vibe-your_topic) 13 + **📡 Blips** - Content submissions to vibes that appear on the radar 14 + **🎵 Grooves** - Community engagement: `looks_good` or `shit_rips` 15 + **🏷️ Tags** - Universal labels that connect content across vibes 15 16 16 - ## Building It 17 - I started off with a simple TypeScript project and got cooking. 17 + ### How It Works 18 18 19 - You can find that in aeb0dc780a395bf6193a8dc90bd4ab4f82f66d90. 19 + 1. **Vibe Creation**: Communities emerge when `#vibe-topic_name` reaches critical mass 20 + 2. **Content Submission**: Users submit blips to vibes with tags for categorization 21 + 3. **Community Engagement**: Others groove on blips, driving popularity 22 + 4. **Radar Discovery**: Trending tagged content surfaces on the frontpage 23 + 5. **Organic Growth**: Popular content attracts more users to related vibes 20 24 21 - ``` 22 - commit aeb0dc780a395bf6193a8dc90bd4ab4f82f66d90 (HEAD -> main) 23 - Author: Bobby Grayson <53058768+notactuallytreyanastasio@users.noreply.github.com> 24 - Date: Thu Jun 19 09:53:56 2025 -0400 25 + ### Community Seeding 25 26 26 - Initial commit with a little structure. 27 + - **🔥 Hot Posts**: AI monitors the Bluesky firehose for trending content (>5 replies) 28 + - **Auto-Population**: Trending external content auto-populates the `bsky_hot` vibe 29 + - **Community Bootstrap**: Seeds engagement to kickstart organic community growth 27 30 28 - We've added the ATProto SDK and set up a really basic setup. 29 - It's all Claude generated, but this is a learning exercise to let's take 30 - a look at it. 31 + ## 🏗️ Architecture 32 + 33 + ### ATProto-Native 34 + 35 + Blonk is built as a first-class ATProto application with custom record types: 36 + 37 + - `com.blonk.vibe` - Community topic feeds 38 + - `com.blonk.blip` - Content submissions 39 + - `com.blonk.groove` - Community engagement 40 + - `com.blonk.tag` - Universal content labels 41 + - `com.blonk.blipTag` - Content categorization associations 42 + 43 + ### Technology Stack 44 + 45 + - **Backend**: Elixir/Phoenix LiveView 46 + - **Database**: PostgreSQL with ATProto record sync 47 + - **Real-time**: WebSocket firehose integration with Bluesky 48 + - **Authentication**: ATProto app passwords 49 + - **Deployment**: Docker-ready 31 50 32 - BlonkAgent - to be renamed, but basically our Bsky client 51 + ## 🚀 Getting Started 33 52 34 - POST_NSID - our namespace identifier (What is this? We'll come back to that) 53 + ### Prerequisites 35 54 36 - PostManager - our interface to create or retrieve posts 55 + - Elixir 1.18+ 56 + - PostgreSQL 14+ 57 + - Bluesky account with app password 37 58 38 - `index.ts` - a super basic page skeleton 59 + ### Installation 39 60 40 - With this I guess we can try to get some shit on a page. 61 + ```bash 62 + # Clone the repository 63 + git clone https://github.com/your-org/elixir_blonk.git 64 + cd elixir_blonk 65 + 66 + # Install dependencies 67 + mix deps.get 68 + 69 + # Set up environment 70 + cp .env.example .env 71 + # Edit .env with your Bluesky credentials 72 + 73 + # Set up database 74 + mix ecto.setup 75 + 76 + # Start the server 77 + source .env && mix phx.server 41 78 ``` 42 79 43 - I guess now I'm just going to see what Claude has cooked up? 80 + ### Environment Configuration 44 81 45 - Once we have some shit on a screen I can think a little more. 82 + ```bash 83 + # .env 84 + export ATP_SERVICE=https://bsky.social 85 + export ATP_IDENTIFIER=your-handle.bsky.social 86 + export ATP_PASSWORD=your-app-password 87 + ``` 46 88 47 - ## The Story So Far 48 - We have a very basic setup that will in fact put something on atproto. 89 + ## 🎮 Usage 49 90 50 - We made a pull request [here](https://github.com/notactuallytreyanastasio/blonk/pull/1) that got us the basics. 91 + ### Creating Vibes 51 92 52 - So what next? 93 + Post `#vibe-topic_name` to create new community vibes: 53 94 54 - Well, first I am going to drop in React. 95 + ``` 96 + Check out this cool #vibe-blockchain project! #defi #web3 97 + ``` 98 + 99 + Once enough community members use `#vibe-blockchain`, it becomes an official vibe. 100 + 101 + ### Submitting Blips 102 + 103 + Submit content to vibes with relevant tags: 55 104 56 105 ``` 57 - lets just drop in react, we will need it later anyways. 58 - let's be adults about it. make sure to use the latest, and to do whatever dan abramov would do. 59 - He's pretty good. 106 + Title: "New DeFi Protocol Launch" 107 + Body: "Exciting developments in yield farming..." 108 + Vibe: blockchain_vibe 109 + Tags: #defi #yield #ethereum 60 110 ``` 61 111 62 - This ought to go pretty far, but we will follow up in another pull request. 112 + ### Community Engagement 113 + 114 + - **👍 looks_good** - Positive community feedback 115 + - **💩 shit_rips** - Critical community feedback 116 + 117 + Grooves drive content visibility and trending algorithms. 118 + 119 + ### Discovery 120 + 121 + - **Radar**: Trending content across all vibes 122 + - **Vibe Pages**: Topic-specific content feeds 123 + - **Tag Pages**: Cross-vibe content by topic 124 + - **Hot Posts**: AI-curated trending external content 63 125 64 - [Here] is the pull request. 126 + ## 🏷️ Tag System 65 127 66 - I am not going to give it a ton of feedback since React isn't really my lane, unless something really jumps out. 128 + ### Universal Tags 67 129 68 - I had to have a little back and forth, but we got to something running pretty quickly. 130 + Tags are community-owned labels that enable cross-vibe discovery: 69 131 70 - ## What now? 71 - Well, right now it only shows blips _from us_ -- we want to see other people's too and let them submit as well. 132 + - **One Tag Per Name**: Only one `#blockchain` tag exists globally 133 + - **Community Driven**: Anyone can use any tag 134 + - **Usage Tracking**: Popular tags surface trending content 135 + - **Rich Metadata**: Tags support descriptions and attribution 72 136 73 - How do we go about that? 74 - Well I am not sure yet. 137 + ### Tag Lifecycle 75 138 76 - Let's dig into some docs and ask Claude, too. 139 + 1. **First Use**: Creates universal tag record in ATProto 140 + 2. **Association**: Links to blips via BlipTag junction records 141 + 3. **Community Growth**: Usage count drives popularity 142 + 4. **Discovery**: Popular tags surface on radar 77 143 78 - Another prompt... 144 + ## 🤖 AI Integration 79 145 80 - ``` 81 - Blips need to have a "vibe" they belong to. 82 - "vibes" are simply a group of people and a feeling. 83 - Its not a topic like a subreddit or a forum. 84 - A vibe can be "Sunset Sunglasses Struts" or "doinkin right" or "dork nerd linkage" - we want people to not feel confined to a topic, but have an idea of the type of content that will come up in that circle. 146 + ### Hot Post Detection 85 147 86 - What do you think a good implementation step here is? 87 - ``` 148 + The HotPostSweeper monitors Bluesky's firehose for trending content: 88 149 89 - This started off looking pretty sane, and we'll look at it more, but I had a quick piece of feedback for it. 150 + - **Sampling**: 1 in 10 posts with links 151 + - **Engagement Check**: Looks for >5 replies after time delay 152 + - **Auto-Population**: Creates blips in `bsky_hot` vibe 153 + - **Community Seeding**: Bootstraps engagement for organic growth 90 154 91 - ``` 92 - lets add some constraints. 155 + ## 🎯 Community Philosophy 93 156 94 - we dont want duplicate vibes to be able to be created. 157 + ### Vibe-Driven Discovery 95 158 96 - we dont want to allow people to create vibes quite yet. 159 + Blonk prioritizes **community vibes over algorithmic feeds**: 97 160 98 - We are going to make a system where instead if enough people skeet a vibe as a #hashtag then we will create one if a certain threshold is hit via the firehose if they match a special form (#vibe-YOUR_VIBE) and make sure vibes must be something like YOUR_VIBE or your_vibe or YOURVIBE but not YOUR VIBE and make sure thats enforced both react client/server/atproto client level 99 - ``` 161 + - Communities form organically around shared interests 162 + - Content quality emerges through peer grooves 163 + - Cross-vibe discovery happens through universal tags 164 + - Trending content reflects genuine community engagement 100 165 101 - Now, we will see where this really goes. 166 + ### Decentralized Social 102 167 103 - I kind of really like this idea of creating them by mention velocity. 168 + Built on ATProto for true decentralization: 104 169 105 - So, let's see what it has come up with now. 170 + - **Data Portability**: Your content, your control 171 + - **Cross-Platform**: Records work across ATProto apps 172 + - **Community Ownership**: Vibes and tags are community resources 173 + - **Open Protocol**: Extensible and interoperable 106 174 107 - `looks at app` 175 + ## 🛠️ Development 108 176 109 - It got the concept of seeding vibes right. 177 + ### Project Structure 110 178 111 - There are 6 it seeded things with. 179 + ``` 180 + lib/ 181 + ├── elixir_blonk/ # Core business logic 182 + │ ├── vibes/ # Community topic management 183 + │ ├── blips/ # Content submission system 184 + │ ├── grooves/ # Community engagement 185 + │ ├── tags/ # Universal tag system 186 + │ ├── blip_tags/ # Tag associations 187 + │ ├── hot_posts/ # AI content curation 188 + │ ├── atproto/ # ATProto client & sync 189 + │ └── firehose/ # Real-time data ingestion 190 + ├── elixir_blonk_web/ # Phoenix web interface 191 + └── priv/repo/migrations/ # Database schema 192 + ``` 112 193 113 - To create a vibe, 5 people must post with #vibe-SOMETHING-OR_WHATEVER and then it will be found and counted. 194 + ### Key Services 114 195 115 - Once this happens, it creates the vibe so people can post in it. 196 + - **SessionManager**: ATProto authentication & session management 197 + - **Firehose.Consumer**: Real-time Bluesky data ingestion 198 + - **HotPostSweeper**: AI-driven content curation 199 + - **ATProto.Client**: Custom record type operations 116 200 117 - Once a vibe has been filled with blips, you can fluff blips with hell_yeah's or links_good's 201 + ### Testing 118 202 119 - However, it didn't detect my first post. 203 + ```bash 204 + # Run tests 205 + mix test 120 206 207 + # Run with coverage 208 + mix test --cover 121 209 ``` 122 - I just posted #vibe-test_post and its not being detected. 210 + 211 + ## 📈 Roadmap 123 212 124 - Are you sure you are monitoring the bluesky firehose for these hashtags and not something else? 213 + ### Phase 1: Community Bootstrap ✅ 214 + - [x] Basic vibe/blip/groove system 215 + - [x] ATProto integration 216 + - [x] Hot post AI curation 217 + - [x] Universal tag system 125 218 126 - I saw it come along the wire in my other firehose monitor. 127 - ``` 219 + ### Phase 2: Enhanced Discovery 220 + - [ ] Advanced radar algorithms 221 + - [ ] User following/recommendations 222 + - [ ] Cross-vibe trending 223 + - [ ] Mobile app 128 224 129 - It wasn't detecting my vibes and tried to take some shortcuts. 225 + ### Phase 3: Community Tools 226 + - [ ] Vibe moderation tools 227 + - [ ] Community governance 228 + - [ ] Creator monetization 229 + - [ ] External integrations 130 230 131 - So, I had it re-think that approach. 231 + ## 🤝 Contributing 132 232 233 + We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. 133 234 134 - ``` 135 - its failing to detect emerging vibes and we have no server logs indicating this. 235 + ### Development Setup 136 236 137 - that is troublesome. 237 + 1. Fork the repository 238 + 2. Create feature branch (`git checkout -b feature/amazing-feature`) 239 + 3. Commit changes (`git commit -m 'Add amazing feature'`) 240 + 4. Push to branch (`git push origin feature/amazing-feature`) 241 + 5. Open Pull Request 138 242 139 - we need to hash out if this firehose is even working and you are just making willy error handlers that cover important flaws in the system. 243 + ## 📄 License 140 244 141 - Why is it using a search to find the vibes? We should be consuming the entire firehose! 142 - ``` 245 + This project is licensed under the MIT License - see [LICENSE](LICENSE) for details. 143 246 144 - And then 247 + ## 🙏 Acknowledgments 145 248 146 - ``` 147 - We should be defining types for all this incoming data! 249 + - **ATProto Team** - For the decentralized social protocol 250 + - **Bluesky** - For the firehose API and ecosystem 251 + - **Phoenix/Elixir** - For the robust web framework 252 + - **Community** - For making vibes happen 148 253 149 - This is becoming incredibly hard to reason about and we still arent monitoring the firehose successfully 150 - ``` 254 + --- 151 255 152 - And some manual editing, comments left for it to eat up, let's see where it gets. 256 + **Ready to find your vibe?** 🌊 153 257 258 + Start exploring at [blonk.app](https://blonk.app) or run your own instance!
blonk.db

This is a binary file and will not be displayed.

-6
elixir_blonk/.formatter.exs
··· 1 - [ 2 - import_deps: [:ecto, :ecto_sql, :phoenix], 3 - subdirectories: ["priv/*/migrations"], 4 - plugins: [Phoenix.LiveView.HTMLFormatter], 5 - inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] 6 - ]
-258
elixir_blonk/README.md
··· 1 - # Blonk 🎯 2 - 3 - **A place to find blips on the radar of your web, with a focus on vibes.** 4 - 5 - Blonk is a community-driven content discovery platform built on ATProto that enables organic topic communities to form around "vibes" - interest-based feeds where users submit "blips" (content) to get "grooves" (community engagement). 6 - 7 - ## 🌟 Core Concepts 8 - 9 - ### The Blonk Ecosystem 10 - 11 - **🎯 Radar** - The frontpage that surfaces trending content across all vibes 12 - **🌊 Vibes** - Topic-based communities created by community action (#vibe-your_topic) 13 - **📡 Blips** - Content submissions to vibes that appear on the radar 14 - **🎵 Grooves** - Community engagement: `looks_good` or `shit_rips` 15 - **🏷️ Tags** - Universal labels that connect content across vibes 16 - 17 - ### How It Works 18 - 19 - 1. **Vibe Creation**: Communities emerge when `#vibe-topic_name` reaches critical mass 20 - 2. **Content Submission**: Users submit blips to vibes with tags for categorization 21 - 3. **Community Engagement**: Others groove on blips, driving popularity 22 - 4. **Radar Discovery**: Trending tagged content surfaces on the frontpage 23 - 5. **Organic Growth**: Popular content attracts more users to related vibes 24 - 25 - ### Community Seeding 26 - 27 - - **🔥 Hot Posts**: AI monitors the Bluesky firehose for trending content (>5 replies) 28 - - **Auto-Population**: Trending external content auto-populates the `bsky_hot` vibe 29 - - **Community Bootstrap**: Seeds engagement to kickstart organic community growth 30 - 31 - ## 🏗️ Architecture 32 - 33 - ### ATProto-Native 34 - 35 - Blonk is built as a first-class ATProto application with custom record types: 36 - 37 - - `com.blonk.vibe` - Community topic feeds 38 - - `com.blonk.blip` - Content submissions 39 - - `com.blonk.groove` - Community engagement 40 - - `com.blonk.tag` - Universal content labels 41 - - `com.blonk.blipTag` - Content categorization associations 42 - 43 - ### Technology Stack 44 - 45 - - **Backend**: Elixir/Phoenix LiveView 46 - - **Database**: PostgreSQL with ATProto record sync 47 - - **Real-time**: WebSocket firehose integration with Bluesky 48 - - **Authentication**: ATProto app passwords 49 - - **Deployment**: Docker-ready 50 - 51 - ## 🚀 Getting Started 52 - 53 - ### Prerequisites 54 - 55 - - Elixir 1.18+ 56 - - PostgreSQL 14+ 57 - - Bluesky account with app password 58 - 59 - ### Installation 60 - 61 - ```bash 62 - # Clone the repository 63 - git clone https://github.com/your-org/elixir_blonk.git 64 - cd elixir_blonk 65 - 66 - # Install dependencies 67 - mix deps.get 68 - 69 - # Set up environment 70 - cp .env.example .env 71 - # Edit .env with your Bluesky credentials 72 - 73 - # Set up database 74 - mix ecto.setup 75 - 76 - # Start the server 77 - source .env && mix phx.server 78 - ``` 79 - 80 - ### Environment Configuration 81 - 82 - ```bash 83 - # .env 84 - export ATP_SERVICE=https://bsky.social 85 - export ATP_IDENTIFIER=your-handle.bsky.social 86 - export ATP_PASSWORD=your-app-password 87 - ``` 88 - 89 - ## 🎮 Usage 90 - 91 - ### Creating Vibes 92 - 93 - Post `#vibe-topic_name` to create new community vibes: 94 - 95 - ``` 96 - Check out this cool #vibe-blockchain project! #defi #web3 97 - ``` 98 - 99 - Once enough community members use `#vibe-blockchain`, it becomes an official vibe. 100 - 101 - ### Submitting Blips 102 - 103 - Submit content to vibes with relevant tags: 104 - 105 - ``` 106 - Title: "New DeFi Protocol Launch" 107 - Body: "Exciting developments in yield farming..." 108 - Vibe: blockchain_vibe 109 - Tags: #defi #yield #ethereum 110 - ``` 111 - 112 - ### Community Engagement 113 - 114 - - **👍 looks_good** - Positive community feedback 115 - - **💩 shit_rips** - Critical community feedback 116 - 117 - Grooves drive content visibility and trending algorithms. 118 - 119 - ### Discovery 120 - 121 - - **Radar**: Trending content across all vibes 122 - - **Vibe Pages**: Topic-specific content feeds 123 - - **Tag Pages**: Cross-vibe content by topic 124 - - **Hot Posts**: AI-curated trending external content 125 - 126 - ## 🏷️ Tag System 127 - 128 - ### Universal Tags 129 - 130 - Tags are community-owned labels that enable cross-vibe discovery: 131 - 132 - - **One Tag Per Name**: Only one `#blockchain` tag exists globally 133 - - **Community Driven**: Anyone can use any tag 134 - - **Usage Tracking**: Popular tags surface trending content 135 - - **Rich Metadata**: Tags support descriptions and attribution 136 - 137 - ### Tag Lifecycle 138 - 139 - 1. **First Use**: Creates universal tag record in ATProto 140 - 2. **Association**: Links to blips via BlipTag junction records 141 - 3. **Community Growth**: Usage count drives popularity 142 - 4. **Discovery**: Popular tags surface on radar 143 - 144 - ## 🤖 AI Integration 145 - 146 - ### Hot Post Detection 147 - 148 - The HotPostSweeper monitors Bluesky's firehose for trending content: 149 - 150 - - **Sampling**: 1 in 10 posts with links 151 - - **Engagement Check**: Looks for >5 replies after time delay 152 - - **Auto-Population**: Creates blips in `bsky_hot` vibe 153 - - **Community Seeding**: Bootstraps engagement for organic growth 154 - 155 - ## 🎯 Community Philosophy 156 - 157 - ### Vibe-Driven Discovery 158 - 159 - Blonk prioritizes **community vibes over algorithmic feeds**: 160 - 161 - - Communities form organically around shared interests 162 - - Content quality emerges through peer grooves 163 - - Cross-vibe discovery happens through universal tags 164 - - Trending content reflects genuine community engagement 165 - 166 - ### Decentralized Social 167 - 168 - Built on ATProto for true decentralization: 169 - 170 - - **Data Portability**: Your content, your control 171 - - **Cross-Platform**: Records work across ATProto apps 172 - - **Community Ownership**: Vibes and tags are community resources 173 - - **Open Protocol**: Extensible and interoperable 174 - 175 - ## 🛠️ Development 176 - 177 - ### Project Structure 178 - 179 - ``` 180 - lib/ 181 - ├── elixir_blonk/ # Core business logic 182 - │ ├── vibes/ # Community topic management 183 - │ ├── blips/ # Content submission system 184 - │ ├── grooves/ # Community engagement 185 - │ ├── tags/ # Universal tag system 186 - │ ├── blip_tags/ # Tag associations 187 - │ ├── hot_posts/ # AI content curation 188 - │ ├── atproto/ # ATProto client & sync 189 - │ └── firehose/ # Real-time data ingestion 190 - ├── elixir_blonk_web/ # Phoenix web interface 191 - └── priv/repo/migrations/ # Database schema 192 - ``` 193 - 194 - ### Key Services 195 - 196 - - **SessionManager**: ATProto authentication & session management 197 - - **Firehose.Consumer**: Real-time Bluesky data ingestion 198 - - **HotPostSweeper**: AI-driven content curation 199 - - **ATProto.Client**: Custom record type operations 200 - 201 - ### Testing 202 - 203 - ```bash 204 - # Run tests 205 - mix test 206 - 207 - # Run with coverage 208 - mix test --cover 209 - ``` 210 - 211 - ## 📈 Roadmap 212 - 213 - ### Phase 1: Community Bootstrap ✅ 214 - - [x] Basic vibe/blip/groove system 215 - - [x] ATProto integration 216 - - [x] Hot post AI curation 217 - - [x] Universal tag system 218 - 219 - ### Phase 2: Enhanced Discovery 220 - - [ ] Advanced radar algorithms 221 - - [ ] User following/recommendations 222 - - [ ] Cross-vibe trending 223 - - [ ] Mobile app 224 - 225 - ### Phase 3: Community Tools 226 - - [ ] Vibe moderation tools 227 - - [ ] Community governance 228 - - [ ] Creator monetization 229 - - [ ] External integrations 230 - 231 - ## 🤝 Contributing 232 - 233 - We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. 234 - 235 - ### Development Setup 236 - 237 - 1. Fork the repository 238 - 2. Create feature branch (`git checkout -b feature/amazing-feature`) 239 - 3. Commit changes (`git commit -m 'Add amazing feature'`) 240 - 4. Push to branch (`git push origin feature/amazing-feature`) 241 - 5. Open Pull Request 242 - 243 - ## 📄 License 244 - 245 - This project is licensed under the MIT License - see [LICENSE](LICENSE) for details. 246 - 247 - ## 🙏 Acknowledgments 248 - 249 - - **ATProto Team** - For the decentralized social protocol 250 - - **Bluesky** - For the firehose API and ecosystem 251 - - **Phoenix/Elixir** - For the robust web framework 252 - - **Community** - For making vibes happen 253 - 254 - --- 255 - 256 - **Ready to find your vibe?** 🌊 257 - 258 - Start exploring at [blonk.app](https://blonk.app) or run your own instance!
elixir_blonk/assets/css/app.css assets/css/app.css
elixir_blonk/assets/js/app.js assets/js/app.js
elixir_blonk/assets/tailwind.config.js assets/tailwind.config.js
elixir_blonk/assets/vendor/topbar.js assets/vendor/topbar.js
elixir_blonk/config/config.exs config/config.exs
elixir_blonk/config/dev.exs config/dev.exs
elixir_blonk/config/prod.exs config/prod.exs
elixir_blonk/config/runtime.exs config/runtime.exs
elixir_blonk/config/test.exs config/test.exs
elixir_blonk/lib/elixir_blonk.ex lib/elixir_blonk.ex
elixir_blonk/lib/elixir_blonk/accounts.ex lib/elixir_blonk/accounts.ex
elixir_blonk/lib/elixir_blonk/accounts/user.ex lib/elixir_blonk/accounts/user.ex
elixir_blonk/lib/elixir_blonk/accounts/user_notifier.ex lib/elixir_blonk/accounts/user_notifier.ex
elixir_blonk/lib/elixir_blonk/accounts/user_token.ex lib/elixir_blonk/accounts/user_token.ex
elixir_blonk/lib/elixir_blonk/application.ex lib/elixir_blonk/application.ex
+60 -10
elixir_blonk/lib/elixir_blonk/atproto.ex lib/elixir_blonk/atproto.ex
··· 1 1 defmodule ElixirBlonk.ATProto do 2 2 @moduledoc """ 3 - Simple ATProto API client for Blonk operations. 3 + Simple, direct ATProto API client for Blonk's decentralized social operations. 4 + 5 + This module provides a clean interface to ATProto services, handling authentication 6 + and making straightforward HTTP requests using Req. Designed to replace complex 7 + session management patterns with a simple, reliable approach. 4 8 5 - This module provides a straightforward interface to ATProto services, 6 - handling authentication and making direct HTTP requests using Req. 9 + ## Philosophy: Keep It Simple 10 + 11 + **Why simple?** Because ATProto is just HTTP APIs with bearer tokens: 12 + - No complex session managers or client wrappers 13 + - Direct Req calls with proper Authorization headers 14 + - Fail fast on authentication issues (critical for Blonk) 15 + - Clean error handling without overengineering 16 + 17 + ## Blonk Integration 18 + 19 + **Powers Blonk's decentralized architecture** by: 20 + - Creating custom record types (blips, vibes, tags, grooves) 21 + - Enabling cross-platform content discovery via ATProto 22 + - Providing engagement analysis for hot post curation 23 + - Maintaining data portability and user ownership 7 24 8 - ## Authentication 25 + ## Authentication Strategy 9 26 10 - Uses app passwords for authentication, storing the access token in 11 - process state for subsequent requests. 27 + Uses **app passwords** for secure, long-lived authentication: 28 + - Authenticate once with user credentials 29 + - Receive access token for subsequent requests 30 + - Store token in client struct for reuse 31 + - System fails fast if authentication fails (no silent degradation) 12 32 13 - ## Usage 33 + ## Custom Record Types 14 34 15 - # Authenticate once 35 + Blonk defines several custom NSIDs for community features: 36 + - `com.blonk.blip` - Content submissions to vibes 37 + - `com.blonk.tag` - Universal community labels 38 + - `com.blonk.blipTag` - Content categorization associations 39 + - `com.blonk.vibe` - Topic-based community feeds (future) 40 + - `com.blonk.groove` - Community engagement records (future) 41 + 42 + ## Error Handling 43 + 44 + **Fail fast and clear** approach: 45 + - Authentication failures crash the system (as intended) 46 + - API errors return structured `{:error, reason}` tuples 47 + - HTTP status codes properly mapped to error types 48 + - No silent failures that could confuse community features 49 + 50 + ## Examples 51 + 52 + # One-time authentication 16 53 {:ok, client} = ATProto.authenticate() 17 54 18 - # Make API calls 55 + # Create Blonk records 56 + {:ok, %{uri: uri, cid: cid}} = ATProto.create_blip(client, blip) 57 + {:ok, %{uri: uri, cid: cid}} = ATProto.create_tag(client, tag) 58 + 59 + # Analyze engagement for hot posts 60 + {:ok, %{reply_count: count}} = ATProto.get_post_engagement(client, post_uri) 61 + 62 + # Direct record creation 19 63 {:ok, %{uri: uri, cid: cid}} = ATProto.create_record(client, "com.blonk.blip", record) 20 - {:ok, post} = ATProto.get_post(client, post_uri) 64 + 65 + ## Performance Characteristics 66 + 67 + - **Lightweight**: Just HTTP calls with bearer token headers 68 + - **Concurrent**: Multiple requests can use the same client 69 + - **Resilient**: Network errors don't break authentication state 70 + - **Efficient**: No unnecessary abstraction layers or state management 21 71 """ 22 72 23 73 require Logger
elixir_blonk/lib/elixir_blonk/atproto/client.ex lib/elixir_blonk/atproto/client.ex
elixir_blonk/lib/elixir_blonk/atproto/session_manager.ex lib/elixir_blonk/atproto/session_manager.ex
-47
elixir_blonk/lib/elixir_blonk/atproto/simple_session.ex
··· 1 - defmodule ElixirBlonk.ATProto.SimpleSession do 2 - @moduledoc """ 3 - Simple session manager that maintains a single authenticated ATProto client. 4 - 5 - This replaces the complex SessionManager with a straightforward approach: 6 - - Authenticate once on startup 7 - - Store the client in GenServer state 8 - - Provide the client for API calls 9 - - Fail fast if authentication fails 10 - """ 11 - 12 - use GenServer 13 - require Logger 14 - 15 - def start_link(opts) do 16 - GenServer.start_link(__MODULE__, opts, name: __MODULE__) 17 - end 18 - 19 - @doc """ 20 - Get the authenticated ATProto client. 21 - """ 22 - def get_client do 23 - GenServer.call(__MODULE__, :get_client) 24 - end 25 - 26 - # GenServer callbacks 27 - 28 - @impl true 29 - def init(_opts) do 30 - Logger.info("Authenticating with ATProto...") 31 - 32 - case ElixirBlonk.ATProto.authenticate() do 33 - {:ok, client} -> 34 - Logger.info("ATProto authentication successful") 35 - {:ok, %{client: client}} 36 - 37 - {:error, reason} -> 38 - Logger.error("CRITICAL: ATProto authentication failed: #{inspect(reason)}") 39 - {:stop, {:atproto_auth_failed, reason}} 40 - end 41 - end 42 - 43 - @impl true 44 - def handle_call(:get_client, _from, %{client: client} = state) do 45 - {:reply, {:ok, client}, state} 46 - end 47 - end
elixir_blonk/lib/elixir_blonk/atproto/sync.ex lib/elixir_blonk/atproto/sync.ex
elixir_blonk/lib/elixir_blonk/blip_tags.ex lib/elixir_blonk/blip_tags.ex
elixir_blonk/lib/elixir_blonk/blip_tags/blip_tag.ex lib/elixir_blonk/blip_tags/blip_tag.ex
+74 -1
elixir_blonk/lib/elixir_blonk/blips.ex lib/elixir_blonk/blips.ex
··· 1 1 defmodule ElixirBlonk.Blips do 2 2 @moduledoc """ 3 - The Blips context. 3 + The Blips context for managing content submissions in the Blonk ecosystem. 4 + 5 + Blips are the fundamental content unit in Blonk - posts submitted to vibes that appear 6 + on the radar for community engagement. This context orchestrates blip creation, discovery, 7 + and the integration with Blonk's universal tag system and ATProto records. 8 + 9 + ## What Are Blips? 10 + 11 + **Blips are content submissions that create community engagement:** 12 + - Posts with title, optional body/URL, and tags 13 + - Submitted to specific vibes for topical organization 14 + - Appear on the radar for cross-vibe discovery 15 + - Receive grooves (looks_good/shit_rips) from community 16 + - Enable organic vibe creation through engagement patterns 17 + 18 + ## Blonk Ecosystem Integration 19 + 20 + - **Vibes**: Blips are submitted to topic-based communities 21 + - **Radar**: Popular blips surface on the frontpage across vibes 22 + - **Tags**: Universal labels enable cross-vibe content discovery 23 + - **Grooves**: Community engagement drives blip visibility 24 + - **ATProto**: Each blip becomes a `com.blonk.blip` record for portability 25 + 26 + ## Content Lifecycle 27 + 28 + 1. **Submission**: User creates blip with title, body, tags for a vibe 29 + 2. **Tag Extraction**: System automatically extracts #hashtags from content 30 + 3. **ATProto Creation**: Blip becomes decentralized record with URI/CID 31 + 4. **Community Discovery**: Appears in vibe feeds and radar trending 32 + 5. **Engagement**: Users groove on content, driving popularity 33 + 6. **Cross-Vibe Discovery**: Tags enable finding related content across vibes 34 + 35 + ## Community Engagement Model 36 + 37 + **Blips are designed to encourage quality content:** 38 + - Submission to relevant vibes ensures targeted audience 39 + - Tag system enables broader discovery beyond vibe boundaries 40 + - Groove system (looks_good/shit_rips) provides clear feedback 41 + - Popular content surfaces on radar, attracting more engagement 42 + - External links in blips can become hot posts for community seeding 43 + 44 + ## Tag Integration 45 + 46 + **Universal tagging system** enhances content discovery: 47 + - Automatic extraction of #hashtags from blip text 48 + - Association with universal community-owned tag records 49 + - Cross-vibe discovery through shared tag vocabulary 50 + - Tag popularity tracking drives trending algorithms 51 + 52 + ## ATProto Integration 53 + 54 + **Decentralized content ownership** through ATProto records: 55 + - Each blip becomes a `com.blonk.blip` ATProto record 56 + - Content portability across ATProto applications 57 + - User ownership of content and engagement data 58 + - Cross-platform discoverability and interaction 59 + 60 + ## Examples 61 + 62 + # Create a blip for the crypto vibe 63 + {:ok, blip} = Blips.create_blip(%{ 64 + title: "New DeFi Protocol Launch", 65 + body: "Exciting developments in yield farming...", 66 + url: "https://protocol.xyz", 67 + vibe_uri: crypto_vibe.uri, 68 + tags: ["defi", "yield", "ethereum"], 69 + author_did: "did:plc:user123" 70 + }) 71 + 72 + # Find blips by tag across all vibes 73 + defi_blips = Blips.list_blips_by_tag("defi") 74 + 75 + # Search blips by content 76 + search_results = Blips.search_blips("protocol") 4 77 """ 5 78 6 79 import Ecto.Query, warn: false
elixir_blonk/lib/elixir_blonk/blips/blip.ex lib/elixir_blonk/blips/blip.ex
elixir_blonk/lib/elixir_blonk/blips/comment.ex lib/elixir_blonk/blips/comment.ex
+82
elixir_blonk/lib/elixir_blonk/firehose/consumer.ex lib/elixir_blonk/firehose/consumer.ex
··· 1 1 defmodule ElixirBlonk.Firehose.Consumer do 2 + @moduledoc """ 3 + Real-time Bluesky firehose consumer that powers Blonk's community discovery and seeding. 4 + 5 + This WebSocket consumer connects to Bluesky's real-time firehose to capture posts as 6 + they're created, enabling two critical Blonk functions: organic vibe creation through 7 + #vibe-name mentions and AI-driven community seeding through hot post detection. 8 + 9 + ## Core Functions 10 + 11 + **1. Vibe Discovery** - Monitors for `#vibe-name` hashtags to create new communities 12 + **2. Hot Post Sampling** - Captures 1 in 10 posts with links for trending analysis 13 + 14 + ## Why the Firehose? 15 + 16 + **Real-time community formation** requires immediate detection of: 17 + - New vibe mentions that could spawn communities 18 + - Trending external content that could seed engagement 19 + - Community activity patterns across the ATProto network 20 + 21 + ## Blonk Integration Strategy 22 + 23 + - **Vibe Creation**: `#vibe-crypto` mentions accumulate until reaching critical mass 24 + - **Content Seeding**: Posts with links get sampled for potential trending analysis 25 + - **Community Bootstrap**: External content helps solve the "empty restaurant" problem 26 + - **Organic Growth**: Real community formation based on actual user interest 27 + 28 + ## Performance Characteristics 29 + 30 + **Designed for high-throughput, low-latency processing:** 31 + - WebSocket connection for real-time data stream 32 + - Async processing to prevent firehose backpressure 33 + - Smart sampling (1 in 10) to avoid overwhelming the system 34 + - Non-blocking operations that don't affect user experience 35 + 36 + ## Data Flow 37 + 38 + 1. **Firehose Stream**: Receives real-time posts from Bluesky network 39 + 2. **Vibe Detection**: Scans for #vibe-name patterns in post text 40 + 3. **Link Sampling**: Identifies posts with external links for hot post analysis 41 + 4. **Async Processing**: Hands off to appropriate handlers without blocking 42 + 5. **Community Impact**: Powers both organic vibe creation and content seeding 43 + 44 + ## Error Handling 45 + 46 + **Resilient by design** to handle network issues and data anomalies: 47 + - Automatic reconnection after disconnects 48 + - Graceful handling of malformed messages 49 + - Continued operation even if individual posts fail processing 50 + - Comprehensive logging for debugging community growth patterns 51 + 52 + ## Community Growth Engine 53 + 54 + The firehose consumer is **Blonk's community growth engine** because it: 55 + - Detects organic community formation through vibe mentions 56 + - Seeds new communities with relevant trending content 57 + - Provides real-time responsiveness to user interests 58 + - Scales community discovery with network growth 59 + 60 + ## Sampling Strategy 61 + 62 + **1 in 10 posts with links** balances: 63 + - **Quality**: Enough samples to catch trending content 64 + - **Performance**: Doesn't overwhelm the hot post analysis system 65 + - **Freshness**: Regular sampling ensures recent trends are captured 66 + - **Diversity**: Broad coverage across different topics and communities 67 + 68 + ## Examples 69 + 70 + # Vibe mention detection 71 + "I love this new #vibe-solana ecosystem!" 72 + → Records vibe mention for potential community creation 73 + 74 + # Hot post sampling 75 + "Check out this amazing new tool: https://cool-tool.com" 76 + → 10% chance of being saved for trending analysis 77 + 78 + # Community seeding result 79 + → Hot post with 8 replies becomes blip in bsky_hot vibe 80 + → Users groove on it, driving engagement 81 + → Topic tags inspire new organic vibes 82 + """ 83 + 2 84 use WebSockex 3 85 require Logger 4 86
elixir_blonk/lib/elixir_blonk/firehose/supervisor.ex lib/elixir_blonk/firehose/supervisor.ex
-145
elixir_blonk/lib/elixir_blonk/grooves.ex
··· 1 - defmodule ElixirBlonk.Grooves do 2 - @moduledoc """ 3 - The Grooves context. 4 - """ 5 - 6 - import Ecto.Query, warn: false 7 - alias ElixirBlonk.Repo 8 - 9 - alias ElixirBlonk.Grooves.Groove 10 - alias ElixirBlonk.Blips 11 - 12 - @doc """ 13 - Creates a groove (reaction) for a blip. 14 - """ 15 - def create_groove(attrs \\ %{}) do 16 - # Find the blip by subject_uri if provided 17 - attrs = if attrs[:subject_uri] do 18 - case Blips.get_blip_by_uri(attrs[:subject_uri]) do 19 - nil -> attrs 20 - blip -> Map.put(attrs, :blip_id, blip.id) 21 - end 22 - else 23 - attrs 24 - end 25 - 26 - %Groove{} 27 - |> Groove.changeset(attrs) 28 - |> Repo.insert() 29 - |> case do 30 - {:ok, groove} -> 31 - # Update groove counts on the blip 32 - if groove.blip_id do 33 - Blips.update_groove_counts(groove.blip_id) 34 - end 35 - {:ok, groove} 36 - error -> error 37 - end 38 - end 39 - 40 - @doc """ 41 - Deletes a groove. 42 - """ 43 - def delete_groove(%Groove{} = groove) do 44 - result = Repo.delete(groove) 45 - 46 - # Update groove counts on the blip 47 - if groove.blip_id do 48 - Blips.update_groove_counts(groove.blip_id) 49 - end 50 - 51 - result 52 - end 53 - 54 - @doc """ 55 - Gets a groove by author and subject. 56 - """ 57 - def get_groove_by_author_and_subject(author_did, subject_uri) do 58 - Groove 59 - |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 60 - |> Repo.one() 61 - end 62 - 63 - @doc """ 64 - Toggles a groove - creates if doesn't exist, changes type if different, deletes if same. 65 - """ 66 - def toggle_groove(author_did, subject_uri, groove_type, attrs \\ %{}) do 67 - case get_groove_by_author_and_subject(author_did, subject_uri) do 68 - nil -> 69 - # Create new groove 70 - attrs = Map.merge(attrs, %{ 71 - author_did: author_did, 72 - subject_uri: subject_uri, 73 - groove_type: groove_type 74 - }) 75 - create_groove(attrs) 76 - 77 - %Groove{groove_type: ^groove_type} = groove -> 78 - # Same type, so remove it 79 - delete_groove(groove) 80 - {:ok, nil} 81 - 82 - groove -> 83 - # Different type, update it 84 - groove 85 - |> Groove.changeset(%{groove_type: groove_type}) 86 - |> Repo.update() 87 - |> case do 88 - {:ok, updated_groove} -> 89 - # Update counts 90 - if updated_groove.blip_id do 91 - Blips.update_groove_counts(updated_groove.blip_id) 92 - end 93 - {:ok, updated_groove} 94 - error -> error 95 - end 96 - end 97 - end 98 - 99 - @doc """ 100 - Lists all grooves for a blip. 101 - """ 102 - def list_grooves_for_blip(blip_id) do 103 - Groove 104 - |> where([g], g.blip_id == ^blip_id) 105 - |> Repo.all() 106 - end 107 - 108 - @doc """ 109 - Lists all grooves by a specific author. 110 - """ 111 - def list_grooves_by_author(author_did) do 112 - Groove 113 - |> where([g], g.author_did == ^author_did) 114 - |> preload(:blip) 115 - |> Repo.all() 116 - end 117 - 118 - @doc """ 119 - Counts grooves by type for a blip. 120 - """ 121 - def count_grooves_by_type(blip_id, groove_type) do 122 - Groove 123 - |> where([g], g.blip_id == ^blip_id and g.groove_type == ^groove_type) 124 - |> Repo.aggregate(:count) 125 - end 126 - 127 - @doc """ 128 - Checks if an author has grooved a specific blip. 129 - """ 130 - def has_grooved?(author_did, subject_uri) do 131 - Groove 132 - |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 133 - |> Repo.exists?() 134 - end 135 - 136 - @doc """ 137 - Gets the groove type for an author on a specific blip. 138 - """ 139 - def get_groove_type(author_did, subject_uri) do 140 - Groove 141 - |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 142 - |> select([g], g.groove_type) 143 - |> Repo.one() 144 - end 145 - end
elixir_blonk/lib/elixir_blonk/grooves/groove.ex lib/elixir_blonk/grooves/groove.ex
-134
elixir_blonk/lib/elixir_blonk/hot_post_sweeper.ex
··· 1 - defmodule ElixirBlonk.HotPostSweeper do 2 - @moduledoc """ 3 - GenServer that periodically sweeps hot posts to check for engagement 4 - and creates blips for trending content. 5 - """ 6 - 7 - use GenServer 8 - require Logger 9 - 10 - alias ElixirBlonk.{HotPosts, Vibes, Blips} 11 - 12 - # Check every 10 minutes 13 - @sweep_interval_ms 10 * 60 * 1000 14 - 15 - def start_link(opts \\ []) do 16 - GenServer.start_link(__MODULE__, opts, name: __MODULE__) 17 - end 18 - 19 - @impl true 20 - def init(_opts) do 21 - Logger.info("Starting HotPostSweeper - checking posts every 10 minutes") 22 - 23 - # Schedule the first sweep 24 - schedule_sweep() 25 - 26 - {:ok, %{}} 27 - end 28 - 29 - @impl true 30 - def handle_info(:sweep, state) do 31 - Logger.info("Starting hot post sweep") 32 - 33 - try do 34 - # Get posts to check (up to 25) 35 - posts_to_check = HotPosts.get_posts_for_checking(25) 36 - Logger.info("Found #{length(posts_to_check)} posts to check for replies") 37 - 38 - # Check each post for replies 39 - Enum.each(posts_to_check, &check_post_replies/1) 40 - 41 - # Clean up old posts 42 - cleanup_count = HotPosts.cleanup_old_posts() 43 - if cleanup_count > 0 do 44 - Logger.info("Cleaned up #{cleanup_count} old hot posts") 45 - end 46 - 47 - # Create blips for trending posts 48 - create_blips_for_trending() 49 - 50 - rescue 51 - error -> 52 - Logger.error("Error in hot post sweep: #{inspect(error)}") 53 - end 54 - 55 - # Schedule next sweep 56 - schedule_sweep() 57 - 58 - {:noreply, state} 59 - end 60 - 61 - defp schedule_sweep do 62 - Process.send_after(self(), :sweep, @sweep_interval_ms) 63 - end 64 - 65 - defp check_post_replies(hot_post) do 66 - Logger.debug("Checking replies for post: #{hot_post.post_uri}") 67 - 68 - case get_post_reply_count(hot_post.post_uri) do 69 - {:ok, reply_count} -> 70 - Logger.debug("Post #{hot_post.post_uri} has #{reply_count} replies") 71 - HotPosts.update_hot_post_check(hot_post, reply_count) 72 - 73 - {:error, reason} -> 74 - Logger.warning("Failed to check replies for #{hot_post.post_uri}: #{inspect(reason)}") 75 - # Still increment check count even if API failed 76 - HotPosts.update_hot_post_check(hot_post, hot_post.reply_count) 77 - end 78 - end 79 - 80 - defp get_post_reply_count(post_uri) do 81 - case ElixirBlonk.ATProto.SimpleSession.get_client() do 82 - {:ok, client} -> 83 - ElixirBlonk.ATProto.get_post_engagement(client, post_uri) 84 - 85 - {:error, reason} -> 86 - {:error, reason} 87 - end 88 - end 89 - 90 - defp create_blips_for_trending do 91 - trending_posts = HotPosts.get_trending_posts(5) 92 - 93 - if length(trending_posts) > 0 do 94 - Logger.info("Found #{length(trending_posts)} trending posts to convert to blips") 95 - end 96 - 97 - Enum.each(trending_posts, &create_blip_from_hot_post/1) 98 - end 99 - 100 - defp create_blip_from_hot_post(hot_post) do 101 - case Vibes.get_vibe_by_name("bsky_hot") do 102 - nil -> 103 - Logger.error("bsky_hot vibe not found - cannot create hot blip") 104 - 105 - bsky_hot_vibe -> 106 - blip_params = %{ 107 - uri: "at://blonk.app/blip/#{Ecto.UUID.generate()}", 108 - cid: "bafyrei#{:crypto.strong_rand_bytes(32) |> Base.encode32(case: :lower, padding: false)}", 109 - author_did: hot_post.author_did, 110 - title: truncate_text(hot_post.text || "", 100), 111 - body: hot_post.text || "", 112 - url: hot_post.external_url || hot_post.post_uri, 113 - tags: ["trending", "hot", "bsky"], 114 - vibe_id: bsky_hot_vibe.id, 115 - vibe_uri: bsky_hot_vibe.uri, 116 - grooves_looks_good: 0, 117 - grooves_shit_rips: 0, 118 - indexed_at: DateTime.utc_now() 119 - } 120 - 121 - case Blips.create_blip(blip_params) do 122 - {:ok, blip} -> 123 - Logger.info("Created hot blip: #{String.slice(blip.title, 0, 50)}... (#{hot_post.reply_count} replies)") 124 - HotPosts.mark_as_converted(hot_post) 125 - 126 - {:error, reason} -> 127 - Logger.error("Failed to create hot blip: #{inspect(reason)}") 128 - end 129 - end 130 - end 131 - 132 - defp truncate_text(text, max_length) when byte_size(text) <= max_length, do: text 133 - defp truncate_text(text, max_length), do: String.slice(text, 0, max_length) <> "..." 134 - end
-76
elixir_blonk/lib/elixir_blonk/hot_posts.ex
··· 1 - defmodule ElixirBlonk.HotPosts do 2 - @moduledoc """ 3 - The HotPosts context for managing potential trending content. 4 - """ 5 - 6 - import Ecto.Query, warn: false 7 - alias ElixirBlonk.Repo 8 - alias ElixirBlonk.HotPosts.HotPost 9 - 10 - @doc """ 11 - Creates a hot post record for later processing. 12 - """ 13 - def create_hot_post(attrs \\ %{}) do 14 - %HotPost{} 15 - |> HotPost.changeset(attrs) 16 - |> Repo.insert() 17 - end 18 - 19 - @doc """ 20 - Gets posts ready for reply checking. 21 - Returns up to `limit` posts that haven't been checked too many times. 22 - """ 23 - def get_posts_for_checking(limit \\ 25) do 24 - HotPost 25 - |> where([h], h.check_count < 10) 26 - |> where([h], h.inserted_at > ago(1, "day")) 27 - |> order_by([h], asc: h.inserted_at) 28 - |> limit(^limit) 29 - |> Repo.all() 30 - end 31 - 32 - @doc """ 33 - Updates the check count and reply count for a hot post. 34 - """ 35 - def update_hot_post_check(hot_post, reply_count) do 36 - hot_post 37 - |> HotPost.update_changeset(%{ 38 - check_count: hot_post.check_count + 1, 39 - reply_count: reply_count, 40 - last_checked_at: DateTime.utc_now() 41 - }) 42 - |> Repo.update() 43 - end 44 - 45 - @doc """ 46 - Deletes old or fully processed hot posts. 47 - """ 48 - def cleanup_old_posts do 49 - # Delete posts older than 1 day OR that have been checked 10 times 50 - {count, _} = 51 - HotPost 52 - |> where([h], h.inserted_at < ago(1, "day") or h.check_count >= 10) 53 - |> Repo.delete_all() 54 - 55 - count 56 - end 57 - 58 - @doc """ 59 - Gets all hot posts with high reply counts that haven't been converted to blips yet. 60 - """ 61 - def get_trending_posts(min_replies \\ 5) do 62 - HotPost 63 - |> where([h], h.reply_count >= ^min_replies) 64 - |> where([h], not h.converted_to_blip) 65 - |> Repo.all() 66 - end 67 - 68 - @doc """ 69 - Marks a hot post as converted to a blip. 70 - """ 71 - def mark_as_converted(hot_post) do 72 - hot_post 73 - |> HotPost.update_changeset(%{converted_to_blip: true}) 74 - |> Repo.update() 75 - end 76 - end
-37
elixir_blonk/lib/elixir_blonk/hot_posts/hot_post.ex
··· 1 - defmodule ElixirBlonk.HotPosts.HotPost do 2 - use Ecto.Schema 3 - import Ecto.Changeset 4 - 5 - @primary_key {:id, :binary_id, autogenerate: true} 6 - @foreign_key_type :binary_id 7 - schema "hot_posts" do 8 - field :post_uri, :string 9 - field :author_did, :string 10 - field :text, :string 11 - field :external_url, :string 12 - field :record_data, :map # Store the full ATProto record 13 - field :check_count, :integer, default: 0 14 - field :reply_count, :integer, default: 0 15 - field :converted_to_blip, :boolean, default: false 16 - field :last_checked_at, :utc_datetime 17 - 18 - timestamps(type: :utc_datetime) 19 - end 20 - 21 - @doc false 22 - def changeset(hot_post, attrs) do 23 - hot_post 24 - |> cast(attrs, [ 25 - :post_uri, :author_did, :text, :external_url, :record_data, 26 - :check_count, :reply_count, :converted_to_blip, :last_checked_at 27 - ]) 28 - |> validate_required([:post_uri, :author_did]) 29 - |> unique_constraint(:post_uri) 30 - end 31 - 32 - @doc false 33 - def update_changeset(hot_post, attrs) do 34 - hot_post 35 - |> cast(attrs, [:check_count, :reply_count, :converted_to_blip, :last_checked_at]) 36 - end 37 - end
elixir_blonk/lib/elixir_blonk/mailer.ex lib/elixir_blonk/mailer.ex
elixir_blonk/lib/elixir_blonk/repo.ex lib/elixir_blonk/repo.ex
elixir_blonk/lib/elixir_blonk/tags.ex lib/elixir_blonk/tags.ex
elixir_blonk/lib/elixir_blonk/tags/tag.ex lib/elixir_blonk/tags/tag.ex
-221
elixir_blonk/lib/elixir_blonk/vibes.ex
··· 1 - defmodule ElixirBlonk.Vibes do 2 - @moduledoc """ 3 - The Vibes context. 4 - """ 5 - 6 - import Ecto.Query, warn: false 7 - require Logger 8 - alias ElixirBlonk.Repo 9 - 10 - alias ElixirBlonk.Vibes.{Vibe, VibeMember, VibeMention} 11 - 12 - @doc """ 13 - Returns the list of vibes. 14 - """ 15 - def list_vibes do 16 - Repo.all(Vibe) 17 - end 18 - 19 - @doc """ 20 - Returns the list of vibes ordered by pulse score. 21 - """ 22 - def list_vibes_by_pulse do 23 - Vibe 24 - |> order_by([v], desc: v.pulse_score) 25 - |> Repo.all() 26 - end 27 - 28 - @doc """ 29 - Returns the list of emerging vibes. 30 - """ 31 - def list_emerging_vibes do 32 - Vibe 33 - |> where([v], v.is_emerging == true) 34 - |> order_by([v], desc: v.pulse_score) 35 - |> Repo.all() 36 - end 37 - 38 - @doc """ 39 - Gets a single vibe. 40 - """ 41 - def get_vibe!(id), do: Repo.get!(Vibe, id) 42 - 43 - @doc """ 44 - Gets a vibe by URI. 45 - """ 46 - def get_vibe_by_uri(uri) do 47 - Repo.get_by(Vibe, uri: uri) 48 - end 49 - 50 - @doc """ 51 - Gets a vibe by name. 52 - """ 53 - def get_vibe_by_name(name) do 54 - Repo.get_by(Vibe, name: name) 55 - end 56 - 57 - @doc """ 58 - Creates a vibe. 59 - """ 60 - def create_vibe(attrs \\ %{}) do 61 - # First create in local database 62 - with {:ok, vibe} <- %Vibe{} 63 - |> Vibe.changeset(attrs) 64 - |> Repo.insert() do 65 - 66 - # Then try to create in ATProto if enabled 67 - if Application.get_env(:elixir_blonk, :atproto_enabled, true) do 68 - Task.Supervisor.start_child(ElixirBlonk.TaskSupervisor, fn -> 69 - create_vibe_in_atproto(vibe) 70 - end) 71 - end 72 - 73 - {:ok, vibe} 74 - end 75 - end 76 - 77 - defp create_vibe_in_atproto(vibe) do 78 - with {:ok, client} <- ElixirBlonk.ATProto.SessionManager.get_client(), 79 - {:ok, %{uri: uri, cid: cid}} <- ElixirBlonk.ATProto.Client.create_vibe(client, vibe) do 80 - 81 - # Update local record with ATProto URI and CID 82 - update_vibe(vibe, %{uri: uri, cid: cid}) 83 - Logger.info("Created vibe in ATProto: #{uri}") 84 - else 85 - {:error, reason} -> 86 - Logger.error("Failed to create vibe in ATProto: #{inspect(reason)}") 87 - end 88 - end 89 - 90 - @doc """ 91 - Updates a vibe. 92 - """ 93 - def update_vibe(%Vibe{} = vibe, attrs) do 94 - vibe 95 - |> Vibe.changeset(attrs) 96 - |> Repo.update() 97 - end 98 - 99 - @doc """ 100 - Deletes a vibe. 101 - """ 102 - def delete_vibe(%Vibe{} = vibe) do 103 - Repo.delete(vibe) 104 - end 105 - 106 - @doc """ 107 - Joins a user to a vibe. 108 - """ 109 - def join_vibe(member_did, vibe_id, attrs \\ %{}) do 110 - attrs = Map.merge(attrs, %{ 111 - member_did: member_did, 112 - vibe_id: vibe_id 113 - }) 114 - 115 - %VibeMember{} 116 - |> VibeMember.changeset(attrs) 117 - |> Repo.insert() 118 - |> case do 119 - {:ok, member} -> 120 - update_member_count(vibe_id) 121 - {:ok, member} 122 - error -> error 123 - end 124 - end 125 - 126 - @doc """ 127 - Checks if a user is a member of a vibe. 128 - """ 129 - def is_member?(member_did, vibe_uri) do 130 - VibeMember 131 - |> where([vm], vm.member_did == ^member_did and vm.vibe_uri == ^vibe_uri) 132 - |> Repo.exists?() 133 - end 134 - 135 - @doc """ 136 - Updates the member count for a vibe. 137 - """ 138 - def update_member_count(vibe_id) do 139 - count = VibeMember 140 - |> where([vm], vm.vibe_id == ^vibe_id) 141 - |> Repo.aggregate(:count) 142 - 143 - vibe = Repo.get!(Vibe, vibe_id) 144 - update_vibe(vibe, %{member_count: count}) 145 - end 146 - 147 - @doc """ 148 - Records a vibe mention. 149 - """ 150 - def record_vibe_mention(attrs) do 151 - %VibeMention{} 152 - |> VibeMention.changeset(attrs) 153 - |> Repo.insert() 154 - |> case do 155 - {:ok, mention} -> 156 - check_and_formalize_vibe(mention.vibe_name) 157 - {:ok, mention} 158 - error -> error 159 - end 160 - end 161 - 162 - @doc """ 163 - Checks if a vibe should be formalized based on mention thresholds. 164 - """ 165 - def check_and_formalize_vibe(vibe_name) do 166 - unique_authors = VibeMention 167 - |> where([vm], vm.vibe_name == ^vibe_name) 168 - |> distinct([vm], vm.author_did) 169 - |> Repo.aggregate(:count) 170 - 171 - total_mentions = VibeMention 172 - |> where([vm], vm.vibe_name == ^vibe_name) 173 - |> Repo.aggregate(:count) 174 - 175 - if unique_authors >= 5 or total_mentions >= 10 do 176 - unless get_vibe_by_name(vibe_name) do 177 - case create_vibe(%{ 178 - uri: "at://blonk.app/vibe/#{vibe_name}", 179 - cid: "bafyrei#{:crypto.strong_rand_bytes(32) |> Base.encode32(case: :lower, padding: false)}", 180 - creator_did: "did:plc:blonk", 181 - name: vibe_name, 182 - mood: vibe_name, 183 - is_emerging: false 184 - }) do 185 - {:ok, vibe} -> 186 - # Broadcast the emergence 187 - Phoenix.PubSub.broadcast( 188 - ElixirBlonk.PubSub, 189 - "vibes:emerged", 190 - {:vibe_emerged, vibe} 191 - ) 192 - {:ok, vibe} 193 - error -> error 194 - end 195 - end 196 - end 197 - end 198 - 199 - @doc """ 200 - Gets vibe mention statistics. 201 - """ 202 - def get_vibe_mention_stats do 203 - VibeMention 204 - |> group_by([vm], vm.vibe_name) 205 - |> select([vm], %{ 206 - vibe_name: vm.vibe_name, 207 - total_mentions: count(vm.id), 208 - unique_authors: count(fragment("DISTINCT ?", vm.author_did)) 209 - }) 210 - |> Repo.all() 211 - end 212 - 213 - @doc """ 214 - Updates pulse scores for all vibes based on recent activity. 215 - """ 216 - def update_pulse_scores do 217 - # This would be called periodically to update vibe pulse scores 218 - # based on recent blip activity, member count, etc. 219 - # Implementation depends on specific scoring algorithm 220 - end 221 - end
elixir_blonk/lib/elixir_blonk/vibes/vibe.ex lib/elixir_blonk/vibes/vibe.ex
elixir_blonk/lib/elixir_blonk/vibes/vibe_member.ex lib/elixir_blonk/vibes/vibe_member.ex
elixir_blonk/lib/elixir_blonk/vibes/vibe_mention.ex lib/elixir_blonk/vibes/vibe_mention.ex
elixir_blonk/lib/elixir_blonk_web.ex lib/elixir_blonk_web.ex
elixir_blonk/lib/elixir_blonk_web/components/core_components.ex lib/elixir_blonk_web/components/core_components.ex
elixir_blonk/lib/elixir_blonk_web/components/layouts.ex lib/elixir_blonk_web/components/layouts.ex
elixir_blonk/lib/elixir_blonk_web/components/layouts/app.html.heex lib/elixir_blonk_web/components/layouts/app.html.heex
elixir_blonk/lib/elixir_blonk_web/components/layouts/root.html.heex lib/elixir_blonk_web/components/layouts/root.html.heex
elixir_blonk/lib/elixir_blonk_web/components/word_cloud_modal.ex lib/elixir_blonk_web/components/word_cloud_modal.ex
elixir_blonk/lib/elixir_blonk_web/controllers/error_html.ex lib/elixir_blonk_web/controllers/error_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/error_json.ex lib/elixir_blonk_web/controllers/error_json.ex
elixir_blonk/lib/elixir_blonk_web/controllers/page_controller.ex lib/elixir_blonk_web/controllers/page_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/page_html.ex lib/elixir_blonk_web/controllers/page_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/page_html/home.html.heex lib/elixir_blonk_web/controllers/page_html/home.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_confirmation_controller.ex lib/elixir_blonk_web/controllers/user_confirmation_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_confirmation_html.ex lib/elixir_blonk_web/controllers/user_confirmation_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_confirmation_html/edit.html.heex lib/elixir_blonk_web/controllers/user_confirmation_html/edit.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_confirmation_html/new.html.heex lib/elixir_blonk_web/controllers/user_confirmation_html/new.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_registration_controller.ex lib/elixir_blonk_web/controllers/user_registration_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_registration_html.ex lib/elixir_blonk_web/controllers/user_registration_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_registration_html/new.html.heex lib/elixir_blonk_web/controllers/user_registration_html/new.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_reset_password_controller.ex lib/elixir_blonk_web/controllers/user_reset_password_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_reset_password_html.ex lib/elixir_blonk_web/controllers/user_reset_password_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_reset_password_html/edit.html.heex lib/elixir_blonk_web/controllers/user_reset_password_html/edit.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_reset_password_html/new.html.heex lib/elixir_blonk_web/controllers/user_reset_password_html/new.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_session_controller.ex lib/elixir_blonk_web/controllers/user_session_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_session_html.ex lib/elixir_blonk_web/controllers/user_session_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_session_html/new.html.heex lib/elixir_blonk_web/controllers/user_session_html/new.html.heex
elixir_blonk/lib/elixir_blonk_web/controllers/user_settings_controller.ex lib/elixir_blonk_web/controllers/user_settings_controller.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_settings_html.ex lib/elixir_blonk_web/controllers/user_settings_html.ex
elixir_blonk/lib/elixir_blonk_web/controllers/user_settings_html/edit.html.heex lib/elixir_blonk_web/controllers/user_settings_html/edit.html.heex
elixir_blonk/lib/elixir_blonk_web/endpoint.ex lib/elixir_blonk_web/endpoint.ex
elixir_blonk/lib/elixir_blonk_web/gettext.ex lib/elixir_blonk_web/gettext.ex
elixir_blonk/lib/elixir_blonk_web/live/blip_live/form_component.ex lib/elixir_blonk_web/live/blip_live/form_component.ex
elixir_blonk/lib/elixir_blonk_web/live/blip_live/index.ex lib/elixir_blonk_web/live/blip_live/index.ex
elixir_blonk/lib/elixir_blonk_web/live/blip_live/index.html.heex lib/elixir_blonk_web/live/blip_live/index.html.heex
elixir_blonk/lib/elixir_blonk_web/live/blip_live/tag.ex lib/elixir_blonk_web/live/blip_live/tag.ex
elixir_blonk/lib/elixir_blonk_web/live/blip_live/tag.html.heex lib/elixir_blonk_web/live/blip_live/tag.html.heex
elixir_blonk/lib/elixir_blonk_web/live/vibe_live/index.ex lib/elixir_blonk_web/live/vibe_live/index.ex
elixir_blonk/lib/elixir_blonk_web/live/vibe_live/index.html.heex lib/elixir_blonk_web/live/vibe_live/index.html.heex
elixir_blonk/lib/elixir_blonk_web/live/vibe_live/show.ex lib/elixir_blonk_web/live/vibe_live/show.ex
elixir_blonk/lib/elixir_blonk_web/live/vibe_live/show.html.heex lib/elixir_blonk_web/live/vibe_live/show.html.heex
elixir_blonk/lib/elixir_blonk_web/router.ex lib/elixir_blonk_web/router.ex
elixir_blonk/lib/elixir_blonk_web/telemetry.ex lib/elixir_blonk_web/telemetry.ex
elixir_blonk/lib/elixir_blonk_web/user_auth.ex lib/elixir_blonk_web/user_auth.ex
elixir_blonk/mix.exs mix.exs
elixir_blonk/mix.lock mix.lock
elixir_blonk/priv/gettext/en/LC_MESSAGES/errors.po priv/gettext/en/LC_MESSAGES/errors.po
elixir_blonk/priv/gettext/errors.pot priv/gettext/errors.pot
elixir_blonk/priv/repo/migrations/.formatter.exs priv/repo/migrations/.formatter.exs
elixir_blonk/priv/repo/migrations/20250619210020_create_vibes.exs priv/repo/migrations/20250619210020_create_vibes.exs
elixir_blonk/priv/repo/migrations/20250619210100_create_blips.exs priv/repo/migrations/20250619210100_create_blips.exs
elixir_blonk/priv/repo/migrations/20250619210115_create_grooves.exs priv/repo/migrations/20250619210115_create_grooves.exs
elixir_blonk/priv/repo/migrations/20250619210126_create_vibe_members.exs priv/repo/migrations/20250619210126_create_vibe_members.exs
elixir_blonk/priv/repo/migrations/20250619210138_create_vibe_mentions.exs priv/repo/migrations/20250619210138_create_vibe_mentions.exs
elixir_blonk/priv/repo/migrations/20250619210149_create_comments.exs priv/repo/migrations/20250619210149_create_comments.exs
elixir_blonk/priv/repo/migrations/20250619221940_create_users_auth_tables.exs priv/repo/migrations/20250619221940_create_users_auth_tables.exs
elixir_blonk/priv/repo/migrations/20250619222140_add_atproto_fields_to_users.exs priv/repo/migrations/20250619222140_add_atproto_fields_to_users.exs
elixir_blonk/priv/repo/migrations/20250619230142_make_hashed_password_nullable.exs priv/repo/migrations/20250619230142_make_hashed_password_nullable.exs
elixir_blonk/priv/repo/migrations/20250620042140_create_hot_posts.exs priv/repo/migrations/20250620042140_create_hot_posts.exs
elixir_blonk/priv/repo/migrations/20250620042756_update_hot_posts_external_url_to_text.exs priv/repo/migrations/20250620042756_update_hot_posts_external_url_to_text.exs
elixir_blonk/priv/repo/migrations/20250620043347_create_tags.exs priv/repo/migrations/20250620043347_create_tags.exs
elixir_blonk/priv/repo/migrations/20250620043400_create_blip_tags.exs priv/repo/migrations/20250620043400_create_blip_tags.exs
elixir_blonk/priv/repo/migrations/20250620044014_update_tags_remove_author_constraint.exs priv/repo/migrations/20250620044014_update_tags_remove_author_constraint.exs
elixir_blonk/priv/repo/seed_bsky_hot_vibe.exs priv/repo/seed_bsky_hot_vibe.exs
elixir_blonk/priv/repo/seed_that_guy_vibe.exs priv/repo/seed_that_guy_vibe.exs
elixir_blonk/priv/repo/seeds.exs priv/repo/seeds.exs
elixir_blonk/priv/repo/test_bsky_hot_blip.exs priv/repo/test_bsky_hot_blip.exs
elixir_blonk/priv/repo/test_reply_count_api.exs priv/repo/test_reply_count_api.exs
elixir_blonk/priv/static/favicon.ico priv/static/favicon.ico
elixir_blonk/priv/static/images/logo.svg priv/static/images/logo.svg
elixir_blonk/priv/static/robots.txt priv/static/robots.txt
elixir_blonk/test/elixir_blonk/accounts_test.exs test/elixir_blonk/accounts_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/error_html_test.exs test/elixir_blonk_web/controllers/error_html_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/error_json_test.exs test/elixir_blonk_web/controllers/error_json_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/page_controller_test.exs test/elixir_blonk_web/controllers/page_controller_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/user_confirmation_controller_test.exs test/elixir_blonk_web/controllers/user_confirmation_controller_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/user_registration_controller_test.exs test/elixir_blonk_web/controllers/user_registration_controller_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/user_reset_password_controller_test.exs test/elixir_blonk_web/controllers/user_reset_password_controller_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/user_session_controller_test.exs test/elixir_blonk_web/controllers/user_session_controller_test.exs
elixir_blonk/test/elixir_blonk_web/controllers/user_settings_controller_test.exs test/elixir_blonk_web/controllers/user_settings_controller_test.exs
elixir_blonk/test/elixir_blonk_web/user_auth_test.exs test/elixir_blonk_web/user_auth_test.exs
elixir_blonk/test/support/conn_case.ex test/support/conn_case.ex
elixir_blonk/test/support/data_case.ex test/support/data_case.ex
elixir_blonk/test/support/fixtures/accounts_fixtures.ex test/support/fixtures/accounts_fixtures.ex
elixir_blonk/test/test_helper.exs test/test_helper.exs
elixir_blonk/test_firehose.exs test_firehose.exs
+100
lib/elixir_blonk/atproto/simple_session.ex
··· 1 + defmodule ElixirBlonk.ATProto.SimpleSession do 2 + @moduledoc """ 3 + Minimal session manager for Blonk's ATProto authentication needs. 4 + 5 + This GenServer maintains a single authenticated ATProto client for the entire 6 + application, replacing complex session management with a simple, reliable pattern 7 + that aligns with Blonk's "fail fast" philosophy. 8 + 9 + ## Why Simple? 10 + 11 + **Complex session management was causing authentication headaches:** 12 + - Over-engineered refresh token logic 13 + - Unnecessary client wrapper abstractions 14 + - Silent failures that broke community features 15 + - Debugging nightmares with nested state management 16 + 17 + ## New Approach: One Client, Clear Failures 18 + 19 + - **Authenticate once** on startup with app password 20 + - **Store client** in GenServer for all requests to use 21 + - **Fail immediately** if authentication fails (no retries) 22 + - **Crash the system** rather than silently degrade 23 + 24 + ## Blonk Integration 25 + 26 + **Critical for community features** that depend on ATProto: 27 + - HotPostSweeper needs authenticated calls to check reply counts 28 + - Blip creation requires valid sessions to store records 29 + - Tag system depends on reliable ATProto record creation 30 + - Firehose processing must authenticate to analyze engagement 31 + 32 + ## Failure Philosophy 33 + 34 + **Better to crash than confuse users:** 35 + - Authentication failure = system shutdown (as intended) 36 + - No degraded mode where some features silently break 37 + - Clear error messages in logs for debugging 38 + - Forces ops teams to fix auth issues immediately 39 + 40 + ## Usage Pattern 41 + 42 + # System startup 43 + {:ok, client} = SimpleSession.get_client() 44 + 45 + # All services use the same authenticated client 46 + ATProto.create_blip(client, blip) 47 + ATProto.get_post_engagement(client, post_uri) 48 + ATProto.create_tag(client, tag) 49 + 50 + ## Performance Benefits 51 + 52 + - **No per-request auth overhead** - client reused across all calls 53 + - **No session refresh logic** - app passwords are long-lived 54 + - **No complex state synchronization** - single source of truth 55 + - **Predictable memory usage** - one client struct for entire app 56 + 57 + ## Error Recovery 58 + 59 + **Intentionally minimal** - authentication should "just work": 60 + - No automatic retries (app passwords rarely fail) 61 + - No graceful degradation (would confuse community features) 62 + - System restart required for auth failures (clear resolution path) 63 + """ 64 + 65 + use GenServer 66 + require Logger 67 + 68 + def start_link(opts) do 69 + GenServer.start_link(__MODULE__, opts, name: __MODULE__) 70 + end 71 + 72 + @doc """ 73 + Get the authenticated ATProto client. 74 + """ 75 + def get_client do 76 + GenServer.call(__MODULE__, :get_client) 77 + end 78 + 79 + # GenServer callbacks 80 + 81 + @impl true 82 + def init(_opts) do 83 + Logger.info("Authenticating with ATProto...") 84 + 85 + case ElixirBlonk.ATProto.authenticate() do 86 + {:ok, client} -> 87 + Logger.info("ATProto authentication successful") 88 + {:ok, %{client: client}} 89 + 90 + {:error, reason} -> 91 + Logger.error("CRITICAL: ATProto authentication failed: #{inspect(reason)}") 92 + {:stop, {:atproto_auth_failed, reason}} 93 + end 94 + end 95 + 96 + @impl true 97 + def handle_call(:get_client, _from, %{client: client} = state) do 98 + {:reply, {:ok, client}, state} 99 + end 100 + end
+228
lib/elixir_blonk/grooves.ex
··· 1 + defmodule ElixirBlonk.Grooves do 2 + @moduledoc """ 3 + The Grooves context for managing community engagement in the Blonk ecosystem. 4 + 5 + Grooves are Blonk's community feedback mechanism - the way users express their 6 + reaction to blips through "looks_good" (positive) or "shit_rips" (critical) 7 + responses. This context orchestrates the engagement that drives content visibility 8 + and community curation. 9 + 10 + ## What Are Grooves? 11 + 12 + **Grooves are binary community feedback on blips:** 13 + - **looks_good** (👍) - Positive community endorsement 14 + - **shit_rips** (💩) - Critical community feedback 15 + - Each user can groove once per blip with either reaction 16 + - Groove counts drive content visibility and trending algorithms 17 + - Community-driven curation without complex scoring systems 18 + 19 + ## Philosophy: Simple, Clear Feedback 20 + 21 + **Why binary grooves instead of complex voting?** 22 + - Clear, unambiguous community sentiment 23 + - Prevents gaming through vote manipulation 24 + - Encourages authentic engagement over optimization 25 + - Simple UI that promotes quick, honest reactions 26 + - Community consensus emerges naturally through patterns 27 + 28 + ## Blonk Ecosystem Integration 29 + 30 + - **Blips**: Content receives grooves from community members 31 + - **Vibes**: Groove activity indicates vibe health and engagement 32 + - **Radar**: Popular (well-grooved) content surfaces on frontpage 33 + - **Tags**: Grooves on tagged content influence tag popularity 34 + - **Community**: Groove patterns reveal quality content and active members 35 + 36 + ## Community Engagement Mechanics 37 + 38 + **Grooves drive organic content curation:** 39 + - High "looks_good" count signals quality content worth surfacing 40 + - "shit_rips" provides critical feedback for content improvement 41 + - Groove ratios help identify controversial vs consensus content 42 + - Activity patterns reveal engaged community members 43 + - Aggregated data drives radar trending algorithms 44 + 45 + ## Content Visibility Impact 46 + 47 + **Grooves determine what the community sees:** 48 + 1. **Vibe Ordering**: Well-grooved blips rise in vibe feeds 49 + 2. **Radar Prominence**: Popular content appears on frontpage 50 + 3. **Tag Trending**: Grooved tagged content influences tag popularity 51 + 4. **Community Health**: Active grooving indicates vibrant community 52 + 5. **Quality Signal**: Consistent groove patterns identify good content 53 + 54 + ## Anti-Gaming Design 55 + 56 + **Simple system resists manipulation:** 57 + - One groove per user per blip (no vote stacking) 58 + - Binary choice prevents complex optimization strategies 59 + - Community patterns harder to fake than individual metrics 60 + - Real engagement required - no anonymous or bulk actions 61 + - ATProto attribution provides accountability 62 + 63 + ## Social Dynamics 64 + 65 + **Grooves create healthy community interaction:** 66 + - Positive reinforcement for quality contributions 67 + - Critical feedback mechanism for improvement 68 + - Community consensus building through collective action 69 + - Recognition for active, thoughtful community members 70 + - Natural moderation through peer feedback 71 + 72 + ## Examples 73 + 74 + # User grooves positively on a blip 75 + {:ok, groove} = Grooves.toggle_groove( 76 + "did:plc:user123", 77 + "at://did:plc:author/com.blonk.blip/rkey", 78 + "looks_good" 79 + ) 80 + 81 + # Check community sentiment on content 82 + %{looks_good: 42, shit_rips: 3} = Grooves.get_groove_counts(blip_id) 83 + 84 + # Find most grooved content in vibe 85 + trending_blips = Blips.list_blips_by_vibe(vibe_uri) 86 + |> Enum.sort_by(&(&1.grooves_looks_good), :desc) 87 + """ 88 + 89 + import Ecto.Query, warn: false 90 + alias ElixirBlonk.Repo 91 + 92 + alias ElixirBlonk.Grooves.Groove 93 + alias ElixirBlonk.Blips 94 + 95 + @doc """ 96 + Creates a groove (reaction) for a blip. 97 + """ 98 + def create_groove(attrs \\ %{}) do 99 + # Find the blip by subject_uri if provided 100 + attrs = if attrs[:subject_uri] do 101 + case Blips.get_blip_by_uri(attrs[:subject_uri]) do 102 + nil -> attrs 103 + blip -> Map.put(attrs, :blip_id, blip.id) 104 + end 105 + else 106 + attrs 107 + end 108 + 109 + %Groove{} 110 + |> Groove.changeset(attrs) 111 + |> Repo.insert() 112 + |> case do 113 + {:ok, groove} -> 114 + # Update groove counts on the blip 115 + if groove.blip_id do 116 + Blips.update_groove_counts(groove.blip_id) 117 + end 118 + {:ok, groove} 119 + error -> error 120 + end 121 + end 122 + 123 + @doc """ 124 + Deletes a groove. 125 + """ 126 + def delete_groove(%Groove{} = groove) do 127 + result = Repo.delete(groove) 128 + 129 + # Update groove counts on the blip 130 + if groove.blip_id do 131 + Blips.update_groove_counts(groove.blip_id) 132 + end 133 + 134 + result 135 + end 136 + 137 + @doc """ 138 + Gets a groove by author and subject. 139 + """ 140 + def get_groove_by_author_and_subject(author_did, subject_uri) do 141 + Groove 142 + |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 143 + |> Repo.one() 144 + end 145 + 146 + @doc """ 147 + Toggles a groove - creates if doesn't exist, changes type if different, deletes if same. 148 + """ 149 + def toggle_groove(author_did, subject_uri, groove_type, attrs \\ %{}) do 150 + case get_groove_by_author_and_subject(author_did, subject_uri) do 151 + nil -> 152 + # Create new groove 153 + attrs = Map.merge(attrs, %{ 154 + author_did: author_did, 155 + subject_uri: subject_uri, 156 + groove_type: groove_type 157 + }) 158 + create_groove(attrs) 159 + 160 + %Groove{groove_type: ^groove_type} = groove -> 161 + # Same type, so remove it 162 + delete_groove(groove) 163 + {:ok, nil} 164 + 165 + groove -> 166 + # Different type, update it 167 + groove 168 + |> Groove.changeset(%{groove_type: groove_type}) 169 + |> Repo.update() 170 + |> case do 171 + {:ok, updated_groove} -> 172 + # Update counts 173 + if updated_groove.blip_id do 174 + Blips.update_groove_counts(updated_groove.blip_id) 175 + end 176 + {:ok, updated_groove} 177 + error -> error 178 + end 179 + end 180 + end 181 + 182 + @doc """ 183 + Lists all grooves for a blip. 184 + """ 185 + def list_grooves_for_blip(blip_id) do 186 + Groove 187 + |> where([g], g.blip_id == ^blip_id) 188 + |> Repo.all() 189 + end 190 + 191 + @doc """ 192 + Lists all grooves by a specific author. 193 + """ 194 + def list_grooves_by_author(author_did) do 195 + Groove 196 + |> where([g], g.author_did == ^author_did) 197 + |> preload(:blip) 198 + |> Repo.all() 199 + end 200 + 201 + @doc """ 202 + Counts grooves by type for a blip. 203 + """ 204 + def count_grooves_by_type(blip_id, groove_type) do 205 + Groove 206 + |> where([g], g.blip_id == ^blip_id and g.groove_type == ^groove_type) 207 + |> Repo.aggregate(:count) 208 + end 209 + 210 + @doc """ 211 + Checks if an author has grooved a specific blip. 212 + """ 213 + def has_grooved?(author_did, subject_uri) do 214 + Groove 215 + |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 216 + |> Repo.exists?() 217 + end 218 + 219 + @doc """ 220 + Gets the groove type for an author on a specific blip. 221 + """ 222 + def get_groove_type(author_did, subject_uri) do 223 + Groove 224 + |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 225 + |> select([g], g.groove_type) 226 + |> Repo.one() 227 + end 228 + end
+197
lib/elixir_blonk/hot_post_sweeper.ex
··· 1 + defmodule ElixirBlonk.HotPostSweeper do 2 + @moduledoc """ 3 + AI-powered content curation service that transforms trending Bluesky posts into Blonk blips. 4 + 5 + The HotPostSweeper is the heart of Blonk's community bootstrap strategy, running every 6 + 10 minutes to analyze engagement on posts captured from the firehose and converting 7 + highly-engaged content into blips that seed community activity. 8 + 9 + ## Core Mission 10 + 11 + **Solve the cold start problem** by ensuring there's always engaging content on the radar: 12 + - Continuously analyze posts captured from Bluesky firehose 13 + - Check reply counts to gauge community interest 14 + - Convert trending content into blips for the bsky_hot vibe 15 + - Maintain system performance through intelligent cleanup 16 + 17 + ## Why Every 10 Minutes? 18 + 19 + - **Fresh Content**: Recent posts need time to accumulate replies 20 + - **System Performance**: Avoid overwhelming ATProto APIs with constant requests 21 + - **Quality Control**: Allows natural filtering - truly engaging content rises 22 + - **Community Timing**: Balances freshness with engagement validation 23 + 24 + ## Integration with Blonk Ecosystem 25 + 26 + - **Firehose Consumer**: Receives posts to analyze from real-time capture 27 + - **ATProto API**: Checks reply counts via authenticated Bluesky calls 28 + - **bsky_hot Vibe**: Creates blips for trending content in this community space 29 + - **Radar**: Newly created blips surface on the frontpage for community grooves 30 + - **HotPosts Context**: Manages the lifecycle of potential trending content 31 + 32 + ## AI Curation Logic 33 + 34 + 1. **Batch Processing**: Analyzes up to 25 posts per sweep for efficiency 35 + 2. **Engagement Threshold**: Posts with ≥5 replies qualify as "hot" 36 + 3. **Retry Logic**: Failed API calls don't block other posts from processing 37 + 4. **Smart Cleanup**: Removes posts >1 day old or checked >10 times 38 + 5. **Conversion Tracking**: Prevents duplicate blips from same hot post 39 + 40 + ## Community Impact 41 + 42 + The sweeper creates a **virtuous cycle of engagement**: 43 + - Quality external content attracts users to Blonk 44 + - Users groove on hot blips, increasing visibility 45 + - Popular topics inspire organic vibe creation 46 + - Growing community activity attracts more users 47 + 48 + ## Performance Characteristics 49 + 50 + - **Non-blocking**: Runs in background without affecting user experience 51 + - **Error Recovery**: Individual post failures don't crash the system 52 + - **Rate Limited**: Respects ATProto API limits through batching 53 + - **Self-cleaning**: Automatically maintains database efficiency 54 + 55 + ## Examples 56 + 57 + # Sweeper finds a trending crypto post 58 + hot_post = %HotPost{ 59 + text: "New DeFi protocol just launched...", 60 + external_url: "https://protocol.xyz", 61 + reply_count: 12 # Above threshold! 62 + } 63 + 64 + # Creates blip in bsky_hot vibe 65 + # → Surfaces on radar 66 + # → Users groove on it 67 + # → Drives more engagement 68 + """ 69 + 70 + use GenServer 71 + require Logger 72 + 73 + alias ElixirBlonk.{HotPosts, Vibes, Blips} 74 + 75 + # Check every 10 minutes 76 + @sweep_interval_ms 10 * 60 * 1000 77 + 78 + def start_link(opts \\ []) do 79 + GenServer.start_link(__MODULE__, opts, name: __MODULE__) 80 + end 81 + 82 + @impl true 83 + def init(_opts) do 84 + Logger.info("Starting HotPostSweeper - checking posts every 10 minutes") 85 + 86 + # Schedule the first sweep 87 + schedule_sweep() 88 + 89 + {:ok, %{}} 90 + end 91 + 92 + @impl true 93 + def handle_info(:sweep, state) do 94 + Logger.info("Starting hot post sweep") 95 + 96 + try do 97 + # Get posts to check (up to 25) 98 + posts_to_check = HotPosts.get_posts_for_checking(25) 99 + Logger.info("Found #{length(posts_to_check)} posts to check for replies") 100 + 101 + # Check each post for replies 102 + Enum.each(posts_to_check, &check_post_replies/1) 103 + 104 + # Clean up old posts 105 + cleanup_count = HotPosts.cleanup_old_posts() 106 + if cleanup_count > 0 do 107 + Logger.info("Cleaned up #{cleanup_count} old hot posts") 108 + end 109 + 110 + # Create blips for trending posts 111 + create_blips_for_trending() 112 + 113 + rescue 114 + error -> 115 + Logger.error("Error in hot post sweep: #{inspect(error)}") 116 + end 117 + 118 + # Schedule next sweep 119 + schedule_sweep() 120 + 121 + {:noreply, state} 122 + end 123 + 124 + defp schedule_sweep do 125 + Process.send_after(self(), :sweep, @sweep_interval_ms) 126 + end 127 + 128 + defp check_post_replies(hot_post) do 129 + Logger.debug("Checking replies for post: #{hot_post.post_uri}") 130 + 131 + case get_post_reply_count(hot_post.post_uri) do 132 + {:ok, reply_count} -> 133 + Logger.debug("Post #{hot_post.post_uri} has #{reply_count} replies") 134 + HotPosts.update_hot_post_check(hot_post, reply_count) 135 + 136 + {:error, reason} -> 137 + Logger.warning("Failed to check replies for #{hot_post.post_uri}: #{inspect(reason)}") 138 + # Still increment check count even if API failed 139 + HotPosts.update_hot_post_check(hot_post, hot_post.reply_count) 140 + end 141 + end 142 + 143 + defp get_post_reply_count(post_uri) do 144 + case ElixirBlonk.ATProto.SimpleSession.get_client() do 145 + {:ok, client} -> 146 + ElixirBlonk.ATProto.get_post_engagement(client, post_uri) 147 + 148 + {:error, reason} -> 149 + {:error, reason} 150 + end 151 + end 152 + 153 + defp create_blips_for_trending do 154 + trending_posts = HotPosts.get_trending_posts(5) 155 + 156 + if length(trending_posts) > 0 do 157 + Logger.info("Found #{length(trending_posts)} trending posts to convert to blips") 158 + end 159 + 160 + Enum.each(trending_posts, &create_blip_from_hot_post/1) 161 + end 162 + 163 + defp create_blip_from_hot_post(hot_post) do 164 + case Vibes.get_vibe_by_name("bsky_hot") do 165 + nil -> 166 + Logger.error("bsky_hot vibe not found - cannot create hot blip") 167 + 168 + bsky_hot_vibe -> 169 + blip_params = %{ 170 + uri: "at://blonk.app/blip/#{Ecto.UUID.generate()}", 171 + cid: "bafyrei#{:crypto.strong_rand_bytes(32) |> Base.encode32(case: :lower, padding: false)}", 172 + author_did: hot_post.author_did, 173 + title: truncate_text(hot_post.text || "", 100), 174 + body: hot_post.text || "", 175 + url: hot_post.external_url || hot_post.post_uri, 176 + tags: ["trending", "hot", "bsky"], 177 + vibe_id: bsky_hot_vibe.id, 178 + vibe_uri: bsky_hot_vibe.uri, 179 + grooves_looks_good: 0, 180 + grooves_shit_rips: 0, 181 + indexed_at: DateTime.utc_now() 182 + } 183 + 184 + case Blips.create_blip(blip_params) do 185 + {:ok, blip} -> 186 + Logger.info("Created hot blip: #{String.slice(blip.title, 0, 50)}... (#{hot_post.reply_count} replies)") 187 + HotPosts.mark_as_converted(hot_post) 188 + 189 + {:error, reason} -> 190 + Logger.error("Failed to create hot blip: #{inspect(reason)}") 191 + end 192 + end 193 + end 194 + 195 + defp truncate_text(text, max_length) when byte_size(text) <= max_length, do: text 196 + defp truncate_text(text, max_length), do: String.slice(text, 0, max_length) <> "..." 197 + end
+130
lib/elixir_blonk/hot_posts.ex
··· 1 + defmodule ElixirBlonk.HotPosts do 2 + @moduledoc """ 3 + The HotPosts context for managing AI-driven content curation in the Blonk ecosystem. 4 + 5 + This context orchestrates the discovery and analysis of trending content from the 6 + Bluesky firehose, providing the community bootstrap mechanism that seeds engagement 7 + and attracts users to the platform. 8 + 9 + ## Core Purpose in Blonk 10 + 11 + **HotPosts solve the cold start problem** for community platforms by: 12 + - Automatically discovering trending external content 13 + - Analyzing community engagement through reply counts 14 + - Converting popular content into blips for community grooves 15 + - Seeding the radar with quality content to drive initial engagement 16 + 17 + ## Integration with Blonk Ecosystem 18 + 19 + - **Firehose**: Captures posts with links from Bluesky's real-time feed 20 + - **bsky_hot Vibe**: Auto-populated community space for trending content 21 + - **Radar**: Hot blips surface on the frontpage across all vibes 22 + - **Grooves**: Community engagement on converted content drives visibility 23 + - **AI Curation**: Algorithmic filtering ensures quality over quantity 24 + 25 + ## Community Bootstrap Strategy 26 + 27 + 1. **Content Discovery**: Monitor Bluesky firehose for posts with external links 28 + 2. **Smart Sampling**: Take 1 in 10 posts to avoid overwhelming the system 29 + 3. **Time-Delayed Analysis**: Wait for posts to accumulate replies naturally 30 + 4. **Engagement Threshold**: Convert posts with ≥5 replies to community blips 31 + 5. **Automatic Cleanup**: Remove old/processed posts to maintain performance 32 + 33 + ## Why This Matters 34 + 35 + Without hot posts, Blonk would face the **empty restaurant problem**: 36 + - No content → no users → no engagement → no growth 37 + - Hot posts create the initial activity that attracts real community 38 + - Quality external content gives users something to groove on immediately 39 + - Trending topics seed organic vibe creation and community formation 40 + 41 + ## Lifecycle Management 42 + 43 + **Capture Phase**: Firehose consumer saves promising posts 44 + **Analysis Phase**: HotPostSweeper checks engagement metrics 45 + **Conversion Phase**: Popular posts become blips in bsky_hot vibe 46 + **Cleanup Phase**: Old/processed posts are automatically removed 47 + 48 + ## Examples 49 + 50 + # Find posts ready for engagement analysis 51 + posts_to_check = HotPosts.get_posts_for_checking(25) 52 + 53 + # Convert highly-engaged posts to community blips 54 + trending_posts = HotPosts.get_trending_posts(5) 55 + 56 + # Cleanup old posts to maintain performance 57 + cleanup_count = HotPosts.cleanup_old_posts() 58 + """ 59 + 60 + import Ecto.Query, warn: false 61 + alias ElixirBlonk.Repo 62 + alias ElixirBlonk.HotPosts.HotPost 63 + 64 + @doc """ 65 + Creates a hot post record for later processing. 66 + """ 67 + def create_hot_post(attrs \\ %{}) do 68 + %HotPost{} 69 + |> HotPost.changeset(attrs) 70 + |> Repo.insert() 71 + end 72 + 73 + @doc """ 74 + Gets posts ready for reply checking. 75 + Returns up to `limit` posts that haven't been checked too many times. 76 + """ 77 + def get_posts_for_checking(limit \\ 25) do 78 + HotPost 79 + |> where([h], h.check_count < 10) 80 + |> where([h], h.inserted_at > ago(1, "day")) 81 + |> order_by([h], asc: h.inserted_at) 82 + |> limit(^limit) 83 + |> Repo.all() 84 + end 85 + 86 + @doc """ 87 + Updates the check count and reply count for a hot post. 88 + """ 89 + def update_hot_post_check(hot_post, reply_count) do 90 + hot_post 91 + |> HotPost.update_changeset(%{ 92 + check_count: hot_post.check_count + 1, 93 + reply_count: reply_count, 94 + last_checked_at: DateTime.utc_now() 95 + }) 96 + |> Repo.update() 97 + end 98 + 99 + @doc """ 100 + Deletes old or fully processed hot posts. 101 + """ 102 + def cleanup_old_posts do 103 + # Delete posts older than 1 day OR that have been checked 10 times 104 + {count, _} = 105 + HotPost 106 + |> where([h], h.inserted_at < ago(1, "day") or h.check_count >= 10) 107 + |> Repo.delete_all() 108 + 109 + count 110 + end 111 + 112 + @doc """ 113 + Gets all hot posts with high reply counts that haven't been converted to blips yet. 114 + """ 115 + def get_trending_posts(min_replies \\ 5) do 116 + HotPost 117 + |> where([h], h.reply_count >= ^min_replies) 118 + |> where([h], not h.converted_to_blip) 119 + |> Repo.all() 120 + end 121 + 122 + @doc """ 123 + Marks a hot post as converted to a blip. 124 + """ 125 + def mark_as_converted(hot_post) do 126 + hot_post 127 + |> HotPost.update_changeset(%{converted_to_blip: true}) 128 + |> Repo.update() 129 + end 130 + end
+93
lib/elixir_blonk/hot_posts/hot_post.ex
··· 1 + defmodule ElixirBlonk.HotPosts.HotPost do 2 + @moduledoc """ 3 + Represents a potential trending post from the Bluesky firehose awaiting engagement analysis. 4 + 5 + HotPost records are created by the firehose consumer when it samples posts with external 6 + links. These posts are then analyzed by the HotPostSweeper to determine if they have 7 + enough community engagement (replies) to become blips in the bsky_hot vibe. 8 + 9 + ## Blonk Integration 10 + 11 + **Hot Posts seed community engagement** by: 12 + - Monitoring Bluesky firehose for content with links 13 + - Sampling 1 in 10 posts to avoid overwhelming the system 14 + - Time-delayed engagement checking (posts need time to get replies) 15 + - Auto-converting trending content into blips for community grooves 16 + 17 + ## Lifecycle in Community Bootstrap 18 + 19 + 1. **Capture**: Firehose consumer saves posts with links from Bluesky 20 + 2. **Patience**: Posts wait for time delay to allow replies to accumulate 21 + 3. **Analysis**: HotPostSweeper checks reply counts via ATProto API 22 + 4. **Conversion**: Posts with ≥5 replies become blips in bsky_hot vibe 23 + 5. **Cleanup**: Old or fully-processed posts are removed automatically 24 + 25 + ## Why This Matters for Blonk 26 + 27 + The hot posts system **bootstraps community engagement** by: 28 + - Seeding the radar with trending external content 29 + - Providing initial blips for users to groove on 30 + - Creating conversation starters across vibes 31 + - Attracting users through quality content discovery 32 + 33 + ## Schema Fields 34 + 35 + - `post_uri` - ATProto URI of the original Bluesky post 36 + - `author_did` - DID of the original post author 37 + - `text` - Post content/body text 38 + - `external_url` - The external link that made this post interesting 39 + - `record_data` - Full ATProto record for reference 40 + - `check_count` - How many times we've checked this post for replies 41 + - `reply_count` - Current number of replies from last check 42 + - `converted_to_blip` - Whether this became a blip in bsky_hot vibe 43 + - `last_checked_at` - When we last analyzed engagement 44 + 45 + ## Examples 46 + 47 + # A hot post awaiting analysis 48 + %HotPost{ 49 + post_uri: "at://did:plc:user/app.bsky.feed.post/rkey", 50 + text: "Check out this amazing new protocol...", 51 + external_url: "https://protocol.xyz/announcement", 52 + check_count: 2, 53 + reply_count: 7, # Above threshold! 54 + converted_to_blip: false # Ready for conversion 55 + } 56 + """ 57 + 58 + use Ecto.Schema 59 + import Ecto.Changeset 60 + 61 + @primary_key {:id, :binary_id, autogenerate: true} 62 + @foreign_key_type :binary_id 63 + schema "hot_posts" do 64 + field :post_uri, :string 65 + field :author_did, :string 66 + field :text, :string 67 + field :external_url, :string 68 + field :record_data, :map # Store the full ATProto record 69 + field :check_count, :integer, default: 0 70 + field :reply_count, :integer, default: 0 71 + field :converted_to_blip, :boolean, default: false 72 + field :last_checked_at, :utc_datetime 73 + 74 + timestamps(type: :utc_datetime) 75 + end 76 + 77 + @doc false 78 + def changeset(hot_post, attrs) do 79 + hot_post 80 + |> cast(attrs, [ 81 + :post_uri, :author_did, :text, :external_url, :record_data, 82 + :check_count, :reply_count, :converted_to_blip, :last_checked_at 83 + ]) 84 + |> validate_required([:post_uri, :author_did]) 85 + |> unique_constraint(:post_uri) 86 + end 87 + 88 + @doc false 89 + def update_changeset(hot_post, attrs) do 90 + hot_post 91 + |> cast(attrs, [:check_count, :reply_count, :converted_to_blip, :last_checked_at]) 92 + end 93 + end
+307
lib/elixir_blonk/vibes.ex
··· 1 + defmodule ElixirBlonk.Vibes do 2 + @moduledoc """ 3 + The Vibes context for managing topic-based communities in the Blonk ecosystem. 4 + 5 + Vibes are the heart of Blonk's community organization - interest-based feeds where 6 + users submit blips and engage through grooves. This context manages the organic 7 + creation, discovery, and growth of community spaces through grassroots engagement. 8 + 9 + ## What Are Vibes? 10 + 11 + **Vibes are community-driven topic feeds:** 12 + - Interest-based communities (e.g., crypto_vibe, art_vibe, tech_vibe) 13 + - Created organically through #vibe-name mentions reaching critical mass 14 + - Contain blips relevant to the community's focus 15 + - Enable targeted audience engagement and content discovery 16 + - Form the foundation for radar trending and cross-vibe connections 17 + 18 + ## Organic Community Creation 19 + 20 + **Vibes emerge naturally from community interest:** 21 + 1. **Mention Phase**: Users post content with #vibe-name hashtags 22 + 2. **Accumulation**: System tracks mentions across the firehose 23 + 3. **Critical Mass**: Once threshold is reached, vibe officially emerges 24 + 4. **Community Growth**: Members join, submit blips, and engage through grooves 25 + 5. **Radar Integration**: Popular vibe content surfaces on the frontpage 26 + 27 + ## Blonk Ecosystem Integration 28 + 29 + - **Blips**: Content submissions that give vibes their substance 30 + - **Grooves**: Community engagement that drives vibe activity 31 + - **Tags**: Universal labels that connect content across vibes 32 + - **Radar**: Popular vibe content surfaces on the frontpage 33 + - **Hot Posts**: AI-curated content seeds engagement in new vibes 34 + 35 + ## Community Philosophy 36 + 37 + **Vibes prioritize authentic community formation:** 38 + - No top-down vibe creation - communities must emerge organically 39 + - Interest-based rather than algorithm-driven organization 40 + - Quality content rises through peer grooves, not engagement manipulation 41 + - Cross-vibe discovery through universal tags promotes healthy growth 42 + - Real community engagement over vanity metrics 43 + 44 + ## Vibe Lifecycle 45 + 46 + 1. **Grassroots Mentions**: Users naturally reference #vibe-topics in posts 47 + 2. **Threshold Detection**: Firehose consumer tracks mention accumulation 48 + 3. **Emergence**: Vibe officially created when community interest is proven 49 + 4. **Content Submission**: Users submit relevant blips to the new vibe 50 + 5. **Community Engagement**: Members groove on content, driving activity 51 + 6. **Radar Visibility**: Popular content attracts new members 52 + 53 + ## Membership and Engagement 54 + 55 + **Flexible community participation:** 56 + - Users can join multiple vibes based on interests 57 + - Member counts visible for community size indication 58 + - Activity levels drive vibe prominence on radar 59 + - Tag frequency analysis reveals community interests 60 + - Cross-vibe connections through shared tags and members 61 + 62 + ## Discovery Mechanisms 63 + 64 + **Multiple pathways for vibe discovery:** 65 + - Emerging vibes list shows communities gaining momentum 66 + - Tag-based discovery reveals related vibes 67 + - Radar trending surfaces popular vibe content 68 + - Member activity patterns suggest relevant communities 69 + 70 + ## Examples 71 + 72 + # Track a potential new vibe 73 + Vibes.record_vibe_mention(%{ 74 + vibe_name: "defi", 75 + author_did: "did:plc:user123", 76 + post_uri: "at://did:plc:user123/app.bsky.feed.post/rkey", 77 + mentioned_at: DateTime.utc_now() 78 + }) 79 + 80 + # Check if vibe has reached emergence threshold 81 + case Vibes.check_vibe_emergence("defi") do 82 + {:emerging, vibe} -> 83 + # New community has formed! 84 + {:not_ready, count} -> 85 + # Still accumulating mentions: #{count} 86 + end 87 + 88 + # Get vibe content for radar 89 + popular_blips = Blips.list_blips_by_vibe(crypto_vibe.uri) 90 + """ 91 + 92 + import Ecto.Query, warn: false 93 + require Logger 94 + alias ElixirBlonk.Repo 95 + 96 + alias ElixirBlonk.Vibes.{Vibe, VibeMember, VibeMention} 97 + 98 + @doc """ 99 + Returns the list of vibes. 100 + """ 101 + def list_vibes do 102 + Repo.all(Vibe) 103 + end 104 + 105 + @doc """ 106 + Returns the list of vibes ordered by pulse score. 107 + """ 108 + def list_vibes_by_pulse do 109 + Vibe 110 + |> order_by([v], desc: v.pulse_score) 111 + |> Repo.all() 112 + end 113 + 114 + @doc """ 115 + Returns the list of emerging vibes. 116 + """ 117 + def list_emerging_vibes do 118 + Vibe 119 + |> where([v], v.is_emerging == true) 120 + |> order_by([v], desc: v.pulse_score) 121 + |> Repo.all() 122 + end 123 + 124 + @doc """ 125 + Gets a single vibe. 126 + """ 127 + def get_vibe!(id), do: Repo.get!(Vibe, id) 128 + 129 + @doc """ 130 + Gets a vibe by URI. 131 + """ 132 + def get_vibe_by_uri(uri) do 133 + Repo.get_by(Vibe, uri: uri) 134 + end 135 + 136 + @doc """ 137 + Gets a vibe by name. 138 + """ 139 + def get_vibe_by_name(name) do 140 + Repo.get_by(Vibe, name: name) 141 + end 142 + 143 + @doc """ 144 + Creates a vibe. 145 + """ 146 + def create_vibe(attrs \\ %{}) do 147 + # First create in local database 148 + with {:ok, vibe} <- %Vibe{} 149 + |> Vibe.changeset(attrs) 150 + |> Repo.insert() do 151 + 152 + # Then try to create in ATProto if enabled 153 + if Application.get_env(:elixir_blonk, :atproto_enabled, true) do 154 + Task.Supervisor.start_child(ElixirBlonk.TaskSupervisor, fn -> 155 + create_vibe_in_atproto(vibe) 156 + end) 157 + end 158 + 159 + {:ok, vibe} 160 + end 161 + end 162 + 163 + defp create_vibe_in_atproto(vibe) do 164 + with {:ok, client} <- ElixirBlonk.ATProto.SessionManager.get_client(), 165 + {:ok, %{uri: uri, cid: cid}} <- ElixirBlonk.ATProto.Client.create_vibe(client, vibe) do 166 + 167 + # Update local record with ATProto URI and CID 168 + update_vibe(vibe, %{uri: uri, cid: cid}) 169 + Logger.info("Created vibe in ATProto: #{uri}") 170 + else 171 + {:error, reason} -> 172 + Logger.error("Failed to create vibe in ATProto: #{inspect(reason)}") 173 + end 174 + end 175 + 176 + @doc """ 177 + Updates a vibe. 178 + """ 179 + def update_vibe(%Vibe{} = vibe, attrs) do 180 + vibe 181 + |> Vibe.changeset(attrs) 182 + |> Repo.update() 183 + end 184 + 185 + @doc """ 186 + Deletes a vibe. 187 + """ 188 + def delete_vibe(%Vibe{} = vibe) do 189 + Repo.delete(vibe) 190 + end 191 + 192 + @doc """ 193 + Joins a user to a vibe. 194 + """ 195 + def join_vibe(member_did, vibe_id, attrs \\ %{}) do 196 + attrs = Map.merge(attrs, %{ 197 + member_did: member_did, 198 + vibe_id: vibe_id 199 + }) 200 + 201 + %VibeMember{} 202 + |> VibeMember.changeset(attrs) 203 + |> Repo.insert() 204 + |> case do 205 + {:ok, member} -> 206 + update_member_count(vibe_id) 207 + {:ok, member} 208 + error -> error 209 + end 210 + end 211 + 212 + @doc """ 213 + Checks if a user is a member of a vibe. 214 + """ 215 + def is_member?(member_did, vibe_uri) do 216 + VibeMember 217 + |> where([vm], vm.member_did == ^member_did and vm.vibe_uri == ^vibe_uri) 218 + |> Repo.exists?() 219 + end 220 + 221 + @doc """ 222 + Updates the member count for a vibe. 223 + """ 224 + def update_member_count(vibe_id) do 225 + count = VibeMember 226 + |> where([vm], vm.vibe_id == ^vibe_id) 227 + |> Repo.aggregate(:count) 228 + 229 + vibe = Repo.get!(Vibe, vibe_id) 230 + update_vibe(vibe, %{member_count: count}) 231 + end 232 + 233 + @doc """ 234 + Records a vibe mention. 235 + """ 236 + def record_vibe_mention(attrs) do 237 + %VibeMention{} 238 + |> VibeMention.changeset(attrs) 239 + |> Repo.insert() 240 + |> case do 241 + {:ok, mention} -> 242 + check_and_formalize_vibe(mention.vibe_name) 243 + {:ok, mention} 244 + error -> error 245 + end 246 + end 247 + 248 + @doc """ 249 + Checks if a vibe should be formalized based on mention thresholds. 250 + """ 251 + def check_and_formalize_vibe(vibe_name) do 252 + unique_authors = VibeMention 253 + |> where([vm], vm.vibe_name == ^vibe_name) 254 + |> distinct([vm], vm.author_did) 255 + |> Repo.aggregate(:count) 256 + 257 + total_mentions = VibeMention 258 + |> where([vm], vm.vibe_name == ^vibe_name) 259 + |> Repo.aggregate(:count) 260 + 261 + if unique_authors >= 5 or total_mentions >= 10 do 262 + unless get_vibe_by_name(vibe_name) do 263 + case create_vibe(%{ 264 + uri: "at://blonk.app/vibe/#{vibe_name}", 265 + cid: "bafyrei#{:crypto.strong_rand_bytes(32) |> Base.encode32(case: :lower, padding: false)}", 266 + creator_did: "did:plc:blonk", 267 + name: vibe_name, 268 + mood: vibe_name, 269 + is_emerging: false 270 + }) do 271 + {:ok, vibe} -> 272 + # Broadcast the emergence 273 + Phoenix.PubSub.broadcast( 274 + ElixirBlonk.PubSub, 275 + "vibes:emerged", 276 + {:vibe_emerged, vibe} 277 + ) 278 + {:ok, vibe} 279 + error -> error 280 + end 281 + end 282 + end 283 + end 284 + 285 + @doc """ 286 + Gets vibe mention statistics. 287 + """ 288 + def get_vibe_mention_stats do 289 + VibeMention 290 + |> group_by([vm], vm.vibe_name) 291 + |> select([vm], %{ 292 + vibe_name: vm.vibe_name, 293 + total_mentions: count(vm.id), 294 + unique_authors: count(fragment("DISTINCT ?", vm.author_did)) 295 + }) 296 + |> Repo.all() 297 + end 298 + 299 + @doc """ 300 + Updates pulse scores for all vibes based on recent activity. 301 + """ 302 + def update_pulse_scores do 303 + # This would be called periodically to update vibe pulse scores 304 + # based on recent blip activity, member count, etc. 305 + # Implementation depends on specific scoring algorithm 306 + end 307 + end
+2370
priv/static/assets/app.css
··· 1 + /* 2 + ! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com 3 + */ 4 + 5 + /* 6 + 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 7 + 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 8 + */ 9 + 10 + *, 11 + ::before, 12 + ::after { 13 + box-sizing: border-box; 14 + /* 1 */ 15 + border-width: 0; 16 + /* 2 */ 17 + border-style: solid; 18 + /* 2 */ 19 + border-color: #e5e7eb; 20 + /* 2 */ 21 + } 22 + 23 + ::before, 24 + ::after { 25 + --tw-content: ''; 26 + } 27 + 28 + /* 29 + 1. Use a consistent sensible line-height in all browsers. 30 + 2. Prevent adjustments of font size after orientation changes in iOS. 31 + 3. Use a more readable tab size. 32 + 4. Use the user's configured `sans` font-family by default. 33 + 5. Use the user's configured `sans` font-feature-settings by default. 34 + 6. Use the user's configured `sans` font-variation-settings by default. 35 + 7. Disable tap highlights on iOS 36 + */ 37 + 38 + html, 39 + :host { 40 + line-height: 1.5; 41 + /* 1 */ 42 + -webkit-text-size-adjust: 100%; 43 + /* 2 */ 44 + -moz-tab-size: 4; 45 + /* 3 */ 46 + -o-tab-size: 4; 47 + tab-size: 4; 48 + /* 3 */ 49 + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 50 + /* 4 */ 51 + font-feature-settings: normal; 52 + /* 5 */ 53 + font-variation-settings: normal; 54 + /* 6 */ 55 + -webkit-tap-highlight-color: transparent; 56 + /* 7 */ 57 + } 58 + 59 + /* 60 + 1. Remove the margin in all browsers. 61 + 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 62 + */ 63 + 64 + body { 65 + margin: 0; 66 + /* 1 */ 67 + line-height: inherit; 68 + /* 2 */ 69 + } 70 + 71 + /* 72 + 1. Add the correct height in Firefox. 73 + 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 74 + 3. Ensure horizontal rules are visible by default. 75 + */ 76 + 77 + hr { 78 + height: 0; 79 + /* 1 */ 80 + color: inherit; 81 + /* 2 */ 82 + border-top-width: 1px; 83 + /* 3 */ 84 + } 85 + 86 + /* 87 + Add the correct text decoration in Chrome, Edge, and Safari. 88 + */ 89 + 90 + abbr:where([title]) { 91 + -webkit-text-decoration: underline dotted; 92 + text-decoration: underline dotted; 93 + } 94 + 95 + /* 96 + Remove the default font size and weight for headings. 97 + */ 98 + 99 + h1, 100 + h2, 101 + h3, 102 + h4, 103 + h5, 104 + h6 { 105 + font-size: inherit; 106 + font-weight: inherit; 107 + } 108 + 109 + /* 110 + Reset links to optimize for opt-in styling instead of opt-out. 111 + */ 112 + 113 + a { 114 + color: inherit; 115 + text-decoration: inherit; 116 + } 117 + 118 + /* 119 + Add the correct font weight in Edge and Safari. 120 + */ 121 + 122 + b, 123 + strong { 124 + font-weight: bolder; 125 + } 126 + 127 + /* 128 + 1. Use the user's configured `mono` font-family by default. 129 + 2. Use the user's configured `mono` font-feature-settings by default. 130 + 3. Use the user's configured `mono` font-variation-settings by default. 131 + 4. Correct the odd `em` font sizing in all browsers. 132 + */ 133 + 134 + code, 135 + kbd, 136 + samp, 137 + pre { 138 + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 139 + /* 1 */ 140 + font-feature-settings: normal; 141 + /* 2 */ 142 + font-variation-settings: normal; 143 + /* 3 */ 144 + font-size: 1em; 145 + /* 4 */ 146 + } 147 + 148 + /* 149 + Add the correct font size in all browsers. 150 + */ 151 + 152 + small { 153 + font-size: 80%; 154 + } 155 + 156 + /* 157 + Prevent `sub` and `sup` elements from affecting the line height in all browsers. 158 + */ 159 + 160 + sub, 161 + sup { 162 + font-size: 75%; 163 + line-height: 0; 164 + position: relative; 165 + vertical-align: baseline; 166 + } 167 + 168 + sub { 169 + bottom: -0.25em; 170 + } 171 + 172 + sup { 173 + top: -0.5em; 174 + } 175 + 176 + /* 177 + 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 178 + 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 179 + 3. Remove gaps between table borders by default. 180 + */ 181 + 182 + table { 183 + text-indent: 0; 184 + /* 1 */ 185 + border-color: inherit; 186 + /* 2 */ 187 + border-collapse: collapse; 188 + /* 3 */ 189 + } 190 + 191 + /* 192 + 1. Change the font styles in all browsers. 193 + 2. Remove the margin in Firefox and Safari. 194 + 3. Remove default padding in all browsers. 195 + */ 196 + 197 + button, 198 + input, 199 + optgroup, 200 + select, 201 + textarea { 202 + font-family: inherit; 203 + /* 1 */ 204 + font-feature-settings: inherit; 205 + /* 1 */ 206 + font-variation-settings: inherit; 207 + /* 1 */ 208 + font-size: 100%; 209 + /* 1 */ 210 + font-weight: inherit; 211 + /* 1 */ 212 + line-height: inherit; 213 + /* 1 */ 214 + letter-spacing: inherit; 215 + /* 1 */ 216 + color: inherit; 217 + /* 1 */ 218 + margin: 0; 219 + /* 2 */ 220 + padding: 0; 221 + /* 3 */ 222 + } 223 + 224 + /* 225 + Remove the inheritance of text transform in Edge and Firefox. 226 + */ 227 + 228 + button, 229 + select { 230 + text-transform: none; 231 + } 232 + 233 + /* 234 + 1. Correct the inability to style clickable types in iOS and Safari. 235 + 2. Remove default button styles. 236 + */ 237 + 238 + button, 239 + input:where([type='button']), 240 + input:where([type='reset']), 241 + input:where([type='submit']) { 242 + -webkit-appearance: button; 243 + /* 1 */ 244 + background-color: transparent; 245 + /* 2 */ 246 + background-image: none; 247 + /* 2 */ 248 + } 249 + 250 + /* 251 + Use the modern Firefox focus style for all focusable elements. 252 + */ 253 + 254 + :-moz-focusring { 255 + outline: auto; 256 + } 257 + 258 + /* 259 + Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 260 + */ 261 + 262 + :-moz-ui-invalid { 263 + box-shadow: none; 264 + } 265 + 266 + /* 267 + Add the correct vertical alignment in Chrome and Firefox. 268 + */ 269 + 270 + progress { 271 + vertical-align: baseline; 272 + } 273 + 274 + /* 275 + Correct the cursor style of increment and decrement buttons in Safari. 276 + */ 277 + 278 + ::-webkit-inner-spin-button, 279 + ::-webkit-outer-spin-button { 280 + height: auto; 281 + } 282 + 283 + /* 284 + 1. Correct the odd appearance in Chrome and Safari. 285 + 2. Correct the outline style in Safari. 286 + */ 287 + 288 + [type='search'] { 289 + -webkit-appearance: textfield; 290 + /* 1 */ 291 + outline-offset: -2px; 292 + /* 2 */ 293 + } 294 + 295 + /* 296 + Remove the inner padding in Chrome and Safari on macOS. 297 + */ 298 + 299 + ::-webkit-search-decoration { 300 + -webkit-appearance: none; 301 + } 302 + 303 + /* 304 + 1. Correct the inability to style clickable types in iOS and Safari. 305 + 2. Change font properties to `inherit` in Safari. 306 + */ 307 + 308 + ::-webkit-file-upload-button { 309 + -webkit-appearance: button; 310 + /* 1 */ 311 + font: inherit; 312 + /* 2 */ 313 + } 314 + 315 + /* 316 + Add the correct display in Chrome and Safari. 317 + */ 318 + 319 + summary { 320 + display: list-item; 321 + } 322 + 323 + /* 324 + Removes the default spacing and border for appropriate elements. 325 + */ 326 + 327 + blockquote, 328 + dl, 329 + dd, 330 + h1, 331 + h2, 332 + h3, 333 + h4, 334 + h5, 335 + h6, 336 + hr, 337 + figure, 338 + p, 339 + pre { 340 + margin: 0; 341 + } 342 + 343 + fieldset { 344 + margin: 0; 345 + padding: 0; 346 + } 347 + 348 + legend { 349 + padding: 0; 350 + } 351 + 352 + ol, 353 + ul, 354 + menu { 355 + list-style: none; 356 + margin: 0; 357 + padding: 0; 358 + } 359 + 360 + /* 361 + Reset default styling for dialogs. 362 + */ 363 + 364 + dialog { 365 + padding: 0; 366 + } 367 + 368 + /* 369 + Prevent resizing textareas horizontally by default. 370 + */ 371 + 372 + textarea { 373 + resize: vertical; 374 + } 375 + 376 + /* 377 + 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 378 + 2. Set the default placeholder color to the user's configured gray 400 color. 379 + */ 380 + 381 + input::-moz-placeholder, textarea::-moz-placeholder { 382 + opacity: 1; 383 + /* 1 */ 384 + color: #9ca3af; 385 + /* 2 */ 386 + } 387 + 388 + input::placeholder, 389 + textarea::placeholder { 390 + opacity: 1; 391 + /* 1 */ 392 + color: #9ca3af; 393 + /* 2 */ 394 + } 395 + 396 + /* 397 + Set the default cursor for buttons. 398 + */ 399 + 400 + button, 401 + [role="button"] { 402 + cursor: pointer; 403 + } 404 + 405 + /* 406 + Make sure disabled buttons don't get the pointer cursor. 407 + */ 408 + 409 + :disabled { 410 + cursor: default; 411 + } 412 + 413 + /* 414 + 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 415 + 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 416 + This can trigger a poorly considered lint error in some tools but is included by design. 417 + */ 418 + 419 + img, 420 + svg, 421 + video, 422 + canvas, 423 + audio, 424 + iframe, 425 + embed, 426 + object { 427 + display: block; 428 + /* 1 */ 429 + vertical-align: middle; 430 + /* 2 */ 431 + } 432 + 433 + /* 434 + Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 435 + */ 436 + 437 + img, 438 + video { 439 + max-width: 100%; 440 + height: auto; 441 + } 442 + 443 + /* Make elements with the HTML hidden attribute stay hidden by default */ 444 + 445 + [hidden] { 446 + display: none; 447 + } 448 + 449 + [type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { 450 + -webkit-appearance: none; 451 + -moz-appearance: none; 452 + appearance: none; 453 + background-color: #fff; 454 + border-color: #6b7280; 455 + border-width: 1px; 456 + border-radius: 0px; 457 + padding-top: 0.5rem; 458 + padding-right: 0.75rem; 459 + padding-bottom: 0.5rem; 460 + padding-left: 0.75rem; 461 + font-size: 1rem; 462 + line-height: 1.5rem; 463 + --tw-shadow: 0 0 #0000; 464 + } 465 + 466 + [type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { 467 + outline: 2px solid transparent; 468 + outline-offset: 2px; 469 + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); 470 + --tw-ring-offset-width: 0px; 471 + --tw-ring-offset-color: #fff; 472 + --tw-ring-color: #2563eb; 473 + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 474 + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 475 + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); 476 + border-color: #2563eb; 477 + } 478 + 479 + input::-moz-placeholder, textarea::-moz-placeholder { 480 + color: #6b7280; 481 + opacity: 1; 482 + } 483 + 484 + input::placeholder,textarea::placeholder { 485 + color: #6b7280; 486 + opacity: 1; 487 + } 488 + 489 + ::-webkit-datetime-edit-fields-wrapper { 490 + padding: 0; 491 + } 492 + 493 + ::-webkit-date-and-time-value { 494 + min-height: 1.5em; 495 + } 496 + 497 + ::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { 498 + padding-top: 0; 499 + padding-bottom: 0; 500 + } 501 + 502 + select { 503 + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); 504 + background-position: right 0.5rem center; 505 + background-repeat: no-repeat; 506 + background-size: 1.5em 1.5em; 507 + padding-right: 2.5rem; 508 + -webkit-print-color-adjust: exact; 509 + print-color-adjust: exact; 510 + } 511 + 512 + [multiple] { 513 + background-image: initial; 514 + background-position: initial; 515 + background-repeat: unset; 516 + background-size: initial; 517 + padding-right: 0.75rem; 518 + -webkit-print-color-adjust: unset; 519 + print-color-adjust: unset; 520 + } 521 + 522 + [type='checkbox'],[type='radio'] { 523 + -webkit-appearance: none; 524 + -moz-appearance: none; 525 + appearance: none; 526 + padding: 0; 527 + -webkit-print-color-adjust: exact; 528 + print-color-adjust: exact; 529 + display: inline-block; 530 + vertical-align: middle; 531 + background-origin: border-box; 532 + -webkit-user-select: none; 533 + -moz-user-select: none; 534 + user-select: none; 535 + flex-shrink: 0; 536 + height: 1rem; 537 + width: 1rem; 538 + color: #2563eb; 539 + background-color: #fff; 540 + border-color: #6b7280; 541 + border-width: 1px; 542 + --tw-shadow: 0 0 #0000; 543 + } 544 + 545 + [type='checkbox'] { 546 + border-radius: 0px; 547 + } 548 + 549 + [type='radio'] { 550 + border-radius: 100%; 551 + } 552 + 553 + [type='checkbox']:focus,[type='radio']:focus { 554 + outline: 2px solid transparent; 555 + outline-offset: 2px; 556 + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); 557 + --tw-ring-offset-width: 2px; 558 + --tw-ring-offset-color: #fff; 559 + --tw-ring-color: #2563eb; 560 + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 561 + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); 562 + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); 563 + } 564 + 565 + [type='checkbox']:checked,[type='radio']:checked { 566 + border-color: transparent; 567 + background-color: currentColor; 568 + background-size: 100% 100%; 569 + background-position: center; 570 + background-repeat: no-repeat; 571 + } 572 + 573 + [type='checkbox']:checked { 574 + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); 575 + } 576 + 577 + [type='radio']:checked { 578 + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); 579 + } 580 + 581 + [type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { 582 + border-color: transparent; 583 + background-color: currentColor; 584 + } 585 + 586 + [type='checkbox']:indeterminate { 587 + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); 588 + border-color: transparent; 589 + background-color: currentColor; 590 + background-size: 100% 100%; 591 + background-position: center; 592 + background-repeat: no-repeat; 593 + } 594 + 595 + [type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { 596 + border-color: transparent; 597 + background-color: currentColor; 598 + } 599 + 600 + [type='file'] { 601 + background: unset; 602 + border-color: inherit; 603 + border-width: 0; 604 + border-radius: 0; 605 + padding: 0; 606 + font-size: unset; 607 + line-height: inherit; 608 + } 609 + 610 + [type='file']:focus { 611 + outline: 1px solid ButtonText; 612 + outline: 1px auto -webkit-focus-ring-color; 613 + } 614 + 615 + *, ::before, ::after { 616 + --tw-border-spacing-x: 0; 617 + --tw-border-spacing-y: 0; 618 + --tw-translate-x: 0; 619 + --tw-translate-y: 0; 620 + --tw-rotate: 0; 621 + --tw-skew-x: 0; 622 + --tw-skew-y: 0; 623 + --tw-scale-x: 1; 624 + --tw-scale-y: 1; 625 + --tw-pan-x: ; 626 + --tw-pan-y: ; 627 + --tw-pinch-zoom: ; 628 + --tw-scroll-snap-strictness: proximity; 629 + --tw-gradient-from-position: ; 630 + --tw-gradient-via-position: ; 631 + --tw-gradient-to-position: ; 632 + --tw-ordinal: ; 633 + --tw-slashed-zero: ; 634 + --tw-numeric-figure: ; 635 + --tw-numeric-spacing: ; 636 + --tw-numeric-fraction: ; 637 + --tw-ring-inset: ; 638 + --tw-ring-offset-width: 0px; 639 + --tw-ring-offset-color: #fff; 640 + --tw-ring-color: rgb(59 130 246 / 0.5); 641 + --tw-ring-offset-shadow: 0 0 #0000; 642 + --tw-ring-shadow: 0 0 #0000; 643 + --tw-shadow: 0 0 #0000; 644 + --tw-shadow-colored: 0 0 #0000; 645 + --tw-blur: ; 646 + --tw-brightness: ; 647 + --tw-contrast: ; 648 + --tw-grayscale: ; 649 + --tw-hue-rotate: ; 650 + --tw-invert: ; 651 + --tw-saturate: ; 652 + --tw-sepia: ; 653 + --tw-drop-shadow: ; 654 + --tw-backdrop-blur: ; 655 + --tw-backdrop-brightness: ; 656 + --tw-backdrop-contrast: ; 657 + --tw-backdrop-grayscale: ; 658 + --tw-backdrop-hue-rotate: ; 659 + --tw-backdrop-invert: ; 660 + --tw-backdrop-opacity: ; 661 + --tw-backdrop-saturate: ; 662 + --tw-backdrop-sepia: ; 663 + --tw-contain-size: ; 664 + --tw-contain-layout: ; 665 + --tw-contain-paint: ; 666 + --tw-contain-style: ; 667 + } 668 + 669 + ::backdrop { 670 + --tw-border-spacing-x: 0; 671 + --tw-border-spacing-y: 0; 672 + --tw-translate-x: 0; 673 + --tw-translate-y: 0; 674 + --tw-rotate: 0; 675 + --tw-skew-x: 0; 676 + --tw-skew-y: 0; 677 + --tw-scale-x: 1; 678 + --tw-scale-y: 1; 679 + --tw-pan-x: ; 680 + --tw-pan-y: ; 681 + --tw-pinch-zoom: ; 682 + --tw-scroll-snap-strictness: proximity; 683 + --tw-gradient-from-position: ; 684 + --tw-gradient-via-position: ; 685 + --tw-gradient-to-position: ; 686 + --tw-ordinal: ; 687 + --tw-slashed-zero: ; 688 + --tw-numeric-figure: ; 689 + --tw-numeric-spacing: ; 690 + --tw-numeric-fraction: ; 691 + --tw-ring-inset: ; 692 + --tw-ring-offset-width: 0px; 693 + --tw-ring-offset-color: #fff; 694 + --tw-ring-color: rgb(59 130 246 / 0.5); 695 + --tw-ring-offset-shadow: 0 0 #0000; 696 + --tw-ring-shadow: 0 0 #0000; 697 + --tw-shadow: 0 0 #0000; 698 + --tw-shadow-colored: 0 0 #0000; 699 + --tw-blur: ; 700 + --tw-brightness: ; 701 + --tw-contrast: ; 702 + --tw-grayscale: ; 703 + --tw-hue-rotate: ; 704 + --tw-invert: ; 705 + --tw-saturate: ; 706 + --tw-sepia: ; 707 + --tw-drop-shadow: ; 708 + --tw-backdrop-blur: ; 709 + --tw-backdrop-brightness: ; 710 + --tw-backdrop-contrast: ; 711 + --tw-backdrop-grayscale: ; 712 + --tw-backdrop-hue-rotate: ; 713 + --tw-backdrop-invert: ; 714 + --tw-backdrop-opacity: ; 715 + --tw-backdrop-saturate: ; 716 + --tw-backdrop-sepia: ; 717 + --tw-contain-size: ; 718 + --tw-contain-layout: ; 719 + --tw-contain-paint: ; 720 + --tw-contain-style: ; 721 + } 722 + 723 + .container { 724 + width: 100%; 725 + } 726 + 727 + @media (min-width: 640px) { 728 + .container { 729 + max-width: 640px; 730 + } 731 + } 732 + 733 + @media (min-width: 768px) { 734 + .container { 735 + max-width: 768px; 736 + } 737 + } 738 + 739 + @media (min-width: 1024px) { 740 + .container { 741 + max-width: 1024px; 742 + } 743 + } 744 + 745 + @media (min-width: 1280px) { 746 + .container { 747 + max-width: 1280px; 748 + } 749 + } 750 + 751 + @media (min-width: 1536px) { 752 + .container { 753 + max-width: 1536px; 754 + } 755 + } 756 + 757 + .hero-arrow-left-solid { 758 + --hero-arrow-left-solid: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon"> <path fill-rule="evenodd" d="M11.03 3.97a.75.75 0 0 1 0 1.06l-6.22 6.22H21a.75.75 0 0 1 0 1.5H4.81l6.22 6.22a.75.75 0 1 1-1.06 1.06l-7.5-7.5a.75.75 0 0 1 0-1.06l7.5-7.5a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd"/></svg>'); 759 + -webkit-mask: var(--hero-arrow-left-solid); 760 + mask: var(--hero-arrow-left-solid); 761 + -webkit-mask-repeat: no-repeat; 762 + mask-repeat: no-repeat; 763 + background-color: currentColor; 764 + vertical-align: middle; 765 + display: inline-block; 766 + width: 1.5rem; 767 + height: 1.5rem; 768 + } 769 + 770 + .hero-arrow-path { 771 + --hero-arrow-path: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/></svg>'); 772 + -webkit-mask: var(--hero-arrow-path); 773 + mask: var(--hero-arrow-path); 774 + -webkit-mask-repeat: no-repeat; 775 + mask-repeat: no-repeat; 776 + background-color: currentColor; 777 + vertical-align: middle; 778 + display: inline-block; 779 + width: 1.5rem; 780 + height: 1.5rem; 781 + } 782 + 783 + .hero-exclamation-circle-mini { 784 + --hero-exclamation-circle-mini: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> <path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-8-5a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-1.5 0v-4.5A.75.75 0 0 1 10 5Zm0 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/></svg>'); 785 + -webkit-mask: var(--hero-exclamation-circle-mini); 786 + mask: var(--hero-exclamation-circle-mini); 787 + -webkit-mask-repeat: no-repeat; 788 + mask-repeat: no-repeat; 789 + background-color: currentColor; 790 + vertical-align: middle; 791 + display: inline-block; 792 + width: 1.25rem; 793 + height: 1.25rem; 794 + } 795 + 796 + .hero-information-circle-mini { 797 + --hero-information-circle-mini: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> <path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd"/></svg>'); 798 + -webkit-mask: var(--hero-information-circle-mini); 799 + mask: var(--hero-information-circle-mini); 800 + -webkit-mask-repeat: no-repeat; 801 + mask-repeat: no-repeat; 802 + background-color: currentColor; 803 + vertical-align: middle; 804 + display: inline-block; 805 + width: 1.25rem; 806 + height: 1.25rem; 807 + } 808 + 809 + .hero-tag { 810 + --hero-tag: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z"/></svg>'); 811 + -webkit-mask: var(--hero-tag); 812 + mask: var(--hero-tag); 813 + -webkit-mask-repeat: no-repeat; 814 + mask-repeat: no-repeat; 815 + background-color: currentColor; 816 + vertical-align: middle; 817 + display: inline-block; 818 + width: 1.5rem; 819 + height: 1.5rem; 820 + } 821 + 822 + .hero-x-mark { 823 + --hero-x-mark: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/></svg>'); 824 + -webkit-mask: var(--hero-x-mark); 825 + mask: var(--hero-x-mark); 826 + -webkit-mask-repeat: no-repeat; 827 + mask-repeat: no-repeat; 828 + background-color: currentColor; 829 + vertical-align: middle; 830 + display: inline-block; 831 + width: 1.5rem; 832 + height: 1.5rem; 833 + } 834 + 835 + .hero-x-mark-solid { 836 + --hero-x-mark-solid: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon"> <path fill-rule="evenodd" d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/></svg>'); 837 + -webkit-mask: var(--hero-x-mark-solid); 838 + mask: var(--hero-x-mark-solid); 839 + -webkit-mask-repeat: no-repeat; 840 + mask-repeat: no-repeat; 841 + background-color: currentColor; 842 + vertical-align: middle; 843 + display: inline-block; 844 + width: 1.5rem; 845 + height: 1.5rem; 846 + } 847 + 848 + .sr-only { 849 + position: absolute; 850 + width: 1px; 851 + height: 1px; 852 + padding: 0; 853 + margin: -1px; 854 + overflow: hidden; 855 + clip: rect(0, 0, 0, 0); 856 + white-space: nowrap; 857 + border-width: 0; 858 + } 859 + 860 + .static { 861 + position: static; 862 + } 863 + 864 + .fixed { 865 + position: fixed; 866 + } 867 + 868 + .absolute { 869 + position: absolute; 870 + } 871 + 872 + .relative { 873 + position: relative; 874 + } 875 + 876 + .inset-0 { 877 + inset: 0px; 878 + } 879 + 880 + .-inset-y-px { 881 + top: -1px; 882 + bottom: -1px; 883 + } 884 + 885 + .inset-y-0 { 886 + top: 0px; 887 + bottom: 0px; 888 + } 889 + 890 + .-left-4 { 891 + left: -1rem; 892 + } 893 + 894 + .-right-4 { 895 + right: -1rem; 896 + } 897 + 898 + .left-0 { 899 + left: 0px; 900 + } 901 + 902 + .left-\[40rem\] { 903 + left: 40rem; 904 + } 905 + 906 + .right-0 { 907 + right: 0px; 908 + } 909 + 910 + .right-1 { 911 + right: 0.25rem; 912 + } 913 + 914 + .right-2 { 915 + right: 0.5rem; 916 + } 917 + 918 + .right-5 { 919 + right: 1.25rem; 920 + } 921 + 922 + .top-1 { 923 + top: 0.25rem; 924 + } 925 + 926 + .top-2 { 927 + top: 0.5rem; 928 + } 929 + 930 + .top-20 { 931 + top: 5rem; 932 + } 933 + 934 + .top-6 { 935 + top: 1.5rem; 936 + } 937 + 938 + .z-0 { 939 + z-index: 0; 940 + } 941 + 942 + .z-10 { 943 + z-index: 10; 944 + } 945 + 946 + .z-50 { 947 + z-index: 50; 948 + } 949 + 950 + .-m-3 { 951 + margin: -0.75rem; 952 + } 953 + 954 + .-mx-2 { 955 + margin-left: -0.5rem; 956 + margin-right: -0.5rem; 957 + } 958 + 959 + .-my-0 { 960 + margin-top: -0px; 961 + margin-bottom: -0px; 962 + } 963 + 964 + .-my-0\.5 { 965 + margin-top: -0.125rem; 966 + margin-bottom: -0.125rem; 967 + } 968 + 969 + .-my-4 { 970 + margin-top: -1rem; 971 + margin-bottom: -1rem; 972 + } 973 + 974 + .mx-auto { 975 + margin-left: auto; 976 + margin-right: auto; 977 + } 978 + 979 + .mb-2 { 980 + margin-bottom: 0.5rem; 981 + } 982 + 983 + .mb-3 { 984 + margin-bottom: 0.75rem; 985 + } 986 + 987 + .mb-4 { 988 + margin-bottom: 1rem; 989 + } 990 + 991 + .mb-6 { 992 + margin-bottom: 1.5rem; 993 + } 994 + 995 + .mb-8 { 996 + margin-bottom: 2rem; 997 + } 998 + 999 + .ml-1 { 1000 + margin-left: 0.25rem; 1001 + } 1002 + 1003 + .ml-2 { 1004 + margin-left: 0.5rem; 1005 + } 1006 + 1007 + .ml-3 { 1008 + margin-left: 0.75rem; 1009 + } 1010 + 1011 + .ml-4 { 1012 + margin-left: 1rem; 1013 + } 1014 + 1015 + .mr-2 { 1016 + margin-right: 0.5rem; 1017 + } 1018 + 1019 + .mt-0 { 1020 + margin-top: 0px; 1021 + } 1022 + 1023 + .mt-0\.5 { 1024 + margin-top: 0.125rem; 1025 + } 1026 + 1027 + .mt-1 { 1028 + margin-top: 0.25rem; 1029 + } 1030 + 1031 + .mt-10 { 1032 + margin-top: 2.5rem; 1033 + } 1034 + 1035 + .mt-11 { 1036 + margin-top: 2.75rem; 1037 + } 1038 + 1039 + .mt-14 { 1040 + margin-top: 3.5rem; 1041 + } 1042 + 1043 + .mt-16 { 1044 + margin-top: 4rem; 1045 + } 1046 + 1047 + .mt-2 { 1048 + margin-top: 0.5rem; 1049 + } 1050 + 1051 + .mt-3 { 1052 + margin-top: 0.75rem; 1053 + } 1054 + 1055 + .mt-4 { 1056 + margin-top: 1rem; 1057 + } 1058 + 1059 + .mt-8 { 1060 + margin-top: 2rem; 1061 + } 1062 + 1063 + .block { 1064 + display: block; 1065 + } 1066 + 1067 + .inline-block { 1068 + display: inline-block; 1069 + } 1070 + 1071 + .flex { 1072 + display: flex; 1073 + } 1074 + 1075 + .inline-flex { 1076 + display: inline-flex; 1077 + } 1078 + 1079 + .table { 1080 + display: table; 1081 + } 1082 + 1083 + .grid { 1084 + display: grid; 1085 + } 1086 + 1087 + .contents { 1088 + display: contents; 1089 + } 1090 + 1091 + .hidden { 1092 + display: none; 1093 + } 1094 + 1095 + .h-12 { 1096 + height: 3rem; 1097 + } 1098 + 1099 + .h-16 { 1100 + height: 4rem; 1101 + } 1102 + 1103 + .h-2 { 1104 + height: 0.5rem; 1105 + } 1106 + 1107 + .h-3 { 1108 + height: 0.75rem; 1109 + } 1110 + 1111 + .h-4 { 1112 + height: 1rem; 1113 + } 1114 + 1115 + .h-5 { 1116 + height: 1.25rem; 1117 + } 1118 + 1119 + .h-6 { 1120 + height: 1.5rem; 1121 + } 1122 + 1123 + .h-full { 1124 + height: 100%; 1125 + } 1126 + 1127 + .min-h-\[200px\] { 1128 + min-height: 200px; 1129 + } 1130 + 1131 + .min-h-\[6rem\] { 1132 + min-height: 6rem; 1133 + } 1134 + 1135 + .min-h-full { 1136 + min-height: 100%; 1137 + } 1138 + 1139 + .w-1\/4 { 1140 + width: 25%; 1141 + } 1142 + 1143 + .w-11\/12 { 1144 + width: 91.666667%; 1145 + } 1146 + 1147 + .w-12 { 1148 + width: 3rem; 1149 + } 1150 + 1151 + .w-14 { 1152 + width: 3.5rem; 1153 + } 1154 + 1155 + .w-3 { 1156 + width: 0.75rem; 1157 + } 1158 + 1159 + .w-32 { 1160 + width: 8rem; 1161 + } 1162 + 1163 + .w-4 { 1164 + width: 1rem; 1165 + } 1166 + 1167 + .w-5 { 1168 + width: 1.25rem; 1169 + } 1170 + 1171 + .w-6 { 1172 + width: 1.5rem; 1173 + } 1174 + 1175 + .w-80 { 1176 + width: 20rem; 1177 + } 1178 + 1179 + .w-\[40rem\] { 1180 + width: 40rem; 1181 + } 1182 + 1183 + .w-full { 1184 + width: 100%; 1185 + } 1186 + 1187 + .min-w-\[3rem\] { 1188 + min-width: 3rem; 1189 + } 1190 + 1191 + .max-w-2xl { 1192 + max-width: 42rem; 1193 + } 1194 + 1195 + .max-w-3xl { 1196 + max-width: 48rem; 1197 + } 1198 + 1199 + .max-w-4xl { 1200 + max-width: 56rem; 1201 + } 1202 + 1203 + .max-w-6xl { 1204 + max-width: 72rem; 1205 + } 1206 + 1207 + .max-w-7xl { 1208 + max-width: 80rem; 1209 + } 1210 + 1211 + .max-w-md { 1212 + max-width: 28rem; 1213 + } 1214 + 1215 + .max-w-sm { 1216 + max-width: 24rem; 1217 + } 1218 + 1219 + .max-w-xl { 1220 + max-width: 36rem; 1221 + } 1222 + 1223 + .flex-1 { 1224 + flex: 1 1 0%; 1225 + } 1226 + 1227 + .flex-none { 1228 + flex: none; 1229 + } 1230 + 1231 + .translate-y-0 { 1232 + --tw-translate-y: 0px; 1233 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1234 + } 1235 + 1236 + .translate-y-4 { 1237 + --tw-translate-y: 1rem; 1238 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1239 + } 1240 + 1241 + .transform { 1242 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1243 + } 1244 + 1245 + @keyframes spin { 1246 + to { 1247 + transform: rotate(360deg); 1248 + } 1249 + } 1250 + 1251 + .animate-spin { 1252 + animation: spin 1s linear infinite; 1253 + } 1254 + 1255 + .cursor-pointer { 1256 + cursor: pointer; 1257 + } 1258 + 1259 + .resize-none { 1260 + resize: none; 1261 + } 1262 + 1263 + .grid-cols-1 { 1264 + grid-template-columns: repeat(1, minmax(0, 1fr)); 1265 + } 1266 + 1267 + .grid-cols-2 { 1268 + grid-template-columns: repeat(2, minmax(0, 1fr)); 1269 + } 1270 + 1271 + .flex-col { 1272 + flex-direction: column; 1273 + } 1274 + 1275 + .flex-wrap { 1276 + flex-wrap: wrap; 1277 + } 1278 + 1279 + .items-start { 1280 + align-items: flex-start; 1281 + } 1282 + 1283 + .items-center { 1284 + align-items: center; 1285 + } 1286 + 1287 + .justify-end { 1288 + justify-content: flex-end; 1289 + } 1290 + 1291 + .justify-center { 1292 + justify-content: center; 1293 + } 1294 + 1295 + .justify-between { 1296 + justify-content: space-between; 1297 + } 1298 + 1299 + .gap-1 { 1300 + gap: 0.25rem; 1301 + } 1302 + 1303 + .gap-1\.5 { 1304 + gap: 0.375rem; 1305 + } 1306 + 1307 + .gap-2 { 1308 + gap: 0.5rem; 1309 + } 1310 + 1311 + .gap-3 { 1312 + gap: 0.75rem; 1313 + } 1314 + 1315 + .gap-4 { 1316 + gap: 1rem; 1317 + } 1318 + 1319 + .gap-6 { 1320 + gap: 1.5rem; 1321 + } 1322 + 1323 + .gap-x-6 { 1324 + -moz-column-gap: 1.5rem; 1325 + column-gap: 1.5rem; 1326 + } 1327 + 1328 + .gap-y-4 { 1329 + row-gap: 1rem; 1330 + } 1331 + 1332 + .space-x-1 > :not([hidden]) ~ :not([hidden]) { 1333 + --tw-space-x-reverse: 0; 1334 + margin-right: calc(0.25rem * var(--tw-space-x-reverse)); 1335 + margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse))); 1336 + } 1337 + 1338 + .space-x-3 > :not([hidden]) ~ :not([hidden]) { 1339 + --tw-space-x-reverse: 0; 1340 + margin-right: calc(0.75rem * var(--tw-space-x-reverse)); 1341 + margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); 1342 + } 1343 + 1344 + .space-x-4 > :not([hidden]) ~ :not([hidden]) { 1345 + --tw-space-x-reverse: 0; 1346 + margin-right: calc(1rem * var(--tw-space-x-reverse)); 1347 + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); 1348 + } 1349 + 1350 + .space-x-6 > :not([hidden]) ~ :not([hidden]) { 1351 + --tw-space-x-reverse: 0; 1352 + margin-right: calc(1.5rem * var(--tw-space-x-reverse)); 1353 + margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); 1354 + } 1355 + 1356 + .space-x-8 > :not([hidden]) ~ :not([hidden]) { 1357 + --tw-space-x-reverse: 0; 1358 + margin-right: calc(2rem * var(--tw-space-x-reverse)); 1359 + margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); 1360 + } 1361 + 1362 + .space-y-12 > :not([hidden]) ~ :not([hidden]) { 1363 + --tw-space-y-reverse: 0; 1364 + margin-top: calc(3rem * calc(1 - var(--tw-space-y-reverse))); 1365 + margin-bottom: calc(3rem * var(--tw-space-y-reverse)); 1366 + } 1367 + 1368 + .space-y-4 > :not([hidden]) ~ :not([hidden]) { 1369 + --tw-space-y-reverse: 0; 1370 + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); 1371 + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); 1372 + } 1373 + 1374 + .space-y-6 > :not([hidden]) ~ :not([hidden]) { 1375 + --tw-space-y-reverse: 0; 1376 + margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); 1377 + margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); 1378 + } 1379 + 1380 + .space-y-8 > :not([hidden]) ~ :not([hidden]) { 1381 + --tw-space-y-reverse: 0; 1382 + margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); 1383 + margin-bottom: calc(2rem * var(--tw-space-y-reverse)); 1384 + } 1385 + 1386 + .divide-y > :not([hidden]) ~ :not([hidden]) { 1387 + --tw-divide-y-reverse: 0; 1388 + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); 1389 + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); 1390 + } 1391 + 1392 + .divide-zinc-100 > :not([hidden]) ~ :not([hidden]) { 1393 + --tw-divide-opacity: 1; 1394 + border-color: rgb(244 244 245 / var(--tw-divide-opacity)); 1395 + } 1396 + 1397 + .overflow-hidden { 1398 + overflow: hidden; 1399 + } 1400 + 1401 + .overflow-y-auto { 1402 + overflow-y: auto; 1403 + } 1404 + 1405 + .whitespace-nowrap { 1406 + white-space: nowrap; 1407 + } 1408 + 1409 + .text-balance { 1410 + text-wrap: balance; 1411 + } 1412 + 1413 + .rounded { 1414 + border-radius: 0.25rem; 1415 + } 1416 + 1417 + .rounded-2xl { 1418 + border-radius: 1rem; 1419 + } 1420 + 1421 + .rounded-full { 1422 + border-radius: 9999px; 1423 + } 1424 + 1425 + .rounded-lg { 1426 + border-radius: 0.5rem; 1427 + } 1428 + 1429 + .rounded-md { 1430 + border-radius: 0.375rem; 1431 + } 1432 + 1433 + .border { 1434 + border-width: 1px; 1435 + } 1436 + 1437 + .border-2 { 1438 + border-width: 2px; 1439 + } 1440 + 1441 + .border-b { 1442 + border-bottom-width: 1px; 1443 + } 1444 + 1445 + .border-t { 1446 + border-top-width: 1px; 1447 + } 1448 + 1449 + .border-black { 1450 + --tw-border-opacity: 1; 1451 + border-color: rgb(0 0 0 / var(--tw-border-opacity)); 1452 + } 1453 + 1454 + .border-blue-200 { 1455 + --tw-border-opacity: 1; 1456 + border-color: rgb(191 219 254 / var(--tw-border-opacity)); 1457 + } 1458 + 1459 + .border-blue-400 { 1460 + --tw-border-opacity: 1; 1461 + border-color: rgb(96 165 250 / var(--tw-border-opacity)); 1462 + } 1463 + 1464 + .border-gray-200 { 1465 + --tw-border-opacity: 1; 1466 + border-color: rgb(229 231 235 / var(--tw-border-opacity)); 1467 + } 1468 + 1469 + .border-gray-300 { 1470 + --tw-border-opacity: 1; 1471 + border-color: rgb(209 213 219 / var(--tw-border-opacity)); 1472 + } 1473 + 1474 + .border-green-400 { 1475 + --tw-border-opacity: 1; 1476 + border-color: rgb(74 222 128 / var(--tw-border-opacity)); 1477 + } 1478 + 1479 + .border-orange-400 { 1480 + --tw-border-opacity: 1; 1481 + border-color: rgb(251 146 60 / var(--tw-border-opacity)); 1482 + } 1483 + 1484 + .border-pink-400 { 1485 + --tw-border-opacity: 1; 1486 + border-color: rgb(244 114 182 / var(--tw-border-opacity)); 1487 + } 1488 + 1489 + .border-red-200 { 1490 + --tw-border-opacity: 1; 1491 + border-color: rgb(254 202 202 / var(--tw-border-opacity)); 1492 + } 1493 + 1494 + .border-rose-400 { 1495 + --tw-border-opacity: 1; 1496 + border-color: rgb(251 113 133 / var(--tw-border-opacity)); 1497 + } 1498 + 1499 + .border-yellow-400 { 1500 + --tw-border-opacity: 1; 1501 + border-color: rgb(250 204 21 / var(--tw-border-opacity)); 1502 + } 1503 + 1504 + .border-zinc-200 { 1505 + --tw-border-opacity: 1; 1506 + border-color: rgb(228 228 231 / var(--tw-border-opacity)); 1507 + } 1508 + 1509 + .border-zinc-300 { 1510 + --tw-border-opacity: 1; 1511 + border-color: rgb(212 212 216 / var(--tw-border-opacity)); 1512 + } 1513 + 1514 + .bg-black { 1515 + --tw-bg-opacity: 1; 1516 + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); 1517 + } 1518 + 1519 + .bg-blue-100 { 1520 + --tw-bg-opacity: 1; 1521 + background-color: rgb(219 234 254 / var(--tw-bg-opacity)); 1522 + } 1523 + 1524 + .bg-blue-50 { 1525 + --tw-bg-opacity: 1; 1526 + background-color: rgb(239 246 255 / var(--tw-bg-opacity)); 1527 + } 1528 + 1529 + .bg-blue-600 { 1530 + --tw-bg-opacity: 1; 1531 + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); 1532 + } 1533 + 1534 + .bg-brand\/5 { 1535 + background-color: rgb(253 79 0 / 0.05); 1536 + } 1537 + 1538 + .bg-emerald-50 { 1539 + --tw-bg-opacity: 1; 1540 + background-color: rgb(236 253 245 / var(--tw-bg-opacity)); 1541 + } 1542 + 1543 + .bg-gray-100 { 1544 + --tw-bg-opacity: 1; 1545 + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); 1546 + } 1547 + 1548 + .bg-gray-200 { 1549 + --tw-bg-opacity: 1; 1550 + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); 1551 + } 1552 + 1553 + .bg-gray-300 { 1554 + --tw-bg-opacity: 1; 1555 + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); 1556 + } 1557 + 1558 + .bg-gray-50 { 1559 + --tw-bg-opacity: 1; 1560 + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 1561 + } 1562 + 1563 + .bg-gray-600 { 1564 + --tw-bg-opacity: 1; 1565 + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); 1566 + } 1567 + 1568 + .bg-red-50 { 1569 + --tw-bg-opacity: 1; 1570 + background-color: rgb(254 242 242 / var(--tw-bg-opacity)); 1571 + } 1572 + 1573 + .bg-rose-50 { 1574 + --tw-bg-opacity: 1; 1575 + background-color: rgb(255 241 242 / var(--tw-bg-opacity)); 1576 + } 1577 + 1578 + .bg-white { 1579 + --tw-bg-opacity: 1; 1580 + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 1581 + } 1582 + 1583 + .bg-zinc-50 { 1584 + --tw-bg-opacity: 1; 1585 + background-color: rgb(250 250 250 / var(--tw-bg-opacity)); 1586 + } 1587 + 1588 + .bg-zinc-50\/90 { 1589 + background-color: rgb(250 250 250 / 0.9); 1590 + } 1591 + 1592 + .bg-zinc-900 { 1593 + --tw-bg-opacity: 1; 1594 + background-color: rgb(24 24 27 / var(--tw-bg-opacity)); 1595 + } 1596 + 1597 + .bg-opacity-50 { 1598 + --tw-bg-opacity: 0.5; 1599 + } 1600 + 1601 + .fill-cyan-900 { 1602 + fill: #164e63; 1603 + } 1604 + 1605 + .fill-rose-900 { 1606 + fill: #881337; 1607 + } 1608 + 1609 + .fill-zinc-400 { 1610 + fill: #a1a1aa; 1611 + } 1612 + 1613 + .p-0 { 1614 + padding: 0px; 1615 + } 1616 + 1617 + .p-14 { 1618 + padding: 3.5rem; 1619 + } 1620 + 1621 + .p-2 { 1622 + padding: 0.5rem; 1623 + } 1624 + 1625 + .p-3 { 1626 + padding: 0.75rem; 1627 + } 1628 + 1629 + .p-4 { 1630 + padding: 1rem; 1631 + } 1632 + 1633 + .p-5 { 1634 + padding: 1.25rem; 1635 + } 1636 + 1637 + .p-6 { 1638 + padding: 1.5rem; 1639 + } 1640 + 1641 + .p-8 { 1642 + padding: 2rem; 1643 + } 1644 + 1645 + .px-1 { 1646 + padding-left: 0.25rem; 1647 + padding-right: 0.25rem; 1648 + } 1649 + 1650 + .px-2 { 1651 + padding-left: 0.5rem; 1652 + padding-right: 0.5rem; 1653 + } 1654 + 1655 + .px-3 { 1656 + padding-left: 0.75rem; 1657 + padding-right: 0.75rem; 1658 + } 1659 + 1660 + .px-4 { 1661 + padding-left: 1rem; 1662 + padding-right: 1rem; 1663 + } 1664 + 1665 + .px-6 { 1666 + padding-left: 1.5rem; 1667 + padding-right: 1.5rem; 1668 + } 1669 + 1670 + .px-8 { 1671 + padding-left: 2rem; 1672 + padding-right: 2rem; 1673 + } 1674 + 1675 + .py-0 { 1676 + padding-top: 0px; 1677 + padding-bottom: 0px; 1678 + } 1679 + 1680 + .py-0\.5 { 1681 + padding-top: 0.125rem; 1682 + padding-bottom: 0.125rem; 1683 + } 1684 + 1685 + .py-1 { 1686 + padding-top: 0.25rem; 1687 + padding-bottom: 0.25rem; 1688 + } 1689 + 1690 + .py-10 { 1691 + padding-top: 2.5rem; 1692 + padding-bottom: 2.5rem; 1693 + } 1694 + 1695 + .py-12 { 1696 + padding-top: 3rem; 1697 + padding-bottom: 3rem; 1698 + } 1699 + 1700 + .py-2 { 1701 + padding-top: 0.5rem; 1702 + padding-bottom: 0.5rem; 1703 + } 1704 + 1705 + .py-3 { 1706 + padding-top: 0.75rem; 1707 + padding-bottom: 0.75rem; 1708 + } 1709 + 1710 + .py-4 { 1711 + padding-top: 1rem; 1712 + padding-bottom: 1rem; 1713 + } 1714 + 1715 + .py-8 { 1716 + padding-top: 2rem; 1717 + padding-bottom: 2rem; 1718 + } 1719 + 1720 + .pb-4 { 1721 + padding-bottom: 1rem; 1722 + } 1723 + 1724 + .pr-6 { 1725 + padding-right: 1.5rem; 1726 + } 1727 + 1728 + .pt-4 { 1729 + padding-top: 1rem; 1730 + } 1731 + 1732 + .text-left { 1733 + text-align: left; 1734 + } 1735 + 1736 + .text-center { 1737 + text-align: center; 1738 + } 1739 + 1740 + .text-right { 1741 + text-align: right; 1742 + } 1743 + 1744 + .font-mono { 1745 + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 1746 + } 1747 + 1748 + .text-2xl { 1749 + font-size: 1.5rem; 1750 + line-height: 2rem; 1751 + } 1752 + 1753 + .text-3xl { 1754 + font-size: 1.875rem; 1755 + line-height: 2.25rem; 1756 + } 1757 + 1758 + .text-4xl { 1759 + font-size: 2.25rem; 1760 + line-height: 2.5rem; 1761 + } 1762 + 1763 + .text-\[0\.8125rem\] { 1764 + font-size: 0.8125rem; 1765 + } 1766 + 1767 + .text-\[2rem\] { 1768 + font-size: 2rem; 1769 + } 1770 + 1771 + .text-base { 1772 + font-size: 1rem; 1773 + line-height: 1.5rem; 1774 + } 1775 + 1776 + .text-lg { 1777 + font-size: 1.125rem; 1778 + line-height: 1.75rem; 1779 + } 1780 + 1781 + .text-sm { 1782 + font-size: 0.875rem; 1783 + line-height: 1.25rem; 1784 + } 1785 + 1786 + .text-xl { 1787 + font-size: 1.25rem; 1788 + line-height: 1.75rem; 1789 + } 1790 + 1791 + .text-xs { 1792 + font-size: 0.75rem; 1793 + line-height: 1rem; 1794 + } 1795 + 1796 + .font-bold { 1797 + font-weight: 700; 1798 + } 1799 + 1800 + .font-medium { 1801 + font-weight: 500; 1802 + } 1803 + 1804 + .font-normal { 1805 + font-weight: 400; 1806 + } 1807 + 1808 + .font-semibold { 1809 + font-weight: 600; 1810 + } 1811 + 1812 + .leading-10 { 1813 + line-height: 2.5rem; 1814 + } 1815 + 1816 + .leading-5 { 1817 + line-height: 1.25rem; 1818 + } 1819 + 1820 + .leading-6 { 1821 + line-height: 1.5rem; 1822 + } 1823 + 1824 + .leading-7 { 1825 + line-height: 1.75rem; 1826 + } 1827 + 1828 + .leading-8 { 1829 + line-height: 2rem; 1830 + } 1831 + 1832 + .leading-relaxed { 1833 + line-height: 1.625; 1834 + } 1835 + 1836 + .tracking-tighter { 1837 + letter-spacing: -0.05em; 1838 + } 1839 + 1840 + .text-blue-400 { 1841 + --tw-text-opacity: 1; 1842 + color: rgb(96 165 250 / var(--tw-text-opacity)); 1843 + } 1844 + 1845 + .text-blue-500 { 1846 + --tw-text-opacity: 1; 1847 + color: rgb(59 130 246 / var(--tw-text-opacity)); 1848 + } 1849 + 1850 + .text-blue-600 { 1851 + --tw-text-opacity: 1; 1852 + color: rgb(37 99 235 / var(--tw-text-opacity)); 1853 + } 1854 + 1855 + .text-blue-700 { 1856 + --tw-text-opacity: 1; 1857 + color: rgb(29 78 216 / var(--tw-text-opacity)); 1858 + } 1859 + 1860 + .text-blue-800 { 1861 + --tw-text-opacity: 1; 1862 + color: rgb(30 64 175 / var(--tw-text-opacity)); 1863 + } 1864 + 1865 + .text-brand { 1866 + --tw-text-opacity: 1; 1867 + color: rgb(253 79 0 / var(--tw-text-opacity)); 1868 + } 1869 + 1870 + .text-emerald-800 { 1871 + --tw-text-opacity: 1; 1872 + color: rgb(6 95 70 / var(--tw-text-opacity)); 1873 + } 1874 + 1875 + .text-gray-400 { 1876 + --tw-text-opacity: 1; 1877 + color: rgb(156 163 175 / var(--tw-text-opacity)); 1878 + } 1879 + 1880 + .text-gray-500 { 1881 + --tw-text-opacity: 1; 1882 + color: rgb(107 114 128 / var(--tw-text-opacity)); 1883 + } 1884 + 1885 + .text-gray-600 { 1886 + --tw-text-opacity: 1; 1887 + color: rgb(75 85 99 / var(--tw-text-opacity)); 1888 + } 1889 + 1890 + .text-gray-700 { 1891 + --tw-text-opacity: 1; 1892 + color: rgb(55 65 81 / var(--tw-text-opacity)); 1893 + } 1894 + 1895 + .text-gray-900 { 1896 + --tw-text-opacity: 1; 1897 + color: rgb(17 24 39 / var(--tw-text-opacity)); 1898 + } 1899 + 1900 + .text-red-700 { 1901 + --tw-text-opacity: 1; 1902 + color: rgb(185 28 28 / var(--tw-text-opacity)); 1903 + } 1904 + 1905 + .text-rose-600 { 1906 + --tw-text-opacity: 1; 1907 + color: rgb(225 29 72 / var(--tw-text-opacity)); 1908 + } 1909 + 1910 + .text-rose-900 { 1911 + --tw-text-opacity: 1; 1912 + color: rgb(136 19 55 / var(--tw-text-opacity)); 1913 + } 1914 + 1915 + .text-white { 1916 + --tw-text-opacity: 1; 1917 + color: rgb(255 255 255 / var(--tw-text-opacity)); 1918 + } 1919 + 1920 + .text-zinc-500 { 1921 + --tw-text-opacity: 1; 1922 + color: rgb(113 113 122 / var(--tw-text-opacity)); 1923 + } 1924 + 1925 + .text-zinc-600 { 1926 + --tw-text-opacity: 1; 1927 + color: rgb(82 82 91 / var(--tw-text-opacity)); 1928 + } 1929 + 1930 + .text-zinc-700 { 1931 + --tw-text-opacity: 1; 1932 + color: rgb(63 63 70 / var(--tw-text-opacity)); 1933 + } 1934 + 1935 + .text-zinc-800 { 1936 + --tw-text-opacity: 1; 1937 + color: rgb(39 39 42 / var(--tw-text-opacity)); 1938 + } 1939 + 1940 + .text-zinc-900 { 1941 + --tw-text-opacity: 1; 1942 + color: rgb(24 24 27 / var(--tw-text-opacity)); 1943 + } 1944 + 1945 + .opacity-0 { 1946 + opacity: 0; 1947 + } 1948 + 1949 + .opacity-100 { 1950 + opacity: 1; 1951 + } 1952 + 1953 + .opacity-20 { 1954 + opacity: 0.2; 1955 + } 1956 + 1957 + .opacity-40 { 1958 + opacity: 0.4; 1959 + } 1960 + 1961 + .shadow-lg { 1962 + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 1963 + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); 1964 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1965 + } 1966 + 1967 + .shadow-md { 1968 + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); 1969 + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); 1970 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1971 + } 1972 + 1973 + .shadow-sm { 1974 + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); 1975 + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); 1976 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 1977 + } 1978 + 1979 + .shadow-zinc-700\/10 { 1980 + --tw-shadow-color: rgb(63 63 70 / 0.1); 1981 + --tw-shadow: var(--tw-shadow-colored); 1982 + } 1983 + 1984 + .outline { 1985 + outline-style: solid; 1986 + } 1987 + 1988 + .ring-1 { 1989 + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 1990 + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); 1991 + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); 1992 + } 1993 + 1994 + .ring-emerald-500 { 1995 + --tw-ring-opacity: 1; 1996 + --tw-ring-color: rgb(16 185 129 / var(--tw-ring-opacity)); 1997 + } 1998 + 1999 + .ring-rose-500 { 2000 + --tw-ring-opacity: 1; 2001 + --tw-ring-color: rgb(244 63 94 / var(--tw-ring-opacity)); 2002 + } 2003 + 2004 + .ring-zinc-700\/10 { 2005 + --tw-ring-color: rgb(63 63 70 / 0.1); 2006 + } 2007 + 2008 + .transition { 2009 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; 2010 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; 2011 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; 2012 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2013 + transition-duration: 150ms; 2014 + } 2015 + 2016 + .transition-all { 2017 + transition-property: all; 2018 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2019 + transition-duration: 150ms; 2020 + } 2021 + 2022 + .transition-colors { 2023 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; 2024 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2025 + transition-duration: 150ms; 2026 + } 2027 + 2028 + .transition-opacity { 2029 + transition-property: opacity; 2030 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2031 + transition-duration: 150ms; 2032 + } 2033 + 2034 + .duration-200 { 2035 + transition-duration: 200ms; 2036 + } 2037 + 2038 + .duration-300 { 2039 + transition-duration: 300ms; 2040 + } 2041 + 2042 + .ease-in { 2043 + transition-timing-function: cubic-bezier(0.4, 0, 1, 1); 2044 + } 2045 + 2046 + .ease-out { 2047 + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); 2048 + } 2049 + 2050 + .\[scrollbar-gutter\:stable\] { 2051 + scrollbar-gutter: stable; 2052 + } 2053 + 2054 + /* This file is for your main application CSS */ 2055 + 2056 + .last\:border-b-0:last-child { 2057 + border-bottom-width: 0px; 2058 + } 2059 + 2060 + .hover\:cursor-pointer:hover { 2061 + cursor: pointer; 2062 + } 2063 + 2064 + .hover\:border-black:hover { 2065 + --tw-border-opacity: 1; 2066 + border-color: rgb(0 0 0 / var(--tw-border-opacity)); 2067 + } 2068 + 2069 + .hover\:bg-blue-200:hover { 2070 + --tw-bg-opacity: 1; 2071 + background-color: rgb(191 219 254 / var(--tw-bg-opacity)); 2072 + } 2073 + 2074 + .hover\:bg-blue-700:hover { 2075 + --tw-bg-opacity: 1; 2076 + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); 2077 + } 2078 + 2079 + .hover\:bg-gray-100:hover { 2080 + --tw-bg-opacity: 1; 2081 + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); 2082 + } 2083 + 2084 + .hover\:bg-gray-400:hover { 2085 + --tw-bg-opacity: 1; 2086 + background-color: rgb(156 163 175 / var(--tw-bg-opacity)); 2087 + } 2088 + 2089 + .hover\:bg-gray-50:hover { 2090 + --tw-bg-opacity: 1; 2091 + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 2092 + } 2093 + 2094 + .hover\:bg-gray-800:hover { 2095 + --tw-bg-opacity: 1; 2096 + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); 2097 + } 2098 + 2099 + .hover\:bg-zinc-50:hover { 2100 + --tw-bg-opacity: 1; 2101 + background-color: rgb(250 250 250 / var(--tw-bg-opacity)); 2102 + } 2103 + 2104 + .hover\:bg-zinc-700:hover { 2105 + --tw-bg-opacity: 1; 2106 + background-color: rgb(63 63 70 / var(--tw-bg-opacity)); 2107 + } 2108 + 2109 + .hover\:text-blue-200:hover { 2110 + --tw-text-opacity: 1; 2111 + color: rgb(191 219 254 / var(--tw-text-opacity)); 2112 + } 2113 + 2114 + .hover\:text-blue-700:hover { 2115 + --tw-text-opacity: 1; 2116 + color: rgb(29 78 216 / var(--tw-text-opacity)); 2117 + } 2118 + 2119 + .hover\:text-gray-600:hover { 2120 + --tw-text-opacity: 1; 2121 + color: rgb(75 85 99 / var(--tw-text-opacity)); 2122 + } 2123 + 2124 + .hover\:text-zinc-700:hover { 2125 + --tw-text-opacity: 1; 2126 + color: rgb(63 63 70 / var(--tw-text-opacity)); 2127 + } 2128 + 2129 + .hover\:text-zinc-900:hover { 2130 + --tw-text-opacity: 1; 2131 + color: rgb(24 24 27 / var(--tw-text-opacity)); 2132 + } 2133 + 2134 + .hover\:underline:hover { 2135 + text-decoration-line: underline; 2136 + } 2137 + 2138 + .hover\:opacity-40:hover { 2139 + opacity: 0.4; 2140 + } 2141 + 2142 + .hover\:shadow-lg:hover { 2143 + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 2144 + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); 2145 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 2146 + } 2147 + 2148 + .focus\:border-rose-400:focus { 2149 + --tw-border-opacity: 1; 2150 + border-color: rgb(251 113 133 / var(--tw-border-opacity)); 2151 + } 2152 + 2153 + .focus\:border-transparent:focus { 2154 + border-color: transparent; 2155 + } 2156 + 2157 + .focus\:border-zinc-400:focus { 2158 + --tw-border-opacity: 1; 2159 + border-color: rgb(161 161 170 / var(--tw-border-opacity)); 2160 + } 2161 + 2162 + .focus\:ring-0:focus { 2163 + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 2164 + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); 2165 + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); 2166 + } 2167 + 2168 + .focus\:ring-2:focus { 2169 + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); 2170 + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); 2171 + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); 2172 + } 2173 + 2174 + .focus\:ring-blue-500:focus { 2175 + --tw-ring-opacity: 1; 2176 + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); 2177 + } 2178 + 2179 + .active\:text-white\/80:active { 2180 + color: rgb(255 255 255 / 0.8); 2181 + } 2182 + 2183 + .group:hover .group-hover\:bg-zinc-100 { 2184 + --tw-bg-opacity: 1; 2185 + background-color: rgb(244 244 245 / var(--tw-bg-opacity)); 2186 + } 2187 + 2188 + .group:hover .group-hover\:bg-zinc-50 { 2189 + --tw-bg-opacity: 1; 2190 + background-color: rgb(250 250 250 / var(--tw-bg-opacity)); 2191 + } 2192 + 2193 + .group:hover .group-hover\:fill-zinc-600 { 2194 + fill: #52525b; 2195 + } 2196 + 2197 + .group:hover .group-hover\:opacity-70 { 2198 + opacity: 0.7; 2199 + } 2200 + 2201 + .phx-submit-loading.phx-submit-loading\:opacity-75 { 2202 + opacity: 0.75; 2203 + } 2204 + 2205 + .phx-submit-loading .phx-submit-loading\:opacity-75 { 2206 + opacity: 0.75; 2207 + } 2208 + 2209 + @media (min-width: 640px) { 2210 + .sm\:w-96 { 2211 + width: 24rem; 2212 + } 2213 + 2214 + .sm\:w-auto { 2215 + width: auto; 2216 + } 2217 + 2218 + .sm\:w-full { 2219 + width: 100%; 2220 + } 2221 + 2222 + .sm\:translate-y-0 { 2223 + --tw-translate-y: 0px; 2224 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 2225 + } 2226 + 2227 + .sm\:scale-100 { 2228 + --tw-scale-x: 1; 2229 + --tw-scale-y: 1; 2230 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 2231 + } 2232 + 2233 + .sm\:scale-95 { 2234 + --tw-scale-x: .95; 2235 + --tw-scale-y: .95; 2236 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 2237 + } 2238 + 2239 + .sm\:grid-cols-2 { 2240 + grid-template-columns: repeat(2, minmax(0, 1fr)); 2241 + } 2242 + 2243 + .sm\:grid-cols-3 { 2244 + grid-template-columns: repeat(3, minmax(0, 1fr)); 2245 + } 2246 + 2247 + .sm\:flex-col { 2248 + flex-direction: column; 2249 + } 2250 + 2251 + .sm\:gap-8 { 2252 + gap: 2rem; 2253 + } 2254 + 2255 + .sm\:overflow-visible { 2256 + overflow: visible; 2257 + } 2258 + 2259 + .sm\:rounded-l-xl { 2260 + border-top-left-radius: 0.75rem; 2261 + border-bottom-left-radius: 0.75rem; 2262 + } 2263 + 2264 + .sm\:rounded-r-xl { 2265 + border-top-right-radius: 0.75rem; 2266 + border-bottom-right-radius: 0.75rem; 2267 + } 2268 + 2269 + .sm\:p-6 { 2270 + padding: 1.5rem; 2271 + } 2272 + 2273 + .sm\:px-0 { 2274 + padding-left: 0px; 2275 + padding-right: 0px; 2276 + } 2277 + 2278 + .sm\:px-6 { 2279 + padding-left: 1.5rem; 2280 + padding-right: 1.5rem; 2281 + } 2282 + 2283 + .sm\:py-28 { 2284 + padding-top: 7rem; 2285 + padding-bottom: 7rem; 2286 + } 2287 + 2288 + .sm\:py-6 { 2289 + padding-top: 1.5rem; 2290 + padding-bottom: 1.5rem; 2291 + } 2292 + 2293 + .sm\:text-sm { 2294 + font-size: 0.875rem; 2295 + line-height: 1.25rem; 2296 + } 2297 + 2298 + .sm\:leading-6 { 2299 + line-height: 1.5rem; 2300 + } 2301 + 2302 + .group:hover .sm\:group-hover\:scale-105 { 2303 + --tw-scale-x: 1.05; 2304 + --tw-scale-y: 1.05; 2305 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 2306 + } 2307 + } 2308 + 2309 + @media (min-width: 768px) { 2310 + .md\:w-3\/4 { 2311 + width: 75%; 2312 + } 2313 + 2314 + .md\:grid-cols-2 { 2315 + grid-template-columns: repeat(2, minmax(0, 1fr)); 2316 + } 2317 + 2318 + .md\:grid-cols-3 { 2319 + grid-template-columns: repeat(3, minmax(0, 1fr)); 2320 + } 2321 + } 2322 + 2323 + @media (min-width: 1024px) { 2324 + .lg\:mx-0 { 2325 + margin-left: 0px; 2326 + margin-right: 0px; 2327 + } 2328 + 2329 + .lg\:block { 2330 + display: block; 2331 + } 2332 + 2333 + .lg\:w-1\/2 { 2334 + width: 50%; 2335 + } 2336 + 2337 + .lg\:grid-cols-3 { 2338 + grid-template-columns: repeat(3, minmax(0, 1fr)); 2339 + } 2340 + 2341 + .lg\:px-8 { 2342 + padding-left: 2rem; 2343 + padding-right: 2rem; 2344 + } 2345 + 2346 + .lg\:py-8 { 2347 + padding-top: 2rem; 2348 + padding-bottom: 2rem; 2349 + } 2350 + } 2351 + 2352 + @media (min-width: 1280px) { 2353 + .xl\:left-\[50rem\] { 2354 + left: 50rem; 2355 + } 2356 + 2357 + .xl\:grid-cols-4 { 2358 + grid-template-columns: repeat(4, minmax(0, 1fr)); 2359 + } 2360 + 2361 + .xl\:px-28 { 2362 + padding-left: 7rem; 2363 + padding-right: 7rem; 2364 + } 2365 + 2366 + .xl\:py-32 { 2367 + padding-top: 8rem; 2368 + padding-bottom: 8rem; 2369 + } 2370 + }
+7282
priv/static/assets/app.js
··· 1 + (() => { 2 + var __create = Object.create; 3 + var __defProp = Object.defineProperty; 4 + var __defProps = Object.defineProperties; 5 + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 6 + var __getOwnPropDescs = Object.getOwnPropertyDescriptors; 7 + var __getOwnPropNames = Object.getOwnPropertyNames; 8 + var __getOwnPropSymbols = Object.getOwnPropertySymbols; 9 + var __getProtoOf = Object.getPrototypeOf; 10 + var __hasOwnProp = Object.prototype.hasOwnProperty; 11 + var __propIsEnum = Object.prototype.propertyIsEnumerable; 12 + var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; 13 + var __spreadValues = (a, b) => { 14 + for (var prop in b || (b = {})) 15 + if (__hasOwnProp.call(b, prop)) 16 + __defNormalProp(a, prop, b[prop]); 17 + if (__getOwnPropSymbols) 18 + for (var prop of __getOwnPropSymbols(b)) { 19 + if (__propIsEnum.call(b, prop)) 20 + __defNormalProp(a, prop, b[prop]); 21 + } 22 + return a; 23 + }; 24 + var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); 25 + var __commonJS = (cb, mod) => function __require() { 26 + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 27 + }; 28 + var __copyProps = (to, from, except, desc) => { 29 + if (from && typeof from === "object" || typeof from === "function") { 30 + for (let key of __getOwnPropNames(from)) 31 + if (!__hasOwnProp.call(to, key) && key !== except) 32 + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 33 + } 34 + return to; 35 + }; 36 + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 37 + // If the importer is in node compatibility mode or this is not an ESM 38 + // file that has been converted to a CommonJS file using a Babel- 39 + // compatible transform (i.e. "__esModule" has not been set), then set 40 + // "default" to the CommonJS "module.exports" for node compatibility. 41 + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 42 + mod 43 + )); 44 + 45 + // vendor/topbar.js 46 + var require_topbar = __commonJS({ 47 + "vendor/topbar.js"(exports, module) { 48 + (function(window2, document2) { 49 + "use strict"; 50 + (function() { 51 + var lastTime = 0; 52 + var vendors = ["ms", "moz", "webkit", "o"]; 53 + for (var x = 0; x < vendors.length && !window2.requestAnimationFrame; ++x) { 54 + window2.requestAnimationFrame = window2[vendors[x] + "RequestAnimationFrame"]; 55 + window2.cancelAnimationFrame = window2[vendors[x] + "CancelAnimationFrame"] || window2[vendors[x] + "CancelRequestAnimationFrame"]; 56 + } 57 + if (!window2.requestAnimationFrame) 58 + window2.requestAnimationFrame = function(callback, element) { 59 + var currTime = (/* @__PURE__ */ new Date()).getTime(); 60 + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 61 + var id = window2.setTimeout(function() { 62 + callback(currTime + timeToCall); 63 + }, timeToCall); 64 + lastTime = currTime + timeToCall; 65 + return id; 66 + }; 67 + if (!window2.cancelAnimationFrame) 68 + window2.cancelAnimationFrame = function(id) { 69 + clearTimeout(id); 70 + }; 71 + })(); 72 + var canvas, currentProgress, showing, progressTimerId = null, fadeTimerId = null, delayTimerId = null, addEvent = function(elem, type, handler) { 73 + if (elem.addEventListener) 74 + elem.addEventListener(type, handler, false); 75 + else if (elem.attachEvent) 76 + elem.attachEvent("on" + type, handler); 77 + else 78 + elem["on" + type] = handler; 79 + }, options = { 80 + autoRun: true, 81 + barThickness: 3, 82 + barColors: { 83 + 0: "rgba(26, 188, 156, .9)", 84 + ".25": "rgba(52, 152, 219, .9)", 85 + ".50": "rgba(241, 196, 15, .9)", 86 + ".75": "rgba(230, 126, 34, .9)", 87 + "1.0": "rgba(211, 84, 0, .9)" 88 + }, 89 + shadowBlur: 10, 90 + shadowColor: "rgba(0, 0, 0, .6)", 91 + className: null 92 + }, repaint = function() { 93 + canvas.width = window2.innerWidth; 94 + canvas.height = options.barThickness * 5; 95 + var ctx = canvas.getContext("2d"); 96 + ctx.shadowBlur = options.shadowBlur; 97 + ctx.shadowColor = options.shadowColor; 98 + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); 99 + for (var stop in options.barColors) 100 + lineGradient.addColorStop(stop, options.barColors[stop]); 101 + ctx.lineWidth = options.barThickness; 102 + ctx.beginPath(); 103 + ctx.moveTo(0, options.barThickness / 2); 104 + ctx.lineTo( 105 + Math.ceil(currentProgress * canvas.width), 106 + options.barThickness / 2 107 + ); 108 + ctx.strokeStyle = lineGradient; 109 + ctx.stroke(); 110 + }, createCanvas = function() { 111 + canvas = document2.createElement("canvas"); 112 + var style = canvas.style; 113 + style.position = "fixed"; 114 + style.top = style.left = style.right = style.margin = style.padding = 0; 115 + style.zIndex = 100001; 116 + style.display = "none"; 117 + if (options.className) 118 + canvas.classList.add(options.className); 119 + document2.body.appendChild(canvas); 120 + addEvent(window2, "resize", repaint); 121 + }, topbar2 = { 122 + config: function(opts) { 123 + for (var key in opts) 124 + if (options.hasOwnProperty(key)) 125 + options[key] = opts[key]; 126 + }, 127 + show: function(delay) { 128 + if (showing) 129 + return; 130 + if (delay) { 131 + if (delayTimerId) 132 + return; 133 + delayTimerId = setTimeout(() => topbar2.show(), delay); 134 + } else { 135 + showing = true; 136 + if (fadeTimerId !== null) 137 + window2.cancelAnimationFrame(fadeTimerId); 138 + if (!canvas) 139 + createCanvas(); 140 + canvas.style.opacity = 1; 141 + canvas.style.display = "block"; 142 + topbar2.progress(0); 143 + if (options.autoRun) { 144 + (function loop() { 145 + progressTimerId = window2.requestAnimationFrame(loop); 146 + topbar2.progress( 147 + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) 148 + ); 149 + })(); 150 + } 151 + } 152 + }, 153 + progress: function(to) { 154 + if (typeof to === "undefined") 155 + return currentProgress; 156 + if (typeof to === "string") { 157 + to = (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 ? currentProgress : 0) + parseFloat(to); 158 + } 159 + currentProgress = to > 1 ? 1 : to; 160 + repaint(); 161 + return currentProgress; 162 + }, 163 + hide: function() { 164 + clearTimeout(delayTimerId); 165 + delayTimerId = null; 166 + if (!showing) 167 + return; 168 + showing = false; 169 + if (progressTimerId != null) { 170 + window2.cancelAnimationFrame(progressTimerId); 171 + progressTimerId = null; 172 + } 173 + (function loop() { 174 + if (topbar2.progress("+.1") >= 1) { 175 + canvas.style.opacity -= 0.05; 176 + if (canvas.style.opacity <= 0.05) { 177 + canvas.style.display = "none"; 178 + fadeTimerId = null; 179 + return; 180 + } 181 + } 182 + fadeTimerId = window2.requestAnimationFrame(loop); 183 + })(); 184 + } 185 + }; 186 + if (typeof module === "object" && typeof module.exports === "object") { 187 + module.exports = topbar2; 188 + } else if (typeof define === "function" && define.amd) { 189 + define(function() { 190 + return topbar2; 191 + }); 192 + } else { 193 + this.topbar = topbar2; 194 + } 195 + }).call(exports, window, document); 196 + } 197 + }); 198 + 199 + // ../deps/phoenix_html/priv/static/phoenix_html.js 200 + (function() { 201 + var PolyfillEvent = eventConstructor(); 202 + function eventConstructor() { 203 + if (typeof window.CustomEvent === "function") 204 + return window.CustomEvent; 205 + function CustomEvent2(event, params) { 206 + params = params || { bubbles: false, cancelable: false, detail: void 0 }; 207 + var evt = document.createEvent("CustomEvent"); 208 + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); 209 + return evt; 210 + } 211 + CustomEvent2.prototype = window.Event.prototype; 212 + return CustomEvent2; 213 + } 214 + function buildHiddenInput(name, value) { 215 + var input = document.createElement("input"); 216 + input.type = "hidden"; 217 + input.name = name; 218 + input.value = value; 219 + return input; 220 + } 221 + function handleClick(element, targetModifierKey) { 222 + var to = element.getAttribute("data-to"), method = buildHiddenInput("_method", element.getAttribute("data-method")), csrf = buildHiddenInput("_csrf_token", element.getAttribute("data-csrf")), form = document.createElement("form"), submit = document.createElement("input"), target = element.getAttribute("target"); 223 + form.method = element.getAttribute("data-method") === "get" ? "get" : "post"; 224 + form.action = to; 225 + form.style.display = "none"; 226 + if (target) 227 + form.target = target; 228 + else if (targetModifierKey) 229 + form.target = "_blank"; 230 + form.appendChild(csrf); 231 + form.appendChild(method); 232 + document.body.appendChild(form); 233 + submit.type = "submit"; 234 + form.appendChild(submit); 235 + submit.click(); 236 + } 237 + window.addEventListener("click", function(e) { 238 + var element = e.target; 239 + if (e.defaultPrevented) 240 + return; 241 + while (element && element.getAttribute) { 242 + var phoenixLinkEvent = new PolyfillEvent("phoenix.link.click", { 243 + "bubbles": true, 244 + "cancelable": true 245 + }); 246 + if (!element.dispatchEvent(phoenixLinkEvent)) { 247 + e.preventDefault(); 248 + e.stopImmediatePropagation(); 249 + return false; 250 + } 251 + if (element.getAttribute("data-method") && element.getAttribute("data-to")) { 252 + handleClick(element, e.metaKey || e.shiftKey); 253 + e.preventDefault(); 254 + return false; 255 + } else { 256 + element = element.parentNode; 257 + } 258 + } 259 + }, false); 260 + window.addEventListener("phoenix.link.click", function(e) { 261 + var message = e.target.getAttribute("data-confirm"); 262 + if (message && !window.confirm(message)) { 263 + e.preventDefault(); 264 + } 265 + }, false); 266 + })(); 267 + 268 + // ../deps/phoenix/priv/static/phoenix.mjs 269 + var closure = (value) => { 270 + if (typeof value === "function") { 271 + return value; 272 + } else { 273 + let closure22 = function() { 274 + return value; 275 + }; 276 + return closure22; 277 + } 278 + }; 279 + var globalSelf = typeof self !== "undefined" ? self : null; 280 + var phxWindow = typeof window !== "undefined" ? window : null; 281 + var global = globalSelf || phxWindow || global; 282 + var DEFAULT_VSN = "2.0.0"; 283 + var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 }; 284 + var DEFAULT_TIMEOUT = 1e4; 285 + var WS_CLOSE_NORMAL = 1e3; 286 + var CHANNEL_STATES = { 287 + closed: "closed", 288 + errored: "errored", 289 + joined: "joined", 290 + joining: "joining", 291 + leaving: "leaving" 292 + }; 293 + var CHANNEL_EVENTS = { 294 + close: "phx_close", 295 + error: "phx_error", 296 + join: "phx_join", 297 + reply: "phx_reply", 298 + leave: "phx_leave" 299 + }; 300 + var TRANSPORTS = { 301 + longpoll: "longpoll", 302 + websocket: "websocket" 303 + }; 304 + var XHR_STATES = { 305 + complete: 4 306 + }; 307 + var Push = class { 308 + constructor(channel, event, payload, timeout) { 309 + this.channel = channel; 310 + this.event = event; 311 + this.payload = payload || function() { 312 + return {}; 313 + }; 314 + this.receivedResp = null; 315 + this.timeout = timeout; 316 + this.timeoutTimer = null; 317 + this.recHooks = []; 318 + this.sent = false; 319 + } 320 + /** 321 + * 322 + * @param {number} timeout 323 + */ 324 + resend(timeout) { 325 + this.timeout = timeout; 326 + this.reset(); 327 + this.send(); 328 + } 329 + /** 330 + * 331 + */ 332 + send() { 333 + if (this.hasReceived("timeout")) { 334 + return; 335 + } 336 + this.startTimeout(); 337 + this.sent = true; 338 + this.channel.socket.push({ 339 + topic: this.channel.topic, 340 + event: this.event, 341 + payload: this.payload(), 342 + ref: this.ref, 343 + join_ref: this.channel.joinRef() 344 + }); 345 + } 346 + /** 347 + * 348 + * @param {*} status 349 + * @param {*} callback 350 + */ 351 + receive(status, callback) { 352 + if (this.hasReceived(status)) { 353 + callback(this.receivedResp.response); 354 + } 355 + this.recHooks.push({ status, callback }); 356 + return this; 357 + } 358 + /** 359 + * @private 360 + */ 361 + reset() { 362 + this.cancelRefEvent(); 363 + this.ref = null; 364 + this.refEvent = null; 365 + this.receivedResp = null; 366 + this.sent = false; 367 + } 368 + /** 369 + * @private 370 + */ 371 + matchReceive({ status, response, _ref }) { 372 + this.recHooks.filter((h) => h.status === status).forEach((h) => h.callback(response)); 373 + } 374 + /** 375 + * @private 376 + */ 377 + cancelRefEvent() { 378 + if (!this.refEvent) { 379 + return; 380 + } 381 + this.channel.off(this.refEvent); 382 + } 383 + /** 384 + * @private 385 + */ 386 + cancelTimeout() { 387 + clearTimeout(this.timeoutTimer); 388 + this.timeoutTimer = null; 389 + } 390 + /** 391 + * @private 392 + */ 393 + startTimeout() { 394 + if (this.timeoutTimer) { 395 + this.cancelTimeout(); 396 + } 397 + this.ref = this.channel.socket.makeRef(); 398 + this.refEvent = this.channel.replyEventName(this.ref); 399 + this.channel.on(this.refEvent, (payload) => { 400 + this.cancelRefEvent(); 401 + this.cancelTimeout(); 402 + this.receivedResp = payload; 403 + this.matchReceive(payload); 404 + }); 405 + this.timeoutTimer = setTimeout(() => { 406 + this.trigger("timeout", {}); 407 + }, this.timeout); 408 + } 409 + /** 410 + * @private 411 + */ 412 + hasReceived(status) { 413 + return this.receivedResp && this.receivedResp.status === status; 414 + } 415 + /** 416 + * @private 417 + */ 418 + trigger(status, response) { 419 + this.channel.trigger(this.refEvent, { status, response }); 420 + } 421 + }; 422 + var Timer = class { 423 + constructor(callback, timerCalc) { 424 + this.callback = callback; 425 + this.timerCalc = timerCalc; 426 + this.timer = null; 427 + this.tries = 0; 428 + } 429 + reset() { 430 + this.tries = 0; 431 + clearTimeout(this.timer); 432 + } 433 + /** 434 + * Cancels any previous scheduleTimeout and schedules callback 435 + */ 436 + scheduleTimeout() { 437 + clearTimeout(this.timer); 438 + this.timer = setTimeout(() => { 439 + this.tries = this.tries + 1; 440 + this.callback(); 441 + }, this.timerCalc(this.tries + 1)); 442 + } 443 + }; 444 + var Channel = class { 445 + constructor(topic, params, socket) { 446 + this.state = CHANNEL_STATES.closed; 447 + this.topic = topic; 448 + this.params = closure(params || {}); 449 + this.socket = socket; 450 + this.bindings = []; 451 + this.bindingRef = 0; 452 + this.timeout = this.socket.timeout; 453 + this.joinedOnce = false; 454 + this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout); 455 + this.pushBuffer = []; 456 + this.stateChangeRefs = []; 457 + this.rejoinTimer = new Timer(() => { 458 + if (this.socket.isConnected()) { 459 + this.rejoin(); 460 + } 461 + }, this.socket.rejoinAfterMs); 462 + this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset())); 463 + this.stateChangeRefs.push( 464 + this.socket.onOpen(() => { 465 + this.rejoinTimer.reset(); 466 + if (this.isErrored()) { 467 + this.rejoin(); 468 + } 469 + }) 470 + ); 471 + this.joinPush.receive("ok", () => { 472 + this.state = CHANNEL_STATES.joined; 473 + this.rejoinTimer.reset(); 474 + this.pushBuffer.forEach((pushEvent) => pushEvent.send()); 475 + this.pushBuffer = []; 476 + }); 477 + this.joinPush.receive("error", () => { 478 + this.state = CHANNEL_STATES.errored; 479 + if (this.socket.isConnected()) { 480 + this.rejoinTimer.scheduleTimeout(); 481 + } 482 + }); 483 + this.onClose(() => { 484 + this.rejoinTimer.reset(); 485 + if (this.socket.hasLogger()) 486 + this.socket.log("channel", `close ${this.topic} ${this.joinRef()}`); 487 + this.state = CHANNEL_STATES.closed; 488 + this.socket.remove(this); 489 + }); 490 + this.onError((reason) => { 491 + if (this.socket.hasLogger()) 492 + this.socket.log("channel", `error ${this.topic}`, reason); 493 + if (this.isJoining()) { 494 + this.joinPush.reset(); 495 + } 496 + this.state = CHANNEL_STATES.errored; 497 + if (this.socket.isConnected()) { 498 + this.rejoinTimer.scheduleTimeout(); 499 + } 500 + }); 501 + this.joinPush.receive("timeout", () => { 502 + if (this.socket.hasLogger()) 503 + this.socket.log("channel", `timeout ${this.topic} (${this.joinRef()})`, this.joinPush.timeout); 504 + let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout); 505 + leavePush.send(); 506 + this.state = CHANNEL_STATES.errored; 507 + this.joinPush.reset(); 508 + if (this.socket.isConnected()) { 509 + this.rejoinTimer.scheduleTimeout(); 510 + } 511 + }); 512 + this.on(CHANNEL_EVENTS.reply, (payload, ref) => { 513 + this.trigger(this.replyEventName(ref), payload); 514 + }); 515 + } 516 + /** 517 + * Join the channel 518 + * @param {integer} timeout 519 + * @returns {Push} 520 + */ 521 + join(timeout = this.timeout) { 522 + if (this.joinedOnce) { 523 + throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance"); 524 + } else { 525 + this.timeout = timeout; 526 + this.joinedOnce = true; 527 + this.rejoin(); 528 + return this.joinPush; 529 + } 530 + } 531 + /** 532 + * Hook into channel close 533 + * @param {Function} callback 534 + */ 535 + onClose(callback) { 536 + this.on(CHANNEL_EVENTS.close, callback); 537 + } 538 + /** 539 + * Hook into channel errors 540 + * @param {Function} callback 541 + */ 542 + onError(callback) { 543 + return this.on(CHANNEL_EVENTS.error, (reason) => callback(reason)); 544 + } 545 + /** 546 + * Subscribes on channel events 547 + * 548 + * Subscription returns a ref counter, which can be used later to 549 + * unsubscribe the exact event listener 550 + * 551 + * @example 552 + * const ref1 = channel.on("event", do_stuff) 553 + * const ref2 = channel.on("event", do_other_stuff) 554 + * channel.off("event", ref1) 555 + * // Since unsubscription, do_stuff won't fire, 556 + * // while do_other_stuff will keep firing on the "event" 557 + * 558 + * @param {string} event 559 + * @param {Function} callback 560 + * @returns {integer} ref 561 + */ 562 + on(event, callback) { 563 + let ref = this.bindingRef++; 564 + this.bindings.push({ event, ref, callback }); 565 + return ref; 566 + } 567 + /** 568 + * Unsubscribes off of channel events 569 + * 570 + * Use the ref returned from a channel.on() to unsubscribe one 571 + * handler, or pass nothing for the ref to unsubscribe all 572 + * handlers for the given event. 573 + * 574 + * @example 575 + * // Unsubscribe the do_stuff handler 576 + * const ref1 = channel.on("event", do_stuff) 577 + * channel.off("event", ref1) 578 + * 579 + * // Unsubscribe all handlers from event 580 + * channel.off("event") 581 + * 582 + * @param {string} event 583 + * @param {integer} ref 584 + */ 585 + off(event, ref) { 586 + this.bindings = this.bindings.filter((bind) => { 587 + return !(bind.event === event && (typeof ref === "undefined" || ref === bind.ref)); 588 + }); 589 + } 590 + /** 591 + * @private 592 + */ 593 + canPush() { 594 + return this.socket.isConnected() && this.isJoined(); 595 + } 596 + /** 597 + * Sends a message `event` to phoenix with the payload `payload`. 598 + * Phoenix receives this in the `handle_in(event, payload, socket)` 599 + * function. if phoenix replies or it times out (default 10000ms), 600 + * then optionally the reply can be received. 601 + * 602 + * @example 603 + * channel.push("event") 604 + * .receive("ok", payload => console.log("phoenix replied:", payload)) 605 + * .receive("error", err => console.log("phoenix errored", err)) 606 + * .receive("timeout", () => console.log("timed out pushing")) 607 + * @param {string} event 608 + * @param {Object} payload 609 + * @param {number} [timeout] 610 + * @returns {Push} 611 + */ 612 + push(event, payload, timeout = this.timeout) { 613 + payload = payload || {}; 614 + if (!this.joinedOnce) { 615 + throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`); 616 + } 617 + let pushEvent = new Push(this, event, function() { 618 + return payload; 619 + }, timeout); 620 + if (this.canPush()) { 621 + pushEvent.send(); 622 + } else { 623 + pushEvent.startTimeout(); 624 + this.pushBuffer.push(pushEvent); 625 + } 626 + return pushEvent; 627 + } 628 + /** Leaves the channel 629 + * 630 + * Unsubscribes from server events, and 631 + * instructs channel to terminate on server 632 + * 633 + * Triggers onClose() hooks 634 + * 635 + * To receive leave acknowledgements, use the `receive` 636 + * hook to bind to the server ack, ie: 637 + * 638 + * @example 639 + * channel.leave().receive("ok", () => alert("left!") ) 640 + * 641 + * @param {integer} timeout 642 + * @returns {Push} 643 + */ 644 + leave(timeout = this.timeout) { 645 + this.rejoinTimer.reset(); 646 + this.joinPush.cancelTimeout(); 647 + this.state = CHANNEL_STATES.leaving; 648 + let onClose = () => { 649 + if (this.socket.hasLogger()) 650 + this.socket.log("channel", `leave ${this.topic}`); 651 + this.trigger(CHANNEL_EVENTS.close, "leave"); 652 + }; 653 + let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout); 654 + leavePush.receive("ok", () => onClose()).receive("timeout", () => onClose()); 655 + leavePush.send(); 656 + if (!this.canPush()) { 657 + leavePush.trigger("ok", {}); 658 + } 659 + return leavePush; 660 + } 661 + /** 662 + * Overridable message hook 663 + * 664 + * Receives all events for specialized message handling 665 + * before dispatching to the channel callbacks. 666 + * 667 + * Must return the payload, modified or unmodified 668 + * @param {string} event 669 + * @param {Object} payload 670 + * @param {integer} ref 671 + * @returns {Object} 672 + */ 673 + onMessage(_event, payload, _ref) { 674 + return payload; 675 + } 676 + /** 677 + * @private 678 + */ 679 + isMember(topic, event, payload, joinRef) { 680 + if (this.topic !== topic) { 681 + return false; 682 + } 683 + if (joinRef && joinRef !== this.joinRef()) { 684 + if (this.socket.hasLogger()) 685 + this.socket.log("channel", "dropping outdated message", { topic, event, payload, joinRef }); 686 + return false; 687 + } else { 688 + return true; 689 + } 690 + } 691 + /** 692 + * @private 693 + */ 694 + joinRef() { 695 + return this.joinPush.ref; 696 + } 697 + /** 698 + * @private 699 + */ 700 + rejoin(timeout = this.timeout) { 701 + if (this.isLeaving()) { 702 + return; 703 + } 704 + this.socket.leaveOpenTopic(this.topic); 705 + this.state = CHANNEL_STATES.joining; 706 + this.joinPush.resend(timeout); 707 + } 708 + /** 709 + * @private 710 + */ 711 + trigger(event, payload, ref, joinRef) { 712 + let handledPayload = this.onMessage(event, payload, ref, joinRef); 713 + if (payload && !handledPayload) { 714 + throw new Error("channel onMessage callbacks must return the payload, modified or unmodified"); 715 + } 716 + let eventBindings = this.bindings.filter((bind) => bind.event === event); 717 + for (let i = 0; i < eventBindings.length; i++) { 718 + let bind = eventBindings[i]; 719 + bind.callback(handledPayload, ref, joinRef || this.joinRef()); 720 + } 721 + } 722 + /** 723 + * @private 724 + */ 725 + replyEventName(ref) { 726 + return `chan_reply_${ref}`; 727 + } 728 + /** 729 + * @private 730 + */ 731 + isClosed() { 732 + return this.state === CHANNEL_STATES.closed; 733 + } 734 + /** 735 + * @private 736 + */ 737 + isErrored() { 738 + return this.state === CHANNEL_STATES.errored; 739 + } 740 + /** 741 + * @private 742 + */ 743 + isJoined() { 744 + return this.state === CHANNEL_STATES.joined; 745 + } 746 + /** 747 + * @private 748 + */ 749 + isJoining() { 750 + return this.state === CHANNEL_STATES.joining; 751 + } 752 + /** 753 + * @private 754 + */ 755 + isLeaving() { 756 + return this.state === CHANNEL_STATES.leaving; 757 + } 758 + }; 759 + var Ajax = class { 760 + static request(method, endPoint, accept, body, timeout, ontimeout, callback) { 761 + if (global.XDomainRequest) { 762 + let req = new global.XDomainRequest(); 763 + return this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback); 764 + } else { 765 + let req = new global.XMLHttpRequest(); 766 + return this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback); 767 + } 768 + } 769 + static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) { 770 + req.timeout = timeout; 771 + req.open(method, endPoint); 772 + req.onload = () => { 773 + let response = this.parseJSON(req.responseText); 774 + callback && callback(response); 775 + }; 776 + if (ontimeout) { 777 + req.ontimeout = ontimeout; 778 + } 779 + req.onprogress = () => { 780 + }; 781 + req.send(body); 782 + return req; 783 + } 784 + static xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) { 785 + req.open(method, endPoint, true); 786 + req.timeout = timeout; 787 + req.setRequestHeader("Content-Type", accept); 788 + req.onerror = () => callback && callback(null); 789 + req.onreadystatechange = () => { 790 + if (req.readyState === XHR_STATES.complete && callback) { 791 + let response = this.parseJSON(req.responseText); 792 + callback(response); 793 + } 794 + }; 795 + if (ontimeout) { 796 + req.ontimeout = ontimeout; 797 + } 798 + req.send(body); 799 + return req; 800 + } 801 + static parseJSON(resp) { 802 + if (!resp || resp === "") { 803 + return null; 804 + } 805 + try { 806 + return JSON.parse(resp); 807 + } catch (e) { 808 + console && console.log("failed to parse JSON response", resp); 809 + return null; 810 + } 811 + } 812 + static serialize(obj, parentKey) { 813 + let queryStr = []; 814 + for (var key in obj) { 815 + if (!Object.prototype.hasOwnProperty.call(obj, key)) { 816 + continue; 817 + } 818 + let paramKey = parentKey ? `${parentKey}[${key}]` : key; 819 + let paramVal = obj[key]; 820 + if (typeof paramVal === "object") { 821 + queryStr.push(this.serialize(paramVal, paramKey)); 822 + } else { 823 + queryStr.push(encodeURIComponent(paramKey) + "=" + encodeURIComponent(paramVal)); 824 + } 825 + } 826 + return queryStr.join("&"); 827 + } 828 + static appendParams(url, params) { 829 + if (Object.keys(params).length === 0) { 830 + return url; 831 + } 832 + let prefix = url.match(/\?/) ? "&" : "?"; 833 + return `${url}${prefix}${this.serialize(params)}`; 834 + } 835 + }; 836 + var arrayBufferToBase64 = (buffer) => { 837 + let binary = ""; 838 + let bytes = new Uint8Array(buffer); 839 + let len = bytes.byteLength; 840 + for (let i = 0; i < len; i++) { 841 + binary += String.fromCharCode(bytes[i]); 842 + } 843 + return btoa(binary); 844 + }; 845 + var LongPoll = class { 846 + constructor(endPoint) { 847 + this.endPoint = null; 848 + this.token = null; 849 + this.skipHeartbeat = true; 850 + this.reqs = /* @__PURE__ */ new Set(); 851 + this.awaitingBatchAck = false; 852 + this.currentBatch = null; 853 + this.currentBatchTimer = null; 854 + this.batchBuffer = []; 855 + this.onopen = function() { 856 + }; 857 + this.onerror = function() { 858 + }; 859 + this.onmessage = function() { 860 + }; 861 + this.onclose = function() { 862 + }; 863 + this.pollEndpoint = this.normalizeEndpoint(endPoint); 864 + this.readyState = SOCKET_STATES.connecting; 865 + setTimeout(() => this.poll(), 0); 866 + } 867 + normalizeEndpoint(endPoint) { 868 + return endPoint.replace("ws://", "http://").replace("wss://", "https://").replace(new RegExp("(.*)/" + TRANSPORTS.websocket), "$1/" + TRANSPORTS.longpoll); 869 + } 870 + endpointURL() { 871 + return Ajax.appendParams(this.pollEndpoint, { token: this.token }); 872 + } 873 + closeAndRetry(code, reason, wasClean) { 874 + this.close(code, reason, wasClean); 875 + this.readyState = SOCKET_STATES.connecting; 876 + } 877 + ontimeout() { 878 + this.onerror("timeout"); 879 + this.closeAndRetry(1005, "timeout", false); 880 + } 881 + isActive() { 882 + return this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting; 883 + } 884 + poll() { 885 + this.ajax("GET", "application/json", null, () => this.ontimeout(), (resp) => { 886 + if (resp) { 887 + var { status, token, messages } = resp; 888 + this.token = token; 889 + } else { 890 + status = 0; 891 + } 892 + switch (status) { 893 + case 200: 894 + messages.forEach((msg) => { 895 + setTimeout(() => this.onmessage({ data: msg }), 0); 896 + }); 897 + this.poll(); 898 + break; 899 + case 204: 900 + this.poll(); 901 + break; 902 + case 410: 903 + this.readyState = SOCKET_STATES.open; 904 + this.onopen({}); 905 + this.poll(); 906 + break; 907 + case 403: 908 + this.onerror(403); 909 + this.close(1008, "forbidden", false); 910 + break; 911 + case 0: 912 + case 500: 913 + this.onerror(500); 914 + this.closeAndRetry(1011, "internal server error", 500); 915 + break; 916 + default: 917 + throw new Error(`unhandled poll status ${status}`); 918 + } 919 + }); 920 + } 921 + // we collect all pushes within the current event loop by 922 + // setTimeout 0, which optimizes back-to-back procedural 923 + // pushes against an empty buffer 924 + send(body) { 925 + if (typeof body !== "string") { 926 + body = arrayBufferToBase64(body); 927 + } 928 + if (this.currentBatch) { 929 + this.currentBatch.push(body); 930 + } else if (this.awaitingBatchAck) { 931 + this.batchBuffer.push(body); 932 + } else { 933 + this.currentBatch = [body]; 934 + this.currentBatchTimer = setTimeout(() => { 935 + this.batchSend(this.currentBatch); 936 + this.currentBatch = null; 937 + }, 0); 938 + } 939 + } 940 + batchSend(messages) { 941 + this.awaitingBatchAck = true; 942 + this.ajax("POST", "application/x-ndjson", messages.join("\n"), () => this.onerror("timeout"), (resp) => { 943 + this.awaitingBatchAck = false; 944 + if (!resp || resp.status !== 200) { 945 + this.onerror(resp && resp.status); 946 + this.closeAndRetry(1011, "internal server error", false); 947 + } else if (this.batchBuffer.length > 0) { 948 + this.batchSend(this.batchBuffer); 949 + this.batchBuffer = []; 950 + } 951 + }); 952 + } 953 + close(code, reason, wasClean) { 954 + for (let req of this.reqs) { 955 + req.abort(); 956 + } 957 + this.readyState = SOCKET_STATES.closed; 958 + let opts = Object.assign({ code: 1e3, reason: void 0, wasClean: true }, { code, reason, wasClean }); 959 + this.batchBuffer = []; 960 + clearTimeout(this.currentBatchTimer); 961 + this.currentBatchTimer = null; 962 + if (typeof CloseEvent !== "undefined") { 963 + this.onclose(new CloseEvent("close", opts)); 964 + } else { 965 + this.onclose(opts); 966 + } 967 + } 968 + ajax(method, contentType, body, onCallerTimeout, callback) { 969 + let req; 970 + let ontimeout = () => { 971 + this.reqs.delete(req); 972 + onCallerTimeout(); 973 + }; 974 + req = Ajax.request(method, this.endpointURL(), contentType, body, this.timeout, ontimeout, (resp) => { 975 + this.reqs.delete(req); 976 + if (this.isActive()) { 977 + callback(resp); 978 + } 979 + }); 980 + this.reqs.add(req); 981 + } 982 + }; 983 + var serializer_default = { 984 + HEADER_LENGTH: 1, 985 + META_LENGTH: 4, 986 + KINDS: { push: 0, reply: 1, broadcast: 2 }, 987 + encode(msg, callback) { 988 + if (msg.payload.constructor === ArrayBuffer) { 989 + return callback(this.binaryEncode(msg)); 990 + } else { 991 + let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]; 992 + return callback(JSON.stringify(payload)); 993 + } 994 + }, 995 + decode(rawPayload, callback) { 996 + if (rawPayload.constructor === ArrayBuffer) { 997 + return callback(this.binaryDecode(rawPayload)); 998 + } else { 999 + let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload); 1000 + return callback({ join_ref, ref, topic, event, payload }); 1001 + } 1002 + }, 1003 + // private 1004 + binaryEncode(message) { 1005 + let { join_ref, ref, event, topic, payload } = message; 1006 + let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length; 1007 + let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength); 1008 + let view = new DataView(header); 1009 + let offset = 0; 1010 + view.setUint8(offset++, this.KINDS.push); 1011 + view.setUint8(offset++, join_ref.length); 1012 + view.setUint8(offset++, ref.length); 1013 + view.setUint8(offset++, topic.length); 1014 + view.setUint8(offset++, event.length); 1015 + Array.from(join_ref, (char) => view.setUint8(offset++, char.charCodeAt(0))); 1016 + Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0))); 1017 + Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0))); 1018 + Array.from(event, (char) => view.setUint8(offset++, char.charCodeAt(0))); 1019 + var combined = new Uint8Array(header.byteLength + payload.byteLength); 1020 + combined.set(new Uint8Array(header), 0); 1021 + combined.set(new Uint8Array(payload), header.byteLength); 1022 + return combined.buffer; 1023 + }, 1024 + binaryDecode(buffer) { 1025 + let view = new DataView(buffer); 1026 + let kind = view.getUint8(0); 1027 + let decoder = new TextDecoder(); 1028 + switch (kind) { 1029 + case this.KINDS.push: 1030 + return this.decodePush(buffer, view, decoder); 1031 + case this.KINDS.reply: 1032 + return this.decodeReply(buffer, view, decoder); 1033 + case this.KINDS.broadcast: 1034 + return this.decodeBroadcast(buffer, view, decoder); 1035 + } 1036 + }, 1037 + decodePush(buffer, view, decoder) { 1038 + let joinRefSize = view.getUint8(1); 1039 + let topicSize = view.getUint8(2); 1040 + let eventSize = view.getUint8(3); 1041 + let offset = this.HEADER_LENGTH + this.META_LENGTH - 1; 1042 + let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize)); 1043 + offset = offset + joinRefSize; 1044 + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); 1045 + offset = offset + topicSize; 1046 + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); 1047 + offset = offset + eventSize; 1048 + let data = buffer.slice(offset, buffer.byteLength); 1049 + return { join_ref: joinRef, ref: null, topic, event, payload: data }; 1050 + }, 1051 + decodeReply(buffer, view, decoder) { 1052 + let joinRefSize = view.getUint8(1); 1053 + let refSize = view.getUint8(2); 1054 + let topicSize = view.getUint8(3); 1055 + let eventSize = view.getUint8(4); 1056 + let offset = this.HEADER_LENGTH + this.META_LENGTH; 1057 + let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize)); 1058 + offset = offset + joinRefSize; 1059 + let ref = decoder.decode(buffer.slice(offset, offset + refSize)); 1060 + offset = offset + refSize; 1061 + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); 1062 + offset = offset + topicSize; 1063 + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); 1064 + offset = offset + eventSize; 1065 + let data = buffer.slice(offset, buffer.byteLength); 1066 + let payload = { status: event, response: data }; 1067 + return { join_ref: joinRef, ref, topic, event: CHANNEL_EVENTS.reply, payload }; 1068 + }, 1069 + decodeBroadcast(buffer, view, decoder) { 1070 + let topicSize = view.getUint8(1); 1071 + let eventSize = view.getUint8(2); 1072 + let offset = this.HEADER_LENGTH + 2; 1073 + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); 1074 + offset = offset + topicSize; 1075 + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); 1076 + offset = offset + eventSize; 1077 + let data = buffer.slice(offset, buffer.byteLength); 1078 + return { join_ref: null, ref: null, topic, event, payload: data }; 1079 + } 1080 + }; 1081 + var Socket = class { 1082 + constructor(endPoint, opts = {}) { 1083 + this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] }; 1084 + this.channels = []; 1085 + this.sendBuffer = []; 1086 + this.ref = 0; 1087 + this.timeout = opts.timeout || DEFAULT_TIMEOUT; 1088 + this.transport = opts.transport || global.WebSocket || LongPoll; 1089 + this.primaryPassedHealthCheck = false; 1090 + this.longPollFallbackMs = opts.longPollFallbackMs; 1091 + this.fallbackTimer = null; 1092 + this.sessionStore = opts.sessionStorage || global && global.sessionStorage; 1093 + this.establishedConnections = 0; 1094 + this.defaultEncoder = serializer_default.encode.bind(serializer_default); 1095 + this.defaultDecoder = serializer_default.decode.bind(serializer_default); 1096 + this.closeWasClean = false; 1097 + this.disconnecting = false; 1098 + this.binaryType = opts.binaryType || "arraybuffer"; 1099 + this.connectClock = 1; 1100 + if (this.transport !== LongPoll) { 1101 + this.encode = opts.encode || this.defaultEncoder; 1102 + this.decode = opts.decode || this.defaultDecoder; 1103 + } else { 1104 + this.encode = this.defaultEncoder; 1105 + this.decode = this.defaultDecoder; 1106 + } 1107 + let awaitingConnectionOnPageShow = null; 1108 + if (phxWindow && phxWindow.addEventListener) { 1109 + phxWindow.addEventListener("pagehide", (_e) => { 1110 + if (this.conn) { 1111 + this.disconnect(); 1112 + awaitingConnectionOnPageShow = this.connectClock; 1113 + } 1114 + }); 1115 + phxWindow.addEventListener("pageshow", (_e) => { 1116 + if (awaitingConnectionOnPageShow === this.connectClock) { 1117 + awaitingConnectionOnPageShow = null; 1118 + this.connect(); 1119 + } 1120 + }); 1121 + } 1122 + this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4; 1123 + this.rejoinAfterMs = (tries) => { 1124 + if (opts.rejoinAfterMs) { 1125 + return opts.rejoinAfterMs(tries); 1126 + } else { 1127 + return [1e3, 2e3, 5e3][tries - 1] || 1e4; 1128 + } 1129 + }; 1130 + this.reconnectAfterMs = (tries) => { 1131 + if (opts.reconnectAfterMs) { 1132 + return opts.reconnectAfterMs(tries); 1133 + } else { 1134 + return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3; 1135 + } 1136 + }; 1137 + this.logger = opts.logger || null; 1138 + if (!this.logger && opts.debug) { 1139 + this.logger = (kind, msg, data) => { 1140 + console.log(`${kind}: ${msg}`, data); 1141 + }; 1142 + } 1143 + this.longpollerTimeout = opts.longpollerTimeout || 2e4; 1144 + this.params = closure(opts.params || {}); 1145 + this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`; 1146 + this.vsn = opts.vsn || DEFAULT_VSN; 1147 + this.heartbeatTimeoutTimer = null; 1148 + this.heartbeatTimer = null; 1149 + this.pendingHeartbeatRef = null; 1150 + this.reconnectTimer = new Timer(() => { 1151 + this.teardown(() => this.connect()); 1152 + }, this.reconnectAfterMs); 1153 + } 1154 + /** 1155 + * Returns the LongPoll transport reference 1156 + */ 1157 + getLongPollTransport() { 1158 + return LongPoll; 1159 + } 1160 + /** 1161 + * Disconnects and replaces the active transport 1162 + * 1163 + * @param {Function} newTransport - The new transport class to instantiate 1164 + * 1165 + */ 1166 + replaceTransport(newTransport) { 1167 + this.connectClock++; 1168 + this.closeWasClean = true; 1169 + clearTimeout(this.fallbackTimer); 1170 + this.reconnectTimer.reset(); 1171 + if (this.conn) { 1172 + this.conn.close(); 1173 + this.conn = null; 1174 + } 1175 + this.transport = newTransport; 1176 + } 1177 + /** 1178 + * Returns the socket protocol 1179 + * 1180 + * @returns {string} 1181 + */ 1182 + protocol() { 1183 + return location.protocol.match(/^https/) ? "wss" : "ws"; 1184 + } 1185 + /** 1186 + * The fully qualified socket url 1187 + * 1188 + * @returns {string} 1189 + */ 1190 + endPointURL() { 1191 + let uri = Ajax.appendParams( 1192 + Ajax.appendParams(this.endPoint, this.params()), 1193 + { vsn: this.vsn } 1194 + ); 1195 + if (uri.charAt(0) !== "/") { 1196 + return uri; 1197 + } 1198 + if (uri.charAt(1) === "/") { 1199 + return `${this.protocol()}:${uri}`; 1200 + } 1201 + return `${this.protocol()}://${location.host}${uri}`; 1202 + } 1203 + /** 1204 + * Disconnects the socket 1205 + * 1206 + * See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes for valid status codes. 1207 + * 1208 + * @param {Function} callback - Optional callback which is called after socket is disconnected. 1209 + * @param {integer} code - A status code for disconnection (Optional). 1210 + * @param {string} reason - A textual description of the reason to disconnect. (Optional) 1211 + */ 1212 + disconnect(callback, code, reason) { 1213 + this.connectClock++; 1214 + this.disconnecting = true; 1215 + this.closeWasClean = true; 1216 + clearTimeout(this.fallbackTimer); 1217 + this.reconnectTimer.reset(); 1218 + this.teardown(() => { 1219 + this.disconnecting = false; 1220 + callback && callback(); 1221 + }, code, reason); 1222 + } 1223 + /** 1224 + * 1225 + * @param {Object} params - The params to send when connecting, for example `{user_id: userToken}` 1226 + * 1227 + * Passing params to connect is deprecated; pass them in the Socket constructor instead: 1228 + * `new Socket("/socket", {params: {user_id: userToken}})`. 1229 + */ 1230 + connect(params) { 1231 + if (params) { 1232 + console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"); 1233 + this.params = closure(params); 1234 + } 1235 + if (this.conn && !this.disconnecting) { 1236 + return; 1237 + } 1238 + if (this.longPollFallbackMs && this.transport !== LongPoll) { 1239 + this.connectWithFallback(LongPoll, this.longPollFallbackMs); 1240 + } else { 1241 + this.transportConnect(); 1242 + } 1243 + } 1244 + /** 1245 + * Logs the message. Override `this.logger` for specialized logging. noops by default 1246 + * @param {string} kind 1247 + * @param {string} msg 1248 + * @param {Object} data 1249 + */ 1250 + log(kind, msg, data) { 1251 + this.logger && this.logger(kind, msg, data); 1252 + } 1253 + /** 1254 + * Returns true if a logger has been set on this socket. 1255 + */ 1256 + hasLogger() { 1257 + return this.logger !== null; 1258 + } 1259 + /** 1260 + * Registers callbacks for connection open events 1261 + * 1262 + * @example socket.onOpen(function(){ console.info("the socket was opened") }) 1263 + * 1264 + * @param {Function} callback 1265 + */ 1266 + onOpen(callback) { 1267 + let ref = this.makeRef(); 1268 + this.stateChangeCallbacks.open.push([ref, callback]); 1269 + return ref; 1270 + } 1271 + /** 1272 + * Registers callbacks for connection close events 1273 + * @param {Function} callback 1274 + */ 1275 + onClose(callback) { 1276 + let ref = this.makeRef(); 1277 + this.stateChangeCallbacks.close.push([ref, callback]); 1278 + return ref; 1279 + } 1280 + /** 1281 + * Registers callbacks for connection error events 1282 + * 1283 + * @example socket.onError(function(error){ alert("An error occurred") }) 1284 + * 1285 + * @param {Function} callback 1286 + */ 1287 + onError(callback) { 1288 + let ref = this.makeRef(); 1289 + this.stateChangeCallbacks.error.push([ref, callback]); 1290 + return ref; 1291 + } 1292 + /** 1293 + * Registers callbacks for connection message events 1294 + * @param {Function} callback 1295 + */ 1296 + onMessage(callback) { 1297 + let ref = this.makeRef(); 1298 + this.stateChangeCallbacks.message.push([ref, callback]); 1299 + return ref; 1300 + } 1301 + /** 1302 + * Pings the server and invokes the callback with the RTT in milliseconds 1303 + * @param {Function} callback 1304 + * 1305 + * Returns true if the ping was pushed or false if unable to be pushed. 1306 + */ 1307 + ping(callback) { 1308 + if (!this.isConnected()) { 1309 + return false; 1310 + } 1311 + let ref = this.makeRef(); 1312 + let startTime = Date.now(); 1313 + this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref }); 1314 + let onMsgRef = this.onMessage((msg) => { 1315 + if (msg.ref === ref) { 1316 + this.off([onMsgRef]); 1317 + callback(Date.now() - startTime); 1318 + } 1319 + }); 1320 + return true; 1321 + } 1322 + /** 1323 + * @private 1324 + */ 1325 + transportConnect() { 1326 + this.connectClock++; 1327 + this.closeWasClean = false; 1328 + this.conn = new this.transport(this.endPointURL()); 1329 + this.conn.binaryType = this.binaryType; 1330 + this.conn.timeout = this.longpollerTimeout; 1331 + this.conn.onopen = () => this.onConnOpen(); 1332 + this.conn.onerror = (error) => this.onConnError(error); 1333 + this.conn.onmessage = (event) => this.onConnMessage(event); 1334 + this.conn.onclose = (event) => this.onConnClose(event); 1335 + } 1336 + getSession(key) { 1337 + return this.sessionStore && this.sessionStore.getItem(key); 1338 + } 1339 + storeSession(key, val) { 1340 + this.sessionStore && this.sessionStore.setItem(key, val); 1341 + } 1342 + connectWithFallback(fallbackTransport, fallbackThreshold = 2500) { 1343 + clearTimeout(this.fallbackTimer); 1344 + let established = false; 1345 + let primaryTransport = true; 1346 + let openRef, errorRef; 1347 + let fallback = (reason) => { 1348 + this.log("transport", `falling back to ${fallbackTransport.name}...`, reason); 1349 + this.off([openRef, errorRef]); 1350 + primaryTransport = false; 1351 + this.replaceTransport(fallbackTransport); 1352 + this.transportConnect(); 1353 + }; 1354 + if (this.getSession(`phx:fallback:${fallbackTransport.name}`)) { 1355 + return fallback("memorized"); 1356 + } 1357 + this.fallbackTimer = setTimeout(fallback, fallbackThreshold); 1358 + errorRef = this.onError((reason) => { 1359 + this.log("transport", "error", reason); 1360 + if (primaryTransport && !established) { 1361 + clearTimeout(this.fallbackTimer); 1362 + fallback(reason); 1363 + } 1364 + }); 1365 + this.onOpen(() => { 1366 + established = true; 1367 + if (!primaryTransport) { 1368 + if (!this.primaryPassedHealthCheck) { 1369 + this.storeSession(`phx:fallback:${fallbackTransport.name}`, "true"); 1370 + } 1371 + return this.log("transport", `established ${fallbackTransport.name} fallback`); 1372 + } 1373 + clearTimeout(this.fallbackTimer); 1374 + this.fallbackTimer = setTimeout(fallback, fallbackThreshold); 1375 + this.ping((rtt) => { 1376 + this.log("transport", "connected to primary after", rtt); 1377 + this.primaryPassedHealthCheck = true; 1378 + clearTimeout(this.fallbackTimer); 1379 + }); 1380 + }); 1381 + this.transportConnect(); 1382 + } 1383 + clearHeartbeats() { 1384 + clearTimeout(this.heartbeatTimer); 1385 + clearTimeout(this.heartbeatTimeoutTimer); 1386 + } 1387 + onConnOpen() { 1388 + if (this.hasLogger()) 1389 + this.log("transport", `${this.transport.name} connected to ${this.endPointURL()}`); 1390 + this.closeWasClean = false; 1391 + this.disconnecting = false; 1392 + this.establishedConnections++; 1393 + this.flushSendBuffer(); 1394 + this.reconnectTimer.reset(); 1395 + this.resetHeartbeat(); 1396 + this.stateChangeCallbacks.open.forEach(([, callback]) => callback()); 1397 + } 1398 + /** 1399 + * @private 1400 + */ 1401 + heartbeatTimeout() { 1402 + if (this.pendingHeartbeatRef) { 1403 + this.pendingHeartbeatRef = null; 1404 + if (this.hasLogger()) { 1405 + this.log("transport", "heartbeat timeout. Attempting to re-establish connection"); 1406 + } 1407 + this.triggerChanError(); 1408 + this.closeWasClean = false; 1409 + this.teardown(() => this.reconnectTimer.scheduleTimeout(), WS_CLOSE_NORMAL, "heartbeat timeout"); 1410 + } 1411 + } 1412 + resetHeartbeat() { 1413 + if (this.conn && this.conn.skipHeartbeat) { 1414 + return; 1415 + } 1416 + this.pendingHeartbeatRef = null; 1417 + this.clearHeartbeats(); 1418 + this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs); 1419 + } 1420 + teardown(callback, code, reason) { 1421 + if (!this.conn) { 1422 + return callback && callback(); 1423 + } 1424 + let connectClock = this.connectClock; 1425 + this.waitForBufferDone(() => { 1426 + if (connectClock !== this.connectClock) { 1427 + return; 1428 + } 1429 + if (this.conn) { 1430 + if (code) { 1431 + this.conn.close(code, reason || ""); 1432 + } else { 1433 + this.conn.close(); 1434 + } 1435 + } 1436 + this.waitForSocketClosed(() => { 1437 + if (connectClock !== this.connectClock) { 1438 + return; 1439 + } 1440 + if (this.conn) { 1441 + this.conn.onopen = function() { 1442 + }; 1443 + this.conn.onerror = function() { 1444 + }; 1445 + this.conn.onmessage = function() { 1446 + }; 1447 + this.conn.onclose = function() { 1448 + }; 1449 + this.conn = null; 1450 + } 1451 + callback && callback(); 1452 + }); 1453 + }); 1454 + } 1455 + waitForBufferDone(callback, tries = 1) { 1456 + if (tries === 5 || !this.conn || !this.conn.bufferedAmount) { 1457 + callback(); 1458 + return; 1459 + } 1460 + setTimeout(() => { 1461 + this.waitForBufferDone(callback, tries + 1); 1462 + }, 150 * tries); 1463 + } 1464 + waitForSocketClosed(callback, tries = 1) { 1465 + if (tries === 5 || !this.conn || this.conn.readyState === SOCKET_STATES.closed) { 1466 + callback(); 1467 + return; 1468 + } 1469 + setTimeout(() => { 1470 + this.waitForSocketClosed(callback, tries + 1); 1471 + }, 150 * tries); 1472 + } 1473 + onConnClose(event) { 1474 + let closeCode = event && event.code; 1475 + if (this.hasLogger()) 1476 + this.log("transport", "close", event); 1477 + this.triggerChanError(); 1478 + this.clearHeartbeats(); 1479 + if (!this.closeWasClean && closeCode !== 1e3) { 1480 + this.reconnectTimer.scheduleTimeout(); 1481 + } 1482 + this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event)); 1483 + } 1484 + /** 1485 + * @private 1486 + */ 1487 + onConnError(error) { 1488 + if (this.hasLogger()) 1489 + this.log("transport", error); 1490 + let transportBefore = this.transport; 1491 + let establishedBefore = this.establishedConnections; 1492 + this.stateChangeCallbacks.error.forEach(([, callback]) => { 1493 + callback(error, transportBefore, establishedBefore); 1494 + }); 1495 + if (transportBefore === this.transport || establishedBefore > 0) { 1496 + this.triggerChanError(); 1497 + } 1498 + } 1499 + /** 1500 + * @private 1501 + */ 1502 + triggerChanError() { 1503 + this.channels.forEach((channel) => { 1504 + if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) { 1505 + channel.trigger(CHANNEL_EVENTS.error); 1506 + } 1507 + }); 1508 + } 1509 + /** 1510 + * @returns {string} 1511 + */ 1512 + connectionState() { 1513 + switch (this.conn && this.conn.readyState) { 1514 + case SOCKET_STATES.connecting: 1515 + return "connecting"; 1516 + case SOCKET_STATES.open: 1517 + return "open"; 1518 + case SOCKET_STATES.closing: 1519 + return "closing"; 1520 + default: 1521 + return "closed"; 1522 + } 1523 + } 1524 + /** 1525 + * @returns {boolean} 1526 + */ 1527 + isConnected() { 1528 + return this.connectionState() === "open"; 1529 + } 1530 + /** 1531 + * @private 1532 + * 1533 + * @param {Channel} 1534 + */ 1535 + remove(channel) { 1536 + this.off(channel.stateChangeRefs); 1537 + this.channels = this.channels.filter((c) => c !== channel); 1538 + } 1539 + /** 1540 + * Removes `onOpen`, `onClose`, `onError,` and `onMessage` registrations. 1541 + * 1542 + * @param {refs} - list of refs returned by calls to 1543 + * `onOpen`, `onClose`, `onError,` and `onMessage` 1544 + */ 1545 + off(refs) { 1546 + for (let key in this.stateChangeCallbacks) { 1547 + this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => { 1548 + return refs.indexOf(ref) === -1; 1549 + }); 1550 + } 1551 + } 1552 + /** 1553 + * Initiates a new channel for the given topic 1554 + * 1555 + * @param {string} topic 1556 + * @param {Object} chanParams - Parameters for the channel 1557 + * @returns {Channel} 1558 + */ 1559 + channel(topic, chanParams = {}) { 1560 + let chan = new Channel(topic, chanParams, this); 1561 + this.channels.push(chan); 1562 + return chan; 1563 + } 1564 + /** 1565 + * @param {Object} data 1566 + */ 1567 + push(data) { 1568 + if (this.hasLogger()) { 1569 + let { topic, event, payload, ref, join_ref } = data; 1570 + this.log("push", `${topic} ${event} (${join_ref}, ${ref})`, payload); 1571 + } 1572 + if (this.isConnected()) { 1573 + this.encode(data, (result) => this.conn.send(result)); 1574 + } else { 1575 + this.sendBuffer.push(() => this.encode(data, (result) => this.conn.send(result))); 1576 + } 1577 + } 1578 + /** 1579 + * Return the next message ref, accounting for overflows 1580 + * @returns {string} 1581 + */ 1582 + makeRef() { 1583 + let newRef = this.ref + 1; 1584 + if (newRef === this.ref) { 1585 + this.ref = 0; 1586 + } else { 1587 + this.ref = newRef; 1588 + } 1589 + return this.ref.toString(); 1590 + } 1591 + sendHeartbeat() { 1592 + if (this.pendingHeartbeatRef && !this.isConnected()) { 1593 + return; 1594 + } 1595 + this.pendingHeartbeatRef = this.makeRef(); 1596 + this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef }); 1597 + this.heartbeatTimeoutTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs); 1598 + } 1599 + flushSendBuffer() { 1600 + if (this.isConnected() && this.sendBuffer.length > 0) { 1601 + this.sendBuffer.forEach((callback) => callback()); 1602 + this.sendBuffer = []; 1603 + } 1604 + } 1605 + onConnMessage(rawMessage) { 1606 + this.decode(rawMessage.data, (msg) => { 1607 + let { topic, event, payload, ref, join_ref } = msg; 1608 + if (ref && ref === this.pendingHeartbeatRef) { 1609 + this.clearHeartbeats(); 1610 + this.pendingHeartbeatRef = null; 1611 + this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs); 1612 + } 1613 + if (this.hasLogger()) 1614 + this.log("receive", `${payload.status || ""} ${topic} ${event} ${ref && "(" + ref + ")" || ""}`, payload); 1615 + for (let i = 0; i < this.channels.length; i++) { 1616 + const channel = this.channels[i]; 1617 + if (!channel.isMember(topic, event, payload, join_ref)) { 1618 + continue; 1619 + } 1620 + channel.trigger(event, payload, ref, join_ref); 1621 + } 1622 + for (let i = 0; i < this.stateChangeCallbacks.message.length; i++) { 1623 + let [, callback] = this.stateChangeCallbacks.message[i]; 1624 + callback(msg); 1625 + } 1626 + }); 1627 + } 1628 + leaveOpenTopic(topic) { 1629 + let dupChannel = this.channels.find((c) => c.topic === topic && (c.isJoined() || c.isJoining())); 1630 + if (dupChannel) { 1631 + if (this.hasLogger()) 1632 + this.log("transport", `leaving duplicate topic "${topic}"`); 1633 + dupChannel.leave(); 1634 + } 1635 + } 1636 + }; 1637 + 1638 + // ../deps/phoenix_live_view/priv/static/phoenix_live_view.esm.js 1639 + var CONSECUTIVE_RELOADS = "consecutive-reloads"; 1640 + var MAX_RELOADS = 10; 1641 + var RELOAD_JITTER_MIN = 5e3; 1642 + var RELOAD_JITTER_MAX = 1e4; 1643 + var FAILSAFE_JITTER = 3e4; 1644 + var PHX_EVENT_CLASSES = [ 1645 + "phx-click-loading", 1646 + "phx-change-loading", 1647 + "phx-submit-loading", 1648 + "phx-keydown-loading", 1649 + "phx-keyup-loading", 1650 + "phx-blur-loading", 1651 + "phx-focus-loading", 1652 + "phx-hook-loading" 1653 + ]; 1654 + var PHX_COMPONENT = "data-phx-component"; 1655 + var PHX_LIVE_LINK = "data-phx-link"; 1656 + var PHX_TRACK_STATIC = "track-static"; 1657 + var PHX_LINK_STATE = "data-phx-link-state"; 1658 + var PHX_REF_LOADING = "data-phx-ref-loading"; 1659 + var PHX_REF_SRC = "data-phx-ref-src"; 1660 + var PHX_REF_LOCK = "data-phx-ref-lock"; 1661 + var PHX_PENDING_REFS = "phx-pending-refs"; 1662 + var PHX_TRACK_UPLOADS = "track-uploads"; 1663 + var PHX_UPLOAD_REF = "data-phx-upload-ref"; 1664 + var PHX_PREFLIGHTED_REFS = "data-phx-preflighted-refs"; 1665 + var PHX_DONE_REFS = "data-phx-done-refs"; 1666 + var PHX_DROP_TARGET = "drop-target"; 1667 + var PHX_ACTIVE_ENTRY_REFS = "data-phx-active-refs"; 1668 + var PHX_LIVE_FILE_UPDATED = "phx:live-file:updated"; 1669 + var PHX_SKIP = "data-phx-skip"; 1670 + var PHX_MAGIC_ID = "data-phx-id"; 1671 + var PHX_PRUNE = "data-phx-prune"; 1672 + var PHX_CONNECTED_CLASS = "phx-connected"; 1673 + var PHX_LOADING_CLASS = "phx-loading"; 1674 + var PHX_ERROR_CLASS = "phx-error"; 1675 + var PHX_CLIENT_ERROR_CLASS = "phx-client-error"; 1676 + var PHX_SERVER_ERROR_CLASS = "phx-server-error"; 1677 + var PHX_PARENT_ID = "data-phx-parent-id"; 1678 + var PHX_MAIN = "data-phx-main"; 1679 + var PHX_ROOT_ID = "data-phx-root-id"; 1680 + var PHX_VIEWPORT_TOP = "viewport-top"; 1681 + var PHX_VIEWPORT_BOTTOM = "viewport-bottom"; 1682 + var PHX_TRIGGER_ACTION = "trigger-action"; 1683 + var PHX_HAS_FOCUSED = "phx-has-focused"; 1684 + var FOCUSABLE_INPUTS = ["text", "textarea", "number", "email", "password", "search", "tel", "url", "date", "time", "datetime-local", "color", "range"]; 1685 + var CHECKABLE_INPUTS = ["checkbox", "radio"]; 1686 + var PHX_HAS_SUBMITTED = "phx-has-submitted"; 1687 + var PHX_SESSION = "data-phx-session"; 1688 + var PHX_VIEW_SELECTOR = `[${PHX_SESSION}]`; 1689 + var PHX_STICKY = "data-phx-sticky"; 1690 + var PHX_STATIC = "data-phx-static"; 1691 + var PHX_READONLY = "data-phx-readonly"; 1692 + var PHX_DISABLED = "data-phx-disabled"; 1693 + var PHX_DISABLE_WITH = "disable-with"; 1694 + var PHX_DISABLE_WITH_RESTORE = "data-phx-disable-with-restore"; 1695 + var PHX_HOOK = "hook"; 1696 + var PHX_DEBOUNCE = "debounce"; 1697 + var PHX_THROTTLE = "throttle"; 1698 + var PHX_UPDATE = "update"; 1699 + var PHX_STREAM = "stream"; 1700 + var PHX_STREAM_REF = "data-phx-stream"; 1701 + var PHX_KEY = "key"; 1702 + var PHX_PRIVATE = "phxPrivate"; 1703 + var PHX_AUTO_RECOVER = "auto-recover"; 1704 + var PHX_LV_DEBUG = "phx:live-socket:debug"; 1705 + var PHX_LV_PROFILE = "phx:live-socket:profiling"; 1706 + var PHX_LV_LATENCY_SIM = "phx:live-socket:latency-sim"; 1707 + var PHX_LV_HISTORY_POSITION = "phx:nav-history-position"; 1708 + var PHX_PROGRESS = "progress"; 1709 + var PHX_MOUNTED = "mounted"; 1710 + var PHX_RELOAD_STATUS = "__phoenix_reload_status__"; 1711 + var LOADER_TIMEOUT = 1; 1712 + var MAX_CHILD_JOIN_ATTEMPTS = 3; 1713 + var BEFORE_UNLOAD_LOADER_TIMEOUT = 200; 1714 + var DISCONNECTED_TIMEOUT = 500; 1715 + var BINDING_PREFIX = "phx-"; 1716 + var PUSH_TIMEOUT = 3e4; 1717 + var DEBOUNCE_TRIGGER = "debounce-trigger"; 1718 + var THROTTLED = "throttled"; 1719 + var DEBOUNCE_PREV_KEY = "debounce-prev-key"; 1720 + var DEFAULTS = { 1721 + debounce: 300, 1722 + throttle: 300 1723 + }; 1724 + var PHX_PENDING_ATTRS = [PHX_REF_LOADING, PHX_REF_SRC, PHX_REF_LOCK]; 1725 + var DYNAMICS = "d"; 1726 + var STATIC = "s"; 1727 + var ROOT = "r"; 1728 + var COMPONENTS = "c"; 1729 + var EVENTS = "e"; 1730 + var REPLY = "r"; 1731 + var TITLE = "t"; 1732 + var TEMPLATES = "p"; 1733 + var STREAM = "stream"; 1734 + var EntryUploader = class { 1735 + constructor(entry, config, liveSocket2) { 1736 + let { chunk_size, chunk_timeout } = config; 1737 + this.liveSocket = liveSocket2; 1738 + this.entry = entry; 1739 + this.offset = 0; 1740 + this.chunkSize = chunk_size; 1741 + this.chunkTimeout = chunk_timeout; 1742 + this.chunkTimer = null; 1743 + this.errored = false; 1744 + this.uploadChannel = liveSocket2.channel(`lvu:${entry.ref}`, { token: entry.metadata() }); 1745 + } 1746 + error(reason) { 1747 + if (this.errored) { 1748 + return; 1749 + } 1750 + this.uploadChannel.leave(); 1751 + this.errored = true; 1752 + clearTimeout(this.chunkTimer); 1753 + this.entry.error(reason); 1754 + } 1755 + upload() { 1756 + this.uploadChannel.onError((reason) => this.error(reason)); 1757 + this.uploadChannel.join().receive("ok", (_data) => this.readNextChunk()).receive("error", (reason) => this.error(reason)); 1758 + } 1759 + isDone() { 1760 + return this.offset >= this.entry.file.size; 1761 + } 1762 + readNextChunk() { 1763 + let reader = new window.FileReader(); 1764 + let blob = this.entry.file.slice(this.offset, this.chunkSize + this.offset); 1765 + reader.onload = (e) => { 1766 + if (e.target.error === null) { 1767 + this.offset += e.target.result.byteLength; 1768 + this.pushChunk(e.target.result); 1769 + } else { 1770 + return logError("Read error: " + e.target.error); 1771 + } 1772 + }; 1773 + reader.readAsArrayBuffer(blob); 1774 + } 1775 + pushChunk(chunk) { 1776 + if (!this.uploadChannel.isJoined()) { 1777 + return; 1778 + } 1779 + this.uploadChannel.push("chunk", chunk, this.chunkTimeout).receive("ok", () => { 1780 + this.entry.progress(this.offset / this.entry.file.size * 100); 1781 + if (!this.isDone()) { 1782 + this.chunkTimer = setTimeout(() => this.readNextChunk(), this.liveSocket.getLatencySim() || 0); 1783 + } 1784 + }).receive("error", ({ reason }) => this.error(reason)); 1785 + } 1786 + }; 1787 + var logError = (msg, obj) => console.error && console.error(msg, obj); 1788 + var isCid = (cid) => { 1789 + let type = typeof cid; 1790 + return type === "number" || type === "string" && /^(0|[1-9]\d*)$/.test(cid); 1791 + }; 1792 + function detectDuplicateIds() { 1793 + let ids = /* @__PURE__ */ new Set(); 1794 + let elems = document.querySelectorAll("*[id]"); 1795 + for (let i = 0, len = elems.length; i < len; i++) { 1796 + if (ids.has(elems[i].id)) { 1797 + console.error(`Multiple IDs detected: ${elems[i].id}. Ensure unique element ids.`); 1798 + } else { 1799 + ids.add(elems[i].id); 1800 + } 1801 + } 1802 + } 1803 + function detectInvalidStreamInserts(inserts) { 1804 + const errors = /* @__PURE__ */ new Set(); 1805 + Object.keys(inserts).forEach((id) => { 1806 + const streamEl = document.getElementById(id); 1807 + if (streamEl && streamEl.parentElement && streamEl.parentElement.getAttribute("phx-update") !== "stream") { 1808 + errors.add(`The stream container with id "${streamEl.parentElement.id}" is missing the phx-update="stream" attribute. Ensure it is set for streams to work properly.`); 1809 + } 1810 + }); 1811 + errors.forEach((error) => console.error(error)); 1812 + } 1813 + var debug = (view, kind, msg, obj) => { 1814 + if (view.liveSocket.isDebugEnabled()) { 1815 + console.log(`${view.id} ${kind}: ${msg} - `, obj); 1816 + } 1817 + }; 1818 + var closure2 = (val) => typeof val === "function" ? val : function() { 1819 + return val; 1820 + }; 1821 + var clone = (obj) => { 1822 + return JSON.parse(JSON.stringify(obj)); 1823 + }; 1824 + var closestPhxBinding = (el, binding, borderEl) => { 1825 + do { 1826 + if (el.matches(`[${binding}]`) && !el.disabled) { 1827 + return el; 1828 + } 1829 + el = el.parentElement || el.parentNode; 1830 + } while (el !== null && el.nodeType === 1 && !(borderEl && borderEl.isSameNode(el) || el.matches(PHX_VIEW_SELECTOR))); 1831 + return null; 1832 + }; 1833 + var isObject = (obj) => { 1834 + return obj !== null && typeof obj === "object" && !(obj instanceof Array); 1835 + }; 1836 + var isEqualObj = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2); 1837 + var isEmpty = (obj) => { 1838 + for (let x in obj) { 1839 + return false; 1840 + } 1841 + return true; 1842 + }; 1843 + var maybe = (el, callback) => el && callback(el); 1844 + var channelUploader = function(entries, onError, resp, liveSocket2) { 1845 + entries.forEach((entry) => { 1846 + let entryUploader = new EntryUploader(entry, resp.config, liveSocket2); 1847 + entryUploader.upload(); 1848 + }); 1849 + }; 1850 + var Browser = { 1851 + canPushState() { 1852 + return typeof history.pushState !== "undefined"; 1853 + }, 1854 + dropLocal(localStorage, namespace, subkey) { 1855 + return localStorage.removeItem(this.localKey(namespace, subkey)); 1856 + }, 1857 + updateLocal(localStorage, namespace, subkey, initial, func) { 1858 + let current = this.getLocal(localStorage, namespace, subkey); 1859 + let key = this.localKey(namespace, subkey); 1860 + let newVal = current === null ? initial : func(current); 1861 + localStorage.setItem(key, JSON.stringify(newVal)); 1862 + return newVal; 1863 + }, 1864 + getLocal(localStorage, namespace, subkey) { 1865 + return JSON.parse(localStorage.getItem(this.localKey(namespace, subkey))); 1866 + }, 1867 + updateCurrentState(callback) { 1868 + if (!this.canPushState()) { 1869 + return; 1870 + } 1871 + history.replaceState(callback(history.state || {}), "", window.location.href); 1872 + }, 1873 + pushState(kind, meta, to) { 1874 + if (this.canPushState()) { 1875 + if (to !== window.location.href) { 1876 + if (meta.type == "redirect" && meta.scroll) { 1877 + let currentState = history.state || {}; 1878 + currentState.scroll = meta.scroll; 1879 + history.replaceState(currentState, "", window.location.href); 1880 + } 1881 + delete meta.scroll; 1882 + history[kind + "State"](meta, "", to || null); 1883 + window.requestAnimationFrame(() => { 1884 + let hashEl = this.getHashTargetEl(window.location.hash); 1885 + if (hashEl) { 1886 + hashEl.scrollIntoView(); 1887 + } else if (meta.type === "redirect") { 1888 + window.scroll(0, 0); 1889 + } 1890 + }); 1891 + } 1892 + } else { 1893 + this.redirect(to); 1894 + } 1895 + }, 1896 + setCookie(name, value, maxAgeSeconds) { 1897 + let expires = typeof maxAgeSeconds === "number" ? ` max-age=${maxAgeSeconds};` : ""; 1898 + document.cookie = `${name}=${value};${expires} path=/`; 1899 + }, 1900 + getCookie(name) { 1901 + return document.cookie.replace(new RegExp(`(?:(?:^|.*;s*)${name}s*=s*([^;]*).*$)|^.*$`), "$1"); 1902 + }, 1903 + deleteCookie(name) { 1904 + document.cookie = `${name}=; max-age=-1; path=/`; 1905 + }, 1906 + redirect(toURL, flash) { 1907 + if (flash) { 1908 + this.setCookie("__phoenix_flash__", flash, 60); 1909 + } 1910 + window.location = toURL; 1911 + }, 1912 + localKey(namespace, subkey) { 1913 + return `${namespace}-${subkey}`; 1914 + }, 1915 + getHashTargetEl(maybeHash) { 1916 + let hash = maybeHash.toString().substring(1); 1917 + if (hash === "") { 1918 + return; 1919 + } 1920 + return document.getElementById(hash) || document.querySelector(`a[name="${hash}"]`); 1921 + } 1922 + }; 1923 + var browser_default = Browser; 1924 + var DOM = { 1925 + byId(id) { 1926 + return document.getElementById(id) || logError(`no id found for ${id}`); 1927 + }, 1928 + removeClass(el, className) { 1929 + el.classList.remove(className); 1930 + if (el.classList.length === 0) { 1931 + el.removeAttribute("class"); 1932 + } 1933 + }, 1934 + all(node, query, callback) { 1935 + if (!node) { 1936 + return []; 1937 + } 1938 + let array = Array.from(node.querySelectorAll(query)); 1939 + return callback ? array.forEach(callback) : array; 1940 + }, 1941 + childNodeLength(html) { 1942 + let template = document.createElement("template"); 1943 + template.innerHTML = html; 1944 + return template.content.childElementCount; 1945 + }, 1946 + isUploadInput(el) { 1947 + return el.type === "file" && el.getAttribute(PHX_UPLOAD_REF) !== null; 1948 + }, 1949 + isAutoUpload(inputEl) { 1950 + return inputEl.hasAttribute("data-phx-auto-upload"); 1951 + }, 1952 + findUploadInputs(node) { 1953 + const formId = node.id; 1954 + const inputsOutsideForm = this.all(document, `input[type="file"][${PHX_UPLOAD_REF}][form="${formId}"]`); 1955 + return this.all(node, `input[type="file"][${PHX_UPLOAD_REF}]`).concat(inputsOutsideForm); 1956 + }, 1957 + findComponentNodeList(node, cid) { 1958 + return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node); 1959 + }, 1960 + isPhxDestroyed(node) { 1961 + return node.id && DOM.private(node, "destroyed") ? true : false; 1962 + }, 1963 + wantsNewTab(e) { 1964 + let wantsNewTab = e.ctrlKey || e.shiftKey || e.metaKey || e.button && e.button === 1; 1965 + let isDownload = e.target instanceof HTMLAnchorElement && e.target.hasAttribute("download"); 1966 + let isTargetBlank = e.target.hasAttribute("target") && e.target.getAttribute("target").toLowerCase() === "_blank"; 1967 + let isTargetNamedTab = e.target.hasAttribute("target") && !e.target.getAttribute("target").startsWith("_"); 1968 + return wantsNewTab || isTargetBlank || isDownload || isTargetNamedTab; 1969 + }, 1970 + isUnloadableFormSubmit(e) { 1971 + let isDialogSubmit = e.target && e.target.getAttribute("method") === "dialog" || e.submitter && e.submitter.getAttribute("formmethod") === "dialog"; 1972 + if (isDialogSubmit) { 1973 + return false; 1974 + } else { 1975 + return !e.defaultPrevented && !this.wantsNewTab(e); 1976 + } 1977 + }, 1978 + isNewPageClick(e, currentLocation) { 1979 + let href = e.target instanceof HTMLAnchorElement ? e.target.getAttribute("href") : null; 1980 + let url; 1981 + if (e.defaultPrevented || href === null || this.wantsNewTab(e)) { 1982 + return false; 1983 + } 1984 + if (href.startsWith("mailto:") || href.startsWith("tel:")) { 1985 + return false; 1986 + } 1987 + if (e.target.isContentEditable) { 1988 + return false; 1989 + } 1990 + try { 1991 + url = new URL(href); 1992 + } catch (e2) { 1993 + try { 1994 + url = new URL(href, currentLocation); 1995 + } catch (e3) { 1996 + return true; 1997 + } 1998 + } 1999 + if (url.host === currentLocation.host && url.protocol === currentLocation.protocol) { 2000 + if (url.pathname === currentLocation.pathname && url.search === currentLocation.search) { 2001 + return url.hash === "" && !url.href.endsWith("#"); 2002 + } 2003 + } 2004 + return url.protocol.startsWith("http"); 2005 + }, 2006 + markPhxChildDestroyed(el) { 2007 + if (this.isPhxChild(el)) { 2008 + el.setAttribute(PHX_SESSION, ""); 2009 + } 2010 + this.putPrivate(el, "destroyed", true); 2011 + }, 2012 + findPhxChildrenInFragment(html, parentId) { 2013 + let template = document.createElement("template"); 2014 + template.innerHTML = html; 2015 + return this.findPhxChildren(template.content, parentId); 2016 + }, 2017 + isIgnored(el, phxUpdate) { 2018 + return (el.getAttribute(phxUpdate) || el.getAttribute("data-phx-update")) === "ignore"; 2019 + }, 2020 + isPhxUpdate(el, phxUpdate, updateTypes) { 2021 + return el.getAttribute && updateTypes.indexOf(el.getAttribute(phxUpdate)) >= 0; 2022 + }, 2023 + findPhxSticky(el) { 2024 + return this.all(el, `[${PHX_STICKY}]`); 2025 + }, 2026 + findPhxChildren(el, parentId) { 2027 + return this.all(el, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}="${parentId}"]`); 2028 + }, 2029 + findExistingParentCIDs(node, cids) { 2030 + let parentCids = /* @__PURE__ */ new Set(); 2031 + let childrenCids = /* @__PURE__ */ new Set(); 2032 + cids.forEach((cid) => { 2033 + this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node).forEach((parent) => { 2034 + parentCids.add(cid); 2035 + this.filterWithinSameLiveView(this.all(parent, `[${PHX_COMPONENT}]`), parent).map((el) => parseInt(el.getAttribute(PHX_COMPONENT))).forEach((childCID) => childrenCids.add(childCID)); 2036 + }); 2037 + }); 2038 + childrenCids.forEach((childCid) => parentCids.delete(childCid)); 2039 + return parentCids; 2040 + }, 2041 + filterWithinSameLiveView(nodes, parent) { 2042 + if (parent.querySelector(PHX_VIEW_SELECTOR)) { 2043 + return nodes.filter((el) => this.withinSameLiveView(el, parent)); 2044 + } else { 2045 + return nodes; 2046 + } 2047 + }, 2048 + withinSameLiveView(node, parent) { 2049 + while (node = node.parentNode) { 2050 + if (node.isSameNode(parent)) { 2051 + return true; 2052 + } 2053 + if (node.getAttribute(PHX_SESSION) !== null) { 2054 + return false; 2055 + } 2056 + } 2057 + }, 2058 + private(el, key) { 2059 + return el[PHX_PRIVATE] && el[PHX_PRIVATE][key]; 2060 + }, 2061 + deletePrivate(el, key) { 2062 + el[PHX_PRIVATE] && delete el[PHX_PRIVATE][key]; 2063 + }, 2064 + putPrivate(el, key, value) { 2065 + if (!el[PHX_PRIVATE]) { 2066 + el[PHX_PRIVATE] = {}; 2067 + } 2068 + el[PHX_PRIVATE][key] = value; 2069 + }, 2070 + updatePrivate(el, key, defaultVal, updateFunc) { 2071 + let existing = this.private(el, key); 2072 + if (existing === void 0) { 2073 + this.putPrivate(el, key, updateFunc(defaultVal)); 2074 + } else { 2075 + this.putPrivate(el, key, updateFunc(existing)); 2076 + } 2077 + }, 2078 + syncPendingAttrs(fromEl, toEl) { 2079 + if (!fromEl.hasAttribute(PHX_REF_SRC)) { 2080 + return; 2081 + } 2082 + PHX_EVENT_CLASSES.forEach((className) => { 2083 + fromEl.classList.contains(className) && toEl.classList.add(className); 2084 + }); 2085 + PHX_PENDING_ATTRS.filter((attr) => fromEl.hasAttribute(attr)).forEach((attr) => { 2086 + toEl.setAttribute(attr, fromEl.getAttribute(attr)); 2087 + }); 2088 + }, 2089 + copyPrivates(target, source) { 2090 + if (source[PHX_PRIVATE]) { 2091 + target[PHX_PRIVATE] = source[PHX_PRIVATE]; 2092 + } 2093 + }, 2094 + putTitle(str) { 2095 + let titleEl = document.querySelector("title"); 2096 + if (titleEl) { 2097 + let { prefix, suffix, default: defaultTitle } = titleEl.dataset; 2098 + let isEmpty2 = typeof str !== "string" || str.trim() === ""; 2099 + if (isEmpty2 && typeof defaultTitle !== "string") { 2100 + return; 2101 + } 2102 + let inner = isEmpty2 ? defaultTitle : str; 2103 + document.title = `${prefix || ""}${inner || ""}${suffix || ""}`; 2104 + } else { 2105 + document.title = str; 2106 + } 2107 + }, 2108 + debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, callback) { 2109 + let debounce = el.getAttribute(phxDebounce); 2110 + let throttle = el.getAttribute(phxThrottle); 2111 + if (debounce === "") { 2112 + debounce = defaultDebounce; 2113 + } 2114 + if (throttle === "") { 2115 + throttle = defaultThrottle; 2116 + } 2117 + let value = debounce || throttle; 2118 + switch (value) { 2119 + case null: 2120 + return callback(); 2121 + case "blur": 2122 + this.incCycle(el, "debounce-blur-cycle", () => { 2123 + if (asyncFilter()) { 2124 + callback(); 2125 + } 2126 + }); 2127 + if (this.once(el, "debounce-blur")) { 2128 + el.addEventListener("blur", () => this.triggerCycle(el, "debounce-blur-cycle")); 2129 + } 2130 + return; 2131 + default: 2132 + let timeout = parseInt(value); 2133 + let trigger = () => throttle ? this.deletePrivate(el, THROTTLED) : callback(); 2134 + let currentCycle = this.incCycle(el, DEBOUNCE_TRIGGER, trigger); 2135 + if (isNaN(timeout)) { 2136 + return logError(`invalid throttle/debounce value: ${value}`); 2137 + } 2138 + if (throttle) { 2139 + let newKeyDown = false; 2140 + if (event.type === "keydown") { 2141 + let prevKey = this.private(el, DEBOUNCE_PREV_KEY); 2142 + this.putPrivate(el, DEBOUNCE_PREV_KEY, event.key); 2143 + newKeyDown = prevKey !== event.key; 2144 + } 2145 + if (!newKeyDown && this.private(el, THROTTLED)) { 2146 + return false; 2147 + } else { 2148 + callback(); 2149 + const t = setTimeout(() => { 2150 + if (asyncFilter()) { 2151 + this.triggerCycle(el, DEBOUNCE_TRIGGER); 2152 + } 2153 + }, timeout); 2154 + this.putPrivate(el, THROTTLED, t); 2155 + } 2156 + } else { 2157 + setTimeout(() => { 2158 + if (asyncFilter()) { 2159 + this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle); 2160 + } 2161 + }, timeout); 2162 + } 2163 + let form = el.form; 2164 + if (form && this.once(form, "bind-debounce")) { 2165 + form.addEventListener("submit", () => { 2166 + Array.from(new FormData(form).entries(), ([name]) => { 2167 + let input = form.querySelector(`[name="${name}"]`); 2168 + this.incCycle(input, DEBOUNCE_TRIGGER); 2169 + this.deletePrivate(input, THROTTLED); 2170 + }); 2171 + }); 2172 + } 2173 + if (this.once(el, "bind-debounce")) { 2174 + el.addEventListener("blur", () => { 2175 + clearTimeout(this.private(el, THROTTLED)); 2176 + this.triggerCycle(el, DEBOUNCE_TRIGGER); 2177 + }); 2178 + } 2179 + } 2180 + }, 2181 + triggerCycle(el, key, currentCycle) { 2182 + let [cycle, trigger] = this.private(el, key); 2183 + if (!currentCycle) { 2184 + currentCycle = cycle; 2185 + } 2186 + if (currentCycle === cycle) { 2187 + this.incCycle(el, key); 2188 + trigger(); 2189 + } 2190 + }, 2191 + once(el, key) { 2192 + if (this.private(el, key) === true) { 2193 + return false; 2194 + } 2195 + this.putPrivate(el, key, true); 2196 + return true; 2197 + }, 2198 + incCycle(el, key, trigger = function() { 2199 + }) { 2200 + let [currentCycle] = this.private(el, key) || [0, trigger]; 2201 + currentCycle++; 2202 + this.putPrivate(el, key, [currentCycle, trigger]); 2203 + return currentCycle; 2204 + }, 2205 + // maintains or adds privately used hook information 2206 + // fromEl and toEl can be the same element in the case of a newly added node 2207 + // fromEl and toEl can be any HTML node type, so we need to check if it's an element node 2208 + maintainPrivateHooks(fromEl, toEl, phxViewportTop, phxViewportBottom) { 2209 + if (fromEl.hasAttribute && fromEl.hasAttribute("data-phx-hook") && !toEl.hasAttribute("data-phx-hook")) { 2210 + toEl.setAttribute("data-phx-hook", fromEl.getAttribute("data-phx-hook")); 2211 + } 2212 + if (toEl.hasAttribute && (toEl.hasAttribute(phxViewportTop) || toEl.hasAttribute(phxViewportBottom))) { 2213 + toEl.setAttribute("data-phx-hook", "Phoenix.InfiniteScroll"); 2214 + } 2215 + }, 2216 + putCustomElHook(el, hook) { 2217 + if (el.isConnected) { 2218 + el.setAttribute("data-phx-hook", ""); 2219 + } else { 2220 + console.error(` 2221 + hook attached to non-connected DOM element 2222 + ensure you are calling createHook within your connectedCallback. ${el.outerHTML} 2223 + `); 2224 + } 2225 + this.putPrivate(el, "custom-el-hook", hook); 2226 + }, 2227 + getCustomElHook(el) { 2228 + return this.private(el, "custom-el-hook"); 2229 + }, 2230 + isUsedInput(el) { 2231 + return el.nodeType === Node.ELEMENT_NODE && (this.private(el, PHX_HAS_FOCUSED) || this.private(el, PHX_HAS_SUBMITTED)); 2232 + }, 2233 + resetForm(form) { 2234 + Array.from(form.elements).forEach((input) => { 2235 + this.deletePrivate(input, PHX_HAS_FOCUSED); 2236 + this.deletePrivate(input, PHX_HAS_SUBMITTED); 2237 + }); 2238 + }, 2239 + isPhxChild(node) { 2240 + return node.getAttribute && node.getAttribute(PHX_PARENT_ID); 2241 + }, 2242 + isPhxSticky(node) { 2243 + return node.getAttribute && node.getAttribute(PHX_STICKY) !== null; 2244 + }, 2245 + isChildOfAny(el, parents) { 2246 + return !!parents.find((parent) => parent.contains(el)); 2247 + }, 2248 + firstPhxChild(el) { 2249 + return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0]; 2250 + }, 2251 + dispatchEvent(target, name, opts = {}) { 2252 + let defaultBubble = true; 2253 + let isUploadTarget = target.nodeName === "INPUT" && target.type === "file"; 2254 + if (isUploadTarget && name === "click") { 2255 + defaultBubble = false; 2256 + } 2257 + let bubbles = opts.bubbles === void 0 ? defaultBubble : !!opts.bubbles; 2258 + let eventOpts = { bubbles, cancelable: true, detail: opts.detail || {} }; 2259 + let event = name === "click" ? new MouseEvent("click", eventOpts) : new CustomEvent(name, eventOpts); 2260 + target.dispatchEvent(event); 2261 + }, 2262 + cloneNode(node, html) { 2263 + if (typeof html === "undefined") { 2264 + return node.cloneNode(true); 2265 + } else { 2266 + let cloned = node.cloneNode(false); 2267 + cloned.innerHTML = html; 2268 + return cloned; 2269 + } 2270 + }, 2271 + // merge attributes from source to target 2272 + // if an element is ignored, we only merge data attributes 2273 + // including removing data attributes that are no longer in the source 2274 + mergeAttrs(target, source, opts = {}) { 2275 + let exclude = new Set(opts.exclude || []); 2276 + let isIgnored = opts.isIgnored; 2277 + let sourceAttrs = source.attributes; 2278 + for (let i = sourceAttrs.length - 1; i >= 0; i--) { 2279 + let name = sourceAttrs[i].name; 2280 + if (!exclude.has(name)) { 2281 + const sourceValue = source.getAttribute(name); 2282 + if (target.getAttribute(name) !== sourceValue && (!isIgnored || isIgnored && name.startsWith("data-"))) { 2283 + target.setAttribute(name, sourceValue); 2284 + } 2285 + } else { 2286 + if (name === "value" && target.value === source.value) { 2287 + target.setAttribute("value", source.getAttribute(name)); 2288 + } 2289 + } 2290 + } 2291 + let targetAttrs = target.attributes; 2292 + for (let i = targetAttrs.length - 1; i >= 0; i--) { 2293 + let name = targetAttrs[i].name; 2294 + if (isIgnored) { 2295 + if (name.startsWith("data-") && !source.hasAttribute(name) && !PHX_PENDING_ATTRS.includes(name)) { 2296 + target.removeAttribute(name); 2297 + } 2298 + } else { 2299 + if (!source.hasAttribute(name)) { 2300 + target.removeAttribute(name); 2301 + } 2302 + } 2303 + } 2304 + }, 2305 + mergeFocusedInput(target, source) { 2306 + if (!(target instanceof HTMLSelectElement)) { 2307 + DOM.mergeAttrs(target, source, { exclude: ["value"] }); 2308 + } 2309 + if (source.readOnly) { 2310 + target.setAttribute("readonly", true); 2311 + } else { 2312 + target.removeAttribute("readonly"); 2313 + } 2314 + }, 2315 + hasSelectionRange(el) { 2316 + return el.setSelectionRange && (el.type === "text" || el.type === "textarea"); 2317 + }, 2318 + restoreFocus(focused, selectionStart, selectionEnd) { 2319 + if (focused instanceof HTMLSelectElement) { 2320 + focused.focus(); 2321 + } 2322 + if (!DOM.isTextualInput(focused)) { 2323 + return; 2324 + } 2325 + let wasFocused = focused.matches(":focus"); 2326 + if (!wasFocused) { 2327 + focused.focus(); 2328 + } 2329 + if (this.hasSelectionRange(focused)) { 2330 + focused.setSelectionRange(selectionStart, selectionEnd); 2331 + } 2332 + }, 2333 + isFormInput(el) { 2334 + return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== "button"; 2335 + }, 2336 + syncAttrsToProps(el) { 2337 + if (el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0) { 2338 + el.checked = el.getAttribute("checked") !== null; 2339 + } 2340 + }, 2341 + isTextualInput(el) { 2342 + return FOCUSABLE_INPUTS.indexOf(el.type) >= 0; 2343 + }, 2344 + isNowTriggerFormExternal(el, phxTriggerExternal) { 2345 + return el.getAttribute && el.getAttribute(phxTriggerExternal) !== null && document.body.contains(el); 2346 + }, 2347 + cleanChildNodes(container, phxUpdate) { 2348 + if (DOM.isPhxUpdate(container, phxUpdate, ["append", "prepend", PHX_STREAM])) { 2349 + let toRemove = []; 2350 + container.childNodes.forEach((childNode) => { 2351 + if (!childNode.id) { 2352 + let isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === ""; 2353 + if (!isEmptyTextNode && childNode.nodeType !== Node.COMMENT_NODE) { 2354 + logError(`only HTML element tags with an id are allowed inside containers with phx-update. 2355 + 2356 + removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}" 2357 + 2358 + `); 2359 + } 2360 + toRemove.push(childNode); 2361 + } 2362 + }); 2363 + toRemove.forEach((childNode) => childNode.remove()); 2364 + } 2365 + }, 2366 + replaceRootContainer(container, tagName, attrs) { 2367 + let retainedAttrs = /* @__PURE__ */ new Set(["id", PHX_SESSION, PHX_STATIC, PHX_MAIN, PHX_ROOT_ID]); 2368 + if (container.tagName.toLowerCase() === tagName.toLowerCase()) { 2369 + Array.from(container.attributes).filter((attr) => !retainedAttrs.has(attr.name.toLowerCase())).forEach((attr) => container.removeAttribute(attr.name)); 2370 + Object.keys(attrs).filter((name) => !retainedAttrs.has(name.toLowerCase())).forEach((attr) => container.setAttribute(attr, attrs[attr])); 2371 + return container; 2372 + } else { 2373 + let newContainer = document.createElement(tagName); 2374 + Object.keys(attrs).forEach((attr) => newContainer.setAttribute(attr, attrs[attr])); 2375 + retainedAttrs.forEach((attr) => newContainer.setAttribute(attr, container.getAttribute(attr))); 2376 + newContainer.innerHTML = container.innerHTML; 2377 + container.replaceWith(newContainer); 2378 + return newContainer; 2379 + } 2380 + }, 2381 + getSticky(el, name, defaultVal) { 2382 + let op = (DOM.private(el, "sticky") || []).find(([existingName]) => name === existingName); 2383 + if (op) { 2384 + let [_name, _op, stashedResult] = op; 2385 + return stashedResult; 2386 + } else { 2387 + return typeof defaultVal === "function" ? defaultVal() : defaultVal; 2388 + } 2389 + }, 2390 + deleteSticky(el, name) { 2391 + this.updatePrivate(el, "sticky", [], (ops) => { 2392 + return ops.filter(([existingName, _]) => existingName !== name); 2393 + }); 2394 + }, 2395 + putSticky(el, name, op) { 2396 + let stashedResult = op(el); 2397 + this.updatePrivate(el, "sticky", [], (ops) => { 2398 + let existingIndex = ops.findIndex(([existingName]) => name === existingName); 2399 + if (existingIndex >= 0) { 2400 + ops[existingIndex] = [name, op, stashedResult]; 2401 + } else { 2402 + ops.push([name, op, stashedResult]); 2403 + } 2404 + return ops; 2405 + }); 2406 + }, 2407 + applyStickyOperations(el) { 2408 + let ops = DOM.private(el, "sticky"); 2409 + if (!ops) { 2410 + return; 2411 + } 2412 + ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op)); 2413 + }, 2414 + isLocked(el) { 2415 + return el.hasAttribute && el.hasAttribute(PHX_REF_LOCK); 2416 + } 2417 + }; 2418 + var dom_default = DOM; 2419 + var UploadEntry = class { 2420 + static isActive(fileEl, file) { 2421 + let isNew = file._phxRef === void 0; 2422 + let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(","); 2423 + let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0; 2424 + return file.size > 0 && (isNew || isActive); 2425 + } 2426 + static isPreflighted(fileEl, file) { 2427 + let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(","); 2428 + let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0; 2429 + return isPreflighted && this.isActive(fileEl, file); 2430 + } 2431 + static isPreflightInProgress(file) { 2432 + return file._preflightInProgress === true; 2433 + } 2434 + static markPreflightInProgress(file) { 2435 + file._preflightInProgress = true; 2436 + } 2437 + constructor(fileEl, file, view, autoUpload) { 2438 + this.ref = LiveUploader.genFileRef(file); 2439 + this.fileEl = fileEl; 2440 + this.file = file; 2441 + this.view = view; 2442 + this.meta = null; 2443 + this._isCancelled = false; 2444 + this._isDone = false; 2445 + this._progress = 0; 2446 + this._lastProgressSent = -1; 2447 + this._onDone = function() { 2448 + }; 2449 + this._onElUpdated = this.onElUpdated.bind(this); 2450 + this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); 2451 + this.autoUpload = autoUpload; 2452 + } 2453 + metadata() { 2454 + return this.meta; 2455 + } 2456 + progress(progress) { 2457 + this._progress = Math.floor(progress); 2458 + if (this._progress > this._lastProgressSent) { 2459 + if (this._progress >= 100) { 2460 + this._progress = 100; 2461 + this._lastProgressSent = 100; 2462 + this._isDone = true; 2463 + this.view.pushFileProgress(this.fileEl, this.ref, 100, () => { 2464 + LiveUploader.untrackFile(this.fileEl, this.file); 2465 + this._onDone(); 2466 + }); 2467 + } else { 2468 + this._lastProgressSent = this._progress; 2469 + this.view.pushFileProgress(this.fileEl, this.ref, this._progress); 2470 + } 2471 + } 2472 + } 2473 + isCancelled() { 2474 + return this._isCancelled; 2475 + } 2476 + cancel() { 2477 + this.file._preflightInProgress = false; 2478 + this._isCancelled = true; 2479 + this._isDone = true; 2480 + this._onDone(); 2481 + } 2482 + isDone() { 2483 + return this._isDone; 2484 + } 2485 + error(reason = "failed") { 2486 + this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); 2487 + this.view.pushFileProgress(this.fileEl, this.ref, { error: reason }); 2488 + if (!this.isAutoUpload()) { 2489 + LiveUploader.clearFiles(this.fileEl); 2490 + } 2491 + } 2492 + isAutoUpload() { 2493 + return this.autoUpload; 2494 + } 2495 + //private 2496 + onDone(callback) { 2497 + this._onDone = () => { 2498 + this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); 2499 + callback(); 2500 + }; 2501 + } 2502 + onElUpdated() { 2503 + let activeRefs = this.fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(","); 2504 + if (activeRefs.indexOf(this.ref) === -1) { 2505 + LiveUploader.untrackFile(this.fileEl, this.file); 2506 + this.cancel(); 2507 + } 2508 + } 2509 + toPreflightPayload() { 2510 + return { 2511 + last_modified: this.file.lastModified, 2512 + name: this.file.name, 2513 + relative_path: this.file.webkitRelativePath, 2514 + size: this.file.size, 2515 + type: this.file.type, 2516 + ref: this.ref, 2517 + meta: typeof this.file.meta === "function" ? this.file.meta() : void 0 2518 + }; 2519 + } 2520 + uploader(uploaders) { 2521 + if (this.meta.uploader) { 2522 + let callback = uploaders[this.meta.uploader] || logError(`no uploader configured for ${this.meta.uploader}`); 2523 + return { name: this.meta.uploader, callback }; 2524 + } else { 2525 + return { name: "channel", callback: channelUploader }; 2526 + } 2527 + } 2528 + zipPostFlight(resp) { 2529 + this.meta = resp.entries[this.ref]; 2530 + if (!this.meta) { 2531 + logError(`no preflight upload response returned with ref ${this.ref}`, { input: this.fileEl, response: resp }); 2532 + } 2533 + } 2534 + }; 2535 + var liveUploaderFileRef = 0; 2536 + var LiveUploader = class _LiveUploader { 2537 + static genFileRef(file) { 2538 + let ref = file._phxRef; 2539 + if (ref !== void 0) { 2540 + return ref; 2541 + } else { 2542 + file._phxRef = (liveUploaderFileRef++).toString(); 2543 + return file._phxRef; 2544 + } 2545 + } 2546 + static getEntryDataURL(inputEl, ref, callback) { 2547 + let file = this.activeFiles(inputEl).find((file2) => this.genFileRef(file2) === ref); 2548 + callback(URL.createObjectURL(file)); 2549 + } 2550 + static hasUploadsInProgress(formEl) { 2551 + let active = 0; 2552 + dom_default.findUploadInputs(formEl).forEach((input) => { 2553 + if (input.getAttribute(PHX_PREFLIGHTED_REFS) !== input.getAttribute(PHX_DONE_REFS)) { 2554 + active++; 2555 + } 2556 + }); 2557 + return active > 0; 2558 + } 2559 + static serializeUploads(inputEl) { 2560 + let files = this.activeFiles(inputEl); 2561 + let fileData = {}; 2562 + files.forEach((file) => { 2563 + let entry = { path: inputEl.name }; 2564 + let uploadRef = inputEl.getAttribute(PHX_UPLOAD_REF); 2565 + fileData[uploadRef] = fileData[uploadRef] || []; 2566 + entry.ref = this.genFileRef(file); 2567 + entry.last_modified = file.lastModified; 2568 + entry.name = file.name || entry.ref; 2569 + entry.relative_path = file.webkitRelativePath; 2570 + entry.type = file.type; 2571 + entry.size = file.size; 2572 + if (typeof file.meta === "function") { 2573 + entry.meta = file.meta(); 2574 + } 2575 + fileData[uploadRef].push(entry); 2576 + }); 2577 + return fileData; 2578 + } 2579 + static clearFiles(inputEl) { 2580 + inputEl.value = null; 2581 + inputEl.removeAttribute(PHX_UPLOAD_REF); 2582 + dom_default.putPrivate(inputEl, "files", []); 2583 + } 2584 + static untrackFile(inputEl, file) { 2585 + dom_default.putPrivate(inputEl, "files", dom_default.private(inputEl, "files").filter((f) => !Object.is(f, file))); 2586 + } 2587 + static trackFiles(inputEl, files, dataTransfer) { 2588 + if (inputEl.getAttribute("multiple") !== null) { 2589 + let newFiles = files.filter((file) => !this.activeFiles(inputEl).find((f) => Object.is(f, file))); 2590 + dom_default.updatePrivate(inputEl, "files", [], (existing) => existing.concat(newFiles)); 2591 + inputEl.value = null; 2592 + } else { 2593 + if (dataTransfer && dataTransfer.files.length > 0) { 2594 + inputEl.files = dataTransfer.files; 2595 + } 2596 + dom_default.putPrivate(inputEl, "files", files); 2597 + } 2598 + } 2599 + static activeFileInputs(formEl) { 2600 + let fileInputs = dom_default.findUploadInputs(formEl); 2601 + return Array.from(fileInputs).filter((el) => el.files && this.activeFiles(el).length > 0); 2602 + } 2603 + static activeFiles(input) { 2604 + return (dom_default.private(input, "files") || []).filter((f) => UploadEntry.isActive(input, f)); 2605 + } 2606 + static inputsAwaitingPreflight(formEl) { 2607 + let fileInputs = dom_default.findUploadInputs(formEl); 2608 + return Array.from(fileInputs).filter((input) => this.filesAwaitingPreflight(input).length > 0); 2609 + } 2610 + static filesAwaitingPreflight(input) { 2611 + return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f) && !UploadEntry.isPreflightInProgress(f)); 2612 + } 2613 + static markPreflightInProgress(entries) { 2614 + entries.forEach((entry) => UploadEntry.markPreflightInProgress(entry.file)); 2615 + } 2616 + constructor(inputEl, view, onComplete) { 2617 + this.autoUpload = dom_default.isAutoUpload(inputEl); 2618 + this.view = view; 2619 + this.onComplete = onComplete; 2620 + this._entries = Array.from(_LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view, this.autoUpload)); 2621 + _LiveUploader.markPreflightInProgress(this._entries); 2622 + this.numEntriesInProgress = this._entries.length; 2623 + } 2624 + isAutoUpload() { 2625 + return this.autoUpload; 2626 + } 2627 + entries() { 2628 + return this._entries; 2629 + } 2630 + initAdapterUpload(resp, onError, liveSocket2) { 2631 + this._entries = this._entries.map((entry) => { 2632 + if (entry.isCancelled()) { 2633 + this.numEntriesInProgress--; 2634 + if (this.numEntriesInProgress === 0) { 2635 + this.onComplete(); 2636 + } 2637 + } else { 2638 + entry.zipPostFlight(resp); 2639 + entry.onDone(() => { 2640 + this.numEntriesInProgress--; 2641 + if (this.numEntriesInProgress === 0) { 2642 + this.onComplete(); 2643 + } 2644 + }); 2645 + } 2646 + return entry; 2647 + }); 2648 + let groupedEntries = this._entries.reduce((acc, entry) => { 2649 + if (!entry.meta) { 2650 + return acc; 2651 + } 2652 + let { name, callback } = entry.uploader(liveSocket2.uploaders); 2653 + acc[name] = acc[name] || { callback, entries: [] }; 2654 + acc[name].entries.push(entry); 2655 + return acc; 2656 + }, {}); 2657 + for (let name in groupedEntries) { 2658 + let { callback, entries } = groupedEntries[name]; 2659 + callback(entries, onError, resp, liveSocket2); 2660 + } 2661 + } 2662 + }; 2663 + var ARIA = { 2664 + anyOf(instance, classes) { 2665 + return classes.find((name) => instance instanceof name); 2666 + }, 2667 + isFocusable(el, interactiveOnly) { 2668 + return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !el.disabled && this.anyOf(el, [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement, HTMLButtonElement]) || el instanceof HTMLIFrameElement || (el.tabIndex >= 0 && el.getAttribute("aria-hidden") !== "true" || !interactiveOnly && el.getAttribute("tabindex") !== null && el.getAttribute("aria-hidden") !== "true"); 2669 + }, 2670 + attemptFocus(el, interactiveOnly) { 2671 + if (this.isFocusable(el, interactiveOnly)) { 2672 + try { 2673 + el.focus(); 2674 + } catch (e) { 2675 + } 2676 + } 2677 + return !!document.activeElement && document.activeElement.isSameNode(el); 2678 + }, 2679 + focusFirstInteractive(el) { 2680 + let child = el.firstElementChild; 2681 + while (child) { 2682 + if (this.attemptFocus(child, true) || this.focusFirstInteractive(child, true)) { 2683 + return true; 2684 + } 2685 + child = child.nextElementSibling; 2686 + } 2687 + }, 2688 + focusFirst(el) { 2689 + let child = el.firstElementChild; 2690 + while (child) { 2691 + if (this.attemptFocus(child) || this.focusFirst(child)) { 2692 + return true; 2693 + } 2694 + child = child.nextElementSibling; 2695 + } 2696 + }, 2697 + focusLast(el) { 2698 + let child = el.lastElementChild; 2699 + while (child) { 2700 + if (this.attemptFocus(child) || this.focusLast(child)) { 2701 + return true; 2702 + } 2703 + child = child.previousElementSibling; 2704 + } 2705 + } 2706 + }; 2707 + var aria_default = ARIA; 2708 + var Hooks = { 2709 + LiveFileUpload: { 2710 + activeRefs() { 2711 + return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS); 2712 + }, 2713 + preflightedRefs() { 2714 + return this.el.getAttribute(PHX_PREFLIGHTED_REFS); 2715 + }, 2716 + mounted() { 2717 + this.preflightedWas = this.preflightedRefs(); 2718 + }, 2719 + updated() { 2720 + let newPreflights = this.preflightedRefs(); 2721 + if (this.preflightedWas !== newPreflights) { 2722 + this.preflightedWas = newPreflights; 2723 + if (newPreflights === "") { 2724 + this.__view().cancelSubmit(this.el.form); 2725 + } 2726 + } 2727 + if (this.activeRefs() === "") { 2728 + this.el.value = null; 2729 + } 2730 + this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED)); 2731 + } 2732 + }, 2733 + LiveImgPreview: { 2734 + mounted() { 2735 + this.ref = this.el.getAttribute("data-phx-entry-ref"); 2736 + this.inputEl = document.getElementById(this.el.getAttribute(PHX_UPLOAD_REF)); 2737 + LiveUploader.getEntryDataURL(this.inputEl, this.ref, (url) => { 2738 + this.url = url; 2739 + this.el.src = url; 2740 + }); 2741 + }, 2742 + destroyed() { 2743 + URL.revokeObjectURL(this.url); 2744 + } 2745 + }, 2746 + FocusWrap: { 2747 + mounted() { 2748 + this.focusStart = this.el.firstElementChild; 2749 + this.focusEnd = this.el.lastElementChild; 2750 + this.focusStart.addEventListener("focus", (e) => { 2751 + if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) { 2752 + const nextFocus = e.target.nextElementSibling; 2753 + aria_default.attemptFocus(nextFocus) || aria_default.focusFirst(nextFocus); 2754 + } else { 2755 + aria_default.focusLast(this.el); 2756 + } 2757 + }); 2758 + this.focusEnd.addEventListener("focus", (e) => { 2759 + if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) { 2760 + const nextFocus = e.target.previousElementSibling; 2761 + aria_default.attemptFocus(nextFocus) || aria_default.focusLast(nextFocus); 2762 + } else { 2763 + aria_default.focusFirst(this.el); 2764 + } 2765 + }); 2766 + this.el.addEventListener("phx:show-end", () => this.el.focus()); 2767 + if (window.getComputedStyle(this.el).display !== "none") { 2768 + aria_default.focusFirst(this.el); 2769 + } 2770 + } 2771 + } 2772 + }; 2773 + var findScrollContainer = (el) => { 2774 + if (["HTML", "BODY"].indexOf(el.nodeName.toUpperCase()) >= 0) 2775 + return null; 2776 + if (["scroll", "auto"].indexOf(getComputedStyle(el).overflowY) >= 0) 2777 + return el; 2778 + return findScrollContainer(el.parentElement); 2779 + }; 2780 + var scrollTop = (scrollContainer) => { 2781 + if (scrollContainer) { 2782 + return scrollContainer.scrollTop; 2783 + } else { 2784 + return document.documentElement.scrollTop || document.body.scrollTop; 2785 + } 2786 + }; 2787 + var bottom = (scrollContainer) => { 2788 + if (scrollContainer) { 2789 + return scrollContainer.getBoundingClientRect().bottom; 2790 + } else { 2791 + return window.innerHeight || document.documentElement.clientHeight; 2792 + } 2793 + }; 2794 + var top = (scrollContainer) => { 2795 + if (scrollContainer) { 2796 + return scrollContainer.getBoundingClientRect().top; 2797 + } else { 2798 + return 0; 2799 + } 2800 + }; 2801 + var isAtViewportTop = (el, scrollContainer) => { 2802 + let rect = el.getBoundingClientRect(); 2803 + return Math.ceil(rect.top) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.top) <= bottom(scrollContainer); 2804 + }; 2805 + var isAtViewportBottom = (el, scrollContainer) => { 2806 + let rect = el.getBoundingClientRect(); 2807 + return Math.ceil(rect.bottom) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.bottom) <= bottom(scrollContainer); 2808 + }; 2809 + var isWithinViewport = (el, scrollContainer) => { 2810 + let rect = el.getBoundingClientRect(); 2811 + return Math.ceil(rect.top) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.top) <= bottom(scrollContainer); 2812 + }; 2813 + Hooks.InfiniteScroll = { 2814 + mounted() { 2815 + this.scrollContainer = findScrollContainer(this.el); 2816 + let scrollBefore = scrollTop(this.scrollContainer); 2817 + let topOverran = false; 2818 + let throttleInterval = 500; 2819 + let pendingOp = null; 2820 + let onTopOverrun = this.throttle(throttleInterval, (topEvent, firstChild) => { 2821 + pendingOp = () => true; 2822 + this.liveSocket.execJSHookPush(this.el, topEvent, { id: firstChild.id, _overran: true }, () => { 2823 + pendingOp = null; 2824 + }); 2825 + }); 2826 + let onFirstChildAtTop = this.throttle(throttleInterval, (topEvent, firstChild) => { 2827 + pendingOp = () => firstChild.scrollIntoView({ block: "start" }); 2828 + this.liveSocket.execJSHookPush(this.el, topEvent, { id: firstChild.id }, () => { 2829 + pendingOp = null; 2830 + window.requestAnimationFrame(() => { 2831 + if (!isWithinViewport(firstChild, this.scrollContainer)) { 2832 + firstChild.scrollIntoView({ block: "start" }); 2833 + } 2834 + }); 2835 + }); 2836 + }); 2837 + let onLastChildAtBottom = this.throttle(throttleInterval, (bottomEvent, lastChild) => { 2838 + pendingOp = () => lastChild.scrollIntoView({ block: "end" }); 2839 + this.liveSocket.execJSHookPush(this.el, bottomEvent, { id: lastChild.id }, () => { 2840 + pendingOp = null; 2841 + window.requestAnimationFrame(() => { 2842 + if (!isWithinViewport(lastChild, this.scrollContainer)) { 2843 + lastChild.scrollIntoView({ block: "end" }); 2844 + } 2845 + }); 2846 + }); 2847 + }); 2848 + this.onScroll = (_e) => { 2849 + let scrollNow = scrollTop(this.scrollContainer); 2850 + if (pendingOp) { 2851 + scrollBefore = scrollNow; 2852 + return pendingOp(); 2853 + } 2854 + let rect = this.el.getBoundingClientRect(); 2855 + let topEvent = this.el.getAttribute(this.liveSocket.binding("viewport-top")); 2856 + let bottomEvent = this.el.getAttribute(this.liveSocket.binding("viewport-bottom")); 2857 + let lastChild = this.el.lastElementChild; 2858 + let firstChild = this.el.firstElementChild; 2859 + let isScrollingUp = scrollNow < scrollBefore; 2860 + let isScrollingDown = scrollNow > scrollBefore; 2861 + if (isScrollingUp && topEvent && !topOverran && rect.top >= 0) { 2862 + topOverran = true; 2863 + onTopOverrun(topEvent, firstChild); 2864 + } else if (isScrollingDown && topOverran && rect.top <= 0) { 2865 + topOverran = false; 2866 + } 2867 + if (topEvent && isScrollingUp && isAtViewportTop(firstChild, this.scrollContainer)) { 2868 + onFirstChildAtTop(topEvent, firstChild); 2869 + } else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild, this.scrollContainer)) { 2870 + onLastChildAtBottom(bottomEvent, lastChild); 2871 + } 2872 + scrollBefore = scrollNow; 2873 + }; 2874 + if (this.scrollContainer) { 2875 + this.scrollContainer.addEventListener("scroll", this.onScroll); 2876 + } else { 2877 + window.addEventListener("scroll", this.onScroll); 2878 + } 2879 + }, 2880 + destroyed() { 2881 + if (this.scrollContainer) { 2882 + this.scrollContainer.removeEventListener("scroll", this.onScroll); 2883 + } else { 2884 + window.removeEventListener("scroll", this.onScroll); 2885 + } 2886 + }, 2887 + throttle(interval, callback) { 2888 + let lastCallAt = 0; 2889 + let timer; 2890 + return (...args) => { 2891 + let now = Date.now(); 2892 + let remainingTime = interval - (now - lastCallAt); 2893 + if (remainingTime <= 0 || remainingTime > interval) { 2894 + if (timer) { 2895 + clearTimeout(timer); 2896 + timer = null; 2897 + } 2898 + lastCallAt = now; 2899 + callback(...args); 2900 + } else if (!timer) { 2901 + timer = setTimeout(() => { 2902 + lastCallAt = Date.now(); 2903 + timer = null; 2904 + callback(...args); 2905 + }, remainingTime); 2906 + } 2907 + }; 2908 + } 2909 + }; 2910 + var hooks_default = Hooks; 2911 + var ElementRef = class { 2912 + static onUnlock(el, callback) { 2913 + if (!dom_default.isLocked(el) && !el.closest(`[${PHX_REF_LOCK}]`)) { 2914 + return callback(); 2915 + } 2916 + const closestLock = el.closest(`[${PHX_REF_LOCK}]`); 2917 + const ref = closestLock.closest(`[${PHX_REF_LOCK}]`).getAttribute(PHX_REF_LOCK); 2918 + closestLock.addEventListener(`phx:undo-lock:${ref}`, () => { 2919 + callback(); 2920 + }, { once: true }); 2921 + } 2922 + constructor(el) { 2923 + this.el = el; 2924 + this.loadingRef = el.hasAttribute(PHX_REF_LOADING) ? parseInt(el.getAttribute(PHX_REF_LOADING), 10) : null; 2925 + this.lockRef = el.hasAttribute(PHX_REF_LOCK) ? parseInt(el.getAttribute(PHX_REF_LOCK), 10) : null; 2926 + } 2927 + // public 2928 + maybeUndo(ref, phxEvent, eachCloneCallback) { 2929 + if (!this.isWithin(ref)) { 2930 + dom_default.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => { 2931 + pendingRefs.push(ref); 2932 + return pendingRefs; 2933 + }); 2934 + return; 2935 + } 2936 + this.undoLocks(ref, phxEvent, eachCloneCallback); 2937 + this.undoLoading(ref, phxEvent); 2938 + dom_default.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => { 2939 + return pendingRefs.filter((pendingRef) => { 2940 + let opts = { 2941 + detail: { ref: pendingRef, event: phxEvent }, 2942 + bubbles: true, 2943 + cancelable: false 2944 + }; 2945 + if (this.loadingRef && this.loadingRef > pendingRef) { 2946 + this.el.dispatchEvent( 2947 + new CustomEvent(`phx:undo-loading:${pendingRef}`, opts) 2948 + ); 2949 + } 2950 + if (this.lockRef && this.lockRef > pendingRef) { 2951 + this.el.dispatchEvent( 2952 + new CustomEvent(`phx:undo-lock:${pendingRef}`, opts) 2953 + ); 2954 + } 2955 + return pendingRef > ref; 2956 + }); 2957 + }); 2958 + if (this.isFullyResolvedBy(ref)) { 2959 + this.el.removeAttribute(PHX_REF_SRC); 2960 + } 2961 + } 2962 + // private 2963 + isWithin(ref) { 2964 + return !(this.loadingRef !== null && this.loadingRef > ref && (this.lockRef !== null && this.lockRef > ref)); 2965 + } 2966 + // Check for cloned PHX_REF_LOCK element that has been morphed behind 2967 + // the scenes while this element was locked in the DOM. 2968 + // When we apply the cloned tree to the active DOM element, we must 2969 + // 2970 + // 1. execute pending mounted hooks for nodes now in the DOM 2971 + // 2. undo any ref inside the cloned tree that has since been ack'd 2972 + undoLocks(ref, phxEvent, eachCloneCallback) { 2973 + if (!this.isLockUndoneBy(ref)) { 2974 + return; 2975 + } 2976 + let clonedTree = dom_default.private(this.el, PHX_REF_LOCK); 2977 + if (clonedTree) { 2978 + eachCloneCallback(clonedTree); 2979 + dom_default.deletePrivate(this.el, PHX_REF_LOCK); 2980 + } 2981 + this.el.removeAttribute(PHX_REF_LOCK); 2982 + let opts = { detail: { ref, event: phxEvent }, bubbles: true, cancelable: false }; 2983 + this.el.dispatchEvent(new CustomEvent(`phx:undo-lock:${this.lockRef}`, opts)); 2984 + } 2985 + undoLoading(ref, phxEvent) { 2986 + if (!this.isLoadingUndoneBy(ref)) { 2987 + if (this.canUndoLoading(ref) && this.el.classList.contains("phx-submit-loading")) { 2988 + this.el.classList.remove("phx-change-loading"); 2989 + } 2990 + return; 2991 + } 2992 + if (this.canUndoLoading(ref)) { 2993 + this.el.removeAttribute(PHX_REF_LOADING); 2994 + let disabledVal = this.el.getAttribute(PHX_DISABLED); 2995 + let readOnlyVal = this.el.getAttribute(PHX_READONLY); 2996 + if (readOnlyVal !== null) { 2997 + this.el.readOnly = readOnlyVal === "true" ? true : false; 2998 + this.el.removeAttribute(PHX_READONLY); 2999 + } 3000 + if (disabledVal !== null) { 3001 + this.el.disabled = disabledVal === "true" ? true : false; 3002 + this.el.removeAttribute(PHX_DISABLED); 3003 + } 3004 + let disableRestore = this.el.getAttribute(PHX_DISABLE_WITH_RESTORE); 3005 + if (disableRestore !== null) { 3006 + this.el.innerText = disableRestore; 3007 + this.el.removeAttribute(PHX_DISABLE_WITH_RESTORE); 3008 + } 3009 + let opts = { detail: { ref, event: phxEvent }, bubbles: true, cancelable: false }; 3010 + this.el.dispatchEvent(new CustomEvent(`phx:undo-loading:${this.loadingRef}`, opts)); 3011 + } 3012 + PHX_EVENT_CLASSES.forEach((name) => { 3013 + if (name !== "phx-submit-loading" || this.canUndoLoading(ref)) { 3014 + dom_default.removeClass(this.el, name); 3015 + } 3016 + }); 3017 + } 3018 + isLoadingUndoneBy(ref) { 3019 + return this.loadingRef === null ? false : this.loadingRef <= ref; 3020 + } 3021 + isLockUndoneBy(ref) { 3022 + return this.lockRef === null ? false : this.lockRef <= ref; 3023 + } 3024 + isFullyResolvedBy(ref) { 3025 + return (this.loadingRef === null || this.loadingRef <= ref) && (this.lockRef === null || this.lockRef <= ref); 3026 + } 3027 + // only remove the phx-submit-loading class if we are not locked 3028 + canUndoLoading(ref) { 3029 + return this.lockRef === null || this.lockRef <= ref; 3030 + } 3031 + }; 3032 + var DOMPostMorphRestorer = class { 3033 + constructor(containerBefore, containerAfter, updateType) { 3034 + let idsBefore = /* @__PURE__ */ new Set(); 3035 + let idsAfter = new Set([...containerAfter.children].map((child) => child.id)); 3036 + let elementsToModify = []; 3037 + Array.from(containerBefore.children).forEach((child) => { 3038 + if (child.id) { 3039 + idsBefore.add(child.id); 3040 + if (idsAfter.has(child.id)) { 3041 + let previousElementId = child.previousElementSibling && child.previousElementSibling.id; 3042 + elementsToModify.push({ elementId: child.id, previousElementId }); 3043 + } 3044 + } 3045 + }); 3046 + this.containerId = containerAfter.id; 3047 + this.updateType = updateType; 3048 + this.elementsToModify = elementsToModify; 3049 + this.elementIdsToAdd = [...idsAfter].filter((id) => !idsBefore.has(id)); 3050 + } 3051 + // We do the following to optimize append/prepend operations: 3052 + // 1) Track ids of modified elements & of new elements 3053 + // 2) All the modified elements are put back in the correct position in the DOM tree 3054 + // by storing the id of their previous sibling 3055 + // 3) New elements are going to be put in the right place by morphdom during append. 3056 + // For prepend, we move them to the first position in the container 3057 + perform() { 3058 + let container = dom_default.byId(this.containerId); 3059 + this.elementsToModify.forEach((elementToModify) => { 3060 + if (elementToModify.previousElementId) { 3061 + maybe(document.getElementById(elementToModify.previousElementId), (previousElem) => { 3062 + maybe(document.getElementById(elementToModify.elementId), (elem) => { 3063 + let isInRightPlace = elem.previousElementSibling && elem.previousElementSibling.id == previousElem.id; 3064 + if (!isInRightPlace) { 3065 + previousElem.insertAdjacentElement("afterend", elem); 3066 + } 3067 + }); 3068 + }); 3069 + } else { 3070 + maybe(document.getElementById(elementToModify.elementId), (elem) => { 3071 + let isInRightPlace = elem.previousElementSibling == null; 3072 + if (!isInRightPlace) { 3073 + container.insertAdjacentElement("afterbegin", elem); 3074 + } 3075 + }); 3076 + } 3077 + }); 3078 + if (this.updateType == "prepend") { 3079 + this.elementIdsToAdd.reverse().forEach((elemId) => { 3080 + maybe(document.getElementById(elemId), (elem) => container.insertAdjacentElement("afterbegin", elem)); 3081 + }); 3082 + } 3083 + } 3084 + }; 3085 + var DOCUMENT_FRAGMENT_NODE = 11; 3086 + function morphAttrs(fromNode, toNode) { 3087 + var toNodeAttrs = toNode.attributes; 3088 + var attr; 3089 + var attrName; 3090 + var attrNamespaceURI; 3091 + var attrValue; 3092 + var fromValue; 3093 + if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) { 3094 + return; 3095 + } 3096 + for (var i = toNodeAttrs.length - 1; i >= 0; i--) { 3097 + attr = toNodeAttrs[i]; 3098 + attrName = attr.name; 3099 + attrNamespaceURI = attr.namespaceURI; 3100 + attrValue = attr.value; 3101 + if (attrNamespaceURI) { 3102 + attrName = attr.localName || attrName; 3103 + fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName); 3104 + if (fromValue !== attrValue) { 3105 + if (attr.prefix === "xmlns") { 3106 + attrName = attr.name; 3107 + } 3108 + fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue); 3109 + } 3110 + } else { 3111 + fromValue = fromNode.getAttribute(attrName); 3112 + if (fromValue !== attrValue) { 3113 + fromNode.setAttribute(attrName, attrValue); 3114 + } 3115 + } 3116 + } 3117 + var fromNodeAttrs = fromNode.attributes; 3118 + for (var d = fromNodeAttrs.length - 1; d >= 0; d--) { 3119 + attr = fromNodeAttrs[d]; 3120 + attrName = attr.name; 3121 + attrNamespaceURI = attr.namespaceURI; 3122 + if (attrNamespaceURI) { 3123 + attrName = attr.localName || attrName; 3124 + if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) { 3125 + fromNode.removeAttributeNS(attrNamespaceURI, attrName); 3126 + } 3127 + } else { 3128 + if (!toNode.hasAttribute(attrName)) { 3129 + fromNode.removeAttribute(attrName); 3130 + } 3131 + } 3132 + } 3133 + } 3134 + var range; 3135 + var NS_XHTML = "http://www.w3.org/1999/xhtml"; 3136 + var doc = typeof document === "undefined" ? void 0 : document; 3137 + var HAS_TEMPLATE_SUPPORT = !!doc && "content" in doc.createElement("template"); 3138 + var HAS_RANGE_SUPPORT = !!doc && doc.createRange && "createContextualFragment" in doc.createRange(); 3139 + function createFragmentFromTemplate(str) { 3140 + var template = doc.createElement("template"); 3141 + template.innerHTML = str; 3142 + return template.content.childNodes[0]; 3143 + } 3144 + function createFragmentFromRange(str) { 3145 + if (!range) { 3146 + range = doc.createRange(); 3147 + range.selectNode(doc.body); 3148 + } 3149 + var fragment = range.createContextualFragment(str); 3150 + return fragment.childNodes[0]; 3151 + } 3152 + function createFragmentFromWrap(str) { 3153 + var fragment = doc.createElement("body"); 3154 + fragment.innerHTML = str; 3155 + return fragment.childNodes[0]; 3156 + } 3157 + function toElement(str) { 3158 + str = str.trim(); 3159 + if (HAS_TEMPLATE_SUPPORT) { 3160 + return createFragmentFromTemplate(str); 3161 + } else if (HAS_RANGE_SUPPORT) { 3162 + return createFragmentFromRange(str); 3163 + } 3164 + return createFragmentFromWrap(str); 3165 + } 3166 + function compareNodeNames(fromEl, toEl) { 3167 + var fromNodeName = fromEl.nodeName; 3168 + var toNodeName = toEl.nodeName; 3169 + var fromCodeStart, toCodeStart; 3170 + if (fromNodeName === toNodeName) { 3171 + return true; 3172 + } 3173 + fromCodeStart = fromNodeName.charCodeAt(0); 3174 + toCodeStart = toNodeName.charCodeAt(0); 3175 + if (fromCodeStart <= 90 && toCodeStart >= 97) { 3176 + return fromNodeName === toNodeName.toUpperCase(); 3177 + } else if (toCodeStart <= 90 && fromCodeStart >= 97) { 3178 + return toNodeName === fromNodeName.toUpperCase(); 3179 + } else { 3180 + return false; 3181 + } 3182 + } 3183 + function createElementNS(name, namespaceURI) { 3184 + return !namespaceURI || namespaceURI === NS_XHTML ? doc.createElement(name) : doc.createElementNS(namespaceURI, name); 3185 + } 3186 + function moveChildren(fromEl, toEl) { 3187 + var curChild = fromEl.firstChild; 3188 + while (curChild) { 3189 + var nextChild = curChild.nextSibling; 3190 + toEl.appendChild(curChild); 3191 + curChild = nextChild; 3192 + } 3193 + return toEl; 3194 + } 3195 + function syncBooleanAttrProp(fromEl, toEl, name) { 3196 + if (fromEl[name] !== toEl[name]) { 3197 + fromEl[name] = toEl[name]; 3198 + if (fromEl[name]) { 3199 + fromEl.setAttribute(name, ""); 3200 + } else { 3201 + fromEl.removeAttribute(name); 3202 + } 3203 + } 3204 + } 3205 + var specialElHandlers = { 3206 + OPTION: function(fromEl, toEl) { 3207 + var parentNode = fromEl.parentNode; 3208 + if (parentNode) { 3209 + var parentName = parentNode.nodeName.toUpperCase(); 3210 + if (parentName === "OPTGROUP") { 3211 + parentNode = parentNode.parentNode; 3212 + parentName = parentNode && parentNode.nodeName.toUpperCase(); 3213 + } 3214 + if (parentName === "SELECT" && !parentNode.hasAttribute("multiple")) { 3215 + if (fromEl.hasAttribute("selected") && !toEl.selected) { 3216 + fromEl.setAttribute("selected", "selected"); 3217 + fromEl.removeAttribute("selected"); 3218 + } 3219 + parentNode.selectedIndex = -1; 3220 + } 3221 + } 3222 + syncBooleanAttrProp(fromEl, toEl, "selected"); 3223 + }, 3224 + /** 3225 + * The "value" attribute is special for the <input> element since it sets 3226 + * the initial value. Changing the "value" attribute without changing the 3227 + * "value" property will have no effect since it is only used to the set the 3228 + * initial value. Similar for the "checked" attribute, and "disabled". 3229 + */ 3230 + INPUT: function(fromEl, toEl) { 3231 + syncBooleanAttrProp(fromEl, toEl, "checked"); 3232 + syncBooleanAttrProp(fromEl, toEl, "disabled"); 3233 + if (fromEl.value !== toEl.value) { 3234 + fromEl.value = toEl.value; 3235 + } 3236 + if (!toEl.hasAttribute("value")) { 3237 + fromEl.removeAttribute("value"); 3238 + } 3239 + }, 3240 + TEXTAREA: function(fromEl, toEl) { 3241 + var newValue = toEl.value; 3242 + if (fromEl.value !== newValue) { 3243 + fromEl.value = newValue; 3244 + } 3245 + var firstChild = fromEl.firstChild; 3246 + if (firstChild) { 3247 + var oldValue = firstChild.nodeValue; 3248 + if (oldValue == newValue || !newValue && oldValue == fromEl.placeholder) { 3249 + return; 3250 + } 3251 + firstChild.nodeValue = newValue; 3252 + } 3253 + }, 3254 + SELECT: function(fromEl, toEl) { 3255 + if (!toEl.hasAttribute("multiple")) { 3256 + var selectedIndex = -1; 3257 + var i = 0; 3258 + var curChild = fromEl.firstChild; 3259 + var optgroup; 3260 + var nodeName; 3261 + while (curChild) { 3262 + nodeName = curChild.nodeName && curChild.nodeName.toUpperCase(); 3263 + if (nodeName === "OPTGROUP") { 3264 + optgroup = curChild; 3265 + curChild = optgroup.firstChild; 3266 + } else { 3267 + if (nodeName === "OPTION") { 3268 + if (curChild.hasAttribute("selected")) { 3269 + selectedIndex = i; 3270 + break; 3271 + } 3272 + i++; 3273 + } 3274 + curChild = curChild.nextSibling; 3275 + if (!curChild && optgroup) { 3276 + curChild = optgroup.nextSibling; 3277 + optgroup = null; 3278 + } 3279 + } 3280 + } 3281 + fromEl.selectedIndex = selectedIndex; 3282 + } 3283 + } 3284 + }; 3285 + var ELEMENT_NODE = 1; 3286 + var DOCUMENT_FRAGMENT_NODE$1 = 11; 3287 + var TEXT_NODE = 3; 3288 + var COMMENT_NODE = 8; 3289 + function noop() { 3290 + } 3291 + function defaultGetNodeKey(node) { 3292 + if (node) { 3293 + return node.getAttribute && node.getAttribute("id") || node.id; 3294 + } 3295 + } 3296 + function morphdomFactory(morphAttrs2) { 3297 + return function morphdom2(fromNode, toNode, options) { 3298 + if (!options) { 3299 + options = {}; 3300 + } 3301 + if (typeof toNode === "string") { 3302 + if (fromNode.nodeName === "#document" || fromNode.nodeName === "HTML" || fromNode.nodeName === "BODY") { 3303 + var toNodeHtml = toNode; 3304 + toNode = doc.createElement("html"); 3305 + toNode.innerHTML = toNodeHtml; 3306 + } else { 3307 + toNode = toElement(toNode); 3308 + } 3309 + } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) { 3310 + toNode = toNode.firstElementChild; 3311 + } 3312 + var getNodeKey = options.getNodeKey || defaultGetNodeKey; 3313 + var onBeforeNodeAdded = options.onBeforeNodeAdded || noop; 3314 + var onNodeAdded = options.onNodeAdded || noop; 3315 + var onBeforeElUpdated = options.onBeforeElUpdated || noop; 3316 + var onElUpdated = options.onElUpdated || noop; 3317 + var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop; 3318 + var onNodeDiscarded = options.onNodeDiscarded || noop; 3319 + var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop; 3320 + var skipFromChildren = options.skipFromChildren || noop; 3321 + var addChild = options.addChild || function(parent, child) { 3322 + return parent.appendChild(child); 3323 + }; 3324 + var childrenOnly = options.childrenOnly === true; 3325 + var fromNodesLookup = /* @__PURE__ */ Object.create(null); 3326 + var keyedRemovalList = []; 3327 + function addKeyedRemoval(key) { 3328 + keyedRemovalList.push(key); 3329 + } 3330 + function walkDiscardedChildNodes(node, skipKeyedNodes) { 3331 + if (node.nodeType === ELEMENT_NODE) { 3332 + var curChild = node.firstChild; 3333 + while (curChild) { 3334 + var key = void 0; 3335 + if (skipKeyedNodes && (key = getNodeKey(curChild))) { 3336 + addKeyedRemoval(key); 3337 + } else { 3338 + onNodeDiscarded(curChild); 3339 + if (curChild.firstChild) { 3340 + walkDiscardedChildNodes(curChild, skipKeyedNodes); 3341 + } 3342 + } 3343 + curChild = curChild.nextSibling; 3344 + } 3345 + } 3346 + } 3347 + function removeNode(node, parentNode, skipKeyedNodes) { 3348 + if (onBeforeNodeDiscarded(node) === false) { 3349 + return; 3350 + } 3351 + if (parentNode) { 3352 + parentNode.removeChild(node); 3353 + } 3354 + onNodeDiscarded(node); 3355 + walkDiscardedChildNodes(node, skipKeyedNodes); 3356 + } 3357 + function indexTree(node) { 3358 + if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) { 3359 + var curChild = node.firstChild; 3360 + while (curChild) { 3361 + var key = getNodeKey(curChild); 3362 + if (key) { 3363 + fromNodesLookup[key] = curChild; 3364 + } 3365 + indexTree(curChild); 3366 + curChild = curChild.nextSibling; 3367 + } 3368 + } 3369 + } 3370 + indexTree(fromNode); 3371 + function handleNodeAdded(el) { 3372 + onNodeAdded(el); 3373 + var curChild = el.firstChild; 3374 + while (curChild) { 3375 + var nextSibling = curChild.nextSibling; 3376 + var key = getNodeKey(curChild); 3377 + if (key) { 3378 + var unmatchedFromEl = fromNodesLookup[key]; 3379 + if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) { 3380 + curChild.parentNode.replaceChild(unmatchedFromEl, curChild); 3381 + morphEl(unmatchedFromEl, curChild); 3382 + } else { 3383 + handleNodeAdded(curChild); 3384 + } 3385 + } else { 3386 + handleNodeAdded(curChild); 3387 + } 3388 + curChild = nextSibling; 3389 + } 3390 + } 3391 + function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) { 3392 + while (curFromNodeChild) { 3393 + var fromNextSibling = curFromNodeChild.nextSibling; 3394 + if (curFromNodeKey = getNodeKey(curFromNodeChild)) { 3395 + addKeyedRemoval(curFromNodeKey); 3396 + } else { 3397 + removeNode( 3398 + curFromNodeChild, 3399 + fromEl, 3400 + true 3401 + /* skip keyed nodes */ 3402 + ); 3403 + } 3404 + curFromNodeChild = fromNextSibling; 3405 + } 3406 + } 3407 + function morphEl(fromEl, toEl, childrenOnly2) { 3408 + var toElKey = getNodeKey(toEl); 3409 + if (toElKey) { 3410 + delete fromNodesLookup[toElKey]; 3411 + } 3412 + if (!childrenOnly2) { 3413 + var beforeUpdateResult = onBeforeElUpdated(fromEl, toEl); 3414 + if (beforeUpdateResult === false) { 3415 + return; 3416 + } else if (beforeUpdateResult instanceof HTMLElement) { 3417 + fromEl = beforeUpdateResult; 3418 + indexTree(fromEl); 3419 + } 3420 + morphAttrs2(fromEl, toEl); 3421 + onElUpdated(fromEl); 3422 + if (onBeforeElChildrenUpdated(fromEl, toEl) === false) { 3423 + return; 3424 + } 3425 + } 3426 + if (fromEl.nodeName !== "TEXTAREA") { 3427 + morphChildren(fromEl, toEl); 3428 + } else { 3429 + specialElHandlers.TEXTAREA(fromEl, toEl); 3430 + } 3431 + } 3432 + function morphChildren(fromEl, toEl) { 3433 + var skipFrom = skipFromChildren(fromEl, toEl); 3434 + var curToNodeChild = toEl.firstChild; 3435 + var curFromNodeChild = fromEl.firstChild; 3436 + var curToNodeKey; 3437 + var curFromNodeKey; 3438 + var fromNextSibling; 3439 + var toNextSibling; 3440 + var matchingFromEl; 3441 + outer: 3442 + while (curToNodeChild) { 3443 + toNextSibling = curToNodeChild.nextSibling; 3444 + curToNodeKey = getNodeKey(curToNodeChild); 3445 + while (!skipFrom && curFromNodeChild) { 3446 + fromNextSibling = curFromNodeChild.nextSibling; 3447 + if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) { 3448 + curToNodeChild = toNextSibling; 3449 + curFromNodeChild = fromNextSibling; 3450 + continue outer; 3451 + } 3452 + curFromNodeKey = getNodeKey(curFromNodeChild); 3453 + var curFromNodeType = curFromNodeChild.nodeType; 3454 + var isCompatible = void 0; 3455 + if (curFromNodeType === curToNodeChild.nodeType) { 3456 + if (curFromNodeType === ELEMENT_NODE) { 3457 + if (curToNodeKey) { 3458 + if (curToNodeKey !== curFromNodeKey) { 3459 + if (matchingFromEl = fromNodesLookup[curToNodeKey]) { 3460 + if (fromNextSibling === matchingFromEl) { 3461 + isCompatible = false; 3462 + } else { 3463 + fromEl.insertBefore(matchingFromEl, curFromNodeChild); 3464 + if (curFromNodeKey) { 3465 + addKeyedRemoval(curFromNodeKey); 3466 + } else { 3467 + removeNode( 3468 + curFromNodeChild, 3469 + fromEl, 3470 + true 3471 + /* skip keyed nodes */ 3472 + ); 3473 + } 3474 + curFromNodeChild = matchingFromEl; 3475 + curFromNodeKey = getNodeKey(curFromNodeChild); 3476 + } 3477 + } else { 3478 + isCompatible = false; 3479 + } 3480 + } 3481 + } else if (curFromNodeKey) { 3482 + isCompatible = false; 3483 + } 3484 + isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild); 3485 + if (isCompatible) { 3486 + morphEl(curFromNodeChild, curToNodeChild); 3487 + } 3488 + } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) { 3489 + isCompatible = true; 3490 + if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) { 3491 + curFromNodeChild.nodeValue = curToNodeChild.nodeValue; 3492 + } 3493 + } 3494 + } 3495 + if (isCompatible) { 3496 + curToNodeChild = toNextSibling; 3497 + curFromNodeChild = fromNextSibling; 3498 + continue outer; 3499 + } 3500 + if (curFromNodeKey) { 3501 + addKeyedRemoval(curFromNodeKey); 3502 + } else { 3503 + removeNode( 3504 + curFromNodeChild, 3505 + fromEl, 3506 + true 3507 + /* skip keyed nodes */ 3508 + ); 3509 + } 3510 + curFromNodeChild = fromNextSibling; 3511 + } 3512 + if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) { 3513 + if (!skipFrom) { 3514 + addChild(fromEl, matchingFromEl); 3515 + } 3516 + morphEl(matchingFromEl, curToNodeChild); 3517 + } else { 3518 + var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild); 3519 + if (onBeforeNodeAddedResult !== false) { 3520 + if (onBeforeNodeAddedResult) { 3521 + curToNodeChild = onBeforeNodeAddedResult; 3522 + } 3523 + if (curToNodeChild.actualize) { 3524 + curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc); 3525 + } 3526 + addChild(fromEl, curToNodeChild); 3527 + handleNodeAdded(curToNodeChild); 3528 + } 3529 + } 3530 + curToNodeChild = toNextSibling; 3531 + curFromNodeChild = fromNextSibling; 3532 + } 3533 + cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey); 3534 + var specialElHandler = specialElHandlers[fromEl.nodeName]; 3535 + if (specialElHandler) { 3536 + specialElHandler(fromEl, toEl); 3537 + } 3538 + } 3539 + var morphedNode = fromNode; 3540 + var morphedNodeType = morphedNode.nodeType; 3541 + var toNodeType = toNode.nodeType; 3542 + if (!childrenOnly) { 3543 + if (morphedNodeType === ELEMENT_NODE) { 3544 + if (toNodeType === ELEMENT_NODE) { 3545 + if (!compareNodeNames(fromNode, toNode)) { 3546 + onNodeDiscarded(fromNode); 3547 + morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI)); 3548 + } 3549 + } else { 3550 + morphedNode = toNode; 3551 + } 3552 + } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { 3553 + if (toNodeType === morphedNodeType) { 3554 + if (morphedNode.nodeValue !== toNode.nodeValue) { 3555 + morphedNode.nodeValue = toNode.nodeValue; 3556 + } 3557 + return morphedNode; 3558 + } else { 3559 + morphedNode = toNode; 3560 + } 3561 + } 3562 + } 3563 + if (morphedNode === toNode) { 3564 + onNodeDiscarded(fromNode); 3565 + } else { 3566 + if (toNode.isSameNode && toNode.isSameNode(morphedNode)) { 3567 + return; 3568 + } 3569 + morphEl(morphedNode, toNode, childrenOnly); 3570 + if (keyedRemovalList) { 3571 + for (var i = 0, len = keyedRemovalList.length; i < len; i++) { 3572 + var elToRemove = fromNodesLookup[keyedRemovalList[i]]; 3573 + if (elToRemove) { 3574 + removeNode(elToRemove, elToRemove.parentNode, false); 3575 + } 3576 + } 3577 + } 3578 + } 3579 + if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) { 3580 + if (morphedNode.actualize) { 3581 + morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc); 3582 + } 3583 + fromNode.parentNode.replaceChild(morphedNode, fromNode); 3584 + } 3585 + return morphedNode; 3586 + }; 3587 + } 3588 + var morphdom = morphdomFactory(morphAttrs); 3589 + var morphdom_esm_default = morphdom; 3590 + var DOMPatch = class { 3591 + constructor(view, container, id, html, streams, targetCID, opts = {}) { 3592 + this.view = view; 3593 + this.liveSocket = view.liveSocket; 3594 + this.container = container; 3595 + this.id = id; 3596 + this.rootID = view.root.id; 3597 + this.html = html; 3598 + this.streams = streams; 3599 + this.streamInserts = {}; 3600 + this.streamComponentRestore = {}; 3601 + this.targetCID = targetCID; 3602 + this.cidPatch = isCid(this.targetCID); 3603 + this.pendingRemoves = []; 3604 + this.phxRemove = this.liveSocket.binding("remove"); 3605 + this.targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container; 3606 + this.callbacks = { 3607 + beforeadded: [], 3608 + beforeupdated: [], 3609 + beforephxChildAdded: [], 3610 + afteradded: [], 3611 + afterupdated: [], 3612 + afterdiscarded: [], 3613 + afterphxChildAdded: [], 3614 + aftertransitionsDiscarded: [] 3615 + }; 3616 + this.withChildren = opts.withChildren || opts.undoRef || false; 3617 + this.undoRef = opts.undoRef; 3618 + } 3619 + before(kind, callback) { 3620 + this.callbacks[`before${kind}`].push(callback); 3621 + } 3622 + after(kind, callback) { 3623 + this.callbacks[`after${kind}`].push(callback); 3624 + } 3625 + trackBefore(kind, ...args) { 3626 + this.callbacks[`before${kind}`].forEach((callback) => callback(...args)); 3627 + } 3628 + trackAfter(kind, ...args) { 3629 + this.callbacks[`after${kind}`].forEach((callback) => callback(...args)); 3630 + } 3631 + markPrunableContentForRemoval() { 3632 + let phxUpdate = this.liveSocket.binding(PHX_UPDATE); 3633 + dom_default.all(this.container, `[${phxUpdate}=append] > *, [${phxUpdate}=prepend] > *`, (el) => { 3634 + el.setAttribute(PHX_PRUNE, ""); 3635 + }); 3636 + } 3637 + perform(isJoinPatch) { 3638 + let { view, liveSocket: liveSocket2, html, container, targetContainer } = this; 3639 + if (this.isCIDPatch() && !targetContainer) { 3640 + return; 3641 + } 3642 + let focused = liveSocket2.getActiveElement(); 3643 + let { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {}; 3644 + let phxUpdate = liveSocket2.binding(PHX_UPDATE); 3645 + let phxViewportTop = liveSocket2.binding(PHX_VIEWPORT_TOP); 3646 + let phxViewportBottom = liveSocket2.binding(PHX_VIEWPORT_BOTTOM); 3647 + let phxTriggerExternal = liveSocket2.binding(PHX_TRIGGER_ACTION); 3648 + let added = []; 3649 + let updates = []; 3650 + let appendPrependUpdates = []; 3651 + let externalFormTriggered = null; 3652 + function morph(targetContainer2, source, withChildren = this.withChildren) { 3653 + let morphCallbacks = { 3654 + // normally, we are running with childrenOnly, as the patch HTML for a LV 3655 + // does not include the LV attrs (data-phx-session, etc.) 3656 + // when we are patching a live component, we do want to patch the root element as well; 3657 + // another case is the recursive patch of a stream item that was kept on reset (-> onBeforeNodeAdded) 3658 + childrenOnly: targetContainer2.getAttribute(PHX_COMPONENT) === null && !withChildren, 3659 + getNodeKey: (node) => { 3660 + if (dom_default.isPhxDestroyed(node)) { 3661 + return null; 3662 + } 3663 + if (isJoinPatch) { 3664 + return node.id; 3665 + } 3666 + return node.id || node.getAttribute && node.getAttribute(PHX_MAGIC_ID); 3667 + }, 3668 + // skip indexing from children when container is stream 3669 + skipFromChildren: (from) => { 3670 + return from.getAttribute(phxUpdate) === PHX_STREAM; 3671 + }, 3672 + // tell morphdom how to add a child 3673 + addChild: (parent, child) => { 3674 + let { ref, streamAt } = this.getStreamInsert(child); 3675 + if (ref === void 0) { 3676 + return parent.appendChild(child); 3677 + } 3678 + this.setStreamRef(child, ref); 3679 + if (streamAt === 0) { 3680 + parent.insertAdjacentElement("afterbegin", child); 3681 + } else if (streamAt === -1) { 3682 + let lastChild = parent.lastElementChild; 3683 + if (lastChild && !lastChild.hasAttribute(PHX_STREAM_REF)) { 3684 + let nonStreamChild = Array.from(parent.children).find((c) => !c.hasAttribute(PHX_STREAM_REF)); 3685 + parent.insertBefore(child, nonStreamChild); 3686 + } else { 3687 + parent.appendChild(child); 3688 + } 3689 + } else if (streamAt > 0) { 3690 + let sibling = Array.from(parent.children)[streamAt]; 3691 + parent.insertBefore(child, sibling); 3692 + } 3693 + }, 3694 + onBeforeNodeAdded: (el) => { 3695 + dom_default.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom); 3696 + this.trackBefore("added", el); 3697 + let morphedEl = el; 3698 + if (this.streamComponentRestore[el.id]) { 3699 + morphedEl = this.streamComponentRestore[el.id]; 3700 + delete this.streamComponentRestore[el.id]; 3701 + morph.call(this, morphedEl, el, true); 3702 + } 3703 + return morphedEl; 3704 + }, 3705 + onNodeAdded: (el) => { 3706 + if (el.getAttribute) { 3707 + this.maybeReOrderStream(el, true); 3708 + } 3709 + if (el instanceof HTMLImageElement && el.srcset) { 3710 + el.srcset = el.srcset; 3711 + } else if (el instanceof HTMLVideoElement && el.autoplay) { 3712 + el.play(); 3713 + } 3714 + if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) { 3715 + externalFormTriggered = el; 3716 + } 3717 + if (dom_default.isPhxChild(el) && view.ownsElement(el) || dom_default.isPhxSticky(el) && view.ownsElement(el.parentNode)) { 3718 + this.trackAfter("phxChildAdded", el); 3719 + } 3720 + added.push(el); 3721 + }, 3722 + onNodeDiscarded: (el) => this.onNodeDiscarded(el), 3723 + onBeforeNodeDiscarded: (el) => { 3724 + if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) { 3725 + return true; 3726 + } 3727 + if (el.parentElement !== null && el.id && dom_default.isPhxUpdate(el.parentElement, phxUpdate, [PHX_STREAM, "append", "prepend"])) { 3728 + return false; 3729 + } 3730 + if (this.maybePendingRemove(el)) { 3731 + return false; 3732 + } 3733 + if (this.skipCIDSibling(el)) { 3734 + return false; 3735 + } 3736 + return true; 3737 + }, 3738 + onElUpdated: (el) => { 3739 + if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) { 3740 + externalFormTriggered = el; 3741 + } 3742 + updates.push(el); 3743 + this.maybeReOrderStream(el, false); 3744 + }, 3745 + onBeforeElUpdated: (fromEl, toEl) => { 3746 + if (fromEl.id && fromEl.isSameNode(targetContainer2) && fromEl.id !== toEl.id) { 3747 + morphCallbacks.onNodeDiscarded(fromEl); 3748 + fromEl.replaceWith(toEl); 3749 + return morphCallbacks.onNodeAdded(toEl); 3750 + } 3751 + dom_default.syncPendingAttrs(fromEl, toEl); 3752 + dom_default.maintainPrivateHooks(fromEl, toEl, phxViewportTop, phxViewportBottom); 3753 + dom_default.cleanChildNodes(toEl, phxUpdate); 3754 + if (this.skipCIDSibling(toEl)) { 3755 + this.maybeReOrderStream(fromEl); 3756 + return false; 3757 + } 3758 + if (dom_default.isPhxSticky(fromEl)) { 3759 + [PHX_SESSION, PHX_STATIC, PHX_ROOT_ID].map((attr) => [attr, fromEl.getAttribute(attr), toEl.getAttribute(attr)]).forEach(([attr, fromVal, toVal]) => { 3760 + if (toVal && fromVal !== toVal) { 3761 + fromEl.setAttribute(attr, toVal); 3762 + } 3763 + }); 3764 + return false; 3765 + } 3766 + if (dom_default.isIgnored(fromEl, phxUpdate) || fromEl.form && fromEl.form.isSameNode(externalFormTriggered)) { 3767 + this.trackBefore("updated", fromEl, toEl); 3768 + dom_default.mergeAttrs(fromEl, toEl, { isIgnored: dom_default.isIgnored(fromEl, phxUpdate) }); 3769 + updates.push(fromEl); 3770 + dom_default.applyStickyOperations(fromEl); 3771 + return false; 3772 + } 3773 + if (fromEl.type === "number" && (fromEl.validity && fromEl.validity.badInput)) { 3774 + return false; 3775 + } 3776 + let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl); 3777 + let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl); 3778 + if (fromEl.hasAttribute(PHX_REF_SRC)) { 3779 + const ref = new ElementRef(fromEl); 3780 + if (ref.lockRef && (!this.undoRef || !ref.isLockUndoneBy(this.undoRef))) { 3781 + if (dom_default.isUploadInput(fromEl)) { 3782 + dom_default.mergeAttrs(fromEl, toEl, { isIgnored: true }); 3783 + this.trackBefore("updated", fromEl, toEl); 3784 + updates.push(fromEl); 3785 + } 3786 + dom_default.applyStickyOperations(fromEl); 3787 + let isLocked = fromEl.hasAttribute(PHX_REF_LOCK); 3788 + let clone2 = isLocked ? dom_default.private(fromEl, PHX_REF_LOCK) || fromEl.cloneNode(true) : null; 3789 + if (clone2) { 3790 + dom_default.putPrivate(fromEl, PHX_REF_LOCK, clone2); 3791 + if (!isFocusedFormEl) { 3792 + fromEl = clone2; 3793 + } 3794 + } 3795 + } 3796 + } 3797 + if (dom_default.isPhxChild(toEl)) { 3798 + let prevSession = fromEl.getAttribute(PHX_SESSION); 3799 + dom_default.mergeAttrs(fromEl, toEl, { exclude: [PHX_STATIC] }); 3800 + if (prevSession !== "") { 3801 + fromEl.setAttribute(PHX_SESSION, prevSession); 3802 + } 3803 + fromEl.setAttribute(PHX_ROOT_ID, this.rootID); 3804 + dom_default.applyStickyOperations(fromEl); 3805 + return false; 3806 + } 3807 + if (this.undoRef && dom_default.private(toEl, PHX_REF_LOCK)) { 3808 + dom_default.putPrivate(fromEl, PHX_REF_LOCK, dom_default.private(toEl, PHX_REF_LOCK)); 3809 + } 3810 + dom_default.copyPrivates(toEl, fromEl); 3811 + if (isFocusedFormEl && fromEl.type !== "hidden" && !focusedSelectChanged) { 3812 + this.trackBefore("updated", fromEl, toEl); 3813 + dom_default.mergeFocusedInput(fromEl, toEl); 3814 + dom_default.syncAttrsToProps(fromEl); 3815 + updates.push(fromEl); 3816 + dom_default.applyStickyOperations(fromEl); 3817 + return false; 3818 + } else { 3819 + if (focusedSelectChanged) { 3820 + fromEl.blur(); 3821 + } 3822 + if (dom_default.isPhxUpdate(toEl, phxUpdate, ["append", "prepend"])) { 3823 + appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate))); 3824 + } 3825 + dom_default.syncAttrsToProps(toEl); 3826 + dom_default.applyStickyOperations(toEl); 3827 + this.trackBefore("updated", fromEl, toEl); 3828 + return fromEl; 3829 + } 3830 + } 3831 + }; 3832 + morphdom_esm_default(targetContainer2, source, morphCallbacks); 3833 + } 3834 + this.trackBefore("added", container); 3835 + this.trackBefore("updated", container, container); 3836 + liveSocket2.time("morphdom", () => { 3837 + this.streams.forEach(([ref, inserts, deleteIds, reset]) => { 3838 + inserts.forEach(([key, streamAt, limit]) => { 3839 + this.streamInserts[key] = { ref, streamAt, limit, reset }; 3840 + }); 3841 + if (reset !== void 0) { 3842 + dom_default.all(container, `[${PHX_STREAM_REF}="${ref}"]`, (child) => { 3843 + this.removeStreamChildElement(child); 3844 + }); 3845 + } 3846 + deleteIds.forEach((id) => { 3847 + let child = container.querySelector(`[id="${id}"]`); 3848 + if (child) { 3849 + this.removeStreamChildElement(child); 3850 + } 3851 + }); 3852 + }); 3853 + if (isJoinPatch) { 3854 + dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`).filter((el) => this.view.ownsElement(el)).forEach((el) => { 3855 + Array.from(el.children).forEach((child) => { 3856 + this.removeStreamChildElement(child, true); 3857 + }); 3858 + }); 3859 + } 3860 + morph.call(this, targetContainer, html); 3861 + }); 3862 + if (liveSocket2.isDebugEnabled()) { 3863 + detectDuplicateIds(); 3864 + detectInvalidStreamInserts(this.streamInserts); 3865 + Array.from(document.querySelectorAll("input[name=id]")).forEach((node) => { 3866 + if (node.form) { 3867 + console.error('Detected an input with name="id" inside a form! This will cause problems when patching the DOM.\n', node); 3868 + } 3869 + }); 3870 + } 3871 + if (appendPrependUpdates.length > 0) { 3872 + liveSocket2.time("post-morph append/prepend restoration", () => { 3873 + appendPrependUpdates.forEach((update) => update.perform()); 3874 + }); 3875 + } 3876 + liveSocket2.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd)); 3877 + dom_default.dispatchEvent(document, "phx:update"); 3878 + added.forEach((el) => this.trackAfter("added", el)); 3879 + updates.forEach((el) => this.trackAfter("updated", el)); 3880 + this.transitionPendingRemoves(); 3881 + if (externalFormTriggered) { 3882 + liveSocket2.unload(); 3883 + const submitter = dom_default.private(externalFormTriggered, "submitter"); 3884 + if (submitter && submitter.name && targetContainer.contains(submitter)) { 3885 + const input = document.createElement("input"); 3886 + input.type = "hidden"; 3887 + const formId = submitter.getAttribute("form"); 3888 + if (formId) { 3889 + input.setAttribute("form", formId); 3890 + } 3891 + input.name = submitter.name; 3892 + input.value = submitter.value; 3893 + submitter.parentElement.insertBefore(input, submitter); 3894 + } 3895 + Object.getPrototypeOf(externalFormTriggered).submit.call(externalFormTriggered); 3896 + } 3897 + return true; 3898 + } 3899 + onNodeDiscarded(el) { 3900 + if (dom_default.isPhxChild(el) || dom_default.isPhxSticky(el)) { 3901 + this.liveSocket.destroyViewByEl(el); 3902 + } 3903 + this.trackAfter("discarded", el); 3904 + } 3905 + maybePendingRemove(node) { 3906 + if (node.getAttribute && node.getAttribute(this.phxRemove) !== null) { 3907 + this.pendingRemoves.push(node); 3908 + return true; 3909 + } else { 3910 + return false; 3911 + } 3912 + } 3913 + removeStreamChildElement(child, force = false) { 3914 + if (!force && !this.view.ownsElement(child)) { 3915 + return; 3916 + } 3917 + if (this.streamInserts[child.id]) { 3918 + this.streamComponentRestore[child.id] = child; 3919 + child.remove(); 3920 + } else { 3921 + if (!this.maybePendingRemove(child)) { 3922 + child.remove(); 3923 + this.onNodeDiscarded(child); 3924 + } 3925 + } 3926 + } 3927 + getStreamInsert(el) { 3928 + let insert = el.id ? this.streamInserts[el.id] : {}; 3929 + return insert || {}; 3930 + } 3931 + setStreamRef(el, ref) { 3932 + dom_default.putSticky(el, PHX_STREAM_REF, (el2) => el2.setAttribute(PHX_STREAM_REF, ref)); 3933 + } 3934 + maybeReOrderStream(el, isNew) { 3935 + let { ref, streamAt, reset } = this.getStreamInsert(el); 3936 + if (streamAt === void 0) { 3937 + return; 3938 + } 3939 + this.setStreamRef(el, ref); 3940 + if (!reset && !isNew) { 3941 + return; 3942 + } 3943 + if (!el.parentElement) { 3944 + return; 3945 + } 3946 + if (streamAt === 0) { 3947 + el.parentElement.insertBefore(el, el.parentElement.firstElementChild); 3948 + } else if (streamAt > 0) { 3949 + let children = Array.from(el.parentElement.children); 3950 + let oldIndex = children.indexOf(el); 3951 + if (streamAt >= children.length - 1) { 3952 + el.parentElement.appendChild(el); 3953 + } else { 3954 + let sibling = children[streamAt]; 3955 + if (oldIndex > streamAt) { 3956 + el.parentElement.insertBefore(el, sibling); 3957 + } else { 3958 + el.parentElement.insertBefore(el, sibling.nextElementSibling); 3959 + } 3960 + } 3961 + } 3962 + this.maybeLimitStream(el); 3963 + } 3964 + maybeLimitStream(el) { 3965 + let { limit } = this.getStreamInsert(el); 3966 + let children = limit !== null && Array.from(el.parentElement.children); 3967 + if (limit && limit < 0 && children.length > limit * -1) { 3968 + children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child)); 3969 + } else if (limit && limit >= 0 && children.length > limit) { 3970 + children.slice(limit).forEach((child) => this.removeStreamChildElement(child)); 3971 + } 3972 + } 3973 + transitionPendingRemoves() { 3974 + let { pendingRemoves, liveSocket: liveSocket2 } = this; 3975 + if (pendingRemoves.length > 0) { 3976 + liveSocket2.transitionRemoves(pendingRemoves, () => { 3977 + pendingRemoves.forEach((el) => { 3978 + let child = dom_default.firstPhxChild(el); 3979 + if (child) { 3980 + liveSocket2.destroyViewByEl(child); 3981 + } 3982 + el.remove(); 3983 + }); 3984 + this.trackAfter("transitionsDiscarded", pendingRemoves); 3985 + }); 3986 + } 3987 + } 3988 + isChangedSelect(fromEl, toEl) { 3989 + if (!(fromEl instanceof HTMLSelectElement) || fromEl.multiple) { 3990 + return false; 3991 + } 3992 + if (fromEl.options.length !== toEl.options.length) { 3993 + return true; 3994 + } 3995 + toEl.value = fromEl.value; 3996 + return !fromEl.isEqualNode(toEl); 3997 + } 3998 + isCIDPatch() { 3999 + return this.cidPatch; 4000 + } 4001 + skipCIDSibling(el) { 4002 + return el.nodeType === Node.ELEMENT_NODE && el.hasAttribute(PHX_SKIP); 4003 + } 4004 + targetCIDContainer(html) { 4005 + if (!this.isCIDPatch()) { 4006 + return; 4007 + } 4008 + let [first, ...rest] = dom_default.findComponentNodeList(this.container, this.targetCID); 4009 + if (rest.length === 0 && dom_default.childNodeLength(html) === 1) { 4010 + return first; 4011 + } else { 4012 + return first && first.parentNode; 4013 + } 4014 + } 4015 + indexOf(parent, child) { 4016 + return Array.from(parent.children).indexOf(child); 4017 + } 4018 + }; 4019 + var VOID_TAGS = /* @__PURE__ */ new Set([ 4020 + "area", 4021 + "base", 4022 + "br", 4023 + "col", 4024 + "command", 4025 + "embed", 4026 + "hr", 4027 + "img", 4028 + "input", 4029 + "keygen", 4030 + "link", 4031 + "meta", 4032 + "param", 4033 + "source", 4034 + "track", 4035 + "wbr" 4036 + ]); 4037 + var quoteChars = /* @__PURE__ */ new Set(["'", '"']); 4038 + var modifyRoot = (html, attrs, clearInnerHTML) => { 4039 + let i = 0; 4040 + let insideComment = false; 4041 + let beforeTag, afterTag, tag, tagNameEndsAt, id, newHTML; 4042 + let lookahead = html.match(/^(\s*(?:<!--.*?-->\s*)*)<([^\s\/>]+)/); 4043 + if (lookahead === null) { 4044 + throw new Error(`malformed html ${html}`); 4045 + } 4046 + i = lookahead[0].length; 4047 + beforeTag = lookahead[1]; 4048 + tag = lookahead[2]; 4049 + tagNameEndsAt = i; 4050 + for (i; i < html.length; i++) { 4051 + if (html.charAt(i) === ">") { 4052 + break; 4053 + } 4054 + if (html.charAt(i) === "=") { 4055 + let isId = html.slice(i - 3, i) === " id"; 4056 + i++; 4057 + let char = html.charAt(i); 4058 + if (quoteChars.has(char)) { 4059 + let attrStartsAt = i; 4060 + i++; 4061 + for (i; i < html.length; i++) { 4062 + if (html.charAt(i) === char) { 4063 + break; 4064 + } 4065 + } 4066 + if (isId) { 4067 + id = html.slice(attrStartsAt + 1, i); 4068 + break; 4069 + } 4070 + } 4071 + } 4072 + } 4073 + let closeAt = html.length - 1; 4074 + insideComment = false; 4075 + while (closeAt >= beforeTag.length + tag.length) { 4076 + let char = html.charAt(closeAt); 4077 + if (insideComment) { 4078 + if (char === "-" && html.slice(closeAt - 3, closeAt) === "<!-") { 4079 + insideComment = false; 4080 + closeAt -= 4; 4081 + } else { 4082 + closeAt -= 1; 4083 + } 4084 + } else if (char === ">" && html.slice(closeAt - 2, closeAt) === "--") { 4085 + insideComment = true; 4086 + closeAt -= 3; 4087 + } else if (char === ">") { 4088 + break; 4089 + } else { 4090 + closeAt -= 1; 4091 + } 4092 + } 4093 + afterTag = html.slice(closeAt + 1, html.length); 4094 + let attrsStr = Object.keys(attrs).map((attr) => attrs[attr] === true ? attr : `${attr}="${attrs[attr]}"`).join(" "); 4095 + if (clearInnerHTML) { 4096 + let idAttrStr = id ? ` id="${id}"` : ""; 4097 + if (VOID_TAGS.has(tag)) { 4098 + newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}/>`; 4099 + } else { 4100 + newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}></${tag}>`; 4101 + } 4102 + } else { 4103 + let rest = html.slice(tagNameEndsAt, closeAt + 1); 4104 + newHTML = `<${tag}${attrsStr === "" ? "" : " "}${attrsStr}${rest}`; 4105 + } 4106 + return [newHTML, beforeTag, afterTag]; 4107 + }; 4108 + var Rendered = class { 4109 + static extract(diff) { 4110 + let { [REPLY]: reply, [EVENTS]: events, [TITLE]: title } = diff; 4111 + delete diff[REPLY]; 4112 + delete diff[EVENTS]; 4113 + delete diff[TITLE]; 4114 + return { diff, title, reply: reply || null, events: events || [] }; 4115 + } 4116 + constructor(viewId, rendered) { 4117 + this.viewId = viewId; 4118 + this.rendered = {}; 4119 + this.magicId = 0; 4120 + this.mergeDiff(rendered); 4121 + } 4122 + parentViewId() { 4123 + return this.viewId; 4124 + } 4125 + toString(onlyCids) { 4126 + let [str, streams] = this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids, true, {}); 4127 + return [str, streams]; 4128 + } 4129 + recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids, changeTracking, rootAttrs) { 4130 + onlyCids = onlyCids ? new Set(onlyCids) : null; 4131 + let output = { buffer: "", components, onlyCids, streams: /* @__PURE__ */ new Set() }; 4132 + this.toOutputBuffer(rendered, null, output, changeTracking, rootAttrs); 4133 + return [output.buffer, output.streams]; 4134 + } 4135 + componentCIDs(diff) { 4136 + return Object.keys(diff[COMPONENTS] || {}).map((i) => parseInt(i)); 4137 + } 4138 + isComponentOnlyDiff(diff) { 4139 + if (!diff[COMPONENTS]) { 4140 + return false; 4141 + } 4142 + return Object.keys(diff).length === 1; 4143 + } 4144 + getComponent(diff, cid) { 4145 + return diff[COMPONENTS][cid]; 4146 + } 4147 + resetRender(cid) { 4148 + if (this.rendered[COMPONENTS][cid]) { 4149 + this.rendered[COMPONENTS][cid].reset = true; 4150 + } 4151 + } 4152 + mergeDiff(diff) { 4153 + let newc = diff[COMPONENTS]; 4154 + let cache = {}; 4155 + delete diff[COMPONENTS]; 4156 + this.rendered = this.mutableMerge(this.rendered, diff); 4157 + this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {}; 4158 + if (newc) { 4159 + let oldc = this.rendered[COMPONENTS]; 4160 + for (let cid in newc) { 4161 + newc[cid] = this.cachedFindComponent(cid, newc[cid], oldc, newc, cache); 4162 + } 4163 + for (let cid in newc) { 4164 + oldc[cid] = newc[cid]; 4165 + } 4166 + diff[COMPONENTS] = newc; 4167 + } 4168 + } 4169 + cachedFindComponent(cid, cdiff, oldc, newc, cache) { 4170 + if (cache[cid]) { 4171 + return cache[cid]; 4172 + } else { 4173 + let ndiff, stat, scid = cdiff[STATIC]; 4174 + if (isCid(scid)) { 4175 + let tdiff; 4176 + if (scid > 0) { 4177 + tdiff = this.cachedFindComponent(scid, newc[scid], oldc, newc, cache); 4178 + } else { 4179 + tdiff = oldc[-scid]; 4180 + } 4181 + stat = tdiff[STATIC]; 4182 + ndiff = this.cloneMerge(tdiff, cdiff, true); 4183 + ndiff[STATIC] = stat; 4184 + } else { 4185 + ndiff = cdiff[STATIC] !== void 0 || oldc[cid] === void 0 ? cdiff : this.cloneMerge(oldc[cid], cdiff, false); 4186 + } 4187 + cache[cid] = ndiff; 4188 + return ndiff; 4189 + } 4190 + } 4191 + mutableMerge(target, source) { 4192 + if (source[STATIC] !== void 0) { 4193 + return source; 4194 + } else { 4195 + this.doMutableMerge(target, source); 4196 + return target; 4197 + } 4198 + } 4199 + doMutableMerge(target, source) { 4200 + for (let key in source) { 4201 + let val = source[key]; 4202 + let targetVal = target[key]; 4203 + let isObjVal = isObject(val); 4204 + if (isObjVal && val[STATIC] === void 0 && isObject(targetVal)) { 4205 + this.doMutableMerge(targetVal, val); 4206 + } else { 4207 + target[key] = val; 4208 + } 4209 + } 4210 + if (target[ROOT]) { 4211 + target.newRender = true; 4212 + } 4213 + } 4214 + // Merges cid trees together, copying statics from source tree. 4215 + // 4216 + // The `pruneMagicId` is passed to control pruning the magicId of the 4217 + // target. We must always prune the magicId when we are sharing statics 4218 + // from another component. If not pruning, we replicate the logic from 4219 + // mutableMerge, where we set newRender to true if there is a root 4220 + // (effectively forcing the new version to be rendered instead of skipped) 4221 + // 4222 + cloneMerge(target, source, pruneMagicId) { 4223 + let merged = __spreadValues(__spreadValues({}, target), source); 4224 + for (let key in merged) { 4225 + let val = source[key]; 4226 + let targetVal = target[key]; 4227 + if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) { 4228 + merged[key] = this.cloneMerge(targetVal, val, pruneMagicId); 4229 + } else if (val === void 0 && isObject(targetVal)) { 4230 + merged[key] = this.cloneMerge(targetVal, {}, pruneMagicId); 4231 + } 4232 + } 4233 + if (pruneMagicId) { 4234 + delete merged.magicId; 4235 + delete merged.newRender; 4236 + } else if (target[ROOT]) { 4237 + merged.newRender = true; 4238 + } 4239 + return merged; 4240 + } 4241 + componentToString(cid) { 4242 + let [str, streams] = this.recursiveCIDToString(this.rendered[COMPONENTS], cid, null); 4243 + let [strippedHTML, _before, _after] = modifyRoot(str, {}); 4244 + return [strippedHTML, streams]; 4245 + } 4246 + pruneCIDs(cids) { 4247 + cids.forEach((cid) => delete this.rendered[COMPONENTS][cid]); 4248 + } 4249 + // private 4250 + get() { 4251 + return this.rendered; 4252 + } 4253 + isNewFingerprint(diff = {}) { 4254 + return !!diff[STATIC]; 4255 + } 4256 + templateStatic(part, templates) { 4257 + if (typeof part === "number") { 4258 + return templates[part]; 4259 + } else { 4260 + return part; 4261 + } 4262 + } 4263 + nextMagicID() { 4264 + this.magicId++; 4265 + return `m${this.magicId}-${this.parentViewId()}`; 4266 + } 4267 + // Converts rendered tree to output buffer. 4268 + // 4269 + // changeTracking controls if we can apply the PHX_SKIP optimization. 4270 + // It is disabled for comprehensions since we must re-render the entire collection 4271 + // and no individual element is tracked inside the comprehension. 4272 + toOutputBuffer(rendered, templates, output, changeTracking, rootAttrs = {}) { 4273 + if (rendered[DYNAMICS]) { 4274 + return this.comprehensionToBuffer(rendered, templates, output); 4275 + } 4276 + let { [STATIC]: statics } = rendered; 4277 + statics = this.templateStatic(statics, templates); 4278 + let isRoot = rendered[ROOT]; 4279 + let prevBuffer = output.buffer; 4280 + if (isRoot) { 4281 + output.buffer = ""; 4282 + } 4283 + if (changeTracking && isRoot && !rendered.magicId) { 4284 + rendered.newRender = true; 4285 + rendered.magicId = this.nextMagicID(); 4286 + } 4287 + output.buffer += statics[0]; 4288 + for (let i = 1; i < statics.length; i++) { 4289 + this.dynamicToBuffer(rendered[i - 1], templates, output, changeTracking); 4290 + output.buffer += statics[i]; 4291 + } 4292 + if (isRoot) { 4293 + let skip = false; 4294 + let attrs; 4295 + if (changeTracking || rendered.magicId) { 4296 + skip = changeTracking && !rendered.newRender; 4297 + attrs = __spreadValues({ [PHX_MAGIC_ID]: rendered.magicId }, rootAttrs); 4298 + } else { 4299 + attrs = rootAttrs; 4300 + } 4301 + if (skip) { 4302 + attrs[PHX_SKIP] = true; 4303 + } 4304 + let [newRoot, commentBefore, commentAfter] = modifyRoot(output.buffer, attrs, skip); 4305 + rendered.newRender = false; 4306 + output.buffer = prevBuffer + commentBefore + newRoot + commentAfter; 4307 + } 4308 + } 4309 + comprehensionToBuffer(rendered, templates, output) { 4310 + let { [DYNAMICS]: dynamics, [STATIC]: statics, [STREAM]: stream } = rendered; 4311 + let [_ref, _inserts, deleteIds, reset] = stream || [null, {}, [], null]; 4312 + statics = this.templateStatic(statics, templates); 4313 + let compTemplates = templates || rendered[TEMPLATES]; 4314 + for (let d = 0; d < dynamics.length; d++) { 4315 + let dynamic = dynamics[d]; 4316 + output.buffer += statics[0]; 4317 + for (let i = 1; i < statics.length; i++) { 4318 + let changeTracking = false; 4319 + this.dynamicToBuffer(dynamic[i - 1], compTemplates, output, changeTracking); 4320 + output.buffer += statics[i]; 4321 + } 4322 + } 4323 + if (stream !== void 0 && (rendered[DYNAMICS].length > 0 || deleteIds.length > 0 || reset)) { 4324 + delete rendered[STREAM]; 4325 + rendered[DYNAMICS] = []; 4326 + output.streams.add(stream); 4327 + } 4328 + } 4329 + dynamicToBuffer(rendered, templates, output, changeTracking) { 4330 + if (typeof rendered === "number") { 4331 + let [str, streams] = this.recursiveCIDToString(output.components, rendered, output.onlyCids); 4332 + output.buffer += str; 4333 + output.streams = /* @__PURE__ */ new Set([...output.streams, ...streams]); 4334 + } else if (isObject(rendered)) { 4335 + this.toOutputBuffer(rendered, templates, output, changeTracking, {}); 4336 + } else { 4337 + output.buffer += rendered; 4338 + } 4339 + } 4340 + recursiveCIDToString(components, cid, onlyCids) { 4341 + let component = components[cid] || logError(`no component for CID ${cid}`, components); 4342 + let attrs = { [PHX_COMPONENT]: cid }; 4343 + let skip = onlyCids && !onlyCids.has(cid); 4344 + component.newRender = !skip; 4345 + component.magicId = `c${cid}-${this.parentViewId()}`; 4346 + let changeTracking = !component.reset; 4347 + let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs); 4348 + delete component.reset; 4349 + return [html, streams]; 4350 + } 4351 + }; 4352 + var focusStack = []; 4353 + var default_transition_time = 200; 4354 + var JS = { 4355 + // private 4356 + exec(e, eventType, phxEvent, view, sourceEl, defaults) { 4357 + let [defaultKind, defaultArgs] = defaults || [null, { callback: defaults && defaults.callback }]; 4358 + let commands = phxEvent.charAt(0) === "[" ? JSON.parse(phxEvent) : [[defaultKind, defaultArgs]]; 4359 + commands.forEach(([kind, args]) => { 4360 + if (kind === defaultKind) { 4361 + args = __spreadValues(__spreadValues({}, defaultArgs), args); 4362 + args.callback = args.callback || defaultArgs.callback; 4363 + } 4364 + this.filterToEls(view.liveSocket, sourceEl, args).forEach((el) => { 4365 + this[`exec_${kind}`](e, eventType, phxEvent, view, sourceEl, el, args); 4366 + }); 4367 + }); 4368 + }, 4369 + isVisible(el) { 4370 + return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0); 4371 + }, 4372 + // returns true if any part of the element is inside the viewport 4373 + isInViewport(el) { 4374 + const rect = el.getBoundingClientRect(); 4375 + const windowHeight = window.innerHeight || document.documentElement.clientHeight; 4376 + const windowWidth = window.innerWidth || document.documentElement.clientWidth; 4377 + return rect.right > 0 && rect.bottom > 0 && rect.left < windowWidth && rect.top < windowHeight; 4378 + }, 4379 + // private 4380 + // commands 4381 + exec_exec(e, eventType, phxEvent, view, sourceEl, el, { attr, to }) { 4382 + let encodedJS = el.getAttribute(attr); 4383 + if (!encodedJS) { 4384 + throw new Error(`expected ${attr} to contain JS command on "${to}"`); 4385 + } 4386 + view.liveSocket.execJS(el, encodedJS, eventType); 4387 + }, 4388 + exec_dispatch(e, eventType, phxEvent, view, sourceEl, el, { event, detail, bubbles }) { 4389 + detail = detail || {}; 4390 + detail.dispatcher = sourceEl; 4391 + dom_default.dispatchEvent(el, event, { detail, bubbles }); 4392 + }, 4393 + exec_push(e, eventType, phxEvent, view, sourceEl, el, args) { 4394 + let { event, data, target, page_loading, loading, value, dispatcher, callback } = args; 4395 + let pushOpts = { loading, value, target, page_loading: !!page_loading }; 4396 + let targetSrc = eventType === "change" && dispatcher ? dispatcher : sourceEl; 4397 + let phxTarget = target || targetSrc.getAttribute(view.binding("target")) || targetSrc; 4398 + const handler = (targetView, targetCtx) => { 4399 + if (!targetView.isConnected()) { 4400 + return; 4401 + } 4402 + if (eventType === "change") { 4403 + let { newCid, _target } = args; 4404 + _target = _target || (dom_default.isFormInput(sourceEl) ? sourceEl.name : void 0); 4405 + if (_target) { 4406 + pushOpts._target = _target; 4407 + } 4408 + targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback); 4409 + } else if (eventType === "submit") { 4410 + let { submitter } = args; 4411 + targetView.submitForm(sourceEl, targetCtx, event || phxEvent, submitter, pushOpts, callback); 4412 + } else { 4413 + targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts, callback); 4414 + } 4415 + }; 4416 + if (args.targetView && args.targetCtx) { 4417 + handler(args.targetView, args.targetCtx); 4418 + } else { 4419 + view.withinTargets(phxTarget, handler); 4420 + } 4421 + }, 4422 + exec_navigate(e, eventType, phxEvent, view, sourceEl, el, { href, replace }) { 4423 + view.liveSocket.historyRedirect(e, href, replace ? "replace" : "push", null, sourceEl); 4424 + }, 4425 + exec_patch(e, eventType, phxEvent, view, sourceEl, el, { href, replace }) { 4426 + view.liveSocket.pushHistoryPatch(e, href, replace ? "replace" : "push", sourceEl); 4427 + }, 4428 + exec_focus(e, eventType, phxEvent, view, sourceEl, el) { 4429 + aria_default.attemptFocus(el); 4430 + window.requestAnimationFrame(() => { 4431 + window.requestAnimationFrame(() => aria_default.attemptFocus(el)); 4432 + }); 4433 + }, 4434 + exec_focus_first(e, eventType, phxEvent, view, sourceEl, el) { 4435 + aria_default.focusFirstInteractive(el) || aria_default.focusFirst(el); 4436 + window.requestAnimationFrame(() => { 4437 + window.requestAnimationFrame(() => aria_default.focusFirstInteractive(el) || aria_default.focusFirst(el)); 4438 + }); 4439 + }, 4440 + exec_push_focus(e, eventType, phxEvent, view, sourceEl, el) { 4441 + focusStack.push(el || sourceEl); 4442 + }, 4443 + exec_pop_focus(_e, _eventType, _phxEvent, _view, _sourceEl, _el) { 4444 + const el = focusStack.pop(); 4445 + if (el) { 4446 + el.focus(); 4447 + window.requestAnimationFrame(() => { 4448 + window.requestAnimationFrame(() => el.focus()); 4449 + }); 4450 + } 4451 + }, 4452 + exec_add_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { 4453 + this.addOrRemoveClasses(el, names, [], transition, time, view, blocking); 4454 + }, 4455 + exec_remove_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { 4456 + this.addOrRemoveClasses(el, [], names, transition, time, view, blocking); 4457 + }, 4458 + exec_toggle_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { 4459 + this.toggleClasses(el, names, transition, time, view, blocking); 4460 + }, 4461 + exec_toggle_attr(e, eventType, phxEvent, view, sourceEl, el, { attr: [attr, val1, val2] }) { 4462 + this.toggleAttr(el, attr, val1, val2); 4463 + }, 4464 + exec_transition(e, eventType, phxEvent, view, sourceEl, el, { time, transition, blocking }) { 4465 + this.addOrRemoveClasses(el, [], [], transition, time, view, blocking); 4466 + }, 4467 + exec_toggle(e, eventType, phxEvent, view, sourceEl, el, { display, ins, outs, time, blocking }) { 4468 + this.toggle(eventType, view, el, display, ins, outs, time, blocking); 4469 + }, 4470 + exec_show(e, eventType, phxEvent, view, sourceEl, el, { display, transition, time, blocking }) { 4471 + this.show(eventType, view, el, display, transition, time, blocking); 4472 + }, 4473 + exec_hide(e, eventType, phxEvent, view, sourceEl, el, { display, transition, time, blocking }) { 4474 + this.hide(eventType, view, el, display, transition, time, blocking); 4475 + }, 4476 + exec_set_attr(e, eventType, phxEvent, view, sourceEl, el, { attr: [attr, val] }) { 4477 + this.setOrRemoveAttrs(el, [[attr, val]], []); 4478 + }, 4479 + exec_remove_attr(e, eventType, phxEvent, view, sourceEl, el, { attr }) { 4480 + this.setOrRemoveAttrs(el, [], [attr]); 4481 + }, 4482 + // utils for commands 4483 + show(eventType, view, el, display, transition, time, blocking) { 4484 + if (!this.isVisible(el)) { 4485 + this.toggle(eventType, view, el, display, transition, null, time, blocking); 4486 + } 4487 + }, 4488 + hide(eventType, view, el, display, transition, time, blocking) { 4489 + if (this.isVisible(el)) { 4490 + this.toggle(eventType, view, el, display, null, transition, time, blocking); 4491 + } 4492 + }, 4493 + toggle(eventType, view, el, display, ins, outs, time, blocking) { 4494 + time = time || default_transition_time; 4495 + let [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []]; 4496 + let [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []]; 4497 + if (inClasses.length > 0 || outClasses.length > 0) { 4498 + if (this.isVisible(el)) { 4499 + let onStart = () => { 4500 + this.addOrRemoveClasses(el, outStartClasses, inClasses.concat(inStartClasses).concat(inEndClasses)); 4501 + window.requestAnimationFrame(() => { 4502 + this.addOrRemoveClasses(el, outClasses, []); 4503 + window.requestAnimationFrame(() => this.addOrRemoveClasses(el, outEndClasses, outStartClasses)); 4504 + }); 4505 + }; 4506 + let onEnd = () => { 4507 + this.addOrRemoveClasses(el, [], outClasses.concat(outEndClasses)); 4508 + dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = "none"); 4509 + el.dispatchEvent(new Event("phx:hide-end")); 4510 + }; 4511 + el.dispatchEvent(new Event("phx:hide-start")); 4512 + if (blocking === false) { 4513 + onStart(); 4514 + setTimeout(onEnd, time); 4515 + } else { 4516 + view.transition(time, onStart, onEnd); 4517 + } 4518 + } else { 4519 + if (eventType === "remove") { 4520 + return; 4521 + } 4522 + let onStart = () => { 4523 + this.addOrRemoveClasses(el, inStartClasses, outClasses.concat(outStartClasses).concat(outEndClasses)); 4524 + const stickyDisplay = display || this.defaultDisplay(el); 4525 + window.requestAnimationFrame(() => { 4526 + this.addOrRemoveClasses(el, inClasses, []); 4527 + window.requestAnimationFrame(() => { 4528 + dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = stickyDisplay); 4529 + this.addOrRemoveClasses(el, inEndClasses, inStartClasses); 4530 + }); 4531 + }); 4532 + }; 4533 + let onEnd = () => { 4534 + this.addOrRemoveClasses(el, [], inClasses.concat(inEndClasses)); 4535 + el.dispatchEvent(new Event("phx:show-end")); 4536 + }; 4537 + el.dispatchEvent(new Event("phx:show-start")); 4538 + if (blocking === false) { 4539 + onStart(); 4540 + setTimeout(onEnd, time); 4541 + } else { 4542 + view.transition(time, onStart, onEnd); 4543 + } 4544 + } 4545 + } else { 4546 + if (this.isVisible(el)) { 4547 + window.requestAnimationFrame(() => { 4548 + el.dispatchEvent(new Event("phx:hide-start")); 4549 + dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = "none"); 4550 + el.dispatchEvent(new Event("phx:hide-end")); 4551 + }); 4552 + } else { 4553 + window.requestAnimationFrame(() => { 4554 + el.dispatchEvent(new Event("phx:show-start")); 4555 + let stickyDisplay = display || this.defaultDisplay(el); 4556 + dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = stickyDisplay); 4557 + el.dispatchEvent(new Event("phx:show-end")); 4558 + }); 4559 + } 4560 + } 4561 + }, 4562 + toggleClasses(el, classes, transition, time, view, blocking) { 4563 + window.requestAnimationFrame(() => { 4564 + let [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]); 4565 + let newAdds = classes.filter((name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name)); 4566 + let newRemoves = classes.filter((name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name)); 4567 + this.addOrRemoveClasses(el, newAdds, newRemoves, transition, time, view, blocking); 4568 + }); 4569 + }, 4570 + toggleAttr(el, attr, val1, val2) { 4571 + if (el.hasAttribute(attr)) { 4572 + if (val2 !== void 0) { 4573 + if (el.getAttribute(attr) === val1) { 4574 + this.setOrRemoveAttrs(el, [[attr, val2]], []); 4575 + } else { 4576 + this.setOrRemoveAttrs(el, [[attr, val1]], []); 4577 + } 4578 + } else { 4579 + this.setOrRemoveAttrs(el, [], [attr]); 4580 + } 4581 + } else { 4582 + this.setOrRemoveAttrs(el, [[attr, val1]], []); 4583 + } 4584 + }, 4585 + addOrRemoveClasses(el, adds, removes, transition, time, view, blocking) { 4586 + time = time || default_transition_time; 4587 + let [transitionRun, transitionStart, transitionEnd] = transition || [[], [], []]; 4588 + if (transitionRun.length > 0) { 4589 + let onStart = () => { 4590 + this.addOrRemoveClasses(el, transitionStart, [].concat(transitionRun).concat(transitionEnd)); 4591 + window.requestAnimationFrame(() => { 4592 + this.addOrRemoveClasses(el, transitionRun, []); 4593 + window.requestAnimationFrame(() => this.addOrRemoveClasses(el, transitionEnd, transitionStart)); 4594 + }); 4595 + }; 4596 + let onDone = () => this.addOrRemoveClasses(el, adds.concat(transitionEnd), removes.concat(transitionRun).concat(transitionStart)); 4597 + if (blocking === false) { 4598 + onStart(); 4599 + setTimeout(onDone, time); 4600 + } else { 4601 + view.transition(time, onStart, onDone); 4602 + } 4603 + return; 4604 + } 4605 + window.requestAnimationFrame(() => { 4606 + let [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]); 4607 + let keepAdds = adds.filter((name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name)); 4608 + let keepRemoves = removes.filter((name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name)); 4609 + let newAdds = prevAdds.filter((name) => removes.indexOf(name) < 0).concat(keepAdds); 4610 + let newRemoves = prevRemoves.filter((name) => adds.indexOf(name) < 0).concat(keepRemoves); 4611 + dom_default.putSticky(el, "classes", (currentEl) => { 4612 + currentEl.classList.remove(...newRemoves); 4613 + currentEl.classList.add(...newAdds); 4614 + return [newAdds, newRemoves]; 4615 + }); 4616 + }); 4617 + }, 4618 + setOrRemoveAttrs(el, sets, removes) { 4619 + let [prevSets, prevRemoves] = dom_default.getSticky(el, "attrs", [[], []]); 4620 + let alteredAttrs = sets.map(([attr, _val]) => attr).concat(removes); 4621 + let newSets = prevSets.filter(([attr, _val]) => !alteredAttrs.includes(attr)).concat(sets); 4622 + let newRemoves = prevRemoves.filter((attr) => !alteredAttrs.includes(attr)).concat(removes); 4623 + dom_default.putSticky(el, "attrs", (currentEl) => { 4624 + newRemoves.forEach((attr) => currentEl.removeAttribute(attr)); 4625 + newSets.forEach(([attr, val]) => currentEl.setAttribute(attr, val)); 4626 + return [newSets, newRemoves]; 4627 + }); 4628 + }, 4629 + hasAllClasses(el, classes) { 4630 + return classes.every((name) => el.classList.contains(name)); 4631 + }, 4632 + isToggledOut(el, outClasses) { 4633 + return !this.isVisible(el) || this.hasAllClasses(el, outClasses); 4634 + }, 4635 + filterToEls(liveSocket2, sourceEl, { to }) { 4636 + let defaultQuery = () => { 4637 + if (typeof to === "string") { 4638 + return document.querySelectorAll(to); 4639 + } else if (to.closest) { 4640 + let toEl = sourceEl.closest(to.closest); 4641 + return toEl ? [toEl] : []; 4642 + } else if (to.inner) { 4643 + return sourceEl.querySelectorAll(to.inner); 4644 + } 4645 + }; 4646 + return to ? liveSocket2.jsQuerySelectorAll(sourceEl, to, defaultQuery) : [sourceEl]; 4647 + }, 4648 + defaultDisplay(el) { 4649 + return { tr: "table-row", td: "table-cell" }[el.tagName.toLowerCase()] || "block"; 4650 + }, 4651 + transitionClasses(val) { 4652 + if (!val) { 4653 + return null; 4654 + } 4655 + let [trans, tStart, tEnd] = Array.isArray(val) ? val : [val.split(" "), [], []]; 4656 + trans = Array.isArray(trans) ? trans : trans.split(" "); 4657 + tStart = Array.isArray(tStart) ? tStart : tStart.split(" "); 4658 + tEnd = Array.isArray(tEnd) ? tEnd : tEnd.split(" "); 4659 + return [trans, tStart, tEnd]; 4660 + } 4661 + }; 4662 + var js_default = JS; 4663 + var HOOK_ID = "hookId"; 4664 + var viewHookID = 1; 4665 + var ViewHook = class { 4666 + static makeID() { 4667 + return viewHookID++; 4668 + } 4669 + static elementID(el) { 4670 + return dom_default.private(el, HOOK_ID); 4671 + } 4672 + constructor(view, el, callbacks) { 4673 + this.el = el; 4674 + this.__attachView(view); 4675 + this.__callbacks = callbacks; 4676 + this.__listeners = /* @__PURE__ */ new Set(); 4677 + this.__isDisconnected = false; 4678 + dom_default.putPrivate(this.el, HOOK_ID, this.constructor.makeID()); 4679 + for (let key in this.__callbacks) { 4680 + this[key] = this.__callbacks[key]; 4681 + } 4682 + } 4683 + __attachView(view) { 4684 + if (view) { 4685 + this.__view = () => view; 4686 + this.liveSocket = view.liveSocket; 4687 + } else { 4688 + this.__view = () => { 4689 + throw new Error(`hook not yet attached to a live view: ${this.el.outerHTML}`); 4690 + }; 4691 + this.liveSocket = null; 4692 + } 4693 + } 4694 + __mounted() { 4695 + this.mounted && this.mounted(); 4696 + } 4697 + __updated() { 4698 + this.updated && this.updated(); 4699 + } 4700 + __beforeUpdate() { 4701 + this.beforeUpdate && this.beforeUpdate(); 4702 + } 4703 + __destroyed() { 4704 + this.destroyed && this.destroyed(); 4705 + dom_default.deletePrivate(this.el, HOOK_ID); 4706 + } 4707 + __reconnected() { 4708 + if (this.__isDisconnected) { 4709 + this.__isDisconnected = false; 4710 + this.reconnected && this.reconnected(); 4711 + } 4712 + } 4713 + __disconnected() { 4714 + this.__isDisconnected = true; 4715 + this.disconnected && this.disconnected(); 4716 + } 4717 + /** 4718 + * Binds the hook to JS commands. 4719 + * 4720 + * @param {ViewHook} hook - The ViewHook instance to bind. 4721 + * 4722 + * @returns {Object} An object with methods to manipulate the DOM and execute JavaScript. 4723 + */ 4724 + js() { 4725 + let hook = this; 4726 + return { 4727 + /** 4728 + * Executes encoded JavaScript in the context of the hook element. 4729 + * 4730 + * @param {string} encodedJS - The encoded JavaScript string to execute. 4731 + */ 4732 + exec(encodedJS) { 4733 + hook.__view().liveSocket.execJS(hook.el, encodedJS, "hook"); 4734 + }, 4735 + /** 4736 + * Shows an element. 4737 + * 4738 + * @param {HTMLElement} el - The element to show. 4739 + * @param {Object} [opts={}] - Optional settings. 4740 + * @param {string} [opts.display] - The CSS display value to set. Defaults "block". 4741 + * @param {string} [opts.transition] - The CSS transition classes to set when showing. 4742 + * @param {number} [opts.time] - The transition duration in milliseconds. Defaults 200. 4743 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4744 + * Defaults `true`. 4745 + */ 4746 + show(el, opts = {}) { 4747 + let owner = hook.__view().liveSocket.owner(el); 4748 + js_default.show("hook", owner, el, opts.display, opts.transition, opts.time, opts.blocking); 4749 + }, 4750 + /** 4751 + * Hides an element. 4752 + * 4753 + * @param {HTMLElement} el - The element to hide. 4754 + * @param {Object} [opts={}] - Optional settings. 4755 + * @param {string} [opts.transition] - The CSS transition classes to set when hiding. 4756 + * @param {number} [opts.time] - The transition duration in milliseconds. Defaults 200. 4757 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4758 + * Defaults `true`. 4759 + */ 4760 + hide(el, opts = {}) { 4761 + let owner = hook.__view().liveSocket.owner(el); 4762 + js_default.hide("hook", owner, el, null, opts.transition, opts.time, opts.blocking); 4763 + }, 4764 + /** 4765 + * Toggles the visibility of an element. 4766 + * 4767 + * @param {HTMLElement} el - The element to toggle. 4768 + * @param {Object} [opts={}] - Optional settings. 4769 + * @param {string} [opts.display] - The CSS display value to set. Defaults "block". 4770 + * @param {string} [opts.in] - The CSS transition classes for showing. 4771 + * Accepts either the string of classes to apply when toggling in, or 4772 + * a 3-tuple containing the transition class, the class to apply 4773 + * to start the transition, and the ending transition class, such as: 4774 + * 4775 + * ["ease-out duration-300", "opacity-0", "opacity-100"] 4776 + * 4777 + * @param {string} [opts.out] - The CSS transition classes for hiding. 4778 + * Accepts either string of classes to apply when toggling out, or 4779 + * a 3-tuple containing the transition class, the class to apply 4780 + * to start the transition, and the ending transition class, such as: 4781 + * 4782 + * ["ease-out duration-300", "opacity-100", "opacity-0"] 4783 + * 4784 + * @param {number} [opts.time] - The transition duration in milliseconds. 4785 + * 4786 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4787 + * Defaults `true`. 4788 + */ 4789 + toggle(el, opts = {}) { 4790 + let owner = hook.__view().liveSocket.owner(el); 4791 + opts.in = js_default.transitionClasses(opts.in); 4792 + opts.out = js_default.transitionClasses(opts.out); 4793 + js_default.toggle("hook", owner, el, opts.display, opts.in, opts.out, opts.time, opts.blocking); 4794 + }, 4795 + /** 4796 + * Adds CSS classes to an element. 4797 + * 4798 + * @param {HTMLElement} el - The element to add classes to. 4799 + * @param {string|string[]} names - The class name(s) to add. 4800 + * @param {Object} [opts={}] - Optional settings. 4801 + * @param {string} [opts.transition] - The CSS transition property to set. 4802 + * Accepts a string of classes to apply when adding classes or 4803 + * a 3-tuple containing the transition class, the class to apply 4804 + * to start the transition, and the ending transition class, such as: 4805 + * 4806 + * ["ease-out duration-300", "opacity-0", "opacity-100"] 4807 + * 4808 + * @param {number} [opts.time] - The transition duration in milliseconds. 4809 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4810 + * Defaults `true`. 4811 + */ 4812 + addClass(el, names, opts = {}) { 4813 + names = Array.isArray(names) ? names : names.split(" "); 4814 + let owner = hook.__view().liveSocket.owner(el); 4815 + js_default.addOrRemoveClasses(el, names, [], opts.transition, opts.time, owner, opts.blocking); 4816 + }, 4817 + /** 4818 + * Removes CSS classes from an element. 4819 + * 4820 + * @param {HTMLElement} el - The element to remove classes from. 4821 + * @param {string|string[]} names - The class name(s) to remove. 4822 + * @param {Object} [opts={}] - Optional settings. 4823 + * @param {string} [opts.transition] - The CSS transition classes to set. 4824 + * Accepts a string of classes to apply when removing classes or 4825 + * a 3-tuple containing the transition class, the class to apply 4826 + * to start the transition, and the ending transition class, such as: 4827 + * 4828 + * ["ease-out duration-300", "opacity-100", "opacity-0"] 4829 + * 4830 + * @param {number} [opts.time] - The transition duration in milliseconds. 4831 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4832 + * Defaults `true`. 4833 + */ 4834 + removeClass(el, names, opts = {}) { 4835 + opts.transition = js_default.transitionClasses(opts.transition); 4836 + names = Array.isArray(names) ? names : names.split(" "); 4837 + let owner = hook.__view().liveSocket.owner(el); 4838 + js_default.addOrRemoveClasses(el, [], names, opts.transition, opts.time, owner, opts.blocking); 4839 + }, 4840 + /** 4841 + * Toggles CSS classes on an element. 4842 + * 4843 + * @param {HTMLElement} el - The element to toggle classes on. 4844 + * @param {string|string[]} names - The class name(s) to toggle. 4845 + * @param {Object} [opts={}] - Optional settings. 4846 + * @param {string} [opts.transition] - The CSS transition classes to set. 4847 + * Accepts a string of classes to apply when toggling classes or 4848 + * a 3-tuple containing the transition class, the class to apply 4849 + * to start the transition, and the ending transition class, such as: 4850 + * 4851 + * ["ease-out duration-300", "opacity-100", "opacity-0"] 4852 + * 4853 + * @param {number} [opts.time] - The transition duration in milliseconds. 4854 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4855 + * Defaults `true`. 4856 + */ 4857 + toggleClass(el, names, opts = {}) { 4858 + opts.transition = js_default.transitionClasses(opts.transition); 4859 + names = Array.isArray(names) ? names : names.split(" "); 4860 + let owner = hook.__view().liveSocket.owner(el); 4861 + js_default.toggleClasses(el, names, opts.transition, opts.time, owner, opts.blocking); 4862 + }, 4863 + /** 4864 + * Applies a CSS transition to an element. 4865 + * 4866 + * @param {HTMLElement} el - The element to apply the transition to. 4867 + * @param {string|string[]} transition - The transition class(es) to apply. 4868 + * Accepts a string of classes to apply when transitioning or 4869 + * a 3-tuple containing the transition class, the class to apply 4870 + * to start the transition, and the ending transition class, such as: 4871 + * 4872 + * ["ease-out duration-300", "opacity-100", "opacity-0"] 4873 + * 4874 + * @param {Object} [opts={}] - Optional settings. 4875 + * @param {number} [opts.time] - The transition duration in milliseconds. 4876 + * @param {boolean} [opts.blocking] - The boolean flag to block the UI during the transition. 4877 + * Defaults `true`. 4878 + */ 4879 + transition(el, transition, opts = {}) { 4880 + let owner = hook.__view().liveSocket.owner(el); 4881 + js_default.addOrRemoveClasses(el, [], [], js_default.transitionClasses(transition), opts.time, owner, opts.blocking); 4882 + }, 4883 + /** 4884 + * Sets an attribute on an element. 4885 + * 4886 + * @param {HTMLElement} el - The element to set the attribute on. 4887 + * @param {string} attr - The attribute name to set. 4888 + * @param {string} val - The value to set for the attribute. 4889 + */ 4890 + setAttribute(el, attr, val) { 4891 + js_default.setOrRemoveAttrs(el, [[attr, val]], []); 4892 + }, 4893 + /** 4894 + * Removes an attribute from an element. 4895 + * 4896 + * @param {HTMLElement} el - The element to remove the attribute from. 4897 + * @param {string} attr - The attribute name to remove. 4898 + */ 4899 + removeAttribute(el, attr) { 4900 + js_default.setOrRemoveAttrs(el, [], [attr]); 4901 + }, 4902 + /** 4903 + * Toggles an attribute on an element between two values. 4904 + * 4905 + * @param {HTMLElement} el - The element to toggle the attribute on. 4906 + * @param {string} attr - The attribute name to toggle. 4907 + * @param {string} val1 - The first value to toggle between. 4908 + * @param {string} val2 - The second value to toggle between. 4909 + */ 4910 + toggleAttribute(el, attr, val1, val2) { 4911 + js_default.toggleAttr(el, attr, val1, val2); 4912 + } 4913 + }; 4914 + } 4915 + pushEvent(event, payload = {}, onReply) { 4916 + if (onReply === void 0) { 4917 + return new Promise((resolve, reject) => { 4918 + try { 4919 + const ref = this.__view().pushHookEvent(this.el, null, event, payload, (reply, _ref) => resolve(reply)); 4920 + if (ref === false) { 4921 + reject(new Error("unable to push hook event. LiveView not connected")); 4922 + } 4923 + } catch (error) { 4924 + reject(error); 4925 + } 4926 + }); 4927 + } 4928 + return this.__view().pushHookEvent(this.el, null, event, payload, onReply); 4929 + } 4930 + pushEventTo(phxTarget, event, payload = {}, onReply) { 4931 + if (onReply === void 0) { 4932 + return new Promise((resolve, reject) => { 4933 + try { 4934 + this.__view().withinTargets(phxTarget, (view, targetCtx) => { 4935 + const ref = view.pushHookEvent(this.el, targetCtx, event, payload, (reply, _ref) => resolve(reply)); 4936 + if (ref === false) { 4937 + reject(new Error("unable to push hook event. LiveView not connected")); 4938 + } 4939 + }); 4940 + } catch (error) { 4941 + reject(error); 4942 + } 4943 + }); 4944 + } 4945 + return this.__view().withinTargets(phxTarget, (view, targetCtx) => { 4946 + return view.pushHookEvent(this.el, targetCtx, event, payload, onReply); 4947 + }); 4948 + } 4949 + handleEvent(event, callback) { 4950 + let callbackRef = (customEvent, bypass) => bypass ? event : callback(customEvent.detail); 4951 + window.addEventListener(`phx:${event}`, callbackRef); 4952 + this.__listeners.add(callbackRef); 4953 + return callbackRef; 4954 + } 4955 + removeHandleEvent(callbackRef) { 4956 + let event = callbackRef(null, true); 4957 + window.removeEventListener(`phx:${event}`, callbackRef); 4958 + this.__listeners.delete(callbackRef); 4959 + } 4960 + upload(name, files) { 4961 + return this.__view().dispatchUploads(null, name, files); 4962 + } 4963 + uploadTo(phxTarget, name, files) { 4964 + return this.__view().withinTargets(phxTarget, (view, targetCtx) => { 4965 + view.dispatchUploads(targetCtx, name, files); 4966 + }); 4967 + } 4968 + __cleanup__() { 4969 + this.__listeners.forEach((callbackRef) => this.removeHandleEvent(callbackRef)); 4970 + } 4971 + }; 4972 + var prependFormDataKey = (key, prefix) => { 4973 + let isArray = key.endsWith("[]"); 4974 + let baseKey = isArray ? key.slice(0, -2) : key; 4975 + baseKey = baseKey.replace(/([^\[\]]+)(\]?$)/, `${prefix}$1$2`); 4976 + if (isArray) { 4977 + baseKey += "[]"; 4978 + } 4979 + return baseKey; 4980 + }; 4981 + var serializeForm = (form, opts, onlyNames = []) => { 4982 + const { submitter } = opts; 4983 + let injectedElement; 4984 + if (submitter && submitter.name) { 4985 + const input = document.createElement("input"); 4986 + input.type = "hidden"; 4987 + const formId = submitter.getAttribute("form"); 4988 + if (formId) { 4989 + input.setAttribute("form", formId); 4990 + } 4991 + input.name = submitter.name; 4992 + input.value = submitter.value; 4993 + submitter.parentElement.insertBefore(input, submitter); 4994 + injectedElement = input; 4995 + } 4996 + const formData = new FormData(form); 4997 + const toRemove = []; 4998 + formData.forEach((val, key, _index) => { 4999 + if (val instanceof File) { 5000 + toRemove.push(key); 5001 + } 5002 + }); 5003 + toRemove.forEach((key) => formData.delete(key)); 5004 + const params = new URLSearchParams(); 5005 + const { inputsUnused, onlyHiddenInputs } = Array.from(form.elements).reduce((acc, input) => { 5006 + const { inputsUnused: inputsUnused2, onlyHiddenInputs: onlyHiddenInputs2 } = acc; 5007 + const key = input.name; 5008 + if (!key) { 5009 + return acc; 5010 + } 5011 + if (inputsUnused2[key] === void 0) { 5012 + inputsUnused2[key] = true; 5013 + } 5014 + if (onlyHiddenInputs2[key] === void 0) { 5015 + onlyHiddenInputs2[key] = true; 5016 + } 5017 + const isUsed = dom_default.private(input, PHX_HAS_FOCUSED) || dom_default.private(input, PHX_HAS_SUBMITTED); 5018 + const isHidden = input.type === "hidden"; 5019 + inputsUnused2[key] = inputsUnused2[key] && !isUsed; 5020 + onlyHiddenInputs2[key] = onlyHiddenInputs2[key] && isHidden; 5021 + return acc; 5022 + }, { inputsUnused: {}, onlyHiddenInputs: {} }); 5023 + for (let [key, val] of formData.entries()) { 5024 + if (onlyNames.length === 0 || onlyNames.indexOf(key) >= 0) { 5025 + let isUnused = inputsUnused[key]; 5026 + let hidden = onlyHiddenInputs[key]; 5027 + if (isUnused && !(submitter && submitter.name == key) && !hidden) { 5028 + params.append(prependFormDataKey(key, "_unused_"), ""); 5029 + } 5030 + params.append(key, val); 5031 + } 5032 + } 5033 + if (submitter && injectedElement) { 5034 + submitter.parentElement.removeChild(injectedElement); 5035 + } 5036 + return params.toString(); 5037 + }; 5038 + var View = class _View { 5039 + static closestView(el) { 5040 + let liveViewEl = el.closest(PHX_VIEW_SELECTOR); 5041 + return liveViewEl ? dom_default.private(liveViewEl, "view") : null; 5042 + } 5043 + constructor(el, liveSocket2, parentView, flash, liveReferer) { 5044 + this.isDead = false; 5045 + this.liveSocket = liveSocket2; 5046 + this.flash = flash; 5047 + this.parent = parentView; 5048 + this.root = parentView ? parentView.root : this; 5049 + this.el = el; 5050 + dom_default.putPrivate(this.el, "view", this); 5051 + this.id = this.el.id; 5052 + this.ref = 0; 5053 + this.lastAckRef = null; 5054 + this.childJoins = 0; 5055 + this.loaderTimer = null; 5056 + this.disconnectedTimer = null; 5057 + this.pendingDiffs = []; 5058 + this.pendingForms = /* @__PURE__ */ new Set(); 5059 + this.redirect = false; 5060 + this.href = null; 5061 + this.joinCount = this.parent ? this.parent.joinCount - 1 : 0; 5062 + this.joinAttempts = 0; 5063 + this.joinPending = true; 5064 + this.destroyed = false; 5065 + this.joinCallback = function(onDone) { 5066 + onDone && onDone(); 5067 + }; 5068 + this.stopCallback = function() { 5069 + }; 5070 + this.pendingJoinOps = this.parent ? null : []; 5071 + this.viewHooks = {}; 5072 + this.formSubmits = []; 5073 + this.children = this.parent ? null : {}; 5074 + this.root.children[this.id] = {}; 5075 + this.formsForRecovery = {}; 5076 + this.channel = this.liveSocket.channel(`lv:${this.id}`, () => { 5077 + let url = this.href && this.expandURL(this.href); 5078 + return { 5079 + redirect: this.redirect ? url : void 0, 5080 + url: this.redirect ? void 0 : url || void 0, 5081 + params: this.connectParams(liveReferer), 5082 + session: this.getSession(), 5083 + static: this.getStatic(), 5084 + flash: this.flash, 5085 + sticky: this.el.hasAttribute(PHX_STICKY) 5086 + }; 5087 + }); 5088 + } 5089 + setHref(href) { 5090 + this.href = href; 5091 + } 5092 + setRedirect(href) { 5093 + this.redirect = true; 5094 + this.href = href; 5095 + } 5096 + isMain() { 5097 + return this.el.hasAttribute(PHX_MAIN); 5098 + } 5099 + connectParams(liveReferer) { 5100 + let params = this.liveSocket.params(this.el); 5101 + let manifest = dom_default.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`).map((node) => node.src || node.href).filter((url) => typeof url === "string"); 5102 + if (manifest.length > 0) { 5103 + params["_track_static"] = manifest; 5104 + } 5105 + params["_mounts"] = this.joinCount; 5106 + params["_mount_attempts"] = this.joinAttempts; 5107 + params["_live_referer"] = liveReferer; 5108 + this.joinAttempts++; 5109 + return params; 5110 + } 5111 + isConnected() { 5112 + return this.channel.canPush(); 5113 + } 5114 + getSession() { 5115 + return this.el.getAttribute(PHX_SESSION); 5116 + } 5117 + getStatic() { 5118 + let val = this.el.getAttribute(PHX_STATIC); 5119 + return val === "" ? null : val; 5120 + } 5121 + destroy(callback = function() { 5122 + }) { 5123 + this.destroyAllChildren(); 5124 + this.destroyed = true; 5125 + delete this.root.children[this.id]; 5126 + if (this.parent) { 5127 + delete this.root.children[this.parent.id][this.id]; 5128 + } 5129 + clearTimeout(this.loaderTimer); 5130 + let onFinished = () => { 5131 + callback(); 5132 + for (let id in this.viewHooks) { 5133 + this.destroyHook(this.viewHooks[id]); 5134 + } 5135 + }; 5136 + dom_default.markPhxChildDestroyed(this.el); 5137 + this.log("destroyed", () => ["the child has been removed from the parent"]); 5138 + this.channel.leave().receive("ok", onFinished).receive("error", onFinished).receive("timeout", onFinished); 5139 + } 5140 + setContainerClasses(...classes) { 5141 + this.el.classList.remove( 5142 + PHX_CONNECTED_CLASS, 5143 + PHX_LOADING_CLASS, 5144 + PHX_ERROR_CLASS, 5145 + PHX_CLIENT_ERROR_CLASS, 5146 + PHX_SERVER_ERROR_CLASS 5147 + ); 5148 + this.el.classList.add(...classes); 5149 + } 5150 + showLoader(timeout) { 5151 + clearTimeout(this.loaderTimer); 5152 + if (timeout) { 5153 + this.loaderTimer = setTimeout(() => this.showLoader(), timeout); 5154 + } else { 5155 + for (let id in this.viewHooks) { 5156 + this.viewHooks[id].__disconnected(); 5157 + } 5158 + this.setContainerClasses(PHX_LOADING_CLASS); 5159 + } 5160 + } 5161 + execAll(binding) { 5162 + dom_default.all(this.el, `[${binding}]`, (el) => this.liveSocket.execJS(el, el.getAttribute(binding))); 5163 + } 5164 + hideLoader() { 5165 + clearTimeout(this.loaderTimer); 5166 + clearTimeout(this.disconnectedTimer); 5167 + this.setContainerClasses(PHX_CONNECTED_CLASS); 5168 + this.execAll(this.binding("connected")); 5169 + } 5170 + triggerReconnected() { 5171 + for (let id in this.viewHooks) { 5172 + this.viewHooks[id].__reconnected(); 5173 + } 5174 + } 5175 + log(kind, msgCallback) { 5176 + this.liveSocket.log(this, kind, msgCallback); 5177 + } 5178 + transition(time, onStart, onDone = function() { 5179 + }) { 5180 + this.liveSocket.transition(time, onStart, onDone); 5181 + } 5182 + // calls the callback with the view and target element for the given phxTarget 5183 + // targets can be: 5184 + // * an element itself, then it is simply passed to liveSocket.owner; 5185 + // * a CID (Component ID), then we first search the component's element in the DOM 5186 + // * a selector, then we search the selector in the DOM and call the callback 5187 + // for each element found with the corresponding owner view 5188 + withinTargets(phxTarget, callback, dom = document, viewEl) { 5189 + if (phxTarget instanceof HTMLElement || phxTarget instanceof SVGElement) { 5190 + return this.liveSocket.owner(phxTarget, (view) => callback(view, phxTarget)); 5191 + } 5192 + if (isCid(phxTarget)) { 5193 + let targets = dom_default.findComponentNodeList(viewEl || this.el, phxTarget); 5194 + if (targets.length === 0) { 5195 + logError(`no component found matching phx-target of ${phxTarget}`); 5196 + } else { 5197 + callback(this, parseInt(phxTarget)); 5198 + } 5199 + } else { 5200 + let targets = Array.from(dom.querySelectorAll(phxTarget)); 5201 + if (targets.length === 0) { 5202 + logError(`nothing found matching the phx-target selector "${phxTarget}"`); 5203 + } 5204 + targets.forEach((target) => this.liveSocket.owner(target, (view) => callback(view, target))); 5205 + } 5206 + } 5207 + applyDiff(type, rawDiff, callback) { 5208 + this.log(type, () => ["", clone(rawDiff)]); 5209 + let { diff, reply, events, title } = Rendered.extract(rawDiff); 5210 + callback({ diff, reply, events }); 5211 + if (typeof title === "string" || type == "mount") { 5212 + window.requestAnimationFrame(() => dom_default.putTitle(title)); 5213 + } 5214 + } 5215 + onJoin(resp) { 5216 + let { rendered, container, liveview_version } = resp; 5217 + if (container) { 5218 + let [tag, attrs] = container; 5219 + this.el = dom_default.replaceRootContainer(this.el, tag, attrs); 5220 + } 5221 + this.childJoins = 0; 5222 + this.joinPending = true; 5223 + this.flash = null; 5224 + if (this.root === this) { 5225 + this.formsForRecovery = this.getFormsForRecovery(); 5226 + } 5227 + if (this.isMain() && window.history.state === null) { 5228 + browser_default.pushState("replace", { 5229 + type: "patch", 5230 + id: this.id, 5231 + position: this.liveSocket.currentHistoryPosition 5232 + }); 5233 + } 5234 + if (liveview_version !== this.liveSocket.version()) { 5235 + console.error(`LiveView asset version mismatch. JavaScript version ${this.liveSocket.version()} vs. server ${liveview_version}. To avoid issues, please ensure that your assets use the same version as the server.`); 5236 + } 5237 + browser_default.dropLocal(this.liveSocket.localStorage, window.location.pathname, CONSECUTIVE_RELOADS); 5238 + this.applyDiff("mount", rendered, ({ diff, events }) => { 5239 + this.rendered = new Rendered(this.id, diff); 5240 + let [html, streams] = this.renderContainer(null, "join"); 5241 + this.dropPendingRefs(); 5242 + this.joinCount++; 5243 + this.joinAttempts = 0; 5244 + this.maybeRecoverForms(html, () => { 5245 + this.onJoinComplete(resp, html, streams, events); 5246 + }); 5247 + }); 5248 + } 5249 + dropPendingRefs() { 5250 + dom_default.all(document, `[${PHX_REF_SRC}="${this.refSrc()}"]`, (el) => { 5251 + el.removeAttribute(PHX_REF_LOADING); 5252 + el.removeAttribute(PHX_REF_SRC); 5253 + el.removeAttribute(PHX_REF_LOCK); 5254 + }); 5255 + } 5256 + onJoinComplete({ live_patch }, html, streams, events) { 5257 + if (this.joinCount > 1 || this.parent && !this.parent.isJoinPending()) { 5258 + return this.applyJoinPatch(live_patch, html, streams, events); 5259 + } 5260 + let newChildren = dom_default.findPhxChildrenInFragment(html, this.id).filter((toEl) => { 5261 + let fromEl = toEl.id && this.el.querySelector(`[id="${toEl.id}"]`); 5262 + let phxStatic = fromEl && fromEl.getAttribute(PHX_STATIC); 5263 + if (phxStatic) { 5264 + toEl.setAttribute(PHX_STATIC, phxStatic); 5265 + } 5266 + if (fromEl) { 5267 + fromEl.setAttribute(PHX_ROOT_ID, this.root.id); 5268 + } 5269 + return this.joinChild(toEl); 5270 + }); 5271 + if (newChildren.length === 0) { 5272 + if (this.parent) { 5273 + this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, streams, events)]); 5274 + this.parent.ackJoin(this); 5275 + } else { 5276 + this.onAllChildJoinsComplete(); 5277 + this.applyJoinPatch(live_patch, html, streams, events); 5278 + } 5279 + } else { 5280 + this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, streams, events)]); 5281 + } 5282 + } 5283 + attachTrueDocEl() { 5284 + this.el = dom_default.byId(this.id); 5285 + this.el.setAttribute(PHX_ROOT_ID, this.root.id); 5286 + } 5287 + // this is invoked for dead and live views, so we must filter by 5288 + // by owner to ensure we aren't duplicating hooks across disconnect 5289 + // and connected states. This also handles cases where hooks exist 5290 + // in a root layout with a LV in the body 5291 + execNewMounted(parent = this.el) { 5292 + let phxViewportTop = this.binding(PHX_VIEWPORT_TOP); 5293 + let phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM); 5294 + dom_default.all(parent, `[${phxViewportTop}], [${phxViewportBottom}]`, (hookEl) => { 5295 + if (this.ownsElement(hookEl)) { 5296 + dom_default.maintainPrivateHooks(hookEl, hookEl, phxViewportTop, phxViewportBottom); 5297 + this.maybeAddNewHook(hookEl); 5298 + } 5299 + }); 5300 + dom_default.all(parent, `[${this.binding(PHX_HOOK)}], [data-phx-${PHX_HOOK}]`, (hookEl) => { 5301 + if (this.ownsElement(hookEl)) { 5302 + this.maybeAddNewHook(hookEl); 5303 + } 5304 + }); 5305 + dom_default.all(parent, `[${this.binding(PHX_MOUNTED)}]`, (el) => { 5306 + if (this.ownsElement(el)) { 5307 + this.maybeMounted(el); 5308 + } 5309 + }); 5310 + } 5311 + applyJoinPatch(live_patch, html, streams, events) { 5312 + this.attachTrueDocEl(); 5313 + let patch = new DOMPatch(this, this.el, this.id, html, streams, null); 5314 + patch.markPrunableContentForRemoval(); 5315 + this.performPatch(patch, false, true); 5316 + this.joinNewChildren(); 5317 + this.execNewMounted(); 5318 + this.joinPending = false; 5319 + this.liveSocket.dispatchEvents(events); 5320 + this.applyPendingUpdates(); 5321 + if (live_patch) { 5322 + let { kind, to } = live_patch; 5323 + this.liveSocket.historyPatch(to, kind); 5324 + } 5325 + this.hideLoader(); 5326 + if (this.joinCount > 1) { 5327 + this.triggerReconnected(); 5328 + } 5329 + this.stopCallback(); 5330 + } 5331 + triggerBeforeUpdateHook(fromEl, toEl) { 5332 + this.liveSocket.triggerDOM("onBeforeElUpdated", [fromEl, toEl]); 5333 + let hook = this.getHook(fromEl); 5334 + let isIgnored = hook && dom_default.isIgnored(fromEl, this.binding(PHX_UPDATE)); 5335 + if (hook && !fromEl.isEqualNode(toEl) && !(isIgnored && isEqualObj(fromEl.dataset, toEl.dataset))) { 5336 + hook.__beforeUpdate(); 5337 + return hook; 5338 + } 5339 + } 5340 + maybeMounted(el) { 5341 + let phxMounted = el.getAttribute(this.binding(PHX_MOUNTED)); 5342 + let hasBeenInvoked = phxMounted && dom_default.private(el, "mounted"); 5343 + if (phxMounted && !hasBeenInvoked) { 5344 + this.liveSocket.execJS(el, phxMounted); 5345 + dom_default.putPrivate(el, "mounted", true); 5346 + } 5347 + } 5348 + maybeAddNewHook(el) { 5349 + let newHook = this.addHook(el); 5350 + if (newHook) { 5351 + newHook.__mounted(); 5352 + } 5353 + } 5354 + performPatch(patch, pruneCids, isJoinPatch = false) { 5355 + let removedEls = []; 5356 + let phxChildrenAdded = false; 5357 + let updatedHookIds = /* @__PURE__ */ new Set(); 5358 + this.liveSocket.triggerDOM("onPatchStart", [patch.targetContainer]); 5359 + patch.after("added", (el) => { 5360 + this.liveSocket.triggerDOM("onNodeAdded", [el]); 5361 + let phxViewportTop = this.binding(PHX_VIEWPORT_TOP); 5362 + let phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM); 5363 + dom_default.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom); 5364 + this.maybeAddNewHook(el); 5365 + if (el.getAttribute) { 5366 + this.maybeMounted(el); 5367 + } 5368 + }); 5369 + patch.after("phxChildAdded", (el) => { 5370 + if (dom_default.isPhxSticky(el)) { 5371 + this.liveSocket.joinRootViews(); 5372 + } else { 5373 + phxChildrenAdded = true; 5374 + } 5375 + }); 5376 + patch.before("updated", (fromEl, toEl) => { 5377 + let hook = this.triggerBeforeUpdateHook(fromEl, toEl); 5378 + if (hook) { 5379 + updatedHookIds.add(fromEl.id); 5380 + } 5381 + }); 5382 + patch.after("updated", (el) => { 5383 + if (updatedHookIds.has(el.id)) { 5384 + this.getHook(el).__updated(); 5385 + } 5386 + }); 5387 + patch.after("discarded", (el) => { 5388 + if (el.nodeType === Node.ELEMENT_NODE) { 5389 + removedEls.push(el); 5390 + } 5391 + }); 5392 + patch.after("transitionsDiscarded", (els) => this.afterElementsRemoved(els, pruneCids)); 5393 + patch.perform(isJoinPatch); 5394 + this.afterElementsRemoved(removedEls, pruneCids); 5395 + this.liveSocket.triggerDOM("onPatchEnd", [patch.targetContainer]); 5396 + return phxChildrenAdded; 5397 + } 5398 + afterElementsRemoved(elements, pruneCids) { 5399 + let destroyedCIDs = []; 5400 + elements.forEach((parent) => { 5401 + let components = dom_default.all(parent, `[${PHX_COMPONENT}]`); 5402 + let hooks = dom_default.all(parent, `[${this.binding(PHX_HOOK)}], [data-phx-hook]`); 5403 + components.concat(parent).forEach((el) => { 5404 + let cid = this.componentID(el); 5405 + if (isCid(cid) && destroyedCIDs.indexOf(cid) === -1) { 5406 + destroyedCIDs.push(cid); 5407 + } 5408 + }); 5409 + hooks.concat(parent).forEach((hookEl) => { 5410 + let hook = this.getHook(hookEl); 5411 + hook && this.destroyHook(hook); 5412 + }); 5413 + }); 5414 + if (pruneCids) { 5415 + this.maybePushComponentsDestroyed(destroyedCIDs); 5416 + } 5417 + } 5418 + joinNewChildren() { 5419 + dom_default.findPhxChildren(this.el, this.id).forEach((el) => this.joinChild(el)); 5420 + } 5421 + maybeRecoverForms(html, callback) { 5422 + const phxChange = this.binding("change"); 5423 + const oldForms = this.root.formsForRecovery; 5424 + let template = document.createElement("template"); 5425 + template.innerHTML = html; 5426 + const rootEl = template.content.firstElementChild; 5427 + rootEl.id = this.id; 5428 + rootEl.setAttribute(PHX_ROOT_ID, this.root.id); 5429 + rootEl.setAttribute(PHX_SESSION, this.getSession()); 5430 + rootEl.setAttribute(PHX_STATIC, this.getStatic()); 5431 + rootEl.setAttribute(PHX_PARENT_ID, this.parent ? this.parent.id : null); 5432 + const formsToRecover = ( 5433 + // we go over all forms in the new DOM; because this is only the HTML for the current 5434 + // view, we can be sure that all forms are owned by this view: 5435 + dom_default.all(template.content, "form").filter((newForm) => newForm.id && oldForms[newForm.id]).filter((newForm) => !this.pendingForms.has(newForm.id)).filter((newForm) => oldForms[newForm.id].getAttribute(phxChange) === newForm.getAttribute(phxChange)).map((newForm) => { 5436 + return [oldForms[newForm.id], newForm]; 5437 + }) 5438 + ); 5439 + if (formsToRecover.length === 0) { 5440 + return callback(); 5441 + } 5442 + formsToRecover.forEach(([oldForm, newForm], i) => { 5443 + this.pendingForms.add(newForm.id); 5444 + this.pushFormRecovery(oldForm, newForm, template.content.firstElementChild, () => { 5445 + this.pendingForms.delete(newForm.id); 5446 + if (i === formsToRecover.length - 1) { 5447 + callback(); 5448 + } 5449 + }); 5450 + }); 5451 + } 5452 + getChildById(id) { 5453 + return this.root.children[this.id][id]; 5454 + } 5455 + getDescendentByEl(el) { 5456 + var _a; 5457 + if (el.id === this.id) { 5458 + return this; 5459 + } else { 5460 + return (_a = this.children[el.getAttribute(PHX_PARENT_ID)]) == null ? void 0 : _a[el.id]; 5461 + } 5462 + } 5463 + destroyDescendent(id) { 5464 + for (let parentId in this.root.children) { 5465 + for (let childId in this.root.children[parentId]) { 5466 + if (childId === id) { 5467 + return this.root.children[parentId][childId].destroy(); 5468 + } 5469 + } 5470 + } 5471 + } 5472 + joinChild(el) { 5473 + let child = this.getChildById(el.id); 5474 + if (!child) { 5475 + let view = new _View(el, this.liveSocket, this); 5476 + this.root.children[this.id][view.id] = view; 5477 + view.join(); 5478 + this.childJoins++; 5479 + return true; 5480 + } 5481 + } 5482 + isJoinPending() { 5483 + return this.joinPending; 5484 + } 5485 + ackJoin(_child) { 5486 + this.childJoins--; 5487 + if (this.childJoins === 0) { 5488 + if (this.parent) { 5489 + this.parent.ackJoin(this); 5490 + } else { 5491 + this.onAllChildJoinsComplete(); 5492 + } 5493 + } 5494 + } 5495 + onAllChildJoinsComplete() { 5496 + this.pendingForms.clear(); 5497 + this.formsForRecovery = {}; 5498 + this.joinCallback(() => { 5499 + this.pendingJoinOps.forEach(([view, op]) => { 5500 + if (!view.isDestroyed()) { 5501 + op(); 5502 + } 5503 + }); 5504 + this.pendingJoinOps = []; 5505 + }); 5506 + } 5507 + update(diff, events) { 5508 + if (this.isJoinPending() || this.liveSocket.hasPendingLink() && this.root.isMain()) { 5509 + return this.pendingDiffs.push({ diff, events }); 5510 + } 5511 + this.rendered.mergeDiff(diff); 5512 + let phxChildrenAdded = false; 5513 + if (this.rendered.isComponentOnlyDiff(diff)) { 5514 + this.liveSocket.time("component patch complete", () => { 5515 + let parentCids = dom_default.findExistingParentCIDs(this.el, this.rendered.componentCIDs(diff)); 5516 + parentCids.forEach((parentCID) => { 5517 + if (this.componentPatch(this.rendered.getComponent(diff, parentCID), parentCID)) { 5518 + phxChildrenAdded = true; 5519 + } 5520 + }); 5521 + }); 5522 + } else if (!isEmpty(diff)) { 5523 + this.liveSocket.time("full patch complete", () => { 5524 + let [html, streams] = this.renderContainer(diff, "update"); 5525 + let patch = new DOMPatch(this, this.el, this.id, html, streams, null); 5526 + phxChildrenAdded = this.performPatch(patch, true); 5527 + }); 5528 + } 5529 + this.liveSocket.dispatchEvents(events); 5530 + if (phxChildrenAdded) { 5531 + this.joinNewChildren(); 5532 + } 5533 + } 5534 + renderContainer(diff, kind) { 5535 + return this.liveSocket.time(`toString diff (${kind})`, () => { 5536 + let tag = this.el.tagName; 5537 + let cids = diff ? this.rendered.componentCIDs(diff) : null; 5538 + let [html, streams] = this.rendered.toString(cids); 5539 + return [`<${tag}>${html}</${tag}>`, streams]; 5540 + }); 5541 + } 5542 + componentPatch(diff, cid) { 5543 + if (isEmpty(diff)) 5544 + return false; 5545 + let [html, streams] = this.rendered.componentToString(cid); 5546 + let patch = new DOMPatch(this, this.el, this.id, html, streams, cid); 5547 + let childrenAdded = this.performPatch(patch, true); 5548 + return childrenAdded; 5549 + } 5550 + getHook(el) { 5551 + return this.viewHooks[ViewHook.elementID(el)]; 5552 + } 5553 + addHook(el) { 5554 + let hookElId = ViewHook.elementID(el); 5555 + if (el.getAttribute && !this.ownsElement(el)) { 5556 + return; 5557 + } 5558 + if (hookElId && !this.viewHooks[hookElId]) { 5559 + let hook = dom_default.getCustomElHook(el) || logError(`no hook found for custom element: ${el.id}`); 5560 + this.viewHooks[hookElId] = hook; 5561 + hook.__attachView(this); 5562 + return hook; 5563 + } else if (hookElId || !el.getAttribute) { 5564 + return; 5565 + } else { 5566 + let hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK)); 5567 + let callbacks = this.liveSocket.getHookCallbacks(hookName); 5568 + if (callbacks) { 5569 + if (!el.id) { 5570 + logError(`no DOM ID for hook "${hookName}". Hooks require a unique ID on each element.`, el); 5571 + } 5572 + let hook = new ViewHook(this, el, callbacks); 5573 + this.viewHooks[ViewHook.elementID(hook.el)] = hook; 5574 + return hook; 5575 + } else if (hookName !== null) { 5576 + logError(`unknown hook found for "${hookName}"`, el); 5577 + } 5578 + } 5579 + } 5580 + destroyHook(hook) { 5581 + const hookId = ViewHook.elementID(hook.el); 5582 + hook.__destroyed(); 5583 + hook.__cleanup__(); 5584 + delete this.viewHooks[hookId]; 5585 + } 5586 + applyPendingUpdates() { 5587 + if (this.liveSocket.hasPendingLink() && this.root.isMain()) { 5588 + return; 5589 + } 5590 + this.pendingDiffs.forEach(({ diff, events }) => this.update(diff, events)); 5591 + this.pendingDiffs = []; 5592 + this.eachChild((child) => child.applyPendingUpdates()); 5593 + } 5594 + eachChild(callback) { 5595 + let children = this.root.children[this.id] || {}; 5596 + for (let id in children) { 5597 + callback(this.getChildById(id)); 5598 + } 5599 + } 5600 + onChannel(event, cb) { 5601 + this.liveSocket.onChannel(this.channel, event, (resp) => { 5602 + if (this.isJoinPending()) { 5603 + this.root.pendingJoinOps.push([this, () => cb(resp)]); 5604 + } else { 5605 + this.liveSocket.requestDOMUpdate(() => cb(resp)); 5606 + } 5607 + }); 5608 + } 5609 + bindChannel() { 5610 + this.liveSocket.onChannel(this.channel, "diff", (rawDiff) => { 5611 + this.liveSocket.requestDOMUpdate(() => { 5612 + this.applyDiff("update", rawDiff, ({ diff, events }) => this.update(diff, events)); 5613 + }); 5614 + }); 5615 + this.onChannel("redirect", ({ to, flash }) => this.onRedirect({ to, flash })); 5616 + this.onChannel("live_patch", (redir) => this.onLivePatch(redir)); 5617 + this.onChannel("live_redirect", (redir) => this.onLiveRedirect(redir)); 5618 + this.channel.onError((reason) => this.onError(reason)); 5619 + this.channel.onClose((reason) => this.onClose(reason)); 5620 + } 5621 + destroyAllChildren() { 5622 + this.eachChild((child) => child.destroy()); 5623 + } 5624 + onLiveRedirect(redir) { 5625 + let { to, kind, flash } = redir; 5626 + let url = this.expandURL(to); 5627 + let e = new CustomEvent("phx:server-navigate", { detail: { to, kind, flash } }); 5628 + this.liveSocket.historyRedirect(e, url, kind, flash); 5629 + } 5630 + onLivePatch(redir) { 5631 + let { to, kind } = redir; 5632 + this.href = this.expandURL(to); 5633 + this.liveSocket.historyPatch(to, kind); 5634 + } 5635 + expandURL(to) { 5636 + return to.startsWith("/") ? `${window.location.protocol}//${window.location.host}${to}` : to; 5637 + } 5638 + onRedirect({ to, flash, reloadToken }) { 5639 + this.liveSocket.redirect(to, flash, reloadToken); 5640 + } 5641 + isDestroyed() { 5642 + return this.destroyed; 5643 + } 5644 + joinDead() { 5645 + this.isDead = true; 5646 + } 5647 + joinPush() { 5648 + this.joinPush = this.joinPush || this.channel.join(); 5649 + return this.joinPush; 5650 + } 5651 + join(callback) { 5652 + this.showLoader(this.liveSocket.loaderTimeout); 5653 + this.bindChannel(); 5654 + if (this.isMain()) { 5655 + this.stopCallback = this.liveSocket.withPageLoading({ to: this.href, kind: "initial" }); 5656 + } 5657 + this.joinCallback = (onDone) => { 5658 + onDone = onDone || function() { 5659 + }; 5660 + callback ? callback(this.joinCount, onDone) : onDone(); 5661 + }; 5662 + this.wrapPush(() => this.channel.join(), { 5663 + ok: (resp) => this.liveSocket.requestDOMUpdate(() => this.onJoin(resp)), 5664 + error: (error) => this.onJoinError(error), 5665 + timeout: () => this.onJoinError({ reason: "timeout" }) 5666 + }); 5667 + } 5668 + onJoinError(resp) { 5669 + if (resp.reason === "reload") { 5670 + this.log("error", () => [`failed mount with ${resp.status}. Falling back to page reload`, resp]); 5671 + this.onRedirect({ to: this.root.href, reloadToken: resp.token }); 5672 + return; 5673 + } else if (resp.reason === "unauthorized" || resp.reason === "stale") { 5674 + this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp]); 5675 + this.onRedirect({ to: this.root.href, flash: this.flash }); 5676 + return; 5677 + } 5678 + if (resp.redirect || resp.live_redirect) { 5679 + this.joinPending = false; 5680 + this.channel.leave(); 5681 + } 5682 + if (resp.redirect) { 5683 + return this.onRedirect(resp.redirect); 5684 + } 5685 + if (resp.live_redirect) { 5686 + return this.onLiveRedirect(resp.live_redirect); 5687 + } 5688 + this.log("error", () => ["unable to join", resp]); 5689 + if (this.isMain()) { 5690 + this.displayError([PHX_LOADING_CLASS, PHX_ERROR_CLASS, PHX_SERVER_ERROR_CLASS]); 5691 + if (this.liveSocket.isConnected()) { 5692 + this.liveSocket.reloadWithJitter(this); 5693 + } 5694 + } else { 5695 + if (this.joinAttempts >= MAX_CHILD_JOIN_ATTEMPTS) { 5696 + this.root.displayError([PHX_LOADING_CLASS, PHX_ERROR_CLASS, PHX_SERVER_ERROR_CLASS]); 5697 + this.log("error", () => [`giving up trying to mount after ${MAX_CHILD_JOIN_ATTEMPTS} tries`, resp]); 5698 + this.destroy(); 5699 + } 5700 + let trueChildEl = dom_default.byId(this.el.id); 5701 + if (trueChildEl) { 5702 + dom_default.mergeAttrs(trueChildEl, this.el); 5703 + this.displayError([PHX_LOADING_CLASS, PHX_ERROR_CLASS, PHX_SERVER_ERROR_CLASS]); 5704 + this.el = trueChildEl; 5705 + } else { 5706 + this.destroy(); 5707 + } 5708 + } 5709 + } 5710 + onClose(reason) { 5711 + if (this.isDestroyed()) { 5712 + return; 5713 + } 5714 + if (this.isMain() && this.liveSocket.hasPendingLink() && reason !== "leave") { 5715 + return this.liveSocket.reloadWithJitter(this); 5716 + } 5717 + this.destroyAllChildren(); 5718 + this.liveSocket.dropActiveElement(this); 5719 + if (document.activeElement) { 5720 + document.activeElement.blur(); 5721 + } 5722 + if (this.liveSocket.isUnloaded()) { 5723 + this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT); 5724 + } 5725 + } 5726 + onError(reason) { 5727 + this.onClose(reason); 5728 + if (this.liveSocket.isConnected()) { 5729 + this.log("error", () => ["view crashed", reason]); 5730 + } 5731 + if (!this.liveSocket.isUnloaded()) { 5732 + if (this.liveSocket.isConnected()) { 5733 + this.displayError([PHX_LOADING_CLASS, PHX_ERROR_CLASS, PHX_SERVER_ERROR_CLASS]); 5734 + } else { 5735 + this.displayError([PHX_LOADING_CLASS, PHX_ERROR_CLASS, PHX_CLIENT_ERROR_CLASS]); 5736 + } 5737 + } 5738 + } 5739 + displayError(classes) { 5740 + if (this.isMain()) { 5741 + dom_default.dispatchEvent(window, "phx:page-loading-start", { detail: { to: this.href, kind: "error" } }); 5742 + } 5743 + this.showLoader(); 5744 + this.setContainerClasses(...classes); 5745 + this.delayedDisconnected(); 5746 + } 5747 + delayedDisconnected() { 5748 + this.disconnectedTimer = setTimeout(() => { 5749 + this.execAll(this.binding("disconnected")); 5750 + }, this.liveSocket.disconnectedTimeout); 5751 + } 5752 + wrapPush(callerPush, receives) { 5753 + let latency = this.liveSocket.getLatencySim(); 5754 + let withLatency = latency ? (cb) => setTimeout(() => !this.isDestroyed() && cb(), latency) : (cb) => !this.isDestroyed() && cb(); 5755 + withLatency(() => { 5756 + callerPush().receive("ok", (resp) => withLatency(() => receives.ok && receives.ok(resp))).receive("error", (reason) => withLatency(() => receives.error && receives.error(reason))).receive("timeout", () => withLatency(() => receives.timeout && receives.timeout())); 5757 + }); 5758 + } 5759 + pushWithReply(refGenerator, event, payload) { 5760 + if (!this.isConnected()) { 5761 + return Promise.reject({ error: "noconnection" }); 5762 + } 5763 + let [ref, [el], opts] = refGenerator ? refGenerator() : [null, [], {}]; 5764 + let oldJoinCount = this.joinCount; 5765 + let onLoadingDone = function() { 5766 + }; 5767 + if (opts.page_loading) { 5768 + onLoadingDone = this.liveSocket.withPageLoading({ kind: "element", target: el }); 5769 + } 5770 + if (typeof payload.cid !== "number") { 5771 + delete payload.cid; 5772 + } 5773 + return new Promise((resolve, reject) => { 5774 + this.wrapPush(() => this.channel.push(event, payload, PUSH_TIMEOUT), { 5775 + ok: (resp) => { 5776 + if (ref !== null) { 5777 + this.lastAckRef = ref; 5778 + } 5779 + let finish = (hookReply) => { 5780 + if (resp.redirect) { 5781 + this.onRedirect(resp.redirect); 5782 + } 5783 + if (resp.live_patch) { 5784 + this.onLivePatch(resp.live_patch); 5785 + } 5786 + if (resp.live_redirect) { 5787 + this.onLiveRedirect(resp.live_redirect); 5788 + } 5789 + onLoadingDone(); 5790 + resolve({ resp, reply: hookReply }); 5791 + }; 5792 + if (resp.diff) { 5793 + this.liveSocket.requestDOMUpdate(() => { 5794 + this.applyDiff("update", resp.diff, ({ diff, reply, events }) => { 5795 + if (ref !== null) { 5796 + this.undoRefs(ref, payload.event); 5797 + } 5798 + this.update(diff, events); 5799 + finish(reply); 5800 + }); 5801 + }); 5802 + } else { 5803 + if (ref !== null) { 5804 + this.undoRefs(ref, payload.event); 5805 + } 5806 + finish(null); 5807 + } 5808 + }, 5809 + error: (reason) => reject({ error: reason }), 5810 + timeout: () => { 5811 + reject({ timeout: true }); 5812 + if (this.joinCount === oldJoinCount) { 5813 + this.liveSocket.reloadWithJitter(this, () => { 5814 + this.log("timeout", () => ["received timeout while communicating with server. Falling back to hard refresh for recovery"]); 5815 + }); 5816 + } 5817 + } 5818 + }); 5819 + }); 5820 + } 5821 + undoRefs(ref, phxEvent, onlyEls) { 5822 + if (!this.isConnected()) { 5823 + return; 5824 + } 5825 + let selector = `[${PHX_REF_SRC}="${this.refSrc()}"]`; 5826 + if (onlyEls) { 5827 + onlyEls = new Set(onlyEls); 5828 + dom_default.all(document, selector, (parent) => { 5829 + if (onlyEls && !onlyEls.has(parent)) { 5830 + return; 5831 + } 5832 + dom_default.all(parent, selector, (child) => this.undoElRef(child, ref, phxEvent)); 5833 + this.undoElRef(parent, ref, phxEvent); 5834 + }); 5835 + } else { 5836 + dom_default.all(document, selector, (el) => this.undoElRef(el, ref, phxEvent)); 5837 + } 5838 + } 5839 + undoElRef(el, ref, phxEvent) { 5840 + let elRef = new ElementRef(el); 5841 + elRef.maybeUndo(ref, phxEvent, (clonedTree) => { 5842 + let patch = new DOMPatch(this, el, this.id, clonedTree, [], null, { undoRef: ref }); 5843 + const phxChildrenAdded = this.performPatch(patch, true); 5844 + dom_default.all(el, `[${PHX_REF_SRC}="${this.refSrc()}"]`, (child) => this.undoElRef(child, ref, phxEvent)); 5845 + if (phxChildrenAdded) { 5846 + this.joinNewChildren(); 5847 + } 5848 + }); 5849 + } 5850 + refSrc() { 5851 + return this.el.id; 5852 + } 5853 + putRef(elements, phxEvent, eventType, opts = {}) { 5854 + let newRef = this.ref++; 5855 + let disableWith = this.binding(PHX_DISABLE_WITH); 5856 + if (opts.loading) { 5857 + let loadingEls = dom_default.all(document, opts.loading).map((el) => { 5858 + return { el, lock: true, loading: true }; 5859 + }); 5860 + elements = elements.concat(loadingEls); 5861 + } 5862 + for (let { el, lock, loading } of elements) { 5863 + if (!lock && !loading) { 5864 + throw new Error("putRef requires lock or loading"); 5865 + } 5866 + el.setAttribute(PHX_REF_SRC, this.refSrc()); 5867 + if (loading) { 5868 + el.setAttribute(PHX_REF_LOADING, newRef); 5869 + } 5870 + if (lock) { 5871 + el.setAttribute(PHX_REF_LOCK, newRef); 5872 + } 5873 + if (!loading || opts.submitter && !(el === opts.submitter || el === opts.form)) { 5874 + continue; 5875 + } 5876 + let lockCompletePromise = new Promise((resolve) => { 5877 + el.addEventListener(`phx:undo-lock:${newRef}`, () => resolve(detail), { once: true }); 5878 + }); 5879 + let loadingCompletePromise = new Promise((resolve) => { 5880 + el.addEventListener(`phx:undo-loading:${newRef}`, () => resolve(detail), { once: true }); 5881 + }); 5882 + el.classList.add(`phx-${eventType}-loading`); 5883 + let disableText = el.getAttribute(disableWith); 5884 + if (disableText !== null) { 5885 + if (!el.getAttribute(PHX_DISABLE_WITH_RESTORE)) { 5886 + el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.innerText); 5887 + } 5888 + if (disableText !== "") { 5889 + el.innerText = disableText; 5890 + } 5891 + el.setAttribute(PHX_DISABLED, el.getAttribute(PHX_DISABLED) || el.disabled); 5892 + el.setAttribute("disabled", ""); 5893 + } 5894 + let detail = { 5895 + event: phxEvent, 5896 + eventType, 5897 + ref: newRef, 5898 + isLoading: loading, 5899 + isLocked: lock, 5900 + lockElements: elements.filter(({ lock: lock2 }) => lock2).map(({ el: el2 }) => el2), 5901 + loadingElements: elements.filter(({ loading: loading2 }) => loading2).map(({ el: el2 }) => el2), 5902 + unlock: (els) => { 5903 + els = Array.isArray(els) ? els : [els]; 5904 + this.undoRefs(newRef, phxEvent, els); 5905 + }, 5906 + lockComplete: lockCompletePromise, 5907 + loadingComplete: loadingCompletePromise, 5908 + lock: (lockEl) => { 5909 + return new Promise((resolve) => { 5910 + if (this.isAcked(newRef)) { 5911 + return resolve(detail); 5912 + } 5913 + lockEl.setAttribute(PHX_REF_LOCK, newRef); 5914 + lockEl.setAttribute(PHX_REF_SRC, this.refSrc()); 5915 + lockEl.addEventListener(`phx:lock-stop:${newRef}`, () => resolve(detail), { once: true }); 5916 + }); 5917 + } 5918 + }; 5919 + el.dispatchEvent(new CustomEvent("phx:push", { 5920 + detail, 5921 + bubbles: true, 5922 + cancelable: false 5923 + })); 5924 + if (phxEvent) { 5925 + el.dispatchEvent(new CustomEvent(`phx:push:${phxEvent}`, { 5926 + detail, 5927 + bubbles: true, 5928 + cancelable: false 5929 + })); 5930 + } 5931 + } 5932 + return [newRef, elements.map(({ el }) => el), opts]; 5933 + } 5934 + isAcked(ref) { 5935 + return this.lastAckRef !== null && this.lastAckRef >= ref; 5936 + } 5937 + componentID(el) { 5938 + let cid = el.getAttribute && el.getAttribute(PHX_COMPONENT); 5939 + return cid ? parseInt(cid) : null; 5940 + } 5941 + targetComponentID(target, targetCtx, opts = {}) { 5942 + if (isCid(targetCtx)) { 5943 + return targetCtx; 5944 + } 5945 + let cidOrSelector = opts.target || target.getAttribute(this.binding("target")); 5946 + if (isCid(cidOrSelector)) { 5947 + return parseInt(cidOrSelector); 5948 + } else if (targetCtx && (cidOrSelector !== null || opts.target)) { 5949 + return this.closestComponentID(targetCtx); 5950 + } else { 5951 + return null; 5952 + } 5953 + } 5954 + closestComponentID(targetCtx) { 5955 + if (isCid(targetCtx)) { 5956 + return targetCtx; 5957 + } else if (targetCtx) { 5958 + return maybe(targetCtx.closest(`[${PHX_COMPONENT}]`), (el) => this.ownsElement(el) && this.componentID(el)); 5959 + } else { 5960 + return null; 5961 + } 5962 + } 5963 + pushHookEvent(el, targetCtx, event, payload, onReply) { 5964 + if (!this.isConnected()) { 5965 + this.log("hook", () => ["unable to push hook event. LiveView not connected", event, payload]); 5966 + return false; 5967 + } 5968 + let [ref, els, opts] = this.putRef([{ el, loading: true, lock: true }], event, "hook"); 5969 + this.pushWithReply(() => [ref, els, opts], "event", { 5970 + type: "hook", 5971 + event, 5972 + value: payload, 5973 + cid: this.closestComponentID(targetCtx) 5974 + }).then(({ resp: _resp, reply: hookReply }) => onReply(hookReply, ref)); 5975 + return ref; 5976 + } 5977 + extractMeta(el, meta, value) { 5978 + let prefix = this.binding("value-"); 5979 + for (let i = 0; i < el.attributes.length; i++) { 5980 + if (!meta) { 5981 + meta = {}; 5982 + } 5983 + let name = el.attributes[i].name; 5984 + if (name.startsWith(prefix)) { 5985 + meta[name.replace(prefix, "")] = el.getAttribute(name); 5986 + } 5987 + } 5988 + if (el.value !== void 0 && !(el instanceof HTMLFormElement)) { 5989 + if (!meta) { 5990 + meta = {}; 5991 + } 5992 + meta.value = el.value; 5993 + if (el.tagName === "INPUT" && CHECKABLE_INPUTS.indexOf(el.type) >= 0 && !el.checked) { 5994 + delete meta.value; 5995 + } 5996 + } 5997 + if (value) { 5998 + if (!meta) { 5999 + meta = {}; 6000 + } 6001 + for (let key in value) { 6002 + meta[key] = value[key]; 6003 + } 6004 + } 6005 + return meta; 6006 + } 6007 + pushEvent(type, el, targetCtx, phxEvent, meta, opts = {}, onReply) { 6008 + this.pushWithReply(() => this.putRef([{ el, loading: true, lock: true }], phxEvent, type, opts), "event", { 6009 + type, 6010 + event: phxEvent, 6011 + value: this.extractMeta(el, meta, opts.value), 6012 + cid: this.targetComponentID(el, targetCtx, opts) 6013 + }).then(({ reply }) => onReply && onReply(reply)).catch((error) => logError("Failed to push event", error)); 6014 + } 6015 + pushFileProgress(fileEl, entryRef, progress, onReply = function() { 6016 + }) { 6017 + this.liveSocket.withinOwners(fileEl.form, (view, targetCtx) => { 6018 + view.pushWithReply(null, "progress", { 6019 + event: fileEl.getAttribute(view.binding(PHX_PROGRESS)), 6020 + ref: fileEl.getAttribute(PHX_UPLOAD_REF), 6021 + entry_ref: entryRef, 6022 + progress, 6023 + cid: view.targetComponentID(fileEl.form, targetCtx) 6024 + }).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push file progress", error)); 6025 + }); 6026 + } 6027 + pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback) { 6028 + if (!inputEl.form) { 6029 + throw new Error("form events require the input to be inside a form"); 6030 + } 6031 + let uploads; 6032 + let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx, opts); 6033 + let refGenerator = () => { 6034 + return this.putRef([ 6035 + { el: inputEl, loading: true, lock: true }, 6036 + { el: inputEl.form, loading: true, lock: true } 6037 + ], phxEvent, "change", opts); 6038 + }; 6039 + let formData; 6040 + let meta = this.extractMeta(inputEl.form, {}, opts.value); 6041 + let serializeOpts = {}; 6042 + if (inputEl instanceof HTMLButtonElement) { 6043 + serializeOpts.submitter = inputEl; 6044 + } 6045 + if (inputEl.getAttribute(this.binding("change"))) { 6046 + formData = serializeForm(inputEl.form, serializeOpts, [inputEl.name]); 6047 + } else { 6048 + formData = serializeForm(inputEl.form, serializeOpts); 6049 + } 6050 + if (dom_default.isUploadInput(inputEl) && inputEl.files && inputEl.files.length > 0) { 6051 + LiveUploader.trackFiles(inputEl, Array.from(inputEl.files)); 6052 + } 6053 + uploads = LiveUploader.serializeUploads(inputEl); 6054 + let event = { 6055 + type: "form", 6056 + event: phxEvent, 6057 + value: formData, 6058 + meta: __spreadValues({ 6059 + // no target was implicitly sent as "undefined" in LV <= 1.0.5, therefore 6060 + // we have to keep it. In 1.0.6 we switched from passing meta as URL encoded data 6061 + // to passing it directly in the event, but the JSON encode would drop keys with 6062 + // undefined values. 6063 + _target: opts._target || "undefined" 6064 + }, meta), 6065 + uploads, 6066 + cid 6067 + }; 6068 + this.pushWithReply(refGenerator, "event", event).then(({ resp }) => { 6069 + if (dom_default.isUploadInput(inputEl) && dom_default.isAutoUpload(inputEl)) { 6070 + ElementRef.onUnlock(inputEl, () => { 6071 + if (LiveUploader.filesAwaitingPreflight(inputEl).length > 0) { 6072 + let [ref, _els] = refGenerator(); 6073 + this.undoRefs(ref, phxEvent, [inputEl.form]); 6074 + this.uploadFiles(inputEl.form, phxEvent, targetCtx, ref, cid, (_uploads) => { 6075 + callback && callback(resp); 6076 + this.triggerAwaitingSubmit(inputEl.form, phxEvent); 6077 + this.undoRefs(ref, phxEvent); 6078 + }); 6079 + } 6080 + }); 6081 + } else { 6082 + callback && callback(resp); 6083 + } 6084 + }).catch((error) => logError("Failed to push input event", error)); 6085 + } 6086 + triggerAwaitingSubmit(formEl, phxEvent) { 6087 + let awaitingSubmit = this.getScheduledSubmit(formEl); 6088 + if (awaitingSubmit) { 6089 + let [_el, _ref, _opts, callback] = awaitingSubmit; 6090 + this.cancelSubmit(formEl, phxEvent); 6091 + callback(); 6092 + } 6093 + } 6094 + getScheduledSubmit(formEl) { 6095 + return this.formSubmits.find(([el, _ref, _opts, _callback]) => el.isSameNode(formEl)); 6096 + } 6097 + scheduleSubmit(formEl, ref, opts, callback) { 6098 + if (this.getScheduledSubmit(formEl)) { 6099 + return true; 6100 + } 6101 + this.formSubmits.push([formEl, ref, opts, callback]); 6102 + } 6103 + cancelSubmit(formEl, phxEvent) { 6104 + this.formSubmits = this.formSubmits.filter(([el, ref, _opts, _callback]) => { 6105 + if (el.isSameNode(formEl)) { 6106 + this.undoRefs(ref, phxEvent); 6107 + return false; 6108 + } else { 6109 + return true; 6110 + } 6111 + }); 6112 + } 6113 + disableForm(formEl, phxEvent, opts = {}) { 6114 + let filterIgnored = (el) => { 6115 + let userIgnored = closestPhxBinding(el, `${this.binding(PHX_UPDATE)}=ignore`, el.form); 6116 + return !(userIgnored || closestPhxBinding(el, "data-phx-update=ignore", el.form)); 6117 + }; 6118 + let filterDisables = (el) => { 6119 + return el.hasAttribute(this.binding(PHX_DISABLE_WITH)); 6120 + }; 6121 + let filterButton = (el) => el.tagName == "BUTTON"; 6122 + let filterInput = (el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName); 6123 + let formElements = Array.from(formEl.elements); 6124 + let disables = formElements.filter(filterDisables); 6125 + let buttons = formElements.filter(filterButton).filter(filterIgnored); 6126 + let inputs = formElements.filter(filterInput).filter(filterIgnored); 6127 + buttons.forEach((button) => { 6128 + button.setAttribute(PHX_DISABLED, button.disabled); 6129 + button.disabled = true; 6130 + }); 6131 + inputs.forEach((input) => { 6132 + input.setAttribute(PHX_READONLY, input.readOnly); 6133 + input.readOnly = true; 6134 + if (input.files) { 6135 + input.setAttribute(PHX_DISABLED, input.disabled); 6136 + input.disabled = true; 6137 + } 6138 + }); 6139 + let formEls = disables.concat(buttons).concat(inputs).map((el) => { 6140 + return { el, loading: true, lock: true }; 6141 + }); 6142 + let els = [{ el: formEl, loading: true, lock: false }].concat(formEls).reverse(); 6143 + return this.putRef(els, phxEvent, "submit", opts); 6144 + } 6145 + pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply) { 6146 + let refGenerator = () => this.disableForm(formEl, phxEvent, __spreadProps(__spreadValues({}, opts), { 6147 + form: formEl, 6148 + submitter 6149 + })); 6150 + dom_default.putPrivate(formEl, "submitter", submitter); 6151 + let cid = this.targetComponentID(formEl, targetCtx); 6152 + if (LiveUploader.hasUploadsInProgress(formEl)) { 6153 + let [ref, _els] = refGenerator(); 6154 + let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply); 6155 + return this.scheduleSubmit(formEl, ref, opts, push); 6156 + } else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) { 6157 + let [ref, els] = refGenerator(); 6158 + let proxyRefGen = () => [ref, els, opts]; 6159 + this.uploadFiles(formEl, phxEvent, targetCtx, ref, cid, (_uploads) => { 6160 + if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) { 6161 + return this.undoRefs(ref, phxEvent); 6162 + } 6163 + let meta = this.extractMeta(formEl, {}, opts.value); 6164 + let formData = serializeForm(formEl, { submitter }); 6165 + this.pushWithReply(proxyRefGen, "event", { 6166 + type: "form", 6167 + event: phxEvent, 6168 + value: formData, 6169 + meta, 6170 + cid 6171 + }).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error)); 6172 + }); 6173 + } else if (!(formEl.hasAttribute(PHX_REF_SRC) && formEl.classList.contains("phx-submit-loading"))) { 6174 + let meta = this.extractMeta(formEl, {}, opts.value); 6175 + let formData = serializeForm(formEl, { submitter }); 6176 + this.pushWithReply(refGenerator, "event", { 6177 + type: "form", 6178 + event: phxEvent, 6179 + value: formData, 6180 + meta, 6181 + cid 6182 + }).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error)); 6183 + } 6184 + } 6185 + uploadFiles(formEl, phxEvent, targetCtx, ref, cid, onComplete) { 6186 + let joinCountAtUpload = this.joinCount; 6187 + let inputEls = LiveUploader.activeFileInputs(formEl); 6188 + let numFileInputsInProgress = inputEls.length; 6189 + inputEls.forEach((inputEl) => { 6190 + let uploader = new LiveUploader(inputEl, this, () => { 6191 + numFileInputsInProgress--; 6192 + if (numFileInputsInProgress === 0) { 6193 + onComplete(); 6194 + } 6195 + }); 6196 + let entries = uploader.entries().map((entry) => entry.toPreflightPayload()); 6197 + if (entries.length === 0) { 6198 + numFileInputsInProgress--; 6199 + return; 6200 + } 6201 + let payload = { 6202 + ref: inputEl.getAttribute(PHX_UPLOAD_REF), 6203 + entries, 6204 + cid: this.targetComponentID(inputEl.form, targetCtx) 6205 + }; 6206 + this.log("upload", () => ["sending preflight request", payload]); 6207 + this.pushWithReply(null, "allow_upload", payload).then(({ resp }) => { 6208 + this.log("upload", () => ["got preflight response", resp]); 6209 + uploader.entries().forEach((entry) => { 6210 + if (resp.entries && !resp.entries[entry.ref]) { 6211 + this.handleFailedEntryPreflight(entry.ref, "failed preflight", uploader); 6212 + } 6213 + }); 6214 + if (resp.error || Object.keys(resp.entries).length === 0) { 6215 + this.undoRefs(ref, phxEvent); 6216 + let errors = resp.error || []; 6217 + errors.map(([entry_ref, reason]) => { 6218 + this.handleFailedEntryPreflight(entry_ref, reason, uploader); 6219 + }); 6220 + } else { 6221 + let onError = (callback) => { 6222 + this.channel.onError(() => { 6223 + if (this.joinCount === joinCountAtUpload) { 6224 + callback(); 6225 + } 6226 + }); 6227 + }; 6228 + uploader.initAdapterUpload(resp, onError, this.liveSocket); 6229 + } 6230 + }).catch((error) => logError("Failed to push upload", error)); 6231 + }); 6232 + } 6233 + handleFailedEntryPreflight(uploadRef, reason, uploader) { 6234 + if (uploader.isAutoUpload()) { 6235 + let entry = uploader.entries().find((entry2) => entry2.ref === uploadRef.toString()); 6236 + if (entry) { 6237 + entry.cancel(); 6238 + } 6239 + } else { 6240 + uploader.entries().map((entry) => entry.cancel()); 6241 + } 6242 + this.log("upload", () => [`error for entry ${uploadRef}`, reason]); 6243 + } 6244 + dispatchUploads(targetCtx, name, filesOrBlobs) { 6245 + let targetElement = this.targetCtxElement(targetCtx) || this.el; 6246 + let inputs = dom_default.findUploadInputs(targetElement).filter((el) => el.name === name); 6247 + if (inputs.length === 0) { 6248 + logError(`no live file inputs found matching the name "${name}"`); 6249 + } else if (inputs.length > 1) { 6250 + logError(`duplicate live file inputs found matching the name "${name}"`); 6251 + } else { 6252 + dom_default.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, { detail: { files: filesOrBlobs } }); 6253 + } 6254 + } 6255 + targetCtxElement(targetCtx) { 6256 + if (isCid(targetCtx)) { 6257 + let [target] = dom_default.findComponentNodeList(this.el, targetCtx); 6258 + return target; 6259 + } else if (targetCtx) { 6260 + return targetCtx; 6261 + } else { 6262 + return null; 6263 + } 6264 + } 6265 + pushFormRecovery(oldForm, newForm, templateDom, callback) { 6266 + const phxChange = this.binding("change"); 6267 + const phxTarget = newForm.getAttribute(this.binding("target")) || newForm; 6268 + const phxEvent = newForm.getAttribute(this.binding(PHX_AUTO_RECOVER)) || newForm.getAttribute(this.binding("change")); 6269 + const inputs = Array.from(oldForm.elements).filter((el) => dom_default.isFormInput(el) && el.name && !el.hasAttribute(phxChange)); 6270 + if (inputs.length === 0) { 6271 + callback(); 6272 + return; 6273 + } 6274 + inputs.forEach((input2) => input2.hasAttribute(PHX_UPLOAD_REF) && LiveUploader.clearFiles(input2)); 6275 + let input = inputs.find((el) => el.type !== "hidden") || inputs[0]; 6276 + let pending = 0; 6277 + this.withinTargets(phxTarget, (targetView, targetCtx) => { 6278 + const cid = this.targetComponentID(newForm, targetCtx); 6279 + pending++; 6280 + let e = new CustomEvent("phx:form-recovery", { detail: { sourceElement: oldForm } }); 6281 + js_default.exec(e, "change", phxEvent, this, input, ["push", { 6282 + _target: input.name, 6283 + targetView, 6284 + targetCtx, 6285 + newCid: cid, 6286 + callback: () => { 6287 + pending--; 6288 + if (pending === 0) { 6289 + callback(); 6290 + } 6291 + } 6292 + }]); 6293 + }, templateDom, templateDom); 6294 + } 6295 + pushLinkPatch(e, href, targetEl, callback) { 6296 + let linkRef = this.liveSocket.setPendingLink(href); 6297 + let loading = e.isTrusted && e.type !== "popstate"; 6298 + let refGen = targetEl ? () => this.putRef([{ el: targetEl, loading, lock: true }], null, "click") : null; 6299 + let fallback = () => this.liveSocket.redirect(window.location.href); 6300 + let url = href.startsWith("/") ? `${location.protocol}//${location.host}${href}` : href; 6301 + this.pushWithReply(refGen, "live_patch", { url }).then( 6302 + ({ resp }) => { 6303 + this.liveSocket.requestDOMUpdate(() => { 6304 + if (resp.link_redirect) { 6305 + this.liveSocket.replaceMain(href, null, callback, linkRef); 6306 + } else { 6307 + if (this.liveSocket.commitPendingLink(linkRef)) { 6308 + this.href = href; 6309 + } 6310 + this.applyPendingUpdates(); 6311 + callback && callback(linkRef); 6312 + } 6313 + }); 6314 + }, 6315 + ({ error: _error, timeout: _timeout }) => fallback() 6316 + ); 6317 + } 6318 + getFormsForRecovery() { 6319 + if (this.joinCount === 0) { 6320 + return {}; 6321 + } 6322 + let phxChange = this.binding("change"); 6323 + return dom_default.all(this.el, `form[${phxChange}]`).filter((form) => form.id).filter((form) => form.elements.length > 0).filter((form) => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== "ignore").map((form) => { 6324 + const clonedForm = form.cloneNode(false); 6325 + dom_default.copyPrivates(clonedForm, form); 6326 + Array.from(form.elements).forEach((el) => { 6327 + const clonedEl = el.cloneNode(true); 6328 + morphdom_esm_default(clonedEl, el); 6329 + dom_default.copyPrivates(clonedEl, el); 6330 + clonedForm.appendChild(clonedEl); 6331 + }); 6332 + return clonedForm; 6333 + }).reduce((acc, form) => { 6334 + acc[form.id] = form; 6335 + return acc; 6336 + }, {}); 6337 + } 6338 + maybePushComponentsDestroyed(destroyedCIDs) { 6339 + let willDestroyCIDs = destroyedCIDs.filter((cid) => { 6340 + return dom_default.findComponentNodeList(this.el, cid).length === 0; 6341 + }); 6342 + if (willDestroyCIDs.length > 0) { 6343 + willDestroyCIDs.forEach((cid) => this.rendered.resetRender(cid)); 6344 + this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }).then(() => { 6345 + this.liveSocket.requestDOMUpdate(() => { 6346 + let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => { 6347 + return dom_default.findComponentNodeList(this.el, cid).length === 0; 6348 + }); 6349 + if (completelyDestroyCIDs.length > 0) { 6350 + this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }).then(({ resp }) => { 6351 + this.rendered.pruneCIDs(resp.cids); 6352 + }).catch((error) => logError("Failed to push components destroyed", error)); 6353 + } 6354 + }); 6355 + }).catch((error) => logError("Failed to push components destroyed", error)); 6356 + } 6357 + } 6358 + ownsElement(el) { 6359 + let parentViewEl = el.closest(PHX_VIEW_SELECTOR); 6360 + return el.getAttribute(PHX_PARENT_ID) === this.id || parentViewEl && parentViewEl.id === this.id || !parentViewEl && this.isDead; 6361 + } 6362 + submitForm(form, targetCtx, phxEvent, submitter, opts = {}) { 6363 + dom_default.putPrivate(form, PHX_HAS_SUBMITTED, true); 6364 + const inputs = Array.from(form.elements); 6365 + inputs.forEach((input) => dom_default.putPrivate(input, PHX_HAS_SUBMITTED, true)); 6366 + this.liveSocket.blurActiveElement(this); 6367 + this.pushFormSubmit(form, targetCtx, phxEvent, submitter, opts, () => { 6368 + this.liveSocket.restorePreviouslyActiveFocus(); 6369 + }); 6370 + } 6371 + binding(kind) { 6372 + return this.liveSocket.binding(kind); 6373 + } 6374 + }; 6375 + var LiveSocket = class { 6376 + constructor(url, phxSocket, opts = {}) { 6377 + this.unloaded = false; 6378 + if (!phxSocket || phxSocket.constructor.name === "Object") { 6379 + throw new Error(` 6380 + a phoenix Socket must be provided as the second argument to the LiveSocket constructor. For example: 6381 + 6382 + import {Socket} from "phoenix" 6383 + import {LiveSocket} from "phoenix_live_view" 6384 + let liveSocket = new LiveSocket("/live", Socket, {...}) 6385 + `); 6386 + } 6387 + this.socket = new phxSocket(url, opts); 6388 + this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX; 6389 + this.opts = opts; 6390 + this.params = closure2(opts.params || {}); 6391 + this.viewLogger = opts.viewLogger; 6392 + this.metadataCallbacks = opts.metadata || {}; 6393 + this.defaults = Object.assign(clone(DEFAULTS), opts.defaults || {}); 6394 + this.activeElement = null; 6395 + this.prevActive = null; 6396 + this.silenced = false; 6397 + this.main = null; 6398 + this.outgoingMainEl = null; 6399 + this.clickStartedAtTarget = null; 6400 + this.linkRef = 1; 6401 + this.roots = {}; 6402 + this.href = window.location.href; 6403 + this.pendingLink = null; 6404 + this.currentLocation = clone(window.location); 6405 + this.hooks = opts.hooks || {}; 6406 + this.uploaders = opts.uploaders || {}; 6407 + this.loaderTimeout = opts.loaderTimeout || LOADER_TIMEOUT; 6408 + this.disconnectedTimeout = opts.disconnectedTimeout || DISCONNECTED_TIMEOUT; 6409 + this.reloadWithJitterTimer = null; 6410 + this.maxReloads = opts.maxReloads || MAX_RELOADS; 6411 + this.reloadJitterMin = opts.reloadJitterMin || RELOAD_JITTER_MIN; 6412 + this.reloadJitterMax = opts.reloadJitterMax || RELOAD_JITTER_MAX; 6413 + this.failsafeJitter = opts.failsafeJitter || FAILSAFE_JITTER; 6414 + this.localStorage = opts.localStorage || window.localStorage; 6415 + this.sessionStorage = opts.sessionStorage || window.sessionStorage; 6416 + this.boundTopLevelEvents = false; 6417 + this.boundEventNames = /* @__PURE__ */ new Set(); 6418 + this.serverCloseRef = null; 6419 + this.domCallbacks = Object.assign( 6420 + { 6421 + jsQuerySelectorAll: null, 6422 + onPatchStart: closure2(), 6423 + onPatchEnd: closure2(), 6424 + onNodeAdded: closure2(), 6425 + onBeforeElUpdated: closure2() 6426 + }, 6427 + opts.dom || {} 6428 + ); 6429 + this.transitions = new TransitionSet(); 6430 + this.currentHistoryPosition = parseInt(this.sessionStorage.getItem(PHX_LV_HISTORY_POSITION)) || 0; 6431 + window.addEventListener("pagehide", (_e) => { 6432 + this.unloaded = true; 6433 + }); 6434 + this.socket.onOpen(() => { 6435 + if (this.isUnloaded()) { 6436 + window.location.reload(); 6437 + } 6438 + }); 6439 + } 6440 + // public 6441 + version() { 6442 + return "1.0.17"; 6443 + } 6444 + isProfileEnabled() { 6445 + return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true"; 6446 + } 6447 + isDebugEnabled() { 6448 + return this.sessionStorage.getItem(PHX_LV_DEBUG) === "true"; 6449 + } 6450 + isDebugDisabled() { 6451 + return this.sessionStorage.getItem(PHX_LV_DEBUG) === "false"; 6452 + } 6453 + enableDebug() { 6454 + this.sessionStorage.setItem(PHX_LV_DEBUG, "true"); 6455 + } 6456 + enableProfiling() { 6457 + this.sessionStorage.setItem(PHX_LV_PROFILE, "true"); 6458 + } 6459 + disableDebug() { 6460 + this.sessionStorage.setItem(PHX_LV_DEBUG, "false"); 6461 + } 6462 + disableProfiling() { 6463 + this.sessionStorage.removeItem(PHX_LV_PROFILE); 6464 + } 6465 + enableLatencySim(upperBoundMs) { 6466 + this.enableDebug(); 6467 + console.log("latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable"); 6468 + this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs); 6469 + } 6470 + disableLatencySim() { 6471 + this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM); 6472 + } 6473 + getLatencySim() { 6474 + let str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM); 6475 + return str ? parseInt(str) : null; 6476 + } 6477 + getSocket() { 6478 + return this.socket; 6479 + } 6480 + connect() { 6481 + if (window.location.hostname === "localhost" && !this.isDebugDisabled()) { 6482 + this.enableDebug(); 6483 + } 6484 + let doConnect = () => { 6485 + this.resetReloadStatus(); 6486 + if (this.joinRootViews()) { 6487 + this.bindTopLevelEvents(); 6488 + this.socket.connect(); 6489 + } else if (this.main) { 6490 + this.socket.connect(); 6491 + } else { 6492 + this.bindTopLevelEvents({ dead: true }); 6493 + } 6494 + this.joinDeadView(); 6495 + }; 6496 + if (["complete", "loaded", "interactive"].indexOf(document.readyState) >= 0) { 6497 + doConnect(); 6498 + } else { 6499 + document.addEventListener("DOMContentLoaded", () => doConnect()); 6500 + } 6501 + } 6502 + disconnect(callback) { 6503 + clearTimeout(this.reloadWithJitterTimer); 6504 + if (this.serverCloseRef) { 6505 + this.socket.off(this.serverCloseRef); 6506 + this.serverCloseRef = null; 6507 + } 6508 + this.socket.disconnect(callback); 6509 + } 6510 + replaceTransport(transport) { 6511 + clearTimeout(this.reloadWithJitterTimer); 6512 + this.socket.replaceTransport(transport); 6513 + this.connect(); 6514 + } 6515 + execJS(el, encodedJS, eventType = null) { 6516 + let e = new CustomEvent("phx:exec", { detail: { sourceElement: el } }); 6517 + this.owner(el, (view) => js_default.exec(e, eventType, encodedJS, view, el)); 6518 + } 6519 + // private 6520 + execJSHookPush(el, phxEvent, data, callback) { 6521 + this.withinOwners(el, (view) => { 6522 + let e = new CustomEvent("phx:exec", { detail: { sourceElement: el } }); 6523 + js_default.exec(e, "hook", phxEvent, view, el, ["push", { data, callback }]); 6524 + }); 6525 + } 6526 + unload() { 6527 + if (this.unloaded) { 6528 + return; 6529 + } 6530 + if (this.main && this.isConnected()) { 6531 + this.log(this.main, "socket", () => ["disconnect for page nav"]); 6532 + } 6533 + this.unloaded = true; 6534 + this.destroyAllViews(); 6535 + this.disconnect(); 6536 + } 6537 + triggerDOM(kind, args) { 6538 + this.domCallbacks[kind](...args); 6539 + } 6540 + time(name, func) { 6541 + if (!this.isProfileEnabled() || !console.time) { 6542 + return func(); 6543 + } 6544 + console.time(name); 6545 + let result = func(); 6546 + console.timeEnd(name); 6547 + return result; 6548 + } 6549 + log(view, kind, msgCallback) { 6550 + if (this.viewLogger) { 6551 + let [msg, obj] = msgCallback(); 6552 + this.viewLogger(view, kind, msg, obj); 6553 + } else if (this.isDebugEnabled()) { 6554 + let [msg, obj] = msgCallback(); 6555 + debug(view, kind, msg, obj); 6556 + } 6557 + } 6558 + requestDOMUpdate(callback) { 6559 + this.transitions.after(callback); 6560 + } 6561 + transition(time, onStart, onDone = function() { 6562 + }) { 6563 + this.transitions.addTransition(time, onStart, onDone); 6564 + } 6565 + onChannel(channel, event, cb) { 6566 + channel.on(event, (data) => { 6567 + let latency = this.getLatencySim(); 6568 + if (!latency) { 6569 + cb(data); 6570 + } else { 6571 + setTimeout(() => cb(data), latency); 6572 + } 6573 + }); 6574 + } 6575 + reloadWithJitter(view, log) { 6576 + clearTimeout(this.reloadWithJitterTimer); 6577 + this.disconnect(); 6578 + let minMs = this.reloadJitterMin; 6579 + let maxMs = this.reloadJitterMax; 6580 + let afterMs = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs; 6581 + let tries = browser_default.updateLocal(this.localStorage, window.location.pathname, CONSECUTIVE_RELOADS, 0, (count) => count + 1); 6582 + if (tries >= this.maxReloads) { 6583 + afterMs = this.failsafeJitter; 6584 + } 6585 + this.reloadWithJitterTimer = setTimeout(() => { 6586 + if (view.isDestroyed() || view.isConnected()) { 6587 + return; 6588 + } 6589 + view.destroy(); 6590 + log ? log() : this.log(view, "join", () => [`encountered ${tries} consecutive reloads`]); 6591 + if (tries >= this.maxReloads) { 6592 + this.log(view, "join", () => [`exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`]); 6593 + } 6594 + if (this.hasPendingLink()) { 6595 + window.location = this.pendingLink; 6596 + } else { 6597 + window.location.reload(); 6598 + } 6599 + }, afterMs); 6600 + } 6601 + getHookCallbacks(name) { 6602 + return name && name.startsWith("Phoenix.") ? hooks_default[name.split(".")[1]] : this.hooks[name]; 6603 + } 6604 + isUnloaded() { 6605 + return this.unloaded; 6606 + } 6607 + isConnected() { 6608 + return this.socket.isConnected(); 6609 + } 6610 + getBindingPrefix() { 6611 + return this.bindingPrefix; 6612 + } 6613 + binding(kind) { 6614 + return `${this.getBindingPrefix()}${kind}`; 6615 + } 6616 + channel(topic, params) { 6617 + return this.socket.channel(topic, params); 6618 + } 6619 + joinDeadView() { 6620 + let body = document.body; 6621 + if (body && !this.isPhxView(body) && !this.isPhxView(document.firstElementChild)) { 6622 + let view = this.newRootView(body); 6623 + view.setHref(this.getHref()); 6624 + view.joinDead(); 6625 + if (!this.main) { 6626 + this.main = view; 6627 + } 6628 + window.requestAnimationFrame(() => { 6629 + var _a; 6630 + view.execNewMounted(); 6631 + this.maybeScroll((_a = history.state) == null ? void 0 : _a.scroll); 6632 + }); 6633 + } 6634 + } 6635 + joinRootViews() { 6636 + let rootsFound = false; 6637 + dom_default.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, (rootEl) => { 6638 + if (!this.getRootById(rootEl.id)) { 6639 + let view = this.newRootView(rootEl); 6640 + if (!dom_default.isPhxSticky(rootEl)) { 6641 + view.setHref(this.getHref()); 6642 + } 6643 + view.join(); 6644 + if (rootEl.hasAttribute(PHX_MAIN)) { 6645 + this.main = view; 6646 + } 6647 + } 6648 + rootsFound = true; 6649 + }); 6650 + return rootsFound; 6651 + } 6652 + redirect(to, flash, reloadToken) { 6653 + if (reloadToken) { 6654 + browser_default.setCookie(PHX_RELOAD_STATUS, reloadToken, 60); 6655 + } 6656 + this.unload(); 6657 + browser_default.redirect(to, flash); 6658 + } 6659 + replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)) { 6660 + const liveReferer = this.currentLocation.href; 6661 + this.outgoingMainEl = this.outgoingMainEl || this.main.el; 6662 + const stickies = dom_default.findPhxSticky(document) || []; 6663 + const removeEls = dom_default.all(this.outgoingMainEl, `[${this.binding("remove")}]`).filter((el) => !dom_default.isChildOfAny(el, stickies)); 6664 + const newMainEl = dom_default.cloneNode(this.outgoingMainEl, ""); 6665 + this.main.showLoader(this.loaderTimeout); 6666 + this.main.destroy(); 6667 + this.main = this.newRootView(newMainEl, flash, liveReferer); 6668 + this.main.setRedirect(href); 6669 + this.transitionRemoves(removeEls); 6670 + this.main.join((joinCount, onDone) => { 6671 + if (joinCount === 1 && this.commitPendingLink(linkRef)) { 6672 + this.requestDOMUpdate(() => { 6673 + removeEls.forEach((el) => el.remove()); 6674 + stickies.forEach((el) => newMainEl.appendChild(el)); 6675 + this.outgoingMainEl.replaceWith(newMainEl); 6676 + this.outgoingMainEl = null; 6677 + callback && callback(linkRef); 6678 + onDone(); 6679 + }); 6680 + } 6681 + }); 6682 + } 6683 + transitionRemoves(elements, callback) { 6684 + let removeAttr = this.binding("remove"); 6685 + let silenceEvents = (e) => { 6686 + e.preventDefault(); 6687 + e.stopImmediatePropagation(); 6688 + }; 6689 + elements.forEach((el) => { 6690 + for (let event of this.boundEventNames) { 6691 + el.addEventListener(event, silenceEvents, true); 6692 + } 6693 + this.execJS(el, el.getAttribute(removeAttr), "remove"); 6694 + }); 6695 + this.requestDOMUpdate(() => { 6696 + elements.forEach((el) => { 6697 + for (let event of this.boundEventNames) { 6698 + el.removeEventListener(event, silenceEvents, true); 6699 + } 6700 + }); 6701 + callback && callback(); 6702 + }); 6703 + } 6704 + isPhxView(el) { 6705 + return el.getAttribute && el.getAttribute(PHX_SESSION) !== null; 6706 + } 6707 + newRootView(el, flash, liveReferer) { 6708 + let view = new View(el, this, null, flash, liveReferer); 6709 + this.roots[view.id] = view; 6710 + return view; 6711 + } 6712 + owner(childEl, callback) { 6713 + let view; 6714 + const closestViewEl = childEl.closest(PHX_VIEW_SELECTOR); 6715 + if (closestViewEl) { 6716 + view = this.getViewByEl(closestViewEl); 6717 + } else { 6718 + view = this.main; 6719 + } 6720 + return view && callback ? callback(view) : view; 6721 + } 6722 + withinOwners(childEl, callback) { 6723 + this.owner(childEl, (view) => callback(view, childEl)); 6724 + } 6725 + getViewByEl(el) { 6726 + let rootId = el.getAttribute(PHX_ROOT_ID); 6727 + return maybe(this.getRootById(rootId), (root) => root.getDescendentByEl(el)); 6728 + } 6729 + getRootById(id) { 6730 + return this.roots[id]; 6731 + } 6732 + destroyAllViews() { 6733 + for (let id in this.roots) { 6734 + this.roots[id].destroy(); 6735 + delete this.roots[id]; 6736 + } 6737 + this.main = null; 6738 + } 6739 + destroyViewByEl(el) { 6740 + let root = this.getRootById(el.getAttribute(PHX_ROOT_ID)); 6741 + if (root && root.id === el.id) { 6742 + root.destroy(); 6743 + delete this.roots[root.id]; 6744 + } else if (root) { 6745 + root.destroyDescendent(el.id); 6746 + } 6747 + } 6748 + getActiveElement() { 6749 + return document.activeElement; 6750 + } 6751 + dropActiveElement(view) { 6752 + if (this.prevActive && view.ownsElement(this.prevActive)) { 6753 + this.prevActive = null; 6754 + } 6755 + } 6756 + restorePreviouslyActiveFocus() { 6757 + if (this.prevActive && this.prevActive !== document.body) { 6758 + this.prevActive.focus(); 6759 + } 6760 + } 6761 + blurActiveElement() { 6762 + this.prevActive = this.getActiveElement(); 6763 + if (this.prevActive !== document.body) { 6764 + this.prevActive.blur(); 6765 + } 6766 + } 6767 + bindTopLevelEvents({ dead } = {}) { 6768 + if (this.boundTopLevelEvents) { 6769 + return; 6770 + } 6771 + this.boundTopLevelEvents = true; 6772 + this.serverCloseRef = this.socket.onClose((event) => { 6773 + if (event && event.code === 1e3 && this.main) { 6774 + return this.reloadWithJitter(this.main); 6775 + } 6776 + }); 6777 + document.body.addEventListener("click", function() { 6778 + }); 6779 + window.addEventListener("pageshow", (e) => { 6780 + if (e.persisted) { 6781 + this.getSocket().disconnect(); 6782 + this.withPageLoading({ to: window.location.href, kind: "redirect" }); 6783 + window.location.reload(); 6784 + } 6785 + }, true); 6786 + if (!dead) { 6787 + this.bindNav(); 6788 + } 6789 + this.bindClicks(); 6790 + if (!dead) { 6791 + this.bindForms(); 6792 + } 6793 + this.bind({ keyup: "keyup", keydown: "keydown" }, (e, type, view, targetEl, phxEvent, _phxTarget) => { 6794 + let matchKey = targetEl.getAttribute(this.binding(PHX_KEY)); 6795 + let pressedKey = e.key && e.key.toLowerCase(); 6796 + if (matchKey && matchKey.toLowerCase() !== pressedKey) { 6797 + return; 6798 + } 6799 + let data = __spreadValues({ key: e.key }, this.eventMeta(type, e, targetEl)); 6800 + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); 6801 + }); 6802 + this.bind({ blur: "focusout", focus: "focusin" }, (e, type, view, targetEl, phxEvent, phxTarget) => { 6803 + if (!phxTarget) { 6804 + let data = __spreadValues({ key: e.key }, this.eventMeta(type, e, targetEl)); 6805 + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); 6806 + } 6807 + }); 6808 + this.bind({ blur: "blur", focus: "focus" }, (e, type, view, targetEl, phxEvent, phxTarget) => { 6809 + if (phxTarget === "window") { 6810 + let data = this.eventMeta(type, e, targetEl); 6811 + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); 6812 + } 6813 + }); 6814 + this.on("dragover", (e) => e.preventDefault()); 6815 + this.on("drop", (e) => { 6816 + e.preventDefault(); 6817 + let dropTargetId = maybe(closestPhxBinding(e.target, this.binding(PHX_DROP_TARGET)), (trueTarget) => { 6818 + return trueTarget.getAttribute(this.binding(PHX_DROP_TARGET)); 6819 + }); 6820 + let dropTarget = dropTargetId && document.getElementById(dropTargetId); 6821 + let files = Array.from(e.dataTransfer.files || []); 6822 + if (!dropTarget || dropTarget.disabled || files.length === 0 || !(dropTarget.files instanceof FileList)) { 6823 + return; 6824 + } 6825 + LiveUploader.trackFiles(dropTarget, files, e.dataTransfer); 6826 + dropTarget.dispatchEvent(new Event("input", { bubbles: true })); 6827 + }); 6828 + this.on(PHX_TRACK_UPLOADS, (e) => { 6829 + let uploadTarget = e.target; 6830 + if (!dom_default.isUploadInput(uploadTarget)) { 6831 + return; 6832 + } 6833 + let files = Array.from(e.detail.files || []).filter((f) => f instanceof File || f instanceof Blob); 6834 + LiveUploader.trackFiles(uploadTarget, files); 6835 + uploadTarget.dispatchEvent(new Event("input", { bubbles: true })); 6836 + }); 6837 + } 6838 + eventMeta(eventName, e, targetEl) { 6839 + let callback = this.metadataCallbacks[eventName]; 6840 + return callback ? callback(e, targetEl) : {}; 6841 + } 6842 + setPendingLink(href) { 6843 + this.linkRef++; 6844 + this.pendingLink = href; 6845 + this.resetReloadStatus(); 6846 + return this.linkRef; 6847 + } 6848 + // anytime we are navigating or connecting, drop reload cookie in case 6849 + // we issue the cookie but the next request was interrupted and the server never dropped it 6850 + resetReloadStatus() { 6851 + browser_default.deleteCookie(PHX_RELOAD_STATUS); 6852 + } 6853 + commitPendingLink(linkRef) { 6854 + if (this.linkRef !== linkRef) { 6855 + return false; 6856 + } else { 6857 + this.href = this.pendingLink; 6858 + this.pendingLink = null; 6859 + return true; 6860 + } 6861 + } 6862 + getHref() { 6863 + return this.href; 6864 + } 6865 + hasPendingLink() { 6866 + return !!this.pendingLink; 6867 + } 6868 + bind(events, callback) { 6869 + for (let event in events) { 6870 + let browserEventName = events[event]; 6871 + this.on(browserEventName, (e) => { 6872 + let binding = this.binding(event); 6873 + let windowBinding = this.binding(`window-${event}`); 6874 + let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding); 6875 + if (targetPhxEvent) { 6876 + this.debounce(e.target, e, browserEventName, () => { 6877 + this.withinOwners(e.target, (view) => { 6878 + callback(e, event, view, e.target, targetPhxEvent, null); 6879 + }); 6880 + }); 6881 + } else { 6882 + dom_default.all(document, `[${windowBinding}]`, (el) => { 6883 + let phxEvent = el.getAttribute(windowBinding); 6884 + this.debounce(el, e, browserEventName, () => { 6885 + this.withinOwners(el, (view) => { 6886 + callback(e, event, view, el, phxEvent, "window"); 6887 + }); 6888 + }); 6889 + }); 6890 + } 6891 + }); 6892 + } 6893 + } 6894 + bindClicks() { 6895 + this.on("mousedown", (e) => this.clickStartedAtTarget = e.target); 6896 + this.bindClick("click", "click"); 6897 + } 6898 + bindClick(eventName, bindingName) { 6899 + let click = this.binding(bindingName); 6900 + window.addEventListener(eventName, (e) => { 6901 + let target = null; 6902 + if (e.detail === 0) 6903 + this.clickStartedAtTarget = e.target; 6904 + let clickStartedAtTarget = this.clickStartedAtTarget || e.target; 6905 + target = closestPhxBinding(e.target, click); 6906 + this.dispatchClickAway(e, clickStartedAtTarget); 6907 + this.clickStartedAtTarget = null; 6908 + let phxEvent = target && target.getAttribute(click); 6909 + if (!phxEvent) { 6910 + if (dom_default.isNewPageClick(e, window.location)) { 6911 + this.unload(); 6912 + } 6913 + return; 6914 + } 6915 + if (target.getAttribute("href") === "#") { 6916 + e.preventDefault(); 6917 + } 6918 + if (target.hasAttribute(PHX_REF_SRC)) { 6919 + return; 6920 + } 6921 + this.debounce(target, e, "click", () => { 6922 + this.withinOwners(target, (view) => { 6923 + js_default.exec(e, "click", phxEvent, view, target, ["push", { data: this.eventMeta("click", e, target) }]); 6924 + }); 6925 + }); 6926 + }, false); 6927 + } 6928 + dispatchClickAway(e, clickStartedAt) { 6929 + let phxClickAway = this.binding("click-away"); 6930 + dom_default.all(document, `[${phxClickAway}]`, (el) => { 6931 + if (!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))) { 6932 + this.withinOwners(el, (view) => { 6933 + let phxEvent = el.getAttribute(phxClickAway); 6934 + if (js_default.isVisible(el) && js_default.isInViewport(el)) { 6935 + js_default.exec(e, "click", phxEvent, view, el, ["push", { data: this.eventMeta("click", e, e.target) }]); 6936 + } 6937 + }); 6938 + } 6939 + }); 6940 + } 6941 + bindNav() { 6942 + if (!browser_default.canPushState()) { 6943 + return; 6944 + } 6945 + if (history.scrollRestoration) { 6946 + history.scrollRestoration = "manual"; 6947 + } 6948 + let scrollTimer = null; 6949 + window.addEventListener("scroll", (_e) => { 6950 + clearTimeout(scrollTimer); 6951 + scrollTimer = setTimeout(() => { 6952 + browser_default.updateCurrentState((state) => Object.assign(state, { scroll: window.scrollY })); 6953 + }, 100); 6954 + }); 6955 + window.addEventListener("popstate", (event) => { 6956 + if (!this.registerNewLocation(window.location)) { 6957 + return; 6958 + } 6959 + let { type, backType, id, scroll, position } = event.state || {}; 6960 + let href = window.location.href; 6961 + let isForward = position > this.currentHistoryPosition; 6962 + type = isForward ? type : backType || type; 6963 + this.currentHistoryPosition = position || 0; 6964 + this.sessionStorage.setItem(PHX_LV_HISTORY_POSITION, this.currentHistoryPosition.toString()); 6965 + dom_default.dispatchEvent(window, "phx:navigate", { detail: { href, patch: type === "patch", pop: true, direction: isForward ? "forward" : "backward" } }); 6966 + this.requestDOMUpdate(() => { 6967 + const callback = () => { 6968 + this.maybeScroll(scroll); 6969 + }; 6970 + if (this.main.isConnected() && (type === "patch" && id === this.main.id)) { 6971 + this.main.pushLinkPatch(event, href, null, callback); 6972 + } else { 6973 + this.replaceMain(href, null, callback); 6974 + } 6975 + }); 6976 + }, false); 6977 + window.addEventListener("click", (e) => { 6978 + let target = closestPhxBinding(e.target, PHX_LIVE_LINK); 6979 + let type = target && target.getAttribute(PHX_LIVE_LINK); 6980 + if (!type || !this.isConnected() || !this.main || dom_default.wantsNewTab(e)) { 6981 + return; 6982 + } 6983 + let href = target.href instanceof SVGAnimatedString ? target.href.baseVal : target.href; 6984 + let linkState = target.getAttribute(PHX_LINK_STATE); 6985 + e.preventDefault(); 6986 + e.stopImmediatePropagation(); 6987 + if (this.pendingLink === href) { 6988 + return; 6989 + } 6990 + this.requestDOMUpdate(() => { 6991 + if (type === "patch") { 6992 + this.pushHistoryPatch(e, href, linkState, target); 6993 + } else if (type === "redirect") { 6994 + this.historyRedirect(e, href, linkState, null, target); 6995 + } else { 6996 + throw new Error(`expected ${PHX_LIVE_LINK} to be "patch" or "redirect", got: ${type}`); 6997 + } 6998 + let phxClick = target.getAttribute(this.binding("click")); 6999 + if (phxClick) { 7000 + this.requestDOMUpdate(() => this.execJS(target, phxClick, "click")); 7001 + } 7002 + }); 7003 + }, false); 7004 + } 7005 + maybeScroll(scroll) { 7006 + if (typeof scroll === "number") { 7007 + requestAnimationFrame(() => { 7008 + window.scrollTo(0, scroll); 7009 + }); 7010 + } 7011 + } 7012 + dispatchEvent(event, payload = {}) { 7013 + dom_default.dispatchEvent(window, `phx:${event}`, { detail: payload }); 7014 + } 7015 + dispatchEvents(events) { 7016 + events.forEach(([event, payload]) => this.dispatchEvent(event, payload)); 7017 + } 7018 + withPageLoading(info, callback) { 7019 + dom_default.dispatchEvent(window, "phx:page-loading-start", { detail: info }); 7020 + let done = () => dom_default.dispatchEvent(window, "phx:page-loading-stop", { detail: info }); 7021 + return callback ? callback(done) : done; 7022 + } 7023 + pushHistoryPatch(e, href, linkState, targetEl) { 7024 + if (!this.isConnected() || !this.main.isMain()) { 7025 + return browser_default.redirect(href); 7026 + } 7027 + this.withPageLoading({ to: href, kind: "patch" }, (done) => { 7028 + this.main.pushLinkPatch(e, href, targetEl, (linkRef) => { 7029 + this.historyPatch(href, linkState, linkRef); 7030 + done(); 7031 + }); 7032 + }); 7033 + } 7034 + historyPatch(href, linkState, linkRef = this.setPendingLink(href)) { 7035 + if (!this.commitPendingLink(linkRef)) { 7036 + return; 7037 + } 7038 + this.currentHistoryPosition++; 7039 + this.sessionStorage.setItem(PHX_LV_HISTORY_POSITION, this.currentHistoryPosition.toString()); 7040 + browser_default.updateCurrentState((state) => __spreadProps(__spreadValues({}, state), { backType: "patch" })); 7041 + browser_default.pushState(linkState, { 7042 + type: "patch", 7043 + id: this.main.id, 7044 + position: this.currentHistoryPosition 7045 + }, href); 7046 + dom_default.dispatchEvent(window, "phx:navigate", { detail: { patch: true, href, pop: false, direction: "forward" } }); 7047 + this.registerNewLocation(window.location); 7048 + } 7049 + historyRedirect(e, href, linkState, flash, targetEl) { 7050 + const clickLoading = targetEl && e.isTrusted && e.type !== "popstate"; 7051 + if (clickLoading) { 7052 + targetEl.classList.add("phx-click-loading"); 7053 + } 7054 + if (!this.isConnected() || !this.main.isMain()) { 7055 + return browser_default.redirect(href, flash); 7056 + } 7057 + if (/^\/$|^\/[^\/]+.*$/.test(href)) { 7058 + let { protocol, host } = window.location; 7059 + href = `${protocol}//${host}${href}`; 7060 + } 7061 + let scroll = window.scrollY; 7062 + this.withPageLoading({ to: href, kind: "redirect" }, (done) => { 7063 + this.replaceMain(href, flash, (linkRef) => { 7064 + if (linkRef === this.linkRef) { 7065 + this.currentHistoryPosition++; 7066 + this.sessionStorage.setItem(PHX_LV_HISTORY_POSITION, this.currentHistoryPosition.toString()); 7067 + browser_default.updateCurrentState((state) => __spreadProps(__spreadValues({}, state), { backType: "redirect" })); 7068 + browser_default.pushState(linkState, { 7069 + type: "redirect", 7070 + id: this.main.id, 7071 + scroll, 7072 + position: this.currentHistoryPosition 7073 + }, href); 7074 + dom_default.dispatchEvent(window, "phx:navigate", { detail: { href, patch: false, pop: false, direction: "forward" } }); 7075 + this.registerNewLocation(window.location); 7076 + } 7077 + if (clickLoading) { 7078 + targetEl.classList.remove("phx-click-loading"); 7079 + } 7080 + done(); 7081 + }); 7082 + }); 7083 + } 7084 + registerNewLocation(newLocation) { 7085 + let { pathname, search } = this.currentLocation; 7086 + if (pathname + search === newLocation.pathname + newLocation.search) { 7087 + return false; 7088 + } else { 7089 + this.currentLocation = clone(newLocation); 7090 + return true; 7091 + } 7092 + } 7093 + bindForms() { 7094 + let iterations = 0; 7095 + let externalFormSubmitted = false; 7096 + this.on("submit", (e) => { 7097 + let phxSubmit = e.target.getAttribute(this.binding("submit")); 7098 + let phxChange = e.target.getAttribute(this.binding("change")); 7099 + if (!externalFormSubmitted && phxChange && !phxSubmit) { 7100 + externalFormSubmitted = true; 7101 + e.preventDefault(); 7102 + this.withinOwners(e.target, (view) => { 7103 + view.disableForm(e.target); 7104 + window.requestAnimationFrame(() => { 7105 + if (dom_default.isUnloadableFormSubmit(e)) { 7106 + this.unload(); 7107 + } 7108 + e.target.submit(); 7109 + }); 7110 + }); 7111 + } 7112 + }); 7113 + this.on("submit", (e) => { 7114 + let phxEvent = e.target.getAttribute(this.binding("submit")); 7115 + if (!phxEvent) { 7116 + if (dom_default.isUnloadableFormSubmit(e)) { 7117 + this.unload(); 7118 + } 7119 + return; 7120 + } 7121 + e.preventDefault(); 7122 + e.target.disabled = true; 7123 + this.withinOwners(e.target, (view) => { 7124 + js_default.exec(e, "submit", phxEvent, view, e.target, ["push", { submitter: e.submitter }]); 7125 + }); 7126 + }); 7127 + for (let type of ["change", "input"]) { 7128 + this.on(type, (e) => { 7129 + if (e instanceof CustomEvent && e.target.form === void 0) { 7130 + if (e.detail && e.detail.dispatcher) { 7131 + throw new Error(`dispatching a custom ${type} event is only supported on input elements inside a form`); 7132 + } 7133 + return; 7134 + } 7135 + let phxChange = this.binding("change"); 7136 + let input = e.target; 7137 + if (e.isComposing) { 7138 + const key = `composition-listener-${type}`; 7139 + if (!dom_default.private(input, key)) { 7140 + dom_default.putPrivate(input, key, true); 7141 + input.addEventListener("compositionend", () => { 7142 + input.dispatchEvent(new Event(type, { bubbles: true })); 7143 + dom_default.deletePrivate(input, key); 7144 + }, { once: true }); 7145 + } 7146 + return; 7147 + } 7148 + let inputEvent = input.getAttribute(phxChange); 7149 + let formEvent = input.form && input.form.getAttribute(phxChange); 7150 + let phxEvent = inputEvent || formEvent; 7151 + if (!phxEvent) { 7152 + return; 7153 + } 7154 + if (input.type === "number" && input.validity && input.validity.badInput) { 7155 + return; 7156 + } 7157 + let dispatcher = inputEvent ? input : input.form; 7158 + let currentIterations = iterations; 7159 + iterations++; 7160 + let { at, type: lastType } = dom_default.private(input, "prev-iteration") || {}; 7161 + if (at === currentIterations - 1 && type === "change" && lastType === "input") { 7162 + return; 7163 + } 7164 + dom_default.putPrivate(input, "prev-iteration", { at: currentIterations, type }); 7165 + this.debounce(input, e, type, () => { 7166 + this.withinOwners(dispatcher, (view) => { 7167 + dom_default.putPrivate(input, PHX_HAS_FOCUSED, true); 7168 + js_default.exec(e, "change", phxEvent, view, input, ["push", { _target: e.target.name, dispatcher }]); 7169 + }); 7170 + }); 7171 + }); 7172 + } 7173 + this.on("reset", (e) => { 7174 + let form = e.target; 7175 + dom_default.resetForm(form); 7176 + let input = Array.from(form.elements).find((el) => el.type === "reset"); 7177 + if (input) { 7178 + window.requestAnimationFrame(() => { 7179 + input.dispatchEvent(new Event("input", { bubbles: true, cancelable: false })); 7180 + }); 7181 + } 7182 + }); 7183 + } 7184 + debounce(el, event, eventType, callback) { 7185 + if (eventType === "blur" || eventType === "focusout") { 7186 + return callback(); 7187 + } 7188 + let phxDebounce = this.binding(PHX_DEBOUNCE); 7189 + let phxThrottle = this.binding(PHX_THROTTLE); 7190 + let defaultDebounce = this.defaults.debounce.toString(); 7191 + let defaultThrottle = this.defaults.throttle.toString(); 7192 + this.withinOwners(el, (view) => { 7193 + let asyncFilter = () => !view.isDestroyed() && document.body.contains(el); 7194 + dom_default.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, () => { 7195 + callback(); 7196 + }); 7197 + }); 7198 + } 7199 + silenceEvents(callback) { 7200 + this.silenced = true; 7201 + callback(); 7202 + this.silenced = false; 7203 + } 7204 + on(event, callback) { 7205 + this.boundEventNames.add(event); 7206 + window.addEventListener(event, (e) => { 7207 + if (!this.silenced) { 7208 + callback(e); 7209 + } 7210 + }); 7211 + } 7212 + jsQuerySelectorAll(sourceEl, query, defaultQuery) { 7213 + let all = this.domCallbacks.jsQuerySelectorAll; 7214 + return all ? all(sourceEl, query, defaultQuery) : defaultQuery(); 7215 + } 7216 + }; 7217 + var TransitionSet = class { 7218 + constructor() { 7219 + this.transitions = /* @__PURE__ */ new Set(); 7220 + this.pendingOps = []; 7221 + } 7222 + reset() { 7223 + this.transitions.forEach((timer) => { 7224 + clearTimeout(timer); 7225 + this.transitions.delete(timer); 7226 + }); 7227 + this.flushPendingOps(); 7228 + } 7229 + after(callback) { 7230 + if (this.size() === 0) { 7231 + callback(); 7232 + } else { 7233 + this.pushPendingOp(callback); 7234 + } 7235 + } 7236 + addTransition(time, onStart, onDone) { 7237 + onStart(); 7238 + let timer = setTimeout(() => { 7239 + this.transitions.delete(timer); 7240 + onDone(); 7241 + this.flushPendingOps(); 7242 + }, time); 7243 + this.transitions.add(timer); 7244 + } 7245 + pushPendingOp(op) { 7246 + this.pendingOps.push(op); 7247 + } 7248 + size() { 7249 + return this.transitions.size; 7250 + } 7251 + flushPendingOps() { 7252 + if (this.size() > 0) { 7253 + return; 7254 + } 7255 + let op = this.pendingOps.shift(); 7256 + if (op) { 7257 + op(); 7258 + this.flushPendingOps(); 7259 + } 7260 + } 7261 + }; 7262 + 7263 + // js/app.js 7264 + var import_topbar = __toESM(require_topbar()); 7265 + var csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content"); 7266 + var liveSocket = new LiveSocket("/live", Socket, { 7267 + longPollFallbackMs: 2500, 7268 + params: { _csrf_token: csrfToken } 7269 + }); 7270 + import_topbar.default.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" }); 7271 + window.addEventListener("phx:page-loading-start", (_info) => import_topbar.default.show(300)); 7272 + window.addEventListener("phx:page-loading-stop", (_info) => import_topbar.default.hide()); 7273 + liveSocket.connect(); 7274 + window.liveSocket = liveSocket; 7275 + })(); 7276 + /** 7277 + * @license MIT 7278 + * topbar 2.0.0, 2023-02-04 7279 + * https://buunguyen.github.io/topbar 7280 + * Copyright (c) 2021 Buu Nguyen 7281 + */ 7282 + //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vYXNzZXRzL3ZlbmRvci90b3BiYXIuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2h0bWwvcHJpdi9zdGF0aWMvcGhvZW5peF9odG1sLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC91dGlscy5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvY29uc3RhbnRzLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9wdXNoLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC90aW1lci5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvY2hhbm5lbC5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvYWpheC5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvbG9uZ3BvbGwuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4L2Fzc2V0cy9qcy9waG9lbml4L3ByZXNlbmNlLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9zZXJpYWxpemVyLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9zb2NrZXQuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvY29uc3RhbnRzLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2VudHJ5X3VwbG9hZGVyLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3V0aWxzLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2Jyb3dzZXIuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3VwbG9hZF9lbnRyeS5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXhfbGl2ZV92aWV3L2Fzc2V0cy9qcy9waG9lbml4X2xpdmVfdmlldy9saXZlX3VwbG9hZGVyLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2FyaWEuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvaG9va3MuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZWxlbWVudF9yZWYuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tX3Bvc3RfbW9ycGhfcmVzdG9yZXIuanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9ub2RlX21vZHVsZXMvbW9ycGhkb20vZGlzdC9tb3JwaGRvbS1lc20uanMiLCAiLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tX3BhdGNoLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3JlbmRlcmVkLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2pzLmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3ZpZXdfaG9vay5qcyIsICIuLi8uLi8uLi9kZXBzL3Bob2VuaXhfbGl2ZV92aWV3L2Fzc2V0cy9qcy9waG9lbml4X2xpdmVfdmlldy92aWV3LmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2xpdmVfc29ja2V0LmpzIiwgIi4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2luZGV4LmpzIiwgIi4uLy4uLy4uL2Fzc2V0cy9qcy9hcHAuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQGxpY2Vuc2UgTUlUXG4gKiB0b3BiYXIgMi4wLjAsIDIwMjMtMDItMDRcbiAqIGh0dHBzOi8vYnV1bmd1eWVuLmdpdGh1Yi5pby90b3BiYXJcbiAqIENvcHlyaWdodCAoYykgMjAyMSBCdXUgTmd1eWVuXG4gKi9cbihmdW5jdGlvbiAod2luZG93LCBkb2N1bWVudCkge1xuICBcInVzZSBzdHJpY3RcIjtcblxuICAvLyBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9wYXVsaXJpc2gvMTU3OTY3MVxuICAoZnVuY3Rpb24gKCkge1xuICAgIHZhciBsYXN0VGltZSA9IDA7XG4gICAgdmFyIHZlbmRvcnMgPSBbXCJtc1wiLCBcIm1velwiLCBcIndlYmtpdFwiLCBcIm9cIl07XG4gICAgZm9yICh2YXIgeCA9IDA7IHggPCB2ZW5kb3JzLmxlbmd0aCAmJiAhd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZTsgKyt4KSB7XG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lID1cbiAgICAgICAgd2luZG93W3ZlbmRvcnNbeF0gKyBcIlJlcXVlc3RBbmltYXRpb25GcmFtZVwiXTtcbiAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSA9XG4gICAgICAgIHdpbmRvd1t2ZW5kb3JzW3hdICsgXCJDYW5jZWxBbmltYXRpb25GcmFtZVwiXSB8fFxuICAgICAgICB3aW5kb3dbdmVuZG9yc1t4XSArIFwiQ2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lXCJdO1xuICAgIH1cbiAgICBpZiAoIXdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUpXG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gZnVuY3Rpb24gKGNhbGxiYWNrLCBlbGVtZW50KSB7XG4gICAgICAgIHZhciBjdXJyVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICB2YXIgdGltZVRvQ2FsbCA9IE1hdGgubWF4KDAsIDE2IC0gKGN1cnJUaW1lIC0gbGFzdFRpbWUpKTtcbiAgICAgICAgdmFyIGlkID0gd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNhbGxiYWNrKGN1cnJUaW1lICsgdGltZVRvQ2FsbCk7XG4gICAgICAgIH0sIHRpbWVUb0NhbGwpO1xuICAgICAgICBsYXN0VGltZSA9IGN1cnJUaW1lICsgdGltZVRvQ2FsbDtcbiAgICAgICAgcmV0dXJuIGlkO1xuICAgICAgfTtcbiAgICBpZiAoIXdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSlcbiAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICBjbGVhclRpbWVvdXQoaWQpO1xuICAgICAgfTtcbiAgfSkoKTtcblxuICB2YXIgY2FudmFzLFxuICAgIGN1cnJlbnRQcm9ncmVzcyxcbiAgICBzaG93aW5nLFxuICAgIHByb2dyZXNzVGltZXJJZCA9IG51bGwsXG4gICAgZmFkZVRpbWVySWQgPSBudWxsLFxuICAgIGRlbGF5VGltZXJJZCA9IG51bGwsXG4gICAgYWRkRXZlbnQgPSBmdW5jdGlvbiAoZWxlbSwgdHlwZSwgaGFuZGxlcikge1xuICAgICAgaWYgKGVsZW0uYWRkRXZlbnRMaXN0ZW5lcikgZWxlbS5hZGRFdmVudExpc3RlbmVyKHR5cGUsIGhhbmRsZXIsIGZhbHNlKTtcbiAgICAgIGVsc2UgaWYgKGVsZW0uYXR0YWNoRXZlbnQpIGVsZW0uYXR0YWNoRXZlbnQoXCJvblwiICsgdHlwZSwgaGFuZGxlcik7XG4gICAgICBlbHNlIGVsZW1bXCJvblwiICsgdHlwZV0gPSBoYW5kbGVyO1xuICAgIH0sXG4gICAgb3B0aW9ucyA9IHtcbiAgICAgIGF1dG9SdW46IHRydWUsXG4gICAgICBiYXJUaGlja25lc3M6IDMsXG4gICAgICBiYXJDb2xvcnM6IHtcbiAgICAgICAgMDogXCJyZ2JhKDI2LCAgMTg4LCAxNTYsIC45KVwiLFxuICAgICAgICBcIi4yNVwiOiBcInJnYmEoNTIsICAxNTIsIDIxOSwgLjkpXCIsXG4gICAgICAgIFwiLjUwXCI6IFwicmdiYSgyNDEsIDE5NiwgMTUsICAuOSlcIixcbiAgICAgICAgXCIuNzVcIjogXCJyZ2JhKDIzMCwgMTI2LCAzNCwgIC45KVwiLFxuICAgICAgICBcIjEuMFwiOiBcInJnYmEoMjExLCA4NCwgIDAsICAgLjkpXCIsXG4gICAgICB9LFxuICAgICAgc2hhZG93Qmx1cjogMTAsXG4gICAgICBzaGFkb3dDb2xvcjogXCJyZ2JhKDAsICAgMCwgICAwLCAgIC42KVwiLFxuICAgICAgY2xhc3NOYW1lOiBudWxsLFxuICAgIH0sXG4gICAgcmVwYWludCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIGNhbnZhcy53aWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuICAgICAgY2FudmFzLmhlaWdodCA9IG9wdGlvbnMuYmFyVGhpY2tuZXNzICogNTsgLy8gbmVlZCBzcGFjZSBmb3Igc2hhZG93XG5cbiAgICAgIHZhciBjdHggPSBjYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xuICAgICAgY3R4LnNoYWRvd0JsdXIgPSBvcHRpb25zLnNoYWRvd0JsdXI7XG4gICAgICBjdHguc2hhZG93Q29sb3IgPSBvcHRpb25zLnNoYWRvd0NvbG9yO1xuXG4gICAgICB2YXIgbGluZUdyYWRpZW50ID0gY3R4LmNyZWF0ZUxpbmVhckdyYWRpZW50KDAsIDAsIGNhbnZhcy53aWR0aCwgMCk7XG4gICAgICBmb3IgKHZhciBzdG9wIGluIG9wdGlvbnMuYmFyQ29sb3JzKVxuICAgICAgICBsaW5lR3JhZGllbnQuYWRkQ29sb3JTdG9wKHN0b3AsIG9wdGlvbnMuYmFyQ29sb3JzW3N0b3BdKTtcbiAgICAgIGN0eC5saW5lV2lkdGggPSBvcHRpb25zLmJhclRoaWNrbmVzcztcbiAgICAgIGN0eC5iZWdpblBhdGgoKTtcbiAgICAgIGN0eC5tb3ZlVG8oMCwgb3B0aW9ucy5iYXJUaGlja25lc3MgLyAyKTtcbiAgICAgIGN0eC5saW5lVG8oXG4gICAgICAgIE1hdGguY2VpbChjdXJyZW50UHJvZ3Jlc3MgKiBjYW52YXMud2lkdGgpLFxuICAgICAgICBvcHRpb25zLmJhclRoaWNrbmVzcyAvIDJcbiAgICAgICk7XG4gICAgICBjdHguc3Ryb2tlU3R5bGUgPSBsaW5lR3JhZGllbnQ7XG4gICAgICBjdHguc3Ryb2tlKCk7XG4gICAgfSxcbiAgICBjcmVhdGVDYW52YXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiY2FudmFzXCIpO1xuICAgICAgdmFyIHN0eWxlID0gY2FudmFzLnN0eWxlO1xuICAgICAgc3R5bGUucG9zaXRpb24gPSBcImZpeGVkXCI7XG4gICAgICBzdHlsZS50b3AgPSBzdHlsZS5sZWZ0ID0gc3R5bGUucmlnaHQgPSBzdHlsZS5tYXJnaW4gPSBzdHlsZS5wYWRkaW5nID0gMDtcbiAgICAgIHN0eWxlLnpJbmRleCA9IDEwMDAwMTtcbiAgICAgIHN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICAgIGlmIChvcHRpb25zLmNsYXNzTmFtZSkgY2FudmFzLmNsYXNzTGlzdC5hZGQob3B0aW9ucy5jbGFzc05hbWUpO1xuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgICAgYWRkRXZlbnQod2luZG93LCBcInJlc2l6ZVwiLCByZXBhaW50KTtcbiAgICB9LFxuICAgIHRvcGJhciA9IHtcbiAgICAgIGNvbmZpZzogZnVuY3Rpb24gKG9wdHMpIHtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIG9wdHMpXG4gICAgICAgICAgaWYgKG9wdGlvbnMuaGFzT3duUHJvcGVydHkoa2V5KSkgb3B0aW9uc1trZXldID0gb3B0c1trZXldO1xuICAgICAgfSxcbiAgICAgIHNob3c6IGZ1bmN0aW9uIChkZWxheSkge1xuICAgICAgICBpZiAoc2hvd2luZykgcmV0dXJuO1xuICAgICAgICBpZiAoZGVsYXkpIHtcbiAgICAgICAgICBpZiAoZGVsYXlUaW1lcklkKSByZXR1cm47XG4gICAgICAgICAgZGVsYXlUaW1lcklkID0gc2V0VGltZW91dCgoKSA9PiB0b3BiYXIuc2hvdygpLCBkZWxheSk7XG4gICAgICAgIH0gZWxzZSAge1xuICAgICAgICAgIHNob3dpbmcgPSB0cnVlO1xuICAgICAgICAgIGlmIChmYWRlVGltZXJJZCAhPT0gbnVsbCkgd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lKGZhZGVUaW1lcklkKTtcbiAgICAgICAgICBpZiAoIWNhbnZhcykgY3JlYXRlQ2FudmFzKCk7XG4gICAgICAgICAgY2FudmFzLnN0eWxlLm9wYWNpdHkgPSAxO1xuICAgICAgICAgIGNhbnZhcy5zdHlsZS5kaXNwbGF5ID0gXCJibG9ja1wiO1xuICAgICAgICAgIHRvcGJhci5wcm9ncmVzcygwKTtcbiAgICAgICAgICBpZiAob3B0aW9ucy5hdXRvUnVuKSB7XG4gICAgICAgICAgICAoZnVuY3Rpb24gbG9vcCgpIHtcbiAgICAgICAgICAgICAgcHJvZ3Jlc3NUaW1lcklkID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShsb29wKTtcbiAgICAgICAgICAgICAgdG9wYmFyLnByb2dyZXNzKFxuICAgICAgICAgICAgICAgIFwiK1wiICsgMC4wNSAqIE1hdGgucG93KDEgLSBNYXRoLnNxcnQoY3VycmVudFByb2dyZXNzKSwgMilcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcHJvZ3Jlc3M6IGZ1bmN0aW9uICh0bykge1xuICAgICAgICBpZiAodHlwZW9mIHRvID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gY3VycmVudFByb2dyZXNzO1xuICAgICAgICBpZiAodHlwZW9mIHRvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgdG8gPVxuICAgICAgICAgICAgKHRvLmluZGV4T2YoXCIrXCIpID49IDAgfHwgdG8uaW5kZXhPZihcIi1cIikgPj0gMFxuICAgICAgICAgICAgICA/IGN1cnJlbnRQcm9ncmVzc1xuICAgICAgICAgICAgICA6IDApICsgcGFyc2VGbG9hdCh0byk7XG4gICAgICAgIH1cbiAgICAgICAgY3VycmVudFByb2dyZXNzID0gdG8gPiAxID8gMSA6IHRvO1xuICAgICAgICByZXBhaW50KCk7XG4gICAgICAgIHJldHVybiBjdXJyZW50UHJvZ3Jlc3M7XG4gICAgICB9LFxuICAgICAgaGlkZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBjbGVhclRpbWVvdXQoZGVsYXlUaW1lcklkKTtcbiAgICAgICAgZGVsYXlUaW1lcklkID0gbnVsbDtcbiAgICAgICAgaWYgKCFzaG93aW5nKSByZXR1cm47XG4gICAgICAgIHNob3dpbmcgPSBmYWxzZTtcbiAgICAgICAgaWYgKHByb2dyZXNzVGltZXJJZCAhPSBudWxsKSB7XG4gICAgICAgICAgd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lKHByb2dyZXNzVGltZXJJZCk7XG4gICAgICAgICAgcHJvZ3Jlc3NUaW1lcklkID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICAoZnVuY3Rpb24gbG9vcCgpIHtcbiAgICAgICAgICBpZiAodG9wYmFyLnByb2dyZXNzKFwiKy4xXCIpID49IDEpIHtcbiAgICAgICAgICAgIGNhbnZhcy5zdHlsZS5vcGFjaXR5IC09IDAuMDU7XG4gICAgICAgICAgICBpZiAoY2FudmFzLnN0eWxlLm9wYWNpdHkgPD0gMC4wNSkge1xuICAgICAgICAgICAgICBjYW52YXMuc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiO1xuICAgICAgICAgICAgICBmYWRlVGltZXJJZCA9IG51bGw7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgZmFkZVRpbWVySWQgPSB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKGxvb3ApO1xuICAgICAgICB9KSgpO1xuICAgICAgfSxcbiAgICB9O1xuXG4gIGlmICh0eXBlb2YgbW9kdWxlID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUuZXhwb3J0cyA9PT0gXCJvYmplY3RcIikge1xuICAgIG1vZHVsZS5leHBvcnRzID0gdG9wYmFyO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSB7XG4gICAgZGVmaW5lKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0b3BiYXI7XG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgdGhpcy50b3BiYXIgPSB0b3BiYXI7XG4gIH1cbn0uY2FsbCh0aGlzLCB3aW5kb3csIGRvY3VtZW50KSk7XG4iLCAiXCJ1c2Ugc3RyaWN0XCI7XG5cbihmdW5jdGlvbigpIHtcbiAgdmFyIFBvbHlmaWxsRXZlbnQgPSBldmVudENvbnN0cnVjdG9yKCk7XG5cbiAgZnVuY3Rpb24gZXZlbnRDb25zdHJ1Y3RvcigpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdy5DdXN0b21FdmVudCA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gd2luZG93LkN1c3RvbUV2ZW50O1xuICAgIC8vIElFPD05IFN1cHBvcnRcbiAgICBmdW5jdGlvbiBDdXN0b21FdmVudChldmVudCwgcGFyYW1zKSB7XG4gICAgICBwYXJhbXMgPSBwYXJhbXMgfHwge2J1YmJsZXM6IGZhbHNlLCBjYW5jZWxhYmxlOiBmYWxzZSwgZGV0YWlsOiB1bmRlZmluZWR9O1xuICAgICAgdmFyIGV2dCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KCdDdXN0b21FdmVudCcpO1xuICAgICAgZXZ0LmluaXRDdXN0b21FdmVudChldmVudCwgcGFyYW1zLmJ1YmJsZXMsIHBhcmFtcy5jYW5jZWxhYmxlLCBwYXJhbXMuZGV0YWlsKTtcbiAgICAgIHJldHVybiBldnQ7XG4gICAgfVxuICAgIEN1c3RvbUV2ZW50LnByb3RvdHlwZSA9IHdpbmRvdy5FdmVudC5wcm90b3R5cGU7XG4gICAgcmV0dXJuIEN1c3RvbUV2ZW50O1xuICB9XG5cbiAgZnVuY3Rpb24gYnVpbGRIaWRkZW5JbnB1dChuYW1lLCB2YWx1ZSkge1xuICAgIHZhciBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiKTtcbiAgICBpbnB1dC50eXBlID0gXCJoaWRkZW5cIjtcbiAgICBpbnB1dC5uYW1lID0gbmFtZTtcbiAgICBpbnB1dC52YWx1ZSA9IHZhbHVlO1xuICAgIHJldHVybiBpbnB1dDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGhhbmRsZUNsaWNrKGVsZW1lbnQsIHRhcmdldE1vZGlmaWVyS2V5KSB7XG4gICAgdmFyIHRvID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXRvXCIpLFxuICAgICAgICBtZXRob2QgPSBidWlsZEhpZGRlbklucHV0KFwiX21ldGhvZFwiLCBlbGVtZW50LmdldEF0dHJpYnV0ZShcImRhdGEtbWV0aG9kXCIpKSxcbiAgICAgICAgY3NyZiA9IGJ1aWxkSGlkZGVuSW5wdXQoXCJfY3NyZl90b2tlblwiLCBlbGVtZW50LmdldEF0dHJpYnV0ZShcImRhdGEtY3NyZlwiKSksXG4gICAgICAgIGZvcm0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZm9ybVwiKSxcbiAgICAgICAgc3VibWl0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImlucHV0XCIpLFxuICAgICAgICB0YXJnZXQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZShcInRhcmdldFwiKTtcblxuICAgIGZvcm0ubWV0aG9kID0gKGVsZW1lbnQuZ2V0QXR0cmlidXRlKFwiZGF0YS1tZXRob2RcIikgPT09IFwiZ2V0XCIpID8gXCJnZXRcIiA6IFwicG9zdFwiO1xuICAgIGZvcm0uYWN0aW9uID0gdG87XG4gICAgZm9ybS5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG5cbiAgICBpZiAodGFyZ2V0KSBmb3JtLnRhcmdldCA9IHRhcmdldDtcbiAgICBlbHNlIGlmICh0YXJnZXRNb2RpZmllcktleSkgZm9ybS50YXJnZXQgPSBcIl9ibGFua1wiO1xuXG4gICAgZm9ybS5hcHBlbmRDaGlsZChjc3JmKTtcbiAgICBmb3JtLmFwcGVuZENoaWxkKG1ldGhvZCk7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChmb3JtKTtcblxuICAgIC8vIEluc2VydCBhIGJ1dHRvbiBhbmQgY2xpY2sgaXQgaW5zdGVhZCBvZiB1c2luZyBgZm9ybS5zdWJtaXRgXG4gICAgLy8gYmVjYXVzZSB0aGUgYHN1Ym1pdGAgZnVuY3Rpb24gZG9lcyBub3QgZW1pdCBhIGBzdWJtaXRgIGV2ZW50LlxuICAgIHN1Ym1pdC50eXBlID0gXCJzdWJtaXRcIjtcbiAgICBmb3JtLmFwcGVuZENoaWxkKHN1Ym1pdCk7XG4gICAgc3VibWl0LmNsaWNrKCk7XG4gIH1cblxuICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGZ1bmN0aW9uKGUpIHtcbiAgICB2YXIgZWxlbWVudCA9IGUudGFyZ2V0O1xuICAgIGlmIChlLmRlZmF1bHRQcmV2ZW50ZWQpIHJldHVybjtcblxuICAgIHdoaWxlIChlbGVtZW50ICYmIGVsZW1lbnQuZ2V0QXR0cmlidXRlKSB7XG4gICAgICB2YXIgcGhvZW5peExpbmtFdmVudCA9IG5ldyBQb2x5ZmlsbEV2ZW50KCdwaG9lbml4LmxpbmsuY2xpY2snLCB7XG4gICAgICAgIFwiYnViYmxlc1wiOiB0cnVlLCBcImNhbmNlbGFibGVcIjogdHJ1ZVxuICAgICAgfSk7XG5cbiAgICAgIGlmICghZWxlbWVudC5kaXNwYXRjaEV2ZW50KHBob2VuaXhMaW5rRXZlbnQpKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJkYXRhLW1ldGhvZFwiKSAmJiBlbGVtZW50LmdldEF0dHJpYnV0ZShcImRhdGEtdG9cIikpIHtcbiAgICAgICAgaGFuZGxlQ2xpY2soZWxlbWVudCwgZS5tZXRhS2V5IHx8IGUuc2hpZnRLZXkpO1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVsZW1lbnQgPSBlbGVtZW50LnBhcmVudE5vZGU7XG4gICAgICB9XG4gICAgfVxuICB9LCBmYWxzZSk7XG5cbiAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Bob2VuaXgubGluay5jbGljaycsIGZ1bmN0aW9uIChlKSB7XG4gICAgdmFyIG1lc3NhZ2UgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoXCJkYXRhLWNvbmZpcm1cIik7XG4gICAgaWYobWVzc2FnZSAmJiAhd2luZG93LmNvbmZpcm0obWVzc2FnZSkpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gIH0sIGZhbHNlKTtcbn0pKCk7XG4iLCAiLy8gd3JhcHMgdmFsdWUgaW4gY2xvc3VyZSBvciByZXR1cm5zIGNsb3N1cmVcbmV4cG9ydCBsZXQgY2xvc3VyZSA9ICh2YWx1ZSkgPT4ge1xuICBpZih0eXBlb2YgdmFsdWUgPT09IFwiZnVuY3Rpb25cIil7XG4gICAgcmV0dXJuIHZhbHVlXG4gIH0gZWxzZSB7XG4gICAgbGV0IGNsb3N1cmUgPSBmdW5jdGlvbiAoKXsgcmV0dXJuIHZhbHVlIH1cbiAgICByZXR1cm4gY2xvc3VyZVxuICB9XG59XG4iLCAiZXhwb3J0IGNvbnN0IGdsb2JhbFNlbGYgPSB0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYgOiBudWxsXG5leHBvcnQgY29uc3QgcGh4V2luZG93ID0gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IG51bGxcbmV4cG9ydCBjb25zdCBnbG9iYWwgPSBnbG9iYWxTZWxmIHx8IHBoeFdpbmRvdyB8fCBnbG9iYWxcbmV4cG9ydCBjb25zdCBERUZBVUxUX1ZTTiA9IFwiMi4wLjBcIlxuZXhwb3J0IGNvbnN0IFNPQ0tFVF9TVEFURVMgPSB7Y29ubmVjdGluZzogMCwgb3BlbjogMSwgY2xvc2luZzogMiwgY2xvc2VkOiAzfVxuZXhwb3J0IGNvbnN0IERFRkFVTFRfVElNRU9VVCA9IDEwMDAwXG5leHBvcnQgY29uc3QgV1NfQ0xPU0VfTk9STUFMID0gMTAwMFxuZXhwb3J0IGNvbnN0IENIQU5ORUxfU1RBVEVTID0ge1xuICBjbG9zZWQ6IFwiY2xvc2VkXCIsXG4gIGVycm9yZWQ6IFwiZXJyb3JlZFwiLFxuICBqb2luZWQ6IFwiam9pbmVkXCIsXG4gIGpvaW5pbmc6IFwiam9pbmluZ1wiLFxuICBsZWF2aW5nOiBcImxlYXZpbmdcIixcbn1cbmV4cG9ydCBjb25zdCBDSEFOTkVMX0VWRU5UUyA9IHtcbiAgY2xvc2U6IFwicGh4X2Nsb3NlXCIsXG4gIGVycm9yOiBcInBoeF9lcnJvclwiLFxuICBqb2luOiBcInBoeF9qb2luXCIsXG4gIHJlcGx5OiBcInBoeF9yZXBseVwiLFxuICBsZWF2ZTogXCJwaHhfbGVhdmVcIlxufVxuXG5leHBvcnQgY29uc3QgVFJBTlNQT1JUUyA9IHtcbiAgbG9uZ3BvbGw6IFwibG9uZ3BvbGxcIixcbiAgd2Vic29ja2V0OiBcIndlYnNvY2tldFwiXG59XG5leHBvcnQgY29uc3QgWEhSX1NUQVRFUyA9IHtcbiAgY29tcGxldGU6IDRcbn1cbiIsICIvKipcbiAqIEluaXRpYWxpemVzIHRoZSBQdXNoXG4gKiBAcGFyYW0ge0NoYW5uZWx9IGNoYW5uZWwgLSBUaGUgQ2hhbm5lbFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IC0gVGhlIGV2ZW50LCBmb3IgZXhhbXBsZSBgXCJwaHhfam9pblwiYFxuICogQHBhcmFtIHtPYmplY3R9IHBheWxvYWQgLSBUaGUgcGF5bG9hZCwgZm9yIGV4YW1wbGUgYHt1c2VyX2lkOiAxMjN9YFxuICogQHBhcmFtIHtudW1iZXJ9IHRpbWVvdXQgLSBUaGUgcHVzaCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kc1xuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBQdXNoIHtcbiAgY29uc3RydWN0b3IoY2hhbm5lbCwgZXZlbnQsIHBheWxvYWQsIHRpbWVvdXQpe1xuICAgIHRoaXMuY2hhbm5lbCA9IGNoYW5uZWxcbiAgICB0aGlzLmV2ZW50ID0gZXZlbnRcbiAgICB0aGlzLnBheWxvYWQgPSBwYXlsb2FkIHx8IGZ1bmN0aW9uICgpeyByZXR1cm4ge30gfVxuICAgIHRoaXMucmVjZWl2ZWRSZXNwID0gbnVsbFxuICAgIHRoaXMudGltZW91dCA9IHRpbWVvdXRcbiAgICB0aGlzLnRpbWVvdXRUaW1lciA9IG51bGxcbiAgICB0aGlzLnJlY0hvb2tzID0gW11cbiAgICB0aGlzLnNlbnQgPSBmYWxzZVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lb3V0XG4gICAqL1xuICByZXNlbmQodGltZW91dCl7XG4gICAgdGhpcy50aW1lb3V0ID0gdGltZW91dFxuICAgIHRoaXMucmVzZXQoKVxuICAgIHRoaXMuc2VuZCgpXG4gIH1cblxuICAvKipcbiAgICpcbiAgICovXG4gIHNlbmQoKXtcbiAgICBpZih0aGlzLmhhc1JlY2VpdmVkKFwidGltZW91dFwiKSl7IHJldHVybiB9XG4gICAgdGhpcy5zdGFydFRpbWVvdXQoKVxuICAgIHRoaXMuc2VudCA9IHRydWVcbiAgICB0aGlzLmNoYW5uZWwuc29ja2V0LnB1c2goe1xuICAgICAgdG9waWM6IHRoaXMuY2hhbm5lbC50b3BpYyxcbiAgICAgIGV2ZW50OiB0aGlzLmV2ZW50LFxuICAgICAgcGF5bG9hZDogdGhpcy5wYXlsb2FkKCksXG4gICAgICByZWY6IHRoaXMucmVmLFxuICAgICAgam9pbl9yZWY6IHRoaXMuY2hhbm5lbC5qb2luUmVmKClcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSB7Kn0gc3RhdHVzXG4gICAqIEBwYXJhbSB7Kn0gY2FsbGJhY2tcbiAgICovXG4gIHJlY2VpdmUoc3RhdHVzLCBjYWxsYmFjayl7XG4gICAgaWYodGhpcy5oYXNSZWNlaXZlZChzdGF0dXMpKXtcbiAgICAgIGNhbGxiYWNrKHRoaXMucmVjZWl2ZWRSZXNwLnJlc3BvbnNlKVxuICAgIH1cblxuICAgIHRoaXMucmVjSG9va3MucHVzaCh7c3RhdHVzLCBjYWxsYmFja30pXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcmVzZXQoKXtcbiAgICB0aGlzLmNhbmNlbFJlZkV2ZW50KClcbiAgICB0aGlzLnJlZiA9IG51bGxcbiAgICB0aGlzLnJlZkV2ZW50ID0gbnVsbFxuICAgIHRoaXMucmVjZWl2ZWRSZXNwID0gbnVsbFxuICAgIHRoaXMuc2VudCA9IGZhbHNlXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIG1hdGNoUmVjZWl2ZSh7c3RhdHVzLCByZXNwb25zZSwgX3JlZn0pe1xuICAgIHRoaXMucmVjSG9va3MuZmlsdGVyKGggPT4gaC5zdGF0dXMgPT09IHN0YXR1cylcbiAgICAgIC5mb3JFYWNoKGggPT4gaC5jYWxsYmFjayhyZXNwb25zZSkpXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGNhbmNlbFJlZkV2ZW50KCl7XG4gICAgaWYoIXRoaXMucmVmRXZlbnQpeyByZXR1cm4gfVxuICAgIHRoaXMuY2hhbm5lbC5vZmYodGhpcy5yZWZFdmVudClcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY2FuY2VsVGltZW91dCgpe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRUaW1lcilcbiAgICB0aGlzLnRpbWVvdXRUaW1lciA9IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgc3RhcnRUaW1lb3V0KCl7XG4gICAgaWYodGhpcy50aW1lb3V0VGltZXIpeyB0aGlzLmNhbmNlbFRpbWVvdXQoKSB9XG4gICAgdGhpcy5yZWYgPSB0aGlzLmNoYW5uZWwuc29ja2V0Lm1ha2VSZWYoKVxuICAgIHRoaXMucmVmRXZlbnQgPSB0aGlzLmNoYW5uZWwucmVwbHlFdmVudE5hbWUodGhpcy5yZWYpXG5cbiAgICB0aGlzLmNoYW5uZWwub24odGhpcy5yZWZFdmVudCwgcGF5bG9hZCA9PiB7XG4gICAgICB0aGlzLmNhbmNlbFJlZkV2ZW50KClcbiAgICAgIHRoaXMuY2FuY2VsVGltZW91dCgpXG4gICAgICB0aGlzLnJlY2VpdmVkUmVzcCA9IHBheWxvYWRcbiAgICAgIHRoaXMubWF0Y2hSZWNlaXZlKHBheWxvYWQpXG4gICAgfSlcblxuICAgIHRoaXMudGltZW91dFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnRyaWdnZXIoXCJ0aW1lb3V0XCIsIHt9KVxuICAgIH0sIHRoaXMudGltZW91dClcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaGFzUmVjZWl2ZWQoc3RhdHVzKXtcbiAgICByZXR1cm4gdGhpcy5yZWNlaXZlZFJlc3AgJiYgdGhpcy5yZWNlaXZlZFJlc3Auc3RhdHVzID09PSBzdGF0dXNcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgdHJpZ2dlcihzdGF0dXMsIHJlc3BvbnNlKXtcbiAgICB0aGlzLmNoYW5uZWwudHJpZ2dlcih0aGlzLnJlZkV2ZW50LCB7c3RhdHVzLCByZXNwb25zZX0pXG4gIH1cbn1cbiIsICIvKipcbiAqXG4gKiBDcmVhdGVzIGEgdGltZXIgdGhhdCBhY2NlcHRzIGEgYHRpbWVyQ2FsY2AgZnVuY3Rpb24gdG8gcGVyZm9ybVxuICogY2FsY3VsYXRlZCB0aW1lb3V0IHJldHJpZXMsIHN1Y2ggYXMgZXhwb25lbnRpYWwgYmFja29mZi5cbiAqXG4gKiBAZXhhbXBsZVxuICogbGV0IHJlY29ubmVjdFRpbWVyID0gbmV3IFRpbWVyKCgpID0+IHRoaXMuY29ubmVjdCgpLCBmdW5jdGlvbih0cmllcyl7XG4gKiAgIHJldHVybiBbMTAwMCwgNTAwMCwgMTAwMDBdW3RyaWVzIC0gMV0gfHwgMTAwMDBcbiAqIH0pXG4gKiByZWNvbm5lY3RUaW1lci5zY2hlZHVsZVRpbWVvdXQoKSAvLyBmaXJlcyBhZnRlciAxMDAwXG4gKiByZWNvbm5lY3RUaW1lci5zY2hlZHVsZVRpbWVvdXQoKSAvLyBmaXJlcyBhZnRlciA1MDAwXG4gKiByZWNvbm5lY3RUaW1lci5yZXNldCgpXG4gKiByZWNvbm5lY3RUaW1lci5zY2hlZHVsZVRpbWVvdXQoKSAvLyBmaXJlcyBhZnRlciAxMDAwXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHRpbWVyQ2FsY1xuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUaW1lciB7XG4gIGNvbnN0cnVjdG9yKGNhbGxiYWNrLCB0aW1lckNhbGMpe1xuICAgIHRoaXMuY2FsbGJhY2sgPSBjYWxsYmFja1xuICAgIHRoaXMudGltZXJDYWxjID0gdGltZXJDYWxjXG4gICAgdGhpcy50aW1lciA9IG51bGxcbiAgICB0aGlzLnRyaWVzID0gMFxuICB9XG5cbiAgcmVzZXQoKXtcbiAgICB0aGlzLnRyaWVzID0gMFxuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyKVxuICB9XG5cbiAgLyoqXG4gICAqIENhbmNlbHMgYW55IHByZXZpb3VzIHNjaGVkdWxlVGltZW91dCBhbmQgc2NoZWR1bGVzIGNhbGxiYWNrXG4gICAqL1xuICBzY2hlZHVsZVRpbWVvdXQoKXtcbiAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lcilcblxuICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudHJpZXMgPSB0aGlzLnRyaWVzICsgMVxuICAgICAgdGhpcy5jYWxsYmFjaygpXG4gICAgfSwgdGhpcy50aW1lckNhbGModGhpcy50cmllcyArIDEpKVxuICB9XG59XG4iLCAiaW1wb3J0IHtjbG9zdXJlfSBmcm9tIFwiLi91dGlsc1wiXG5pbXBvcnQge1xuICBDSEFOTkVMX0VWRU5UUyxcbiAgQ0hBTk5FTF9TVEFURVMsXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCBQdXNoIGZyb20gXCIuL3B1c2hcIlxuaW1wb3J0IFRpbWVyIGZyb20gXCIuL3RpbWVyXCJcblxuLyoqXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRvcGljXG4gKiBAcGFyYW0geyhPYmplY3R8ZnVuY3Rpb24pfSBwYXJhbXNcbiAqIEBwYXJhbSB7U29ja2V0fSBzb2NrZXRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ2hhbm5lbCB7XG4gIGNvbnN0cnVjdG9yKHRvcGljLCBwYXJhbXMsIHNvY2tldCl7XG4gICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmNsb3NlZFxuICAgIHRoaXMudG9waWMgPSB0b3BpY1xuICAgIHRoaXMucGFyYW1zID0gY2xvc3VyZShwYXJhbXMgfHwge30pXG4gICAgdGhpcy5zb2NrZXQgPSBzb2NrZXRcbiAgICB0aGlzLmJpbmRpbmdzID0gW11cbiAgICB0aGlzLmJpbmRpbmdSZWYgPSAwXG4gICAgdGhpcy50aW1lb3V0ID0gdGhpcy5zb2NrZXQudGltZW91dFxuICAgIHRoaXMuam9pbmVkT25jZSA9IGZhbHNlXG4gICAgdGhpcy5qb2luUHVzaCA9IG5ldyBQdXNoKHRoaXMsIENIQU5ORUxfRVZFTlRTLmpvaW4sIHRoaXMucGFyYW1zLCB0aGlzLnRpbWVvdXQpXG4gICAgdGhpcy5wdXNoQnVmZmVyID0gW11cbiAgICB0aGlzLnN0YXRlQ2hhbmdlUmVmcyA9IFtdXG5cbiAgICB0aGlzLnJlam9pblRpbWVyID0gbmV3IFRpbWVyKCgpID0+IHtcbiAgICAgIGlmKHRoaXMuc29ja2V0LmlzQ29ubmVjdGVkKCkpeyB0aGlzLnJlam9pbigpIH1cbiAgICB9LCB0aGlzLnNvY2tldC5yZWpvaW5BZnRlck1zKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VSZWZzLnB1c2godGhpcy5zb2NrZXQub25FcnJvcigoKSA9PiB0aGlzLnJlam9pblRpbWVyLnJlc2V0KCkpKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VSZWZzLnB1c2godGhpcy5zb2NrZXQub25PcGVuKCgpID0+IHtcbiAgICAgIHRoaXMucmVqb2luVGltZXIucmVzZXQoKVxuICAgICAgaWYodGhpcy5pc0Vycm9yZWQoKSl7IHRoaXMucmVqb2luKCkgfVxuICAgIH0pXG4gICAgKVxuICAgIHRoaXMuam9pblB1c2gucmVjZWl2ZShcIm9rXCIsICgpID0+IHtcbiAgICAgIHRoaXMuc3RhdGUgPSBDSEFOTkVMX1NUQVRFUy5qb2luZWRcbiAgICAgIHRoaXMucmVqb2luVGltZXIucmVzZXQoKVxuICAgICAgdGhpcy5wdXNoQnVmZmVyLmZvckVhY2gocHVzaEV2ZW50ID0+IHB1c2hFdmVudC5zZW5kKCkpXG4gICAgICB0aGlzLnB1c2hCdWZmZXIgPSBbXVxuICAgIH0pXG4gICAgdGhpcy5qb2luUHVzaC5yZWNlaXZlKFwiZXJyb3JcIiwgKCkgPT4ge1xuICAgICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmVycm9yZWRcbiAgICAgIGlmKHRoaXMuc29ja2V0LmlzQ29ubmVjdGVkKCkpeyB0aGlzLnJlam9pblRpbWVyLnNjaGVkdWxlVGltZW91dCgpIH1cbiAgICB9KVxuICAgIHRoaXMub25DbG9zZSgoKSA9PiB7XG4gICAgICB0aGlzLnJlam9pblRpbWVyLnJlc2V0KClcbiAgICAgIGlmKHRoaXMuc29ja2V0Lmhhc0xvZ2dlcigpKSB0aGlzLnNvY2tldC5sb2coXCJjaGFubmVsXCIsIGBjbG9zZSAke3RoaXMudG9waWN9ICR7dGhpcy5qb2luUmVmKCl9YClcbiAgICAgIHRoaXMuc3RhdGUgPSBDSEFOTkVMX1NUQVRFUy5jbG9zZWRcbiAgICAgIHRoaXMuc29ja2V0LnJlbW92ZSh0aGlzKVxuICAgIH0pXG4gICAgdGhpcy5vbkVycm9yKHJlYXNvbiA9PiB7XG4gICAgICBpZih0aGlzLnNvY2tldC5oYXNMb2dnZXIoKSkgdGhpcy5zb2NrZXQubG9nKFwiY2hhbm5lbFwiLCBgZXJyb3IgJHt0aGlzLnRvcGljfWAsIHJlYXNvbilcbiAgICAgIGlmKHRoaXMuaXNKb2luaW5nKCkpeyB0aGlzLmpvaW5QdXNoLnJlc2V0KCkgfVxuICAgICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmVycm9yZWRcbiAgICAgIGlmKHRoaXMuc29ja2V0LmlzQ29ubmVjdGVkKCkpeyB0aGlzLnJlam9pblRpbWVyLnNjaGVkdWxlVGltZW91dCgpIH1cbiAgICB9KVxuICAgIHRoaXMuam9pblB1c2gucmVjZWl2ZShcInRpbWVvdXRcIiwgKCkgPT4ge1xuICAgICAgaWYodGhpcy5zb2NrZXQuaGFzTG9nZ2VyKCkpIHRoaXMuc29ja2V0LmxvZyhcImNoYW5uZWxcIiwgYHRpbWVvdXQgJHt0aGlzLnRvcGljfSAoJHt0aGlzLmpvaW5SZWYoKX0pYCwgdGhpcy5qb2luUHVzaC50aW1lb3V0KVxuICAgICAgbGV0IGxlYXZlUHVzaCA9IG5ldyBQdXNoKHRoaXMsIENIQU5ORUxfRVZFTlRTLmxlYXZlLCBjbG9zdXJlKHt9KSwgdGhpcy50aW1lb3V0KVxuICAgICAgbGVhdmVQdXNoLnNlbmQoKVxuICAgICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmVycm9yZWRcbiAgICAgIHRoaXMuam9pblB1c2gucmVzZXQoKVxuICAgICAgaWYodGhpcy5zb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMucmVqb2luVGltZXIuc2NoZWR1bGVUaW1lb3V0KCkgfVxuICAgIH0pXG4gICAgdGhpcy5vbihDSEFOTkVMX0VWRU5UUy5yZXBseSwgKHBheWxvYWQsIHJlZikgPT4ge1xuICAgICAgdGhpcy50cmlnZ2VyKHRoaXMucmVwbHlFdmVudE5hbWUocmVmKSwgcGF5bG9hZClcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEpvaW4gdGhlIGNoYW5uZWxcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSB0aW1lb3V0XG4gICAqIEByZXR1cm5zIHtQdXNofVxuICAgKi9cbiAgam9pbih0aW1lb3V0ID0gdGhpcy50aW1lb3V0KXtcbiAgICBpZih0aGlzLmpvaW5lZE9uY2Upe1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwidHJpZWQgdG8gam9pbiBtdWx0aXBsZSB0aW1lcy4gJ2pvaW4nIGNhbiBvbmx5IGJlIGNhbGxlZCBhIHNpbmdsZSB0aW1lIHBlciBjaGFubmVsIGluc3RhbmNlXCIpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudGltZW91dCA9IHRpbWVvdXRcbiAgICAgIHRoaXMuam9pbmVkT25jZSA9IHRydWVcbiAgICAgIHRoaXMucmVqb2luKClcbiAgICAgIHJldHVybiB0aGlzLmpvaW5QdXNoXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhvb2sgaW50byBjaGFubmVsIGNsb3NlXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAqL1xuICBvbkNsb3NlKGNhbGxiYWNrKXtcbiAgICB0aGlzLm9uKENIQU5ORUxfRVZFTlRTLmNsb3NlLCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBIb29rIGludG8gY2hhbm5lbCBlcnJvcnNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICovXG4gIG9uRXJyb3IoY2FsbGJhY2spe1xuICAgIHJldHVybiB0aGlzLm9uKENIQU5ORUxfRVZFTlRTLmVycm9yLCByZWFzb24gPT4gY2FsbGJhY2socmVhc29uKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmVzIG9uIGNoYW5uZWwgZXZlbnRzXG4gICAqXG4gICAqIFN1YnNjcmlwdGlvbiByZXR1cm5zIGEgcmVmIGNvdW50ZXIsIHdoaWNoIGNhbiBiZSB1c2VkIGxhdGVyIHRvXG4gICAqIHVuc3Vic2NyaWJlIHRoZSBleGFjdCBldmVudCBsaXN0ZW5lclxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBjb25zdCByZWYxID0gY2hhbm5lbC5vbihcImV2ZW50XCIsIGRvX3N0dWZmKVxuICAgKiBjb25zdCByZWYyID0gY2hhbm5lbC5vbihcImV2ZW50XCIsIGRvX290aGVyX3N0dWZmKVxuICAgKiBjaGFubmVsLm9mZihcImV2ZW50XCIsIHJlZjEpXG4gICAqIC8vIFNpbmNlIHVuc3Vic2NyaXB0aW9uLCBkb19zdHVmZiB3b24ndCBmaXJlLFxuICAgKiAvLyB3aGlsZSBkb19vdGhlcl9zdHVmZiB3aWxsIGtlZXAgZmlyaW5nIG9uIHRoZSBcImV2ZW50XCJcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50XG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAqIEByZXR1cm5zIHtpbnRlZ2VyfSByZWZcbiAgICovXG4gIG9uKGV2ZW50LCBjYWxsYmFjayl7XG4gICAgbGV0IHJlZiA9IHRoaXMuYmluZGluZ1JlZisrXG4gICAgdGhpcy5iaW5kaW5ncy5wdXNoKHtldmVudCwgcmVmLCBjYWxsYmFja30pXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgLyoqXG4gICAqIFVuc3Vic2NyaWJlcyBvZmYgb2YgY2hhbm5lbCBldmVudHNcbiAgICpcbiAgICogVXNlIHRoZSByZWYgcmV0dXJuZWQgZnJvbSBhIGNoYW5uZWwub24oKSB0byB1bnN1YnNjcmliZSBvbmVcbiAgICogaGFuZGxlciwgb3IgcGFzcyBub3RoaW5nIGZvciB0aGUgcmVmIHRvIHVuc3Vic2NyaWJlIGFsbFxuICAgKiBoYW5kbGVycyBmb3IgdGhlIGdpdmVuIGV2ZW50LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAvLyBVbnN1YnNjcmliZSB0aGUgZG9fc3R1ZmYgaGFuZGxlclxuICAgKiBjb25zdCByZWYxID0gY2hhbm5lbC5vbihcImV2ZW50XCIsIGRvX3N0dWZmKVxuICAgKiBjaGFubmVsLm9mZihcImV2ZW50XCIsIHJlZjEpXG4gICAqXG4gICAqIC8vIFVuc3Vic2NyaWJlIGFsbCBoYW5kbGVycyBmcm9tIGV2ZW50XG4gICAqIGNoYW5uZWwub2ZmKFwiZXZlbnRcIilcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50XG4gICAqIEBwYXJhbSB7aW50ZWdlcn0gcmVmXG4gICAqL1xuICBvZmYoZXZlbnQsIHJlZil7XG4gICAgdGhpcy5iaW5kaW5ncyA9IHRoaXMuYmluZGluZ3MuZmlsdGVyKChiaW5kKSA9PiB7XG4gICAgICByZXR1cm4gIShiaW5kLmV2ZW50ID09PSBldmVudCAmJiAodHlwZW9mIHJlZiA9PT0gXCJ1bmRlZmluZWRcIiB8fCByZWYgPT09IGJpbmQucmVmKSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBjYW5QdXNoKCl7IHJldHVybiB0aGlzLnNvY2tldC5pc0Nvbm5lY3RlZCgpICYmIHRoaXMuaXNKb2luZWQoKSB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIGEgbWVzc2FnZSBgZXZlbnRgIHRvIHBob2VuaXggd2l0aCB0aGUgcGF5bG9hZCBgcGF5bG9hZGAuXG4gICAqIFBob2VuaXggcmVjZWl2ZXMgdGhpcyBpbiB0aGUgYGhhbmRsZV9pbihldmVudCwgcGF5bG9hZCwgc29ja2V0KWBcbiAgICogZnVuY3Rpb24uIGlmIHBob2VuaXggcmVwbGllcyBvciBpdCB0aW1lcyBvdXQgKGRlZmF1bHQgMTAwMDBtcyksXG4gICAqIHRoZW4gb3B0aW9uYWxseSB0aGUgcmVwbHkgY2FuIGJlIHJlY2VpdmVkLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBjaGFubmVsLnB1c2goXCJldmVudFwiKVxuICAgKiAgIC5yZWNlaXZlKFwib2tcIiwgcGF5bG9hZCA9PiBjb25zb2xlLmxvZyhcInBob2VuaXggcmVwbGllZDpcIiwgcGF5bG9hZCkpXG4gICAqICAgLnJlY2VpdmUoXCJlcnJvclwiLCBlcnIgPT4gY29uc29sZS5sb2coXCJwaG9lbml4IGVycm9yZWRcIiwgZXJyKSlcbiAgICogICAucmVjZWl2ZShcInRpbWVvdXRcIiwgKCkgPT4gY29uc29sZS5sb2coXCJ0aW1lZCBvdXQgcHVzaGluZ1wiKSlcbiAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50XG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXlsb2FkXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dF1cbiAgICogQHJldHVybnMge1B1c2h9XG4gICAqL1xuICBwdXNoKGV2ZW50LCBwYXlsb2FkLCB0aW1lb3V0ID0gdGhpcy50aW1lb3V0KXtcbiAgICBwYXlsb2FkID0gcGF5bG9hZCB8fCB7fVxuICAgIGlmKCF0aGlzLmpvaW5lZE9uY2Upe1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB0cmllZCB0byBwdXNoICcke2V2ZW50fScgdG8gJyR7dGhpcy50b3BpY30nIGJlZm9yZSBqb2luaW5nLiBVc2UgY2hhbm5lbC5qb2luKCkgYmVmb3JlIHB1c2hpbmcgZXZlbnRzYClcbiAgICB9XG4gICAgbGV0IHB1c2hFdmVudCA9IG5ldyBQdXNoKHRoaXMsIGV2ZW50LCBmdW5jdGlvbiAoKXsgcmV0dXJuIHBheWxvYWQgfSwgdGltZW91dClcbiAgICBpZih0aGlzLmNhblB1c2goKSl7XG4gICAgICBwdXNoRXZlbnQuc2VuZCgpXG4gICAgfSBlbHNlIHtcbiAgICAgIHB1c2hFdmVudC5zdGFydFRpbWVvdXQoKVxuICAgICAgdGhpcy5wdXNoQnVmZmVyLnB1c2gocHVzaEV2ZW50KVxuICAgIH1cblxuICAgIHJldHVybiBwdXNoRXZlbnRcbiAgfVxuXG4gIC8qKiBMZWF2ZXMgdGhlIGNoYW5uZWxcbiAgICpcbiAgICogVW5zdWJzY3JpYmVzIGZyb20gc2VydmVyIGV2ZW50cywgYW5kXG4gICAqIGluc3RydWN0cyBjaGFubmVsIHRvIHRlcm1pbmF0ZSBvbiBzZXJ2ZXJcbiAgICpcbiAgICogVHJpZ2dlcnMgb25DbG9zZSgpIGhvb2tzXG4gICAqXG4gICAqIFRvIHJlY2VpdmUgbGVhdmUgYWNrbm93bGVkZ2VtZW50cywgdXNlIHRoZSBgcmVjZWl2ZWBcbiAgICogaG9vayB0byBiaW5kIHRvIHRoZSBzZXJ2ZXIgYWNrLCBpZTpcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogY2hhbm5lbC5sZWF2ZSgpLnJlY2VpdmUoXCJva1wiLCAoKSA9PiBhbGVydChcImxlZnQhXCIpIClcbiAgICpcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSB0aW1lb3V0XG4gICAqIEByZXR1cm5zIHtQdXNofVxuICAgKi9cbiAgbGVhdmUodGltZW91dCA9IHRoaXMudGltZW91dCl7XG4gICAgdGhpcy5yZWpvaW5UaW1lci5yZXNldCgpXG4gICAgdGhpcy5qb2luUHVzaC5jYW5jZWxUaW1lb3V0KClcblxuICAgIHRoaXMuc3RhdGUgPSBDSEFOTkVMX1NUQVRFUy5sZWF2aW5nXG4gICAgbGV0IG9uQ2xvc2UgPSAoKSA9PiB7XG4gICAgICBpZih0aGlzLnNvY2tldC5oYXNMb2dnZXIoKSkgdGhpcy5zb2NrZXQubG9nKFwiY2hhbm5lbFwiLCBgbGVhdmUgJHt0aGlzLnRvcGljfWApXG4gICAgICB0aGlzLnRyaWdnZXIoQ0hBTk5FTF9FVkVOVFMuY2xvc2UsIFwibGVhdmVcIilcbiAgICB9XG4gICAgbGV0IGxlYXZlUHVzaCA9IG5ldyBQdXNoKHRoaXMsIENIQU5ORUxfRVZFTlRTLmxlYXZlLCBjbG9zdXJlKHt9KSwgdGltZW91dClcbiAgICBsZWF2ZVB1c2gucmVjZWl2ZShcIm9rXCIsICgpID0+IG9uQ2xvc2UoKSlcbiAgICAgIC5yZWNlaXZlKFwidGltZW91dFwiLCAoKSA9PiBvbkNsb3NlKCkpXG4gICAgbGVhdmVQdXNoLnNlbmQoKVxuICAgIGlmKCF0aGlzLmNhblB1c2goKSl7IGxlYXZlUHVzaC50cmlnZ2VyKFwib2tcIiwge30pIH1cblxuICAgIHJldHVybiBsZWF2ZVB1c2hcbiAgfVxuXG4gIC8qKlxuICAgKiBPdmVycmlkYWJsZSBtZXNzYWdlIGhvb2tcbiAgICpcbiAgICogUmVjZWl2ZXMgYWxsIGV2ZW50cyBmb3Igc3BlY2lhbGl6ZWQgbWVzc2FnZSBoYW5kbGluZ1xuICAgKiBiZWZvcmUgZGlzcGF0Y2hpbmcgdG8gdGhlIGNoYW5uZWwgY2FsbGJhY2tzLlxuICAgKlxuICAgKiBNdXN0IHJldHVybiB0aGUgcGF5bG9hZCwgbW9kaWZpZWQgb3IgdW5tb2RpZmllZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRcbiAgICogQHBhcmFtIHtPYmplY3R9IHBheWxvYWRcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSByZWZcbiAgICogQHJldHVybnMge09iamVjdH1cbiAgICovXG4gIG9uTWVzc2FnZShfZXZlbnQsIHBheWxvYWQsIF9yZWYpeyByZXR1cm4gcGF5bG9hZCB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBpc01lbWJlcih0b3BpYywgZXZlbnQsIHBheWxvYWQsIGpvaW5SZWYpe1xuICAgIGlmKHRoaXMudG9waWMgIT09IHRvcGljKXsgcmV0dXJuIGZhbHNlIH1cblxuICAgIGlmKGpvaW5SZWYgJiYgam9pblJlZiAhPT0gdGhpcy5qb2luUmVmKCkpe1xuICAgICAgaWYodGhpcy5zb2NrZXQuaGFzTG9nZ2VyKCkpIHRoaXMuc29ja2V0LmxvZyhcImNoYW5uZWxcIiwgXCJkcm9wcGluZyBvdXRkYXRlZCBtZXNzYWdlXCIsIHt0b3BpYywgZXZlbnQsIHBheWxvYWQsIGpvaW5SZWZ9KVxuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0cnVlXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBqb2luUmVmKCl7IHJldHVybiB0aGlzLmpvaW5QdXNoLnJlZiB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICByZWpvaW4odGltZW91dCA9IHRoaXMudGltZW91dCl7XG4gICAgaWYodGhpcy5pc0xlYXZpbmcoKSl7IHJldHVybiB9XG4gICAgdGhpcy5zb2NrZXQubGVhdmVPcGVuVG9waWModGhpcy50b3BpYylcbiAgICB0aGlzLnN0YXRlID0gQ0hBTk5FTF9TVEFURVMuam9pbmluZ1xuICAgIHRoaXMuam9pblB1c2gucmVzZW5kKHRpbWVvdXQpXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHRyaWdnZXIoZXZlbnQsIHBheWxvYWQsIHJlZiwgam9pblJlZil7XG4gICAgbGV0IGhhbmRsZWRQYXlsb2FkID0gdGhpcy5vbk1lc3NhZ2UoZXZlbnQsIHBheWxvYWQsIHJlZiwgam9pblJlZilcbiAgICBpZihwYXlsb2FkICYmICFoYW5kbGVkUGF5bG9hZCl7IHRocm93IG5ldyBFcnJvcihcImNoYW5uZWwgb25NZXNzYWdlIGNhbGxiYWNrcyBtdXN0IHJldHVybiB0aGUgcGF5bG9hZCwgbW9kaWZpZWQgb3IgdW5tb2RpZmllZFwiKSB9XG5cbiAgICBsZXQgZXZlbnRCaW5kaW5ncyA9IHRoaXMuYmluZGluZ3MuZmlsdGVyKGJpbmQgPT4gYmluZC5ldmVudCA9PT0gZXZlbnQpXG5cbiAgICBmb3IobGV0IGkgPSAwOyBpIDwgZXZlbnRCaW5kaW5ncy5sZW5ndGg7IGkrKyl7XG4gICAgICBsZXQgYmluZCA9IGV2ZW50QmluZGluZ3NbaV1cbiAgICAgIGJpbmQuY2FsbGJhY2soaGFuZGxlZFBheWxvYWQsIHJlZiwgam9pblJlZiB8fCB0aGlzLmpvaW5SZWYoKSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHJlcGx5RXZlbnROYW1lKHJlZil7IHJldHVybiBgY2hhbl9yZXBseV8ke3JlZn1gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGlzQ2xvc2VkKCl7IHJldHVybiB0aGlzLnN0YXRlID09PSBDSEFOTkVMX1NUQVRFUy5jbG9zZWQgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaXNFcnJvcmVkKCl7IHJldHVybiB0aGlzLnN0YXRlID09PSBDSEFOTkVMX1NUQVRFUy5lcnJvcmVkIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGlzSm9pbmVkKCl7IHJldHVybiB0aGlzLnN0YXRlID09PSBDSEFOTkVMX1NUQVRFUy5qb2luZWQgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaXNKb2luaW5nKCl7IHJldHVybiB0aGlzLnN0YXRlID09PSBDSEFOTkVMX1NUQVRFUy5qb2luaW5nIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGlzTGVhdmluZygpeyByZXR1cm4gdGhpcy5zdGF0ZSA9PT0gQ0hBTk5FTF9TVEFURVMubGVhdmluZyB9XG59XG4iLCAiaW1wb3J0IHtcbiAgZ2xvYmFsLFxuICBYSFJfU1RBVEVTXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEFqYXgge1xuXG4gIHN0YXRpYyByZXF1ZXN0KG1ldGhvZCwgZW5kUG9pbnQsIGFjY2VwdCwgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjayl7XG4gICAgaWYoZ2xvYmFsLlhEb21haW5SZXF1ZXN0KXtcbiAgICAgIGxldCByZXEgPSBuZXcgZ2xvYmFsLlhEb21haW5SZXF1ZXN0KCkgLy8gSUU4LCBJRTlcbiAgICAgIHJldHVybiB0aGlzLnhkb21haW5SZXF1ZXN0KHJlcSwgbWV0aG9kLCBlbmRQb2ludCwgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjaylcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IHJlcSA9IG5ldyBnbG9iYWwuWE1MSHR0cFJlcXVlc3QoKSAvLyBJRTcrLCBGaXJlZm94LCBDaHJvbWUsIE9wZXJhLCBTYWZhcmlcbiAgICAgIHJldHVybiB0aGlzLnhoclJlcXVlc3QocmVxLCBtZXRob2QsIGVuZFBvaW50LCBhY2NlcHQsIGJvZHksIHRpbWVvdXQsIG9udGltZW91dCwgY2FsbGJhY2spXG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHhkb21haW5SZXF1ZXN0KHJlcSwgbWV0aG9kLCBlbmRQb2ludCwgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjayl7XG4gICAgcmVxLnRpbWVvdXQgPSB0aW1lb3V0XG4gICAgcmVxLm9wZW4obWV0aG9kLCBlbmRQb2ludClcbiAgICByZXEub25sb2FkID0gKCkgPT4ge1xuICAgICAgbGV0IHJlc3BvbnNlID0gdGhpcy5wYXJzZUpTT04ocmVxLnJlc3BvbnNlVGV4dClcbiAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKHJlc3BvbnNlKVxuICAgIH1cbiAgICBpZihvbnRpbWVvdXQpeyByZXEub250aW1lb3V0ID0gb250aW1lb3V0IH1cblxuICAgIC8vIFdvcmsgYXJvdW5kIGJ1ZyBpbiBJRTkgdGhhdCByZXF1aXJlcyBhbiBhdHRhY2hlZCBvbnByb2dyZXNzIGhhbmRsZXJcbiAgICByZXEub25wcm9ncmVzcyA9ICgpID0+IHsgfVxuXG4gICAgcmVxLnNlbmQoYm9keSlcbiAgICByZXR1cm4gcmVxXG4gIH1cblxuICBzdGF0aWMgeGhyUmVxdWVzdChyZXEsIG1ldGhvZCwgZW5kUG9pbnQsIGFjY2VwdCwgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjayl7XG4gICAgcmVxLm9wZW4obWV0aG9kLCBlbmRQb2ludCwgdHJ1ZSlcbiAgICByZXEudGltZW91dCA9IHRpbWVvdXRcbiAgICByZXEuc2V0UmVxdWVzdEhlYWRlcihcIkNvbnRlbnQtVHlwZVwiLCBhY2NlcHQpXG4gICAgcmVxLm9uZXJyb3IgPSAoKSA9PiBjYWxsYmFjayAmJiBjYWxsYmFjayhudWxsKVxuICAgIHJlcS5vbnJlYWR5c3RhdGVjaGFuZ2UgPSAoKSA9PiB7XG4gICAgICBpZihyZXEucmVhZHlTdGF0ZSA9PT0gWEhSX1NUQVRFUy5jb21wbGV0ZSAmJiBjYWxsYmFjayl7XG4gICAgICAgIGxldCByZXNwb25zZSA9IHRoaXMucGFyc2VKU09OKHJlcS5yZXNwb25zZVRleHQpXG4gICAgICAgIGNhbGxiYWNrKHJlc3BvbnNlKVxuICAgICAgfVxuICAgIH1cbiAgICBpZihvbnRpbWVvdXQpeyByZXEub250aW1lb3V0ID0gb250aW1lb3V0IH1cblxuICAgIHJlcS5zZW5kKGJvZHkpXG4gICAgcmV0dXJuIHJlcVxuICB9XG5cbiAgc3RhdGljIHBhcnNlSlNPTihyZXNwKXtcbiAgICBpZighcmVzcCB8fCByZXNwID09PSBcIlwiKXsgcmV0dXJuIG51bGwgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlc3ApXG4gICAgfSBjYXRjaCAoZSl7XG4gICAgICBjb25zb2xlICYmIGNvbnNvbGUubG9nKFwiZmFpbGVkIHRvIHBhcnNlIEpTT04gcmVzcG9uc2VcIiwgcmVzcClcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHNlcmlhbGl6ZShvYmosIHBhcmVudEtleSl7XG4gICAgbGV0IHF1ZXJ5U3RyID0gW11cbiAgICBmb3IodmFyIGtleSBpbiBvYmope1xuICAgICAgaWYoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpeyBjb250aW51ZSB9XG4gICAgICBsZXQgcGFyYW1LZXkgPSBwYXJlbnRLZXkgPyBgJHtwYXJlbnRLZXl9WyR7a2V5fV1gIDoga2V5XG4gICAgICBsZXQgcGFyYW1WYWwgPSBvYmpba2V5XVxuICAgICAgaWYodHlwZW9mIHBhcmFtVmFsID09PSBcIm9iamVjdFwiKXtcbiAgICAgICAgcXVlcnlTdHIucHVzaCh0aGlzLnNlcmlhbGl6ZShwYXJhbVZhbCwgcGFyYW1LZXkpKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcXVlcnlTdHIucHVzaChlbmNvZGVVUklDb21wb25lbnQocGFyYW1LZXkpICsgXCI9XCIgKyBlbmNvZGVVUklDb21wb25lbnQocGFyYW1WYWwpKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcXVlcnlTdHIuam9pbihcIiZcIilcbiAgfVxuXG4gIHN0YXRpYyBhcHBlbmRQYXJhbXModXJsLCBwYXJhbXMpe1xuICAgIGlmKE9iamVjdC5rZXlzKHBhcmFtcykubGVuZ3RoID09PSAwKXsgcmV0dXJuIHVybCB9XG5cbiAgICBsZXQgcHJlZml4ID0gdXJsLm1hdGNoKC9cXD8vKSA/IFwiJlwiIDogXCI/XCJcbiAgICByZXR1cm4gYCR7dXJsfSR7cHJlZml4fSR7dGhpcy5zZXJpYWxpemUocGFyYW1zKX1gXG4gIH1cbn1cbiIsICJpbXBvcnQge1xuICBTT0NLRVRfU1RBVEVTLFxuICBUUkFOU1BPUlRTXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCBBamF4IGZyb20gXCIuL2FqYXhcIlxuXG5sZXQgYXJyYXlCdWZmZXJUb0Jhc2U2NCA9IChidWZmZXIpID0+IHtcbiAgbGV0IGJpbmFyeSA9IFwiXCJcbiAgbGV0IGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoYnVmZmVyKVxuICBsZXQgbGVuID0gYnl0ZXMuYnl0ZUxlbmd0aFxuICBmb3IobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspeyBiaW5hcnkgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSkgfVxuICByZXR1cm4gYnRvYShiaW5hcnkpXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExvbmdQb2xsIHtcblxuICBjb25zdHJ1Y3RvcihlbmRQb2ludCl7XG4gICAgdGhpcy5lbmRQb2ludCA9IG51bGxcbiAgICB0aGlzLnRva2VuID0gbnVsbFxuICAgIHRoaXMuc2tpcEhlYXJ0YmVhdCA9IHRydWVcbiAgICB0aGlzLnJlcXMgPSBuZXcgU2V0KClcbiAgICB0aGlzLmF3YWl0aW5nQmF0Y2hBY2sgPSBmYWxzZVxuICAgIHRoaXMuY3VycmVudEJhdGNoID0gbnVsbFxuICAgIHRoaXMuY3VycmVudEJhdGNoVGltZXIgPSBudWxsXG4gICAgdGhpcy5iYXRjaEJ1ZmZlciA9IFtdXG4gICAgdGhpcy5vbm9wZW4gPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgdGhpcy5vbmVycm9yID0gZnVuY3Rpb24gKCl7IH0gLy8gbm9vcFxuICAgIHRoaXMub25tZXNzYWdlID0gZnVuY3Rpb24gKCl7IH0gLy8gbm9vcFxuICAgIHRoaXMub25jbG9zZSA9IGZ1bmN0aW9uICgpeyB9IC8vIG5vb3BcbiAgICB0aGlzLnBvbGxFbmRwb2ludCA9IHRoaXMubm9ybWFsaXplRW5kcG9pbnQoZW5kUG9pbnQpXG4gICAgdGhpcy5yZWFkeVN0YXRlID0gU09DS0VUX1NUQVRFUy5jb25uZWN0aW5nXG4gICAgLy8gd2UgbXVzdCB3YWl0IGZvciB0aGUgY2FsbGVyIHRvIGZpbmlzaCBzZXR0aW5nIHVwIG91ciBjYWxsYmFja3MgYW5kIHRpbWVvdXQgcHJvcGVydGllc1xuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5wb2xsKCksIDApXG4gIH1cblxuICBub3JtYWxpemVFbmRwb2ludChlbmRQb2ludCl7XG4gICAgcmV0dXJuIChlbmRQb2ludFxuICAgICAgLnJlcGxhY2UoXCJ3czovL1wiLCBcImh0dHA6Ly9cIilcbiAgICAgIC5yZXBsYWNlKFwid3NzOi8vXCIsIFwiaHR0cHM6Ly9cIilcbiAgICAgIC5yZXBsYWNlKG5ldyBSZWdFeHAoXCIoLiopXFwvXCIgKyBUUkFOU1BPUlRTLndlYnNvY2tldCksIFwiJDEvXCIgKyBUUkFOU1BPUlRTLmxvbmdwb2xsKSlcbiAgfVxuXG4gIGVuZHBvaW50VVJMKCl7XG4gICAgcmV0dXJuIEFqYXguYXBwZW5kUGFyYW1zKHRoaXMucG9sbEVuZHBvaW50LCB7dG9rZW46IHRoaXMudG9rZW59KVxuICB9XG5cbiAgY2xvc2VBbmRSZXRyeShjb2RlLCByZWFzb24sIHdhc0NsZWFuKXtcbiAgICB0aGlzLmNsb3NlKGNvZGUsIHJlYXNvbiwgd2FzQ2xlYW4pXG4gICAgdGhpcy5yZWFkeVN0YXRlID0gU09DS0VUX1NUQVRFUy5jb25uZWN0aW5nXG4gIH1cblxuICBvbnRpbWVvdXQoKXtcbiAgICB0aGlzLm9uZXJyb3IoXCJ0aW1lb3V0XCIpXG4gICAgdGhpcy5jbG9zZUFuZFJldHJ5KDEwMDUsIFwidGltZW91dFwiLCBmYWxzZSlcbiAgfVxuXG4gIGlzQWN0aXZlKCl7IHJldHVybiB0aGlzLnJlYWR5U3RhdGUgPT09IFNPQ0tFVF9TVEFURVMub3BlbiB8fCB0aGlzLnJlYWR5U3RhdGUgPT09IFNPQ0tFVF9TVEFURVMuY29ubmVjdGluZyB9XG5cbiAgcG9sbCgpe1xuICAgIHRoaXMuYWpheChcIkdFVFwiLCBcImFwcGxpY2F0aW9uL2pzb25cIiwgbnVsbCwgKCkgPT4gdGhpcy5vbnRpbWVvdXQoKSwgcmVzcCA9PiB7XG4gICAgICBpZihyZXNwKXtcbiAgICAgICAgdmFyIHtzdGF0dXMsIHRva2VuLCBtZXNzYWdlc30gPSByZXNwXG4gICAgICAgIHRoaXMudG9rZW4gPSB0b2tlblxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RhdHVzID0gMFxuICAgICAgfVxuXG4gICAgICBzd2l0Y2goc3RhdHVzKXtcbiAgICAgICAgY2FzZSAyMDA6XG4gICAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChtc2cgPT4ge1xuICAgICAgICAgICAgLy8gVGFza3MgYXJlIHdoYXQgdGhpbmdzIGxpa2UgZXZlbnQgaGFuZGxlcnMsIHNldFRpbWVvdXQgY2FsbGJhY2tzLFxuICAgICAgICAgICAgLy8gcHJvbWlzZSByZXNvbHZlcyBhbmQgbW9yZSBhcmUgcnVuIHdpdGhpbi5cbiAgICAgICAgICAgIC8vIEluIG1vZGVybiBicm93c2VycywgdGhlcmUgYXJlIHR3byBkaWZmZXJlbnQga2luZHMgb2YgdGFza3MsXG4gICAgICAgICAgICAvLyBtaWNyb3Rhc2tzIGFuZCBtYWNyb3Rhc2tzLlxuICAgICAgICAgICAgLy8gTWljcm90YXNrcyBhcmUgbWFpbmx5IHVzZWQgZm9yIFByb21pc2VzLCB3aGlsZSBtYWNyb3Rhc2tzIGFyZVxuICAgICAgICAgICAgLy8gdXNlZCBmb3IgZXZlcnl0aGluZyBlbHNlLlxuICAgICAgICAgICAgLy8gTWljcm90YXNrcyBhbHdheXMgaGF2ZSBwcmlvcml0eSBvdmVyIG1hY3JvdGFza3MuIElmIHRoZSBKUyBlbmdpbmVcbiAgICAgICAgICAgIC8vIGlzIGxvb2tpbmcgZm9yIGEgdGFzayB0byBydW4sIGl0IHdpbGwgYWx3YXlzIHRyeSB0byBlbXB0eSB0aGVcbiAgICAgICAgICAgIC8vIG1pY3JvdGFzayBxdWV1ZSBiZWZvcmUgYXR0ZW1wdGluZyB0byBydW4gYW55dGhpbmcgZnJvbSB0aGVcbiAgICAgICAgICAgIC8vIG1hY3JvdGFzayBxdWV1ZS5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBGb3IgdGhlIFdlYlNvY2tldCB0cmFuc3BvcnQsIG1lc3NhZ2VzIGFsd2F5cyBhcnJpdmUgaW4gdGhlaXIgb3duXG4gICAgICAgICAgICAvLyBldmVudC4gVGhpcyBtZWFucyB0aGF0IGlmIGFueSBwcm9taXNlcyBhcmUgcmVzb2x2ZWQgZnJvbSB3aXRoaW4sXG4gICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3Mgd2lsbCBhbHdheXMgZmluaXNoIGV4ZWN1dGlvbiBieSB0aGUgdGltZSB0aGVcbiAgICAgICAgICAgIC8vIG5leHQgbWVzc2FnZSBldmVudCBoYW5kbGVyIGlzIHJ1bi5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBJbiBvcmRlciB0byBlbXVsYXRlIHRoaXMgYmVoYXZpb3VyLCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSBlYWNoXG4gICAgICAgICAgICAvLyBvbm1lc3NhZ2UgaGFuZGxlciBpcyBydW4gd2l0aGluIGl0cyBvd24gbWFjcm90YXNrLlxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLm9ubWVzc2FnZSh7ZGF0YTogbXNnfSksIDApXG4gICAgICAgICAgfSlcbiAgICAgICAgICB0aGlzLnBvbGwoKVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgMjA0OlxuICAgICAgICAgIHRoaXMucG9sbCgpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0MTA6XG4gICAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gU09DS0VUX1NUQVRFUy5vcGVuXG4gICAgICAgICAgdGhpcy5vbm9wZW4oe30pXG4gICAgICAgICAgdGhpcy5wb2xsKClcbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQwMzpcbiAgICAgICAgICB0aGlzLm9uZXJyb3IoNDAzKVxuICAgICAgICAgIHRoaXMuY2xvc2UoMTAwOCwgXCJmb3JiaWRkZW5cIiwgZmFsc2UpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAwOlxuICAgICAgICBjYXNlIDUwMDpcbiAgICAgICAgICB0aGlzLm9uZXJyb3IoNTAwKVxuICAgICAgICAgIHRoaXMuY2xvc2VBbmRSZXRyeSgxMDExLCBcImludGVybmFsIHNlcnZlciBlcnJvclwiLCA1MDApXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKGB1bmhhbmRsZWQgcG9sbCBzdGF0dXMgJHtzdGF0dXN9YClcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLy8gd2UgY29sbGVjdCBhbGwgcHVzaGVzIHdpdGhpbiB0aGUgY3VycmVudCBldmVudCBsb29wIGJ5XG4gIC8vIHNldFRpbWVvdXQgMCwgd2hpY2ggb3B0aW1pemVzIGJhY2stdG8tYmFjayBwcm9jZWR1cmFsXG4gIC8vIHB1c2hlcyBhZ2FpbnN0IGFuIGVtcHR5IGJ1ZmZlclxuXG4gIHNlbmQoYm9keSl7XG4gICAgaWYodHlwZW9mKGJvZHkpICE9PSBcInN0cmluZ1wiKXsgYm9keSA9IGFycmF5QnVmZmVyVG9CYXNlNjQoYm9keSkgfVxuICAgIGlmKHRoaXMuY3VycmVudEJhdGNoKXtcbiAgICAgIHRoaXMuY3VycmVudEJhdGNoLnB1c2goYm9keSlcbiAgICB9IGVsc2UgaWYodGhpcy5hd2FpdGluZ0JhdGNoQWNrKXtcbiAgICAgIHRoaXMuYmF0Y2hCdWZmZXIucHVzaChib2R5KVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmN1cnJlbnRCYXRjaCA9IFtib2R5XVxuICAgICAgdGhpcy5jdXJyZW50QmF0Y2hUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmJhdGNoU2VuZCh0aGlzLmN1cnJlbnRCYXRjaClcbiAgICAgICAgdGhpcy5jdXJyZW50QmF0Y2ggPSBudWxsXG4gICAgICB9LCAwKVxuICAgIH1cbiAgfVxuXG4gIGJhdGNoU2VuZChtZXNzYWdlcyl7XG4gICAgdGhpcy5hd2FpdGluZ0JhdGNoQWNrID0gdHJ1ZVxuICAgIHRoaXMuYWpheChcIlBPU1RcIiwgXCJhcHBsaWNhdGlvbi94LW5kanNvblwiLCBtZXNzYWdlcy5qb2luKFwiXFxuXCIpLCAoKSA9PiB0aGlzLm9uZXJyb3IoXCJ0aW1lb3V0XCIpLCByZXNwID0+IHtcbiAgICAgIHRoaXMuYXdhaXRpbmdCYXRjaEFjayA9IGZhbHNlXG4gICAgICBpZighcmVzcCB8fCByZXNwLnN0YXR1cyAhPT0gMjAwKXtcbiAgICAgICAgdGhpcy5vbmVycm9yKHJlc3AgJiYgcmVzcC5zdGF0dXMpXG4gICAgICAgIHRoaXMuY2xvc2VBbmRSZXRyeSgxMDExLCBcImludGVybmFsIHNlcnZlciBlcnJvclwiLCBmYWxzZSlcbiAgICAgIH0gZWxzZSBpZih0aGlzLmJhdGNoQnVmZmVyLmxlbmd0aCA+IDApe1xuICAgICAgICB0aGlzLmJhdGNoU2VuZCh0aGlzLmJhdGNoQnVmZmVyKVxuICAgICAgICB0aGlzLmJhdGNoQnVmZmVyID0gW11cbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgY2xvc2UoY29kZSwgcmVhc29uLCB3YXNDbGVhbil7XG4gICAgZm9yKGxldCByZXEgb2YgdGhpcy5yZXFzKXsgcmVxLmFib3J0KCkgfVxuICAgIHRoaXMucmVhZHlTdGF0ZSA9IFNPQ0tFVF9TVEFURVMuY2xvc2VkXG4gICAgbGV0IG9wdHMgPSBPYmplY3QuYXNzaWduKHtjb2RlOiAxMDAwLCByZWFzb246IHVuZGVmaW5lZCwgd2FzQ2xlYW46IHRydWV9LCB7Y29kZSwgcmVhc29uLCB3YXNDbGVhbn0pXG4gICAgdGhpcy5iYXRjaEJ1ZmZlciA9IFtdXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuY3VycmVudEJhdGNoVGltZXIpXG4gICAgdGhpcy5jdXJyZW50QmF0Y2hUaW1lciA9IG51bGxcbiAgICBpZih0eXBlb2YoQ2xvc2VFdmVudCkgIT09IFwidW5kZWZpbmVkXCIpe1xuICAgICAgdGhpcy5vbmNsb3NlKG5ldyBDbG9zZUV2ZW50KFwiY2xvc2VcIiwgb3B0cykpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMub25jbG9zZShvcHRzKVxuICAgIH1cbiAgfVxuXG4gIGFqYXgobWV0aG9kLCBjb250ZW50VHlwZSwgYm9keSwgb25DYWxsZXJUaW1lb3V0LCBjYWxsYmFjayl7XG4gICAgbGV0IHJlcVxuICAgIGxldCBvbnRpbWVvdXQgPSAoKSA9PiB7XG4gICAgICB0aGlzLnJlcXMuZGVsZXRlKHJlcSlcbiAgICAgIG9uQ2FsbGVyVGltZW91dCgpXG4gICAgfVxuICAgIHJlcSA9IEFqYXgucmVxdWVzdChtZXRob2QsIHRoaXMuZW5kcG9pbnRVUkwoKSwgY29udGVudFR5cGUsIGJvZHksIHRoaXMudGltZW91dCwgb250aW1lb3V0LCByZXNwID0+IHtcbiAgICAgIHRoaXMucmVxcy5kZWxldGUocmVxKVxuICAgICAgaWYodGhpcy5pc0FjdGl2ZSgpKXsgY2FsbGJhY2socmVzcCkgfVxuICAgIH0pXG4gICAgdGhpcy5yZXFzLmFkZChyZXEpXG4gIH1cbn1cbiIsICIvKipcbiAqIEluaXRpYWxpemVzIHRoZSBQcmVzZW5jZVxuICogQHBhcmFtIHtDaGFubmVsfSBjaGFubmVsIC0gVGhlIENoYW5uZWxcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gVGhlIG9wdGlvbnMsXG4gKiAgICAgICAgZm9yIGV4YW1wbGUgYHtldmVudHM6IHtzdGF0ZTogXCJzdGF0ZVwiLCBkaWZmOiBcImRpZmZcIn19YFxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBQcmVzZW5jZSB7XG5cbiAgY29uc3RydWN0b3IoY2hhbm5lbCwgb3B0cyA9IHt9KXtcbiAgICBsZXQgZXZlbnRzID0gb3B0cy5ldmVudHMgfHwge3N0YXRlOiBcInByZXNlbmNlX3N0YXRlXCIsIGRpZmY6IFwicHJlc2VuY2VfZGlmZlwifVxuICAgIHRoaXMuc3RhdGUgPSB7fVxuICAgIHRoaXMucGVuZGluZ0RpZmZzID0gW11cbiAgICB0aGlzLmNoYW5uZWwgPSBjaGFubmVsXG4gICAgdGhpcy5qb2luUmVmID0gbnVsbFxuICAgIHRoaXMuY2FsbGVyID0ge1xuICAgICAgb25Kb2luOiBmdW5jdGlvbiAoKXsgfSxcbiAgICAgIG9uTGVhdmU6IGZ1bmN0aW9uICgpeyB9LFxuICAgICAgb25TeW5jOiBmdW5jdGlvbiAoKXsgfVxuICAgIH1cblxuICAgIHRoaXMuY2hhbm5lbC5vbihldmVudHMuc3RhdGUsIG5ld1N0YXRlID0+IHtcbiAgICAgIGxldCB7b25Kb2luLCBvbkxlYXZlLCBvblN5bmN9ID0gdGhpcy5jYWxsZXJcblxuICAgICAgdGhpcy5qb2luUmVmID0gdGhpcy5jaGFubmVsLmpvaW5SZWYoKVxuICAgICAgdGhpcy5zdGF0ZSA9IFByZXNlbmNlLnN5bmNTdGF0ZSh0aGlzLnN0YXRlLCBuZXdTdGF0ZSwgb25Kb2luLCBvbkxlYXZlKVxuXG4gICAgICB0aGlzLnBlbmRpbmdEaWZmcy5mb3JFYWNoKGRpZmYgPT4ge1xuICAgICAgICB0aGlzLnN0YXRlID0gUHJlc2VuY2Uuc3luY0RpZmYodGhpcy5zdGF0ZSwgZGlmZiwgb25Kb2luLCBvbkxlYXZlKVxuICAgICAgfSlcbiAgICAgIHRoaXMucGVuZGluZ0RpZmZzID0gW11cbiAgICAgIG9uU3luYygpXG4gICAgfSlcblxuICAgIHRoaXMuY2hhbm5lbC5vbihldmVudHMuZGlmZiwgZGlmZiA9PiB7XG4gICAgICBsZXQge29uSm9pbiwgb25MZWF2ZSwgb25TeW5jfSA9IHRoaXMuY2FsbGVyXG5cbiAgICAgIGlmKHRoaXMuaW5QZW5kaW5nU3luY1N0YXRlKCkpe1xuICAgICAgICB0aGlzLnBlbmRpbmdEaWZmcy5wdXNoKGRpZmYpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnN0YXRlID0gUHJlc2VuY2Uuc3luY0RpZmYodGhpcy5zdGF0ZSwgZGlmZiwgb25Kb2luLCBvbkxlYXZlKVxuICAgICAgICBvblN5bmMoKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBvbkpvaW4oY2FsbGJhY2speyB0aGlzLmNhbGxlci5vbkpvaW4gPSBjYWxsYmFjayB9XG5cbiAgb25MZWF2ZShjYWxsYmFjayl7IHRoaXMuY2FsbGVyLm9uTGVhdmUgPSBjYWxsYmFjayB9XG5cbiAgb25TeW5jKGNhbGxiYWNrKXsgdGhpcy5jYWxsZXIub25TeW5jID0gY2FsbGJhY2sgfVxuXG4gIGxpc3QoYnkpeyByZXR1cm4gUHJlc2VuY2UubGlzdCh0aGlzLnN0YXRlLCBieSkgfVxuXG4gIGluUGVuZGluZ1N5bmNTdGF0ZSgpe1xuICAgIHJldHVybiAhdGhpcy5qb2luUmVmIHx8ICh0aGlzLmpvaW5SZWYgIT09IHRoaXMuY2hhbm5lbC5qb2luUmVmKCkpXG4gIH1cblxuICAvLyBsb3dlci1sZXZlbCBwdWJsaWMgc3RhdGljIEFQSVxuXG4gIC8qKlxuICAgKiBVc2VkIHRvIHN5bmMgdGhlIGxpc3Qgb2YgcHJlc2VuY2VzIG9uIHRoZSBzZXJ2ZXJcbiAgICogd2l0aCB0aGUgY2xpZW50J3Mgc3RhdGUuIEFuIG9wdGlvbmFsIGBvbkpvaW5gIGFuZCBgb25MZWF2ZWAgY2FsbGJhY2sgY2FuXG4gICAqIGJlIHByb3ZpZGVkIHRvIHJlYWN0IHRvIGNoYW5nZXMgaW4gdGhlIGNsaWVudCdzIGxvY2FsIHByZXNlbmNlcyBhY3Jvc3NcbiAgICogZGlzY29ubmVjdHMgYW5kIHJlY29ubmVjdHMgd2l0aCB0aGUgc2VydmVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJlc2VuY2V9XG4gICAqL1xuICBzdGF0aWMgc3luY1N0YXRlKGN1cnJlbnRTdGF0ZSwgbmV3U3RhdGUsIG9uSm9pbiwgb25MZWF2ZSl7XG4gICAgbGV0IHN0YXRlID0gdGhpcy5jbG9uZShjdXJyZW50U3RhdGUpXG4gICAgbGV0IGpvaW5zID0ge31cbiAgICBsZXQgbGVhdmVzID0ge31cblxuICAgIHRoaXMubWFwKHN0YXRlLCAoa2V5LCBwcmVzZW5jZSkgPT4ge1xuICAgICAgaWYoIW5ld1N0YXRlW2tleV0pe1xuICAgICAgICBsZWF2ZXNba2V5XSA9IHByZXNlbmNlXG4gICAgICB9XG4gICAgfSlcbiAgICB0aGlzLm1hcChuZXdTdGF0ZSwgKGtleSwgbmV3UHJlc2VuY2UpID0+IHtcbiAgICAgIGxldCBjdXJyZW50UHJlc2VuY2UgPSBzdGF0ZVtrZXldXG4gICAgICBpZihjdXJyZW50UHJlc2VuY2Upe1xuICAgICAgICBsZXQgbmV3UmVmcyA9IG5ld1ByZXNlbmNlLm1ldGFzLm1hcChtID0+IG0ucGh4X3JlZilcbiAgICAgICAgbGV0IGN1clJlZnMgPSBjdXJyZW50UHJlc2VuY2UubWV0YXMubWFwKG0gPT4gbS5waHhfcmVmKVxuICAgICAgICBsZXQgam9pbmVkTWV0YXMgPSBuZXdQcmVzZW5jZS5tZXRhcy5maWx0ZXIobSA9PiBjdXJSZWZzLmluZGV4T2YobS5waHhfcmVmKSA8IDApXG4gICAgICAgIGxldCBsZWZ0TWV0YXMgPSBjdXJyZW50UHJlc2VuY2UubWV0YXMuZmlsdGVyKG0gPT4gbmV3UmVmcy5pbmRleE9mKG0ucGh4X3JlZikgPCAwKVxuICAgICAgICBpZihqb2luZWRNZXRhcy5sZW5ndGggPiAwKXtcbiAgICAgICAgICBqb2luc1trZXldID0gbmV3UHJlc2VuY2VcbiAgICAgICAgICBqb2luc1trZXldLm1ldGFzID0gam9pbmVkTWV0YXNcbiAgICAgICAgfVxuICAgICAgICBpZihsZWZ0TWV0YXMubGVuZ3RoID4gMCl7XG4gICAgICAgICAgbGVhdmVzW2tleV0gPSB0aGlzLmNsb25lKGN1cnJlbnRQcmVzZW5jZSlcbiAgICAgICAgICBsZWF2ZXNba2V5XS5tZXRhcyA9IGxlZnRNZXRhc1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBqb2luc1trZXldID0gbmV3UHJlc2VuY2VcbiAgICAgIH1cbiAgICB9KVxuICAgIHJldHVybiB0aGlzLnN5bmNEaWZmKHN0YXRlLCB7am9pbnM6IGpvaW5zLCBsZWF2ZXM6IGxlYXZlc30sIG9uSm9pbiwgb25MZWF2ZSlcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBVc2VkIHRvIHN5bmMgYSBkaWZmIG9mIHByZXNlbmNlIGpvaW4gYW5kIGxlYXZlXG4gICAqIGV2ZW50cyBmcm9tIHRoZSBzZXJ2ZXIsIGFzIHRoZXkgaGFwcGVuLiBMaWtlIGBzeW5jU3RhdGVgLCBgc3luY0RpZmZgXG4gICAqIGFjY2VwdHMgb3B0aW9uYWwgYG9uSm9pbmAgYW5kIGBvbkxlYXZlYCBjYWxsYmFja3MgdG8gcmVhY3QgdG8gYSB1c2VyXG4gICAqIGpvaW5pbmcgb3IgbGVhdmluZyBmcm9tIGEgZGV2aWNlLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJlc2VuY2V9XG4gICAqL1xuICBzdGF0aWMgc3luY0RpZmYoc3RhdGUsIGRpZmYsIG9uSm9pbiwgb25MZWF2ZSl7XG4gICAgbGV0IHtqb2lucywgbGVhdmVzfSA9IHRoaXMuY2xvbmUoZGlmZilcbiAgICBpZighb25Kb2luKXsgb25Kb2luID0gZnVuY3Rpb24gKCl7IH0gfVxuICAgIGlmKCFvbkxlYXZlKXsgb25MZWF2ZSA9IGZ1bmN0aW9uICgpeyB9IH1cblxuICAgIHRoaXMubWFwKGpvaW5zLCAoa2V5LCBuZXdQcmVzZW5jZSkgPT4ge1xuICAgICAgbGV0IGN1cnJlbnRQcmVzZW5jZSA9IHN0YXRlW2tleV1cbiAgICAgIHN0YXRlW2tleV0gPSB0aGlzLmNsb25lKG5ld1ByZXNlbmNlKVxuICAgICAgaWYoY3VycmVudFByZXNlbmNlKXtcbiAgICAgICAgbGV0IGpvaW5lZFJlZnMgPSBzdGF0ZVtrZXldLm1ldGFzLm1hcChtID0+IG0ucGh4X3JlZilcbiAgICAgICAgbGV0IGN1ck1ldGFzID0gY3VycmVudFByZXNlbmNlLm1ldGFzLmZpbHRlcihtID0+IGpvaW5lZFJlZnMuaW5kZXhPZihtLnBoeF9yZWYpIDwgMClcbiAgICAgICAgc3RhdGVba2V5XS5tZXRhcy51bnNoaWZ0KC4uLmN1ck1ldGFzKVxuICAgICAgfVxuICAgICAgb25Kb2luKGtleSwgY3VycmVudFByZXNlbmNlLCBuZXdQcmVzZW5jZSlcbiAgICB9KVxuICAgIHRoaXMubWFwKGxlYXZlcywgKGtleSwgbGVmdFByZXNlbmNlKSA9PiB7XG4gICAgICBsZXQgY3VycmVudFByZXNlbmNlID0gc3RhdGVba2V5XVxuICAgICAgaWYoIWN1cnJlbnRQcmVzZW5jZSl7IHJldHVybiB9XG4gICAgICBsZXQgcmVmc1RvUmVtb3ZlID0gbGVmdFByZXNlbmNlLm1ldGFzLm1hcChtID0+IG0ucGh4X3JlZilcbiAgICAgIGN1cnJlbnRQcmVzZW5jZS5tZXRhcyA9IGN1cnJlbnRQcmVzZW5jZS5tZXRhcy5maWx0ZXIocCA9PiB7XG4gICAgICAgIHJldHVybiByZWZzVG9SZW1vdmUuaW5kZXhPZihwLnBoeF9yZWYpIDwgMFxuICAgICAgfSlcbiAgICAgIG9uTGVhdmUoa2V5LCBjdXJyZW50UHJlc2VuY2UsIGxlZnRQcmVzZW5jZSlcbiAgICAgIGlmKGN1cnJlbnRQcmVzZW5jZS5tZXRhcy5sZW5ndGggPT09IDApe1xuICAgICAgICBkZWxldGUgc3RhdGVba2V5XVxuICAgICAgfVxuICAgIH0pXG4gICAgcmV0dXJuIHN0YXRlXG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgcHJlc2VuY2VzLCB3aXRoIHNlbGVjdGVkIG1ldGFkYXRhLlxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gcHJlc2VuY2VzXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNob29zZXJcbiAgICpcbiAgICogQHJldHVybnMge1ByZXNlbmNlfVxuICAgKi9cbiAgc3RhdGljIGxpc3QocHJlc2VuY2VzLCBjaG9vc2VyKXtcbiAgICBpZighY2hvb3Nlcil7IGNob29zZXIgPSBmdW5jdGlvbiAoa2V5LCBwcmVzKXsgcmV0dXJuIHByZXMgfSB9XG5cbiAgICByZXR1cm4gdGhpcy5tYXAocHJlc2VuY2VzLCAoa2V5LCBwcmVzZW5jZSkgPT4ge1xuICAgICAgcmV0dXJuIGNob29zZXIoa2V5LCBwcmVzZW5jZSlcbiAgICB9KVxuICB9XG5cbiAgLy8gcHJpdmF0ZVxuXG4gIHN0YXRpYyBtYXAob2JqLCBmdW5jKXtcbiAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob2JqKS5tYXAoa2V5ID0+IGZ1bmMoa2V5LCBvYmpba2V5XSkpXG4gIH1cblxuICBzdGF0aWMgY2xvbmUob2JqKXsgcmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkob2JqKSkgfVxufVxuIiwgIi8qIFRoZSBkZWZhdWx0IHNlcmlhbGl6ZXIgZm9yIGVuY29kaW5nIGFuZCBkZWNvZGluZyBtZXNzYWdlcyAqL1xuaW1wb3J0IHtcbiAgQ0hBTk5FTF9FVkVOVFNcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuZXhwb3J0IGRlZmF1bHQge1xuICBIRUFERVJfTEVOR1RIOiAxLFxuICBNRVRBX0xFTkdUSDogNCxcbiAgS0lORFM6IHtwdXNoOiAwLCByZXBseTogMSwgYnJvYWRjYXN0OiAyfSxcblxuICBlbmNvZGUobXNnLCBjYWxsYmFjayl7XG4gICAgaWYobXNnLnBheWxvYWQuY29uc3RydWN0b3IgPT09IEFycmF5QnVmZmVyKXtcbiAgICAgIHJldHVybiBjYWxsYmFjayh0aGlzLmJpbmFyeUVuY29kZShtc2cpKVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgcGF5bG9hZCA9IFttc2cuam9pbl9yZWYsIG1zZy5yZWYsIG1zZy50b3BpYywgbXNnLmV2ZW50LCBtc2cucGF5bG9hZF1cbiAgICAgIHJldHVybiBjYWxsYmFjayhKU09OLnN0cmluZ2lmeShwYXlsb2FkKSlcbiAgICB9XG4gIH0sXG5cbiAgZGVjb2RlKHJhd1BheWxvYWQsIGNhbGxiYWNrKXtcbiAgICBpZihyYXdQYXlsb2FkLmNvbnN0cnVjdG9yID09PSBBcnJheUJ1ZmZlcil7XG4gICAgICByZXR1cm4gY2FsbGJhY2sodGhpcy5iaW5hcnlEZWNvZGUocmF3UGF5bG9hZCkpXG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBbam9pbl9yZWYsIHJlZiwgdG9waWMsIGV2ZW50LCBwYXlsb2FkXSA9IEpTT04ucGFyc2UocmF3UGF5bG9hZClcbiAgICAgIHJldHVybiBjYWxsYmFjayh7am9pbl9yZWYsIHJlZiwgdG9waWMsIGV2ZW50LCBwYXlsb2FkfSlcbiAgICB9XG4gIH0sXG5cbiAgLy8gcHJpdmF0ZVxuXG4gIGJpbmFyeUVuY29kZShtZXNzYWdlKXtcbiAgICBsZXQge2pvaW5fcmVmLCByZWYsIGV2ZW50LCB0b3BpYywgcGF5bG9hZH0gPSBtZXNzYWdlXG4gICAgbGV0IG1ldGFMZW5ndGggPSB0aGlzLk1FVEFfTEVOR1RIICsgam9pbl9yZWYubGVuZ3RoICsgcmVmLmxlbmd0aCArIHRvcGljLmxlbmd0aCArIGV2ZW50Lmxlbmd0aFxuICAgIGxldCBoZWFkZXIgPSBuZXcgQXJyYXlCdWZmZXIodGhpcy5IRUFERVJfTEVOR1RIICsgbWV0YUxlbmd0aClcbiAgICBsZXQgdmlldyA9IG5ldyBEYXRhVmlldyhoZWFkZXIpXG4gICAgbGV0IG9mZnNldCA9IDBcblxuICAgIHZpZXcuc2V0VWludDgob2Zmc2V0KyssIHRoaXMuS0lORFMucHVzaCkgLy8ga2luZFxuICAgIHZpZXcuc2V0VWludDgob2Zmc2V0KyssIGpvaW5fcmVmLmxlbmd0aClcbiAgICB2aWV3LnNldFVpbnQ4KG9mZnNldCsrLCByZWYubGVuZ3RoKVxuICAgIHZpZXcuc2V0VWludDgob2Zmc2V0KyssIHRvcGljLmxlbmd0aClcbiAgICB2aWV3LnNldFVpbnQ4KG9mZnNldCsrLCBldmVudC5sZW5ndGgpXG4gICAgQXJyYXkuZnJvbShqb2luX3JlZiwgY2hhciA9PiB2aWV3LnNldFVpbnQ4KG9mZnNldCsrLCBjaGFyLmNoYXJDb2RlQXQoMCkpKVxuICAgIEFycmF5LmZyb20ocmVmLCBjaGFyID0+IHZpZXcuc2V0VWludDgob2Zmc2V0KyssIGNoYXIuY2hhckNvZGVBdCgwKSkpXG4gICAgQXJyYXkuZnJvbSh0b3BpYywgY2hhciA9PiB2aWV3LnNldFVpbnQ4KG9mZnNldCsrLCBjaGFyLmNoYXJDb2RlQXQoMCkpKVxuICAgIEFycmF5LmZyb20oZXZlbnQsIGNoYXIgPT4gdmlldy5zZXRVaW50OChvZmZzZXQrKywgY2hhci5jaGFyQ29kZUF0KDApKSlcblxuICAgIHZhciBjb21iaW5lZCA9IG5ldyBVaW50OEFycmF5KGhlYWRlci5ieXRlTGVuZ3RoICsgcGF5bG9hZC5ieXRlTGVuZ3RoKVxuICAgIGNvbWJpbmVkLnNldChuZXcgVWludDhBcnJheShoZWFkZXIpLCAwKVxuICAgIGNvbWJpbmVkLnNldChuZXcgVWludDhBcnJheShwYXlsb2FkKSwgaGVhZGVyLmJ5dGVMZW5ndGgpXG5cbiAgICByZXR1cm4gY29tYmluZWQuYnVmZmVyXG4gIH0sXG5cbiAgYmluYXJ5RGVjb2RlKGJ1ZmZlcil7XG4gICAgbGV0IHZpZXcgPSBuZXcgRGF0YVZpZXcoYnVmZmVyKVxuICAgIGxldCBraW5kID0gdmlldy5nZXRVaW50OCgwKVxuICAgIGxldCBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKClcbiAgICBzd2l0Y2goa2luZCl7XG4gICAgICBjYXNlIHRoaXMuS0lORFMucHVzaDogcmV0dXJuIHRoaXMuZGVjb2RlUHVzaChidWZmZXIsIHZpZXcsIGRlY29kZXIpXG4gICAgICBjYXNlIHRoaXMuS0lORFMucmVwbHk6IHJldHVybiB0aGlzLmRlY29kZVJlcGx5KGJ1ZmZlciwgdmlldywgZGVjb2RlcilcbiAgICAgIGNhc2UgdGhpcy5LSU5EUy5icm9hZGNhc3Q6IHJldHVybiB0aGlzLmRlY29kZUJyb2FkY2FzdChidWZmZXIsIHZpZXcsIGRlY29kZXIpXG4gICAgfVxuICB9LFxuXG4gIGRlY29kZVB1c2goYnVmZmVyLCB2aWV3LCBkZWNvZGVyKXtcbiAgICBsZXQgam9pblJlZlNpemUgPSB2aWV3LmdldFVpbnQ4KDEpXG4gICAgbGV0IHRvcGljU2l6ZSA9IHZpZXcuZ2V0VWludDgoMilcbiAgICBsZXQgZXZlbnRTaXplID0gdmlldy5nZXRVaW50OCgzKVxuICAgIGxldCBvZmZzZXQgPSB0aGlzLkhFQURFUl9MRU5HVEggKyB0aGlzLk1FVEFfTEVOR1RIIC0gMSAvLyBwdXNoZXMgaGF2ZSBubyByZWZcbiAgICBsZXQgam9pblJlZiA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIGpvaW5SZWZTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyBqb2luUmVmU2l6ZVxuICAgIGxldCB0b3BpYyA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIHRvcGljU2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgdG9waWNTaXplXG4gICAgbGV0IGV2ZW50ID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgZXZlbnRTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyBldmVudFNpemVcbiAgICBsZXQgZGF0YSA9IGJ1ZmZlci5zbGljZShvZmZzZXQsIGJ1ZmZlci5ieXRlTGVuZ3RoKVxuICAgIHJldHVybiB7am9pbl9yZWY6IGpvaW5SZWYsIHJlZjogbnVsbCwgdG9waWM6IHRvcGljLCBldmVudDogZXZlbnQsIHBheWxvYWQ6IGRhdGF9XG4gIH0sXG5cbiAgZGVjb2RlUmVwbHkoYnVmZmVyLCB2aWV3LCBkZWNvZGVyKXtcbiAgICBsZXQgam9pblJlZlNpemUgPSB2aWV3LmdldFVpbnQ4KDEpXG4gICAgbGV0IHJlZlNpemUgPSB2aWV3LmdldFVpbnQ4KDIpXG4gICAgbGV0IHRvcGljU2l6ZSA9IHZpZXcuZ2V0VWludDgoMylcbiAgICBsZXQgZXZlbnRTaXplID0gdmlldy5nZXRVaW50OCg0KVxuICAgIGxldCBvZmZzZXQgPSB0aGlzLkhFQURFUl9MRU5HVEggKyB0aGlzLk1FVEFfTEVOR1RIXG4gICAgbGV0IGpvaW5SZWYgPSBkZWNvZGVyLmRlY29kZShidWZmZXIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBqb2luUmVmU2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgam9pblJlZlNpemVcbiAgICBsZXQgcmVmID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgcmVmU2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgcmVmU2l6ZVxuICAgIGxldCB0b3BpYyA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIHRvcGljU2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgdG9waWNTaXplXG4gICAgbGV0IGV2ZW50ID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgZXZlbnRTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyBldmVudFNpemVcbiAgICBsZXQgZGF0YSA9IGJ1ZmZlci5zbGljZShvZmZzZXQsIGJ1ZmZlci5ieXRlTGVuZ3RoKVxuICAgIGxldCBwYXlsb2FkID0ge3N0YXR1czogZXZlbnQsIHJlc3BvbnNlOiBkYXRhfVxuICAgIHJldHVybiB7am9pbl9yZWY6IGpvaW5SZWYsIHJlZjogcmVmLCB0b3BpYzogdG9waWMsIGV2ZW50OiBDSEFOTkVMX0VWRU5UUy5yZXBseSwgcGF5bG9hZDogcGF5bG9hZH1cbiAgfSxcblxuICBkZWNvZGVCcm9hZGNhc3QoYnVmZmVyLCB2aWV3LCBkZWNvZGVyKXtcbiAgICBsZXQgdG9waWNTaXplID0gdmlldy5nZXRVaW50OCgxKVxuICAgIGxldCBldmVudFNpemUgPSB2aWV3LmdldFVpbnQ4KDIpXG4gICAgbGV0IG9mZnNldCA9IHRoaXMuSEVBREVSX0xFTkdUSCArIDJcbiAgICBsZXQgdG9waWMgPSBkZWNvZGVyLmRlY29kZShidWZmZXIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyB0b3BpY1NpemUpKVxuICAgIG9mZnNldCA9IG9mZnNldCArIHRvcGljU2l6ZVxuICAgIGxldCBldmVudCA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIGV2ZW50U2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgZXZlbnRTaXplXG4gICAgbGV0IGRhdGEgPSBidWZmZXIuc2xpY2Uob2Zmc2V0LCBidWZmZXIuYnl0ZUxlbmd0aClcblxuICAgIHJldHVybiB7am9pbl9yZWY6IG51bGwsIHJlZjogbnVsbCwgdG9waWM6IHRvcGljLCBldmVudDogZXZlbnQsIHBheWxvYWQ6IGRhdGF9XG4gIH1cbn1cbiIsICJpbXBvcnQge1xuICBnbG9iYWwsXG4gIHBoeFdpbmRvdyxcbiAgQ0hBTk5FTF9FVkVOVFMsXG4gIERFRkFVTFRfVElNRU9VVCxcbiAgREVGQVVMVF9WU04sXG4gIFNPQ0tFVF9TVEFURVMsXG4gIFRSQU5TUE9SVFMsXG4gIFdTX0NMT1NFX05PUk1BTFxufSBmcm9tIFwiLi9jb25zdGFudHNcIlxuXG5pbXBvcnQge1xuICBjbG9zdXJlXG59IGZyb20gXCIuL3V0aWxzXCJcblxuaW1wb3J0IEFqYXggZnJvbSBcIi4vYWpheFwiXG5pbXBvcnQgQ2hhbm5lbCBmcm9tIFwiLi9jaGFubmVsXCJcbmltcG9ydCBMb25nUG9sbCBmcm9tIFwiLi9sb25ncG9sbFwiXG5pbXBvcnQgU2VyaWFsaXplciBmcm9tIFwiLi9zZXJpYWxpemVyXCJcbmltcG9ydCBUaW1lciBmcm9tIFwiLi90aW1lclwiXG5cbi8qKiBJbml0aWFsaXplcyB0aGUgU29ja2V0ICpcbiAqXG4gKiBGb3IgSUU4IHN1cHBvcnQgdXNlIGFuIEVTNS1zaGltIChodHRwczovL2dpdGh1Yi5jb20vZXMtc2hpbXMvZXM1LXNoaW0pXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGVuZFBvaW50IC0gVGhlIHN0cmluZyBXZWJTb2NrZXQgZW5kcG9pbnQsIGllLCBgXCJ3czovL2V4YW1wbGUuY29tL3NvY2tldFwiYCxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgXCJ3c3M6Ly9leGFtcGxlLmNvbVwiYFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBcIi9zb2NrZXRcImAgKGluaGVyaXRlZCBob3N0ICYgcHJvdG9jb2wpXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdHNdIC0gT3B0aW9uYWwgY29uZmlndXJhdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMudHJhbnNwb3J0XSAtIFRoZSBXZWJzb2NrZXQgVHJhbnNwb3J0LCBmb3IgZXhhbXBsZSBXZWJTb2NrZXQgb3IgUGhvZW5peC5Mb25nUG9sbC5cbiAqXG4gKiBEZWZhdWx0cyB0byBXZWJTb2NrZXQgd2l0aCBhdXRvbWF0aWMgTG9uZ1BvbGwgZmFsbGJhY2sgaWYgV2ViU29ja2V0IGlzIG5vdCBkZWZpbmVkLlxuICogVG8gZmFsbGJhY2sgdG8gTG9uZ1BvbGwgd2hlbiBXZWJTb2NrZXQgYXR0ZW1wdHMgZmFpbCwgdXNlIGBsb25nUG9sbEZhbGxiYWNrTXM6IDI1MDBgLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRzLmxvbmdQb2xsRmFsbGJhY2tNc10gLSBUaGUgbWlsbGlzZWNvbmQgdGltZSB0byBhdHRlbXB0IHRoZSBwcmltYXJ5IHRyYW5zcG9ydFxuICogYmVmb3JlIGZhbGxpbmcgYmFjayB0byB0aGUgTG9uZ1BvbGwgdHJhbnNwb3J0LiBEaXNhYmxlZCBieSBkZWZhdWx0LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRzLmRlYnVnXSAtIFdoZW4gdHJ1ZSwgZW5hYmxlcyBkZWJ1ZyBsb2dnaW5nLiBEZWZhdWx0IGZhbHNlLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRzLmVuY29kZV0gLSBUaGUgZnVuY3Rpb24gdG8gZW5jb2RlIG91dGdvaW5nIG1lc3NhZ2VzLlxuICpcbiAqIERlZmF1bHRzIHRvIEpTT04gZW5jb2Rlci5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBbb3B0cy5kZWNvZGVdIC0gVGhlIGZ1bmN0aW9uIHRvIGRlY29kZSBpbmNvbWluZyBtZXNzYWdlcy5cbiAqXG4gKiBEZWZhdWx0cyB0byBKU09OOlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIChwYXlsb2FkLCBjYWxsYmFjaykgPT4gY2FsbGJhY2soSlNPTi5wYXJzZShwYXlsb2FkKSlcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lb3V0XSAtIFRoZSBkZWZhdWx0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIHRvIHRyaWdnZXIgcHVzaCB0aW1lb3V0cy5cbiAqXG4gKiBEZWZhdWx0cyBgREVGQVVMVF9USU1FT1VUYFxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLmhlYXJ0YmVhdEludGVydmFsTXNdIC0gVGhlIG1pbGxpc2VjIGludGVydmFsIHRvIHNlbmQgYSBoZWFydGJlYXQgbWVzc2FnZVxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLnJlY29ubmVjdEFmdGVyTXNdIC0gVGhlIG9wdGlvbmFsIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgbWlsbGlzZWNcbiAqIHNvY2tldCByZWNvbm5lY3QgaW50ZXJ2YWwuXG4gKlxuICogRGVmYXVsdHMgdG8gc3RlcHBlZCBiYWNrb2ZmIG9mOlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIGZ1bmN0aW9uKHRyaWVzKXtcbiAqICAgcmV0dXJuIFsxMCwgNTAsIDEwMCwgMTUwLCAyMDAsIDI1MCwgNTAwLCAxMDAwLCAyMDAwXVt0cmllcyAtIDFdIHx8IDUwMDBcbiAqIH1cbiAqIGBgYGBcbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gW29wdHMucmVqb2luQWZ0ZXJNc10gLSBUaGUgb3B0aW9uYWwgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBtaWxsaXNlY1xuICogcmVqb2luIGludGVydmFsIGZvciBpbmRpdmlkdWFsIGNoYW5uZWxzLlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIGZ1bmN0aW9uKHRyaWVzKXtcbiAqICAgcmV0dXJuIFsxMDAwLCAyMDAwLCA1MDAwXVt0cmllcyAtIDFdIHx8IDEwMDAwXG4gKiB9XG4gKiBgYGBgXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMubG9nZ2VyXSAtIFRoZSBvcHRpb25hbCBmdW5jdGlvbiBmb3Igc3BlY2lhbGl6ZWQgbG9nZ2luZywgaWU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogZnVuY3Rpb24oa2luZCwgbXNnLCBkYXRhKSB7XG4gKiAgIGNvbnNvbGUubG9nKGAke2tpbmR9OiAke21zZ31gLCBkYXRhKVxuICogfVxuICogYGBgXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLmxvbmdwb2xsZXJUaW1lb3V0XSAtIFRoZSBtYXhpbXVtIHRpbWVvdXQgb2YgYSBsb25nIHBvbGwgQUpBWCByZXF1ZXN0LlxuICpcbiAqIERlZmF1bHRzIHRvIDIwcyAoZG91YmxlIHRoZSBzZXJ2ZXIgbG9uZyBwb2xsIHRpbWVyKS5cbiAqXG4gKiBAcGFyYW0geyhPYmplY3R8ZnVuY3Rpb24pfSBbb3B0cy5wYXJhbXNdIC0gVGhlIG9wdGlvbmFsIHBhcmFtcyB0byBwYXNzIHdoZW4gY29ubmVjdGluZ1xuICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmJpbmFyeVR5cGVdIC0gVGhlIGJpbmFyeSB0eXBlIHRvIHVzZSBmb3IgYmluYXJ5IFdlYlNvY2tldCBmcmFtZXMuXG4gKlxuICogRGVmYXVsdHMgdG8gXCJhcnJheWJ1ZmZlclwiXG4gKlxuICogQHBhcmFtIHt2c259IFtvcHRzLnZzbl0gLSBUaGUgc2VyaWFsaXplcidzIHByb3RvY29sIHZlcnNpb24gdG8gc2VuZCBvbiBjb25uZWN0LlxuICpcbiAqIERlZmF1bHRzIHRvIERFRkFVTFRfVlNOLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5zZXNzaW9uU3RvcmFnZV0gLSBBbiBvcHRpb25hbCBTdG9yYWdlIGNvbXBhdGlibGUgb2JqZWN0XG4gKiBQaG9lbml4IHVzZXMgc2Vzc2lvblN0b3JhZ2UgZm9yIGxvbmdwb2xsIGZhbGxiYWNrIGhpc3RvcnkuIE92ZXJyaWRpbmcgdGhlIHN0b3JlIGlzXG4gKiB1c2VmdWwgd2hlbiBQaG9lbml4IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBzZXNzaW9uU3RvcmFnZWAuIEZvciBleGFtcGxlLCBUaGlzIGNvdWxkXG4gKiBoYXBwZW4gaWYgYSBzaXRlIGxvYWRzIGEgY3Jvc3MtZG9tYWluIGNoYW5uZWwgaW4gYW4gaWZyYW1lLiBFeGFtcGxlIHVzYWdlOlxuICpcbiAqICAgICBjbGFzcyBJbk1lbW9yeVN0b3JhZ2Uge1xuICogICAgICAgY29uc3RydWN0b3IoKSB7IHRoaXMuc3RvcmFnZSA9IHt9IH1cbiAqICAgICAgIGdldEl0ZW0oa2V5TmFtZSkgeyByZXR1cm4gdGhpcy5zdG9yYWdlW2tleU5hbWVdIHx8IG51bGwgfVxuICogICAgICAgcmVtb3ZlSXRlbShrZXlOYW1lKSB7IGRlbGV0ZSB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gfVxuICogICAgICAgc2V0SXRlbShrZXlOYW1lLCBrZXlWYWx1ZSkgeyB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gPSBrZXlWYWx1ZSB9XG4gKiAgICAgfVxuICpcbiovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTb2NrZXQge1xuICBjb25zdHJ1Y3RvcihlbmRQb2ludCwgb3B0cyA9IHt9KXtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzID0ge29wZW46IFtdLCBjbG9zZTogW10sIGVycm9yOiBbXSwgbWVzc2FnZTogW119XG4gICAgdGhpcy5jaGFubmVscyA9IFtdXG4gICAgdGhpcy5zZW5kQnVmZmVyID0gW11cbiAgICB0aGlzLnJlZiA9IDBcbiAgICB0aGlzLnRpbWVvdXQgPSBvcHRzLnRpbWVvdXQgfHwgREVGQVVMVF9USU1FT1VUXG4gICAgdGhpcy50cmFuc3BvcnQgPSBvcHRzLnRyYW5zcG9ydCB8fCBnbG9iYWwuV2ViU29ja2V0IHx8IExvbmdQb2xsXG4gICAgdGhpcy5wcmltYXJ5UGFzc2VkSGVhbHRoQ2hlY2sgPSBmYWxzZVxuICAgIHRoaXMubG9uZ1BvbGxGYWxsYmFja01zID0gb3B0cy5sb25nUG9sbEZhbGxiYWNrTXNcbiAgICB0aGlzLmZhbGxiYWNrVGltZXIgPSBudWxsXG4gICAgdGhpcy5zZXNzaW9uU3RvcmUgPSBvcHRzLnNlc3Npb25TdG9yYWdlIHx8IChnbG9iYWwgJiYgZ2xvYmFsLnNlc3Npb25TdG9yYWdlKVxuICAgIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9ucyA9IDBcbiAgICB0aGlzLmRlZmF1bHRFbmNvZGVyID0gU2VyaWFsaXplci5lbmNvZGUuYmluZChTZXJpYWxpemVyKVxuICAgIHRoaXMuZGVmYXVsdERlY29kZXIgPSBTZXJpYWxpemVyLmRlY29kZS5iaW5kKFNlcmlhbGl6ZXIpXG4gICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gZmFsc2VcbiAgICB0aGlzLmRpc2Nvbm5lY3RpbmcgPSBmYWxzZVxuICAgIHRoaXMuYmluYXJ5VHlwZSA9IG9wdHMuYmluYXJ5VHlwZSB8fCBcImFycmF5YnVmZmVyXCJcbiAgICB0aGlzLmNvbm5lY3RDbG9jayA9IDFcbiAgICBpZih0aGlzLnRyYW5zcG9ydCAhPT0gTG9uZ1BvbGwpe1xuICAgICAgdGhpcy5lbmNvZGUgPSBvcHRzLmVuY29kZSB8fCB0aGlzLmRlZmF1bHRFbmNvZGVyXG4gICAgICB0aGlzLmRlY29kZSA9IG9wdHMuZGVjb2RlIHx8IHRoaXMuZGVmYXVsdERlY29kZXJcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5lbmNvZGUgPSB0aGlzLmRlZmF1bHRFbmNvZGVyXG4gICAgICB0aGlzLmRlY29kZSA9IHRoaXMuZGVmYXVsdERlY29kZXJcbiAgICB9XG4gICAgbGV0IGF3YWl0aW5nQ29ubmVjdGlvbk9uUGFnZVNob3cgPSBudWxsXG4gICAgaWYocGh4V2luZG93ICYmIHBoeFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKXtcbiAgICAgIHBoeFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGFnZWhpZGVcIiwgX2UgPT4ge1xuICAgICAgICBpZih0aGlzLmNvbm4pe1xuICAgICAgICAgIHRoaXMuZGlzY29ubmVjdCgpXG4gICAgICAgICAgYXdhaXRpbmdDb25uZWN0aW9uT25QYWdlU2hvdyA9IHRoaXMuY29ubmVjdENsb2NrXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICBwaHhXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBhZ2VzaG93XCIsIF9lID0+IHtcbiAgICAgICAgaWYoYXdhaXRpbmdDb25uZWN0aW9uT25QYWdlU2hvdyA9PT0gdGhpcy5jb25uZWN0Q2xvY2spe1xuICAgICAgICAgIGF3YWl0aW5nQ29ubmVjdGlvbk9uUGFnZVNob3cgPSBudWxsXG4gICAgICAgICAgdGhpcy5jb25uZWN0KClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG4gICAgdGhpcy5oZWFydGJlYXRJbnRlcnZhbE1zID0gb3B0cy5oZWFydGJlYXRJbnRlcnZhbE1zIHx8IDMwMDAwXG4gICAgdGhpcy5yZWpvaW5BZnRlck1zID0gKHRyaWVzKSA9PiB7XG4gICAgICBpZihvcHRzLnJlam9pbkFmdGVyTXMpe1xuICAgICAgICByZXR1cm4gb3B0cy5yZWpvaW5BZnRlck1zKHRyaWVzKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFsxMDAwLCAyMDAwLCA1MDAwXVt0cmllcyAtIDFdIHx8IDEwMDAwXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVjb25uZWN0QWZ0ZXJNcyA9ICh0cmllcykgPT4ge1xuICAgICAgaWYob3B0cy5yZWNvbm5lY3RBZnRlck1zKXtcbiAgICAgICAgcmV0dXJuIG9wdHMucmVjb25uZWN0QWZ0ZXJNcyh0cmllcylcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBbMTAsIDUwLCAxMDAsIDE1MCwgMjAwLCAyNTAsIDUwMCwgMTAwMCwgMjAwMF1bdHJpZXMgLSAxXSB8fCA1MDAwXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMubG9nZ2VyID0gb3B0cy5sb2dnZXIgfHwgbnVsbFxuICAgIGlmKCF0aGlzLmxvZ2dlciAmJiBvcHRzLmRlYnVnKXtcbiAgICAgIHRoaXMubG9nZ2VyID0gKGtpbmQsIG1zZywgZGF0YSkgPT4geyBjb25zb2xlLmxvZyhgJHtraW5kfTogJHttc2d9YCwgZGF0YSkgfVxuICAgIH1cbiAgICB0aGlzLmxvbmdwb2xsZXJUaW1lb3V0ID0gb3B0cy5sb25ncG9sbGVyVGltZW91dCB8fCAyMDAwMFxuICAgIHRoaXMucGFyYW1zID0gY2xvc3VyZShvcHRzLnBhcmFtcyB8fCB7fSlcbiAgICB0aGlzLmVuZFBvaW50ID0gYCR7ZW5kUG9pbnR9LyR7VFJBTlNQT1JUUy53ZWJzb2NrZXR9YFxuICAgIHRoaXMudnNuID0gb3B0cy52c24gfHwgREVGQVVMVF9WU05cbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVvdXRUaW1lciA9IG51bGxcbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVyID0gbnVsbFxuICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IG51bGxcbiAgICB0aGlzLnJlY29ubmVjdFRpbWVyID0gbmV3IFRpbWVyKCgpID0+IHtcbiAgICAgIHRoaXMudGVhcmRvd24oKCkgPT4gdGhpcy5jb25uZWN0KCkpXG4gICAgfSwgdGhpcy5yZWNvbm5lY3RBZnRlck1zKVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIExvbmdQb2xsIHRyYW5zcG9ydCByZWZlcmVuY2VcbiAgICovXG4gIGdldExvbmdQb2xsVHJhbnNwb3J0KCl7IHJldHVybiBMb25nUG9sbCB9XG5cbiAgLyoqXG4gICAqIERpc2Nvbm5lY3RzIGFuZCByZXBsYWNlcyB0aGUgYWN0aXZlIHRyYW5zcG9ydFxuICAgKlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXdUcmFuc3BvcnQgLSBUaGUgbmV3IHRyYW5zcG9ydCBjbGFzcyB0byBpbnN0YW50aWF0ZVxuICAgKlxuICAgKi9cbiAgcmVwbGFjZVRyYW5zcG9ydChuZXdUcmFuc3BvcnQpe1xuICAgIHRoaXMuY29ubmVjdENsb2NrKytcbiAgICB0aGlzLmNsb3NlV2FzQ2xlYW4gPSB0cnVlXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuZmFsbGJhY2tUaW1lcilcbiAgICB0aGlzLnJlY29ubmVjdFRpbWVyLnJlc2V0KClcbiAgICBpZih0aGlzLmNvbm4pe1xuICAgICAgdGhpcy5jb25uLmNsb3NlKClcbiAgICAgIHRoaXMuY29ubiA9IG51bGxcbiAgICB9XG4gICAgdGhpcy50cmFuc3BvcnQgPSBuZXdUcmFuc3BvcnRcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBzb2NrZXQgcHJvdG9jb2xcbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIHByb3RvY29sKCl7IHJldHVybiBsb2NhdGlvbi5wcm90b2NvbC5tYXRjaCgvXmh0dHBzLykgPyBcIndzc1wiIDogXCJ3c1wiIH1cblxuICAvKipcbiAgICogVGhlIGZ1bGx5IHF1YWxpZmllZCBzb2NrZXQgdXJsXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBlbmRQb2ludFVSTCgpe1xuICAgIGxldCB1cmkgPSBBamF4LmFwcGVuZFBhcmFtcyhcbiAgICAgIEFqYXguYXBwZW5kUGFyYW1zKHRoaXMuZW5kUG9pbnQsIHRoaXMucGFyYW1zKCkpLCB7dnNuOiB0aGlzLnZzbn0pXG4gICAgaWYodXJpLmNoYXJBdCgwKSAhPT0gXCIvXCIpeyByZXR1cm4gdXJpIH1cbiAgICBpZih1cmkuY2hhckF0KDEpID09PSBcIi9cIil7IHJldHVybiBgJHt0aGlzLnByb3RvY29sKCl9OiR7dXJpfWAgfVxuXG4gICAgcmV0dXJuIGAke3RoaXMucHJvdG9jb2woKX06Ly8ke2xvY2F0aW9uLmhvc3R9JHt1cml9YFxuICB9XG5cbiAgLyoqXG4gICAqIERpc2Nvbm5lY3RzIHRoZSBzb2NrZXRcbiAgICpcbiAgICogU2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9DbG9zZUV2ZW50I1N0YXR1c19jb2RlcyBmb3IgdmFsaWQgc3RhdHVzIGNvZGVzLlxuICAgKlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayAtIE9wdGlvbmFsIGNhbGxiYWNrIHdoaWNoIGlzIGNhbGxlZCBhZnRlciBzb2NrZXQgaXMgZGlzY29ubmVjdGVkLlxuICAgKiBAcGFyYW0ge2ludGVnZXJ9IGNvZGUgLSBBIHN0YXR1cyBjb2RlIGZvciBkaXNjb25uZWN0aW9uIChPcHRpb25hbCkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWFzb24gLSBBIHRleHR1YWwgZGVzY3JpcHRpb24gb2YgdGhlIHJlYXNvbiB0byBkaXNjb25uZWN0LiAoT3B0aW9uYWwpXG4gICAqL1xuICBkaXNjb25uZWN0KGNhbGxiYWNrLCBjb2RlLCByZWFzb24pe1xuICAgIHRoaXMuY29ubmVjdENsb2NrKytcbiAgICB0aGlzLmRpc2Nvbm5lY3RpbmcgPSB0cnVlXG4gICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gdHJ1ZVxuICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgdGhpcy5yZWNvbm5lY3RUaW1lci5yZXNldCgpXG4gICAgdGhpcy50ZWFyZG93bigoKSA9PiB7XG4gICAgICB0aGlzLmRpc2Nvbm5lY3RpbmcgPSBmYWxzZVxuICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soKVxuICAgIH0sIGNvZGUsIHJlYXNvbilcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gcGFyYW1zIC0gVGhlIHBhcmFtcyB0byBzZW5kIHdoZW4gY29ubmVjdGluZywgZm9yIGV4YW1wbGUgYHt1c2VyX2lkOiB1c2VyVG9rZW59YFxuICAgKlxuICAgKiBQYXNzaW5nIHBhcmFtcyB0byBjb25uZWN0IGlzIGRlcHJlY2F0ZWQ7IHBhc3MgdGhlbSBpbiB0aGUgU29ja2V0IGNvbnN0cnVjdG9yIGluc3RlYWQ6XG4gICAqIGBuZXcgU29ja2V0KFwiL3NvY2tldFwiLCB7cGFyYW1zOiB7dXNlcl9pZDogdXNlclRva2VufX0pYC5cbiAgICovXG4gIGNvbm5lY3QocGFyYW1zKXtcbiAgICBpZihwYXJhbXMpe1xuICAgICAgY29uc29sZSAmJiBjb25zb2xlLmxvZyhcInBhc3NpbmcgcGFyYW1zIHRvIGNvbm5lY3QgaXMgZGVwcmVjYXRlZC4gSW5zdGVhZCBwYXNzIDpwYXJhbXMgdG8gdGhlIFNvY2tldCBjb25zdHJ1Y3RvclwiKVxuICAgICAgdGhpcy5wYXJhbXMgPSBjbG9zdXJlKHBhcmFtcylcbiAgICB9XG4gICAgaWYodGhpcy5jb25uICYmICF0aGlzLmRpc2Nvbm5lY3RpbmcpeyByZXR1cm4gfVxuICAgIGlmKHRoaXMubG9uZ1BvbGxGYWxsYmFja01zICYmIHRoaXMudHJhbnNwb3J0ICE9PSBMb25nUG9sbCl7XG4gICAgICB0aGlzLmNvbm5lY3RXaXRoRmFsbGJhY2soTG9uZ1BvbGwsIHRoaXMubG9uZ1BvbGxGYWxsYmFja01zKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRyYW5zcG9ydENvbm5lY3QoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBMb2dzIHRoZSBtZXNzYWdlLiBPdmVycmlkZSBgdGhpcy5sb2dnZXJgIGZvciBzcGVjaWFsaXplZCBsb2dnaW5nLiBub29wcyBieSBkZWZhdWx0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBraW5kXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtc2dcbiAgICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAgICovXG4gIGxvZyhraW5kLCBtc2csIGRhdGEpeyB0aGlzLmxvZ2dlciAmJiB0aGlzLmxvZ2dlcihraW5kLCBtc2csIGRhdGEpIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGEgbG9nZ2VyIGhhcyBiZWVuIHNldCBvbiB0aGlzIHNvY2tldC5cbiAgICovXG4gIGhhc0xvZ2dlcigpeyByZXR1cm4gdGhpcy5sb2dnZXIgIT09IG51bGwgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlcnMgY2FsbGJhY2tzIGZvciBjb25uZWN0aW9uIG9wZW4gZXZlbnRzXG4gICAqXG4gICAqIEBleGFtcGxlIHNvY2tldC5vbk9wZW4oZnVuY3Rpb24oKXsgY29uc29sZS5pbmZvKFwidGhlIHNvY2tldCB3YXMgb3BlbmVkXCIpIH0pXG4gICAqXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAqL1xuICBvbk9wZW4oY2FsbGJhY2spe1xuICAgIGxldCByZWYgPSB0aGlzLm1ha2VSZWYoKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3Mub3Blbi5wdXNoKFtyZWYsIGNhbGxiYWNrXSlcbiAgICByZXR1cm4gcmVmXG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGNhbGxiYWNrcyBmb3IgY29ubmVjdGlvbiBjbG9zZSBldmVudHNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICovXG4gIG9uQ2xvc2UoY2FsbGJhY2spe1xuICAgIGxldCByZWYgPSB0aGlzLm1ha2VSZWYoKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3MuY2xvc2UucHVzaChbcmVmLCBjYWxsYmFja10pXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBjYWxsYmFja3MgZm9yIGNvbm5lY3Rpb24gZXJyb3IgZXZlbnRzXG4gICAqXG4gICAqIEBleGFtcGxlIHNvY2tldC5vbkVycm9yKGZ1bmN0aW9uKGVycm9yKXsgYWxlcnQoXCJBbiBlcnJvciBvY2N1cnJlZFwiKSB9KVxuICAgKlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgKi9cbiAgb25FcnJvcihjYWxsYmFjayl7XG4gICAgbGV0IHJlZiA9IHRoaXMubWFrZVJlZigpXG4gICAgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5lcnJvci5wdXNoKFtyZWYsIGNhbGxiYWNrXSlcbiAgICByZXR1cm4gcmVmXG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGNhbGxiYWNrcyBmb3IgY29ubmVjdGlvbiBtZXNzYWdlIGV2ZW50c1xuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgKi9cbiAgb25NZXNzYWdlKGNhbGxiYWNrKXtcbiAgICBsZXQgcmVmID0gdGhpcy5tYWtlUmVmKClcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzLm1lc3NhZ2UucHVzaChbcmVmLCBjYWxsYmFja10pXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgLyoqXG4gICAqIFBpbmdzIHRoZSBzZXJ2ZXIgYW5kIGludm9rZXMgdGhlIGNhbGxiYWNrIHdpdGggdGhlIFJUVCBpbiBtaWxsaXNlY29uZHNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICpcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBwaW5nIHdhcyBwdXNoZWQgb3IgZmFsc2UgaWYgdW5hYmxlIHRvIGJlIHB1c2hlZC5cbiAgICovXG4gIHBpbmcoY2FsbGJhY2spe1xuICAgIGlmKCF0aGlzLmlzQ29ubmVjdGVkKCkpeyByZXR1cm4gZmFsc2UgfVxuICAgIGxldCByZWYgPSB0aGlzLm1ha2VSZWYoKVxuICAgIGxldCBzdGFydFRpbWUgPSBEYXRlLm5vdygpXG4gICAgdGhpcy5wdXNoKHt0b3BpYzogXCJwaG9lbml4XCIsIGV2ZW50OiBcImhlYXJ0YmVhdFwiLCBwYXlsb2FkOiB7fSwgcmVmOiByZWZ9KVxuICAgIGxldCBvbk1zZ1JlZiA9IHRoaXMub25NZXNzYWdlKG1zZyA9PiB7XG4gICAgICBpZihtc2cucmVmID09PSByZWYpe1xuICAgICAgICB0aGlzLm9mZihbb25Nc2dSZWZdKVxuICAgICAgICBjYWxsYmFjayhEYXRlLm5vdygpIC0gc3RhcnRUaW1lKVxuICAgICAgfVxuICAgIH0pXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cblxuICB0cmFuc3BvcnRDb25uZWN0KCl7XG4gICAgdGhpcy5jb25uZWN0Q2xvY2srK1xuICAgIHRoaXMuY2xvc2VXYXNDbGVhbiA9IGZhbHNlXG4gICAgdGhpcy5jb25uID0gbmV3IHRoaXMudHJhbnNwb3J0KHRoaXMuZW5kUG9pbnRVUkwoKSlcbiAgICB0aGlzLmNvbm4uYmluYXJ5VHlwZSA9IHRoaXMuYmluYXJ5VHlwZVxuICAgIHRoaXMuY29ubi50aW1lb3V0ID0gdGhpcy5sb25ncG9sbGVyVGltZW91dFxuICAgIHRoaXMuY29ubi5vbm9wZW4gPSAoKSA9PiB0aGlzLm9uQ29ubk9wZW4oKVxuICAgIHRoaXMuY29ubi5vbmVycm9yID0gZXJyb3IgPT4gdGhpcy5vbkNvbm5FcnJvcihlcnJvcilcbiAgICB0aGlzLmNvbm4ub25tZXNzYWdlID0gZXZlbnQgPT4gdGhpcy5vbkNvbm5NZXNzYWdlKGV2ZW50KVxuICAgIHRoaXMuY29ubi5vbmNsb3NlID0gZXZlbnQgPT4gdGhpcy5vbkNvbm5DbG9zZShldmVudClcbiAgfVxuXG4gIGdldFNlc3Npb24oa2V5KXsgcmV0dXJuIHRoaXMuc2Vzc2lvblN0b3JlICYmIHRoaXMuc2Vzc2lvblN0b3JlLmdldEl0ZW0oa2V5KSB9XG5cbiAgc3RvcmVTZXNzaW9uKGtleSwgdmFsKXsgdGhpcy5zZXNzaW9uU3RvcmUgJiYgdGhpcy5zZXNzaW9uU3RvcmUuc2V0SXRlbShrZXksIHZhbCkgfVxuXG4gIGNvbm5lY3RXaXRoRmFsbGJhY2soZmFsbGJhY2tUcmFuc3BvcnQsIGZhbGxiYWNrVGhyZXNob2xkID0gMjUwMCl7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuZmFsbGJhY2tUaW1lcilcbiAgICBsZXQgZXN0YWJsaXNoZWQgPSBmYWxzZVxuICAgIGxldCBwcmltYXJ5VHJhbnNwb3J0ID0gdHJ1ZVxuICAgIGxldCBvcGVuUmVmLCBlcnJvclJlZlxuICAgIGxldCBmYWxsYmFjayA9IChyZWFzb24pID0+IHtcbiAgICAgIHRoaXMubG9nKFwidHJhbnNwb3J0XCIsIGBmYWxsaW5nIGJhY2sgdG8gJHtmYWxsYmFja1RyYW5zcG9ydC5uYW1lfS4uLmAsIHJlYXNvbilcbiAgICAgIHRoaXMub2ZmKFtvcGVuUmVmLCBlcnJvclJlZl0pXG4gICAgICBwcmltYXJ5VHJhbnNwb3J0ID0gZmFsc2VcbiAgICAgIHRoaXMucmVwbGFjZVRyYW5zcG9ydChmYWxsYmFja1RyYW5zcG9ydClcbiAgICAgIHRoaXMudHJhbnNwb3J0Q29ubmVjdCgpXG4gICAgfVxuICAgIGlmKHRoaXMuZ2V0U2Vzc2lvbihgcGh4OmZhbGxiYWNrOiR7ZmFsbGJhY2tUcmFuc3BvcnQubmFtZX1gKSl7IHJldHVybiBmYWxsYmFjayhcIm1lbW9yaXplZFwiKSB9XG5cbiAgICB0aGlzLmZhbGxiYWNrVGltZXIgPSBzZXRUaW1lb3V0KGZhbGxiYWNrLCBmYWxsYmFja1RocmVzaG9sZClcblxuICAgIGVycm9yUmVmID0gdGhpcy5vbkVycm9yKHJlYXNvbiA9PiB7XG4gICAgICB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBcImVycm9yXCIsIHJlYXNvbilcbiAgICAgIGlmKHByaW1hcnlUcmFuc3BvcnQgJiYgIWVzdGFibGlzaGVkKXtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuZmFsbGJhY2tUaW1lcilcbiAgICAgICAgZmFsbGJhY2socmVhc29uKVxuICAgICAgfVxuICAgIH0pXG4gICAgdGhpcy5vbk9wZW4oKCkgPT4ge1xuICAgICAgZXN0YWJsaXNoZWQgPSB0cnVlXG4gICAgICBpZighcHJpbWFyeVRyYW5zcG9ydCl7XG4gICAgICAgIC8vIG9ubHkgbWVtb3JpemUgTFAgaWYgd2UgbmV2ZXIgY29ubmVjdGVkIHRvIHByaW1hcnlcbiAgICAgICAgaWYoIXRoaXMucHJpbWFyeVBhc3NlZEhlYWx0aENoZWNrKXsgdGhpcy5zdG9yZVNlc3Npb24oYHBoeDpmYWxsYmFjazoke2ZhbGxiYWNrVHJhbnNwb3J0Lm5hbWV9YCwgXCJ0cnVlXCIpIH1cbiAgICAgICAgcmV0dXJuIHRoaXMubG9nKFwidHJhbnNwb3J0XCIsIGBlc3RhYmxpc2hlZCAke2ZhbGxiYWNrVHJhbnNwb3J0Lm5hbWV9IGZhbGxiYWNrYClcbiAgICAgIH1cbiAgICAgIC8vIGlmIHdlJ3ZlIGVzdGFibGlzaGVkIHByaW1hcnksIGdpdmUgdGhlIGZhbGxiYWNrIGEgbmV3IHBlcmlvZCB0byBhdHRlbXB0IHBpbmdcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgICB0aGlzLmZhbGxiYWNrVGltZXIgPSBzZXRUaW1lb3V0KGZhbGxiYWNrLCBmYWxsYmFja1RocmVzaG9sZClcbiAgICAgIHRoaXMucGluZyhydHQgPT4ge1xuICAgICAgICB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBcImNvbm5lY3RlZCB0byBwcmltYXJ5IGFmdGVyXCIsIHJ0dClcbiAgICAgICAgdGhpcy5wcmltYXJ5UGFzc2VkSGVhbHRoQ2hlY2sgPSB0cnVlXG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgICB9KVxuICAgIH0pXG4gICAgdGhpcy50cmFuc3BvcnRDb25uZWN0KClcbiAgfVxuXG4gIGNsZWFySGVhcnRiZWF0cygpe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLmhlYXJ0YmVhdFRpbWVyKVxuICAgIGNsZWFyVGltZW91dCh0aGlzLmhlYXJ0YmVhdFRpbWVvdXRUaW1lcilcbiAgfVxuXG4gIG9uQ29ubk9wZW4oKXtcbiAgICBpZih0aGlzLmhhc0xvZ2dlcigpKSB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBgJHt0aGlzLnRyYW5zcG9ydC5uYW1lfSBjb25uZWN0ZWQgdG8gJHt0aGlzLmVuZFBvaW50VVJMKCl9YClcbiAgICB0aGlzLmNsb3NlV2FzQ2xlYW4gPSBmYWxzZVxuICAgIHRoaXMuZGlzY29ubmVjdGluZyA9IGZhbHNlXG4gICAgdGhpcy5lc3RhYmxpc2hlZENvbm5lY3Rpb25zKytcbiAgICB0aGlzLmZsdXNoU2VuZEJ1ZmZlcigpXG4gICAgdGhpcy5yZWNvbm5lY3RUaW1lci5yZXNldCgpXG4gICAgdGhpcy5yZXNldEhlYXJ0YmVhdCgpXG4gICAgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5vcGVuLmZvckVhY2goKFssIGNhbGxiYWNrXSkgPT4gY2FsbGJhY2soKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cblxuICBoZWFydGJlYXRUaW1lb3V0KCl7XG4gICAgaWYodGhpcy5wZW5kaW5nSGVhcnRiZWF0UmVmKXtcbiAgICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IG51bGxcbiAgICAgIGlmKHRoaXMuaGFzTG9nZ2VyKCkpeyB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBcImhlYXJ0YmVhdCB0aW1lb3V0LiBBdHRlbXB0aW5nIHRvIHJlLWVzdGFibGlzaCBjb25uZWN0aW9uXCIpIH1cbiAgICAgIHRoaXMudHJpZ2dlckNoYW5FcnJvcigpXG4gICAgICB0aGlzLmNsb3NlV2FzQ2xlYW4gPSBmYWxzZVxuICAgICAgdGhpcy50ZWFyZG93bigoKSA9PiB0aGlzLnJlY29ubmVjdFRpbWVyLnNjaGVkdWxlVGltZW91dCgpLCBXU19DTE9TRV9OT1JNQUwsIFwiaGVhcnRiZWF0IHRpbWVvdXRcIilcbiAgICB9XG4gIH1cblxuICByZXNldEhlYXJ0YmVhdCgpe1xuICAgIGlmKHRoaXMuY29ubiAmJiB0aGlzLmNvbm4uc2tpcEhlYXJ0YmVhdCl7IHJldHVybiB9XG4gICAgdGhpcy5wZW5kaW5nSGVhcnRiZWF0UmVmID0gbnVsbFxuICAgIHRoaXMuY2xlYXJIZWFydGJlYXRzKClcbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnNlbmRIZWFydGJlYXQoKSwgdGhpcy5oZWFydGJlYXRJbnRlcnZhbE1zKVxuICB9XG5cbiAgdGVhcmRvd24oY2FsbGJhY2ssIGNvZGUsIHJlYXNvbil7XG4gICAgaWYoIXRoaXMuY29ubil7XG4gICAgICByZXR1cm4gY2FsbGJhY2sgJiYgY2FsbGJhY2soKVxuICAgIH1cbiAgICBsZXQgY29ubmVjdENsb2NrID0gdGhpcy5jb25uZWN0Q2xvY2tcblxuICAgIHRoaXMud2FpdEZvckJ1ZmZlckRvbmUoKCkgPT4ge1xuICAgICAgaWYoY29ubmVjdENsb2NrICE9PSB0aGlzLmNvbm5lY3RDbG9jayl7IHJldHVybiB9XG4gICAgICBpZih0aGlzLmNvbm4pe1xuICAgICAgICBpZihjb2RlKXsgdGhpcy5jb25uLmNsb3NlKGNvZGUsIHJlYXNvbiB8fCBcIlwiKSB9IGVsc2UgeyB0aGlzLmNvbm4uY2xvc2UoKSB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMud2FpdEZvclNvY2tldENsb3NlZCgoKSA9PiB7XG4gICAgICAgIGlmKGNvbm5lY3RDbG9jayAhPT0gdGhpcy5jb25uZWN0Q2xvY2speyByZXR1cm4gfVxuICAgICAgICBpZih0aGlzLmNvbm4pe1xuICAgICAgICAgIHRoaXMuY29ubi5vbm9wZW4gPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgICAgICAgdGhpcy5jb25uLm9uZXJyb3IgPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgICAgICAgdGhpcy5jb25uLm9ubWVzc2FnZSA9IGZ1bmN0aW9uICgpeyB9IC8vIG5vb3BcbiAgICAgICAgICB0aGlzLmNvbm4ub25jbG9zZSA9IGZ1bmN0aW9uICgpeyB9IC8vIG5vb3BcbiAgICAgICAgICB0aGlzLmNvbm4gPSBudWxsXG4gICAgICAgIH1cblxuICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjaygpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICB3YWl0Rm9yQnVmZmVyRG9uZShjYWxsYmFjaywgdHJpZXMgPSAxKXtcbiAgICBpZih0cmllcyA9PT0gNSB8fCAhdGhpcy5jb25uIHx8ICF0aGlzLmNvbm4uYnVmZmVyZWRBbW91bnQpe1xuICAgICAgY2FsbGJhY2soKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLndhaXRGb3JCdWZmZXJEb25lKGNhbGxiYWNrLCB0cmllcyArIDEpXG4gICAgfSwgMTUwICogdHJpZXMpXG4gIH1cblxuICB3YWl0Rm9yU29ja2V0Q2xvc2VkKGNhbGxiYWNrLCB0cmllcyA9IDEpe1xuICAgIGlmKHRyaWVzID09PSA1IHx8ICF0aGlzLmNvbm4gfHwgdGhpcy5jb25uLnJlYWR5U3RhdGUgPT09IFNPQ0tFVF9TVEFURVMuY2xvc2VkKXtcbiAgICAgIGNhbGxiYWNrKClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy53YWl0Rm9yU29ja2V0Q2xvc2VkKGNhbGxiYWNrLCB0cmllcyArIDEpXG4gICAgfSwgMTUwICogdHJpZXMpXG4gIH1cblxuICBvbkNvbm5DbG9zZShldmVudCl7XG4gICAgbGV0IGNsb3NlQ29kZSA9IGV2ZW50ICYmIGV2ZW50LmNvZGVcbiAgICBpZih0aGlzLmhhc0xvZ2dlcigpKSB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBcImNsb3NlXCIsIGV2ZW50KVxuICAgIHRoaXMudHJpZ2dlckNoYW5FcnJvcigpXG4gICAgdGhpcy5jbGVhckhlYXJ0YmVhdHMoKVxuICAgIGlmKCF0aGlzLmNsb3NlV2FzQ2xlYW4gJiYgY2xvc2VDb2RlICE9PSAxMDAwKXtcbiAgICAgIHRoaXMucmVjb25uZWN0VGltZXIuc2NoZWR1bGVUaW1lb3V0KClcbiAgICB9XG4gICAgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5jbG9zZS5mb3JFYWNoKChbLCBjYWxsYmFja10pID0+IGNhbGxiYWNrKGV2ZW50KSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgb25Db25uRXJyb3IoZXJyb3Ipe1xuICAgIGlmKHRoaXMuaGFzTG9nZ2VyKCkpIHRoaXMubG9nKFwidHJhbnNwb3J0XCIsIGVycm9yKVxuICAgIGxldCB0cmFuc3BvcnRCZWZvcmUgPSB0aGlzLnRyYW5zcG9ydFxuICAgIGxldCBlc3RhYmxpc2hlZEJlZm9yZSA9IHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9uc1xuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3MuZXJyb3IuZm9yRWFjaCgoWywgY2FsbGJhY2tdKSA9PiB7XG4gICAgICBjYWxsYmFjayhlcnJvciwgdHJhbnNwb3J0QmVmb3JlLCBlc3RhYmxpc2hlZEJlZm9yZSlcbiAgICB9KVxuICAgIGlmKHRyYW5zcG9ydEJlZm9yZSA9PT0gdGhpcy50cmFuc3BvcnQgfHwgZXN0YWJsaXNoZWRCZWZvcmUgPiAwKXtcbiAgICAgIHRoaXMudHJpZ2dlckNoYW5FcnJvcigpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICB0cmlnZ2VyQ2hhbkVycm9yKCl7XG4gICAgdGhpcy5jaGFubmVscy5mb3JFYWNoKGNoYW5uZWwgPT4ge1xuICAgICAgaWYoIShjaGFubmVsLmlzRXJyb3JlZCgpIHx8IGNoYW5uZWwuaXNMZWF2aW5nKCkgfHwgY2hhbm5lbC5pc0Nsb3NlZCgpKSl7XG4gICAgICAgIGNoYW5uZWwudHJpZ2dlcihDSEFOTkVMX0VWRU5UUy5lcnJvcilcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBjb25uZWN0aW9uU3RhdGUoKXtcbiAgICBzd2l0Y2godGhpcy5jb25uICYmIHRoaXMuY29ubi5yZWFkeVN0YXRlKXtcbiAgICAgIGNhc2UgU09DS0VUX1NUQVRFUy5jb25uZWN0aW5nOiByZXR1cm4gXCJjb25uZWN0aW5nXCJcbiAgICAgIGNhc2UgU09DS0VUX1NUQVRFUy5vcGVuOiByZXR1cm4gXCJvcGVuXCJcbiAgICAgIGNhc2UgU09DS0VUX1NUQVRFUy5jbG9zaW5nOiByZXR1cm4gXCJjbG9zaW5nXCJcbiAgICAgIGRlZmF1bHQ6IHJldHVybiBcImNsb3NlZFwiXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgaXNDb25uZWN0ZWQoKXsgcmV0dXJuIHRoaXMuY29ubmVjdGlvblN0YXRlKCkgPT09IFwib3BlblwiIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICpcbiAgICogQHBhcmFtIHtDaGFubmVsfVxuICAgKi9cbiAgcmVtb3ZlKGNoYW5uZWwpe1xuICAgIHRoaXMub2ZmKGNoYW5uZWwuc3RhdGVDaGFuZ2VSZWZzKVxuICAgIHRoaXMuY2hhbm5lbHMgPSB0aGlzLmNoYW5uZWxzLmZpbHRlcihjID0+IGMgIT09IGNoYW5uZWwpXG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBgb25PcGVuYCwgYG9uQ2xvc2VgLCBgb25FcnJvcixgIGFuZCBgb25NZXNzYWdlYCByZWdpc3RyYXRpb25zLlxuICAgKlxuICAgKiBAcGFyYW0ge3JlZnN9IC0gbGlzdCBvZiByZWZzIHJldHVybmVkIGJ5IGNhbGxzIHRvXG4gICAqICAgICAgICAgICAgICAgICBgb25PcGVuYCwgYG9uQ2xvc2VgLCBgb25FcnJvcixgIGFuZCBgb25NZXNzYWdlYFxuICAgKi9cbiAgb2ZmKHJlZnMpe1xuICAgIGZvcihsZXQga2V5IGluIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3Mpe1xuICAgICAgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrc1trZXldID0gdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrc1trZXldLmZpbHRlcigoW3JlZl0pID0+IHtcbiAgICAgICAgcmV0dXJuIHJlZnMuaW5kZXhPZihyZWYpID09PSAtMVxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhdGVzIGEgbmV3IGNoYW5uZWwgZm9yIHRoZSBnaXZlbiB0b3BpY1xuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9waWNcbiAgICogQHBhcmFtIHtPYmplY3R9IGNoYW5QYXJhbXMgLSBQYXJhbWV0ZXJzIGZvciB0aGUgY2hhbm5lbFxuICAgKiBAcmV0dXJucyB7Q2hhbm5lbH1cbiAgICovXG4gIGNoYW5uZWwodG9waWMsIGNoYW5QYXJhbXMgPSB7fSl7XG4gICAgbGV0IGNoYW4gPSBuZXcgQ2hhbm5lbCh0b3BpYywgY2hhblBhcmFtcywgdGhpcylcbiAgICB0aGlzLmNoYW5uZWxzLnB1c2goY2hhbilcbiAgICByZXR1cm4gY2hhblxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXG4gICAqL1xuICBwdXNoKGRhdGEpe1xuICAgIGlmKHRoaXMuaGFzTG9nZ2VyKCkpe1xuICAgICAgbGV0IHt0b3BpYywgZXZlbnQsIHBheWxvYWQsIHJlZiwgam9pbl9yZWZ9ID0gZGF0YVxuICAgICAgdGhpcy5sb2coXCJwdXNoXCIsIGAke3RvcGljfSAke2V2ZW50fSAoJHtqb2luX3JlZn0sICR7cmVmfSlgLCBwYXlsb2FkKVxuICAgIH1cblxuICAgIGlmKHRoaXMuaXNDb25uZWN0ZWQoKSl7XG4gICAgICB0aGlzLmVuY29kZShkYXRhLCByZXN1bHQgPT4gdGhpcy5jb25uLnNlbmQocmVzdWx0KSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZW5kQnVmZmVyLnB1c2goKCkgPT4gdGhpcy5lbmNvZGUoZGF0YSwgcmVzdWx0ID0+IHRoaXMuY29ubi5zZW5kKHJlc3VsdCkpKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIG5leHQgbWVzc2FnZSByZWYsIGFjY291bnRpbmcgZm9yIG92ZXJmbG93c1xuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgbWFrZVJlZigpe1xuICAgIGxldCBuZXdSZWYgPSB0aGlzLnJlZiArIDFcbiAgICBpZihuZXdSZWYgPT09IHRoaXMucmVmKXsgdGhpcy5yZWYgPSAwIH0gZWxzZSB7IHRoaXMucmVmID0gbmV3UmVmIH1cblxuICAgIHJldHVybiB0aGlzLnJlZi50b1N0cmluZygpXG4gIH1cblxuICBzZW5kSGVhcnRiZWF0KCl7XG4gICAgaWYodGhpcy5wZW5kaW5nSGVhcnRiZWF0UmVmICYmICF0aGlzLmlzQ29ubmVjdGVkKCkpeyByZXR1cm4gfVxuICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IHRoaXMubWFrZVJlZigpXG4gICAgdGhpcy5wdXNoKHt0b3BpYzogXCJwaG9lbml4XCIsIGV2ZW50OiBcImhlYXJ0YmVhdFwiLCBwYXlsb2FkOiB7fSwgcmVmOiB0aGlzLnBlbmRpbmdIZWFydGJlYXRSZWZ9KVxuICAgIHRoaXMuaGVhcnRiZWF0VGltZW91dFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLmhlYXJ0YmVhdFRpbWVvdXQoKSwgdGhpcy5oZWFydGJlYXRJbnRlcnZhbE1zKVxuICB9XG5cbiAgZmx1c2hTZW5kQnVmZmVyKCl7XG4gICAgaWYodGhpcy5pc0Nvbm5lY3RlZCgpICYmIHRoaXMuc2VuZEJ1ZmZlci5sZW5ndGggPiAwKXtcbiAgICAgIHRoaXMuc2VuZEJ1ZmZlci5mb3JFYWNoKGNhbGxiYWNrID0+IGNhbGxiYWNrKCkpXG4gICAgICB0aGlzLnNlbmRCdWZmZXIgPSBbXVxuICAgIH1cbiAgfVxuXG4gIG9uQ29ubk1lc3NhZ2UocmF3TWVzc2FnZSl7XG4gICAgdGhpcy5kZWNvZGUocmF3TWVzc2FnZS5kYXRhLCBtc2cgPT4ge1xuICAgICAgbGV0IHt0b3BpYywgZXZlbnQsIHBheWxvYWQsIHJlZiwgam9pbl9yZWZ9ID0gbXNnXG4gICAgICBpZihyZWYgJiYgcmVmID09PSB0aGlzLnBlbmRpbmdIZWFydGJlYXRSZWYpe1xuICAgICAgICB0aGlzLmNsZWFySGVhcnRiZWF0cygpXG4gICAgICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IG51bGxcbiAgICAgICAgdGhpcy5oZWFydGJlYXRUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZW5kSGVhcnRiZWF0KCksIHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWxNcylcbiAgICAgIH1cblxuICAgICAgaWYodGhpcy5oYXNMb2dnZXIoKSkgdGhpcy5sb2coXCJyZWNlaXZlXCIsIGAke3BheWxvYWQuc3RhdHVzIHx8IFwiXCJ9ICR7dG9waWN9ICR7ZXZlbnR9ICR7cmVmICYmIFwiKFwiICsgcmVmICsgXCIpXCIgfHwgXCJcIn1gLCBwYXlsb2FkKVxuXG4gICAgICBmb3IobGV0IGkgPSAwOyBpIDwgdGhpcy5jaGFubmVscy5sZW5ndGg7IGkrKyl7XG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmNoYW5uZWxzW2ldXG4gICAgICAgIGlmKCFjaGFubmVsLmlzTWVtYmVyKHRvcGljLCBldmVudCwgcGF5bG9hZCwgam9pbl9yZWYpKXsgY29udGludWUgfVxuICAgICAgICBjaGFubmVsLnRyaWdnZXIoZXZlbnQsIHBheWxvYWQsIHJlZiwgam9pbl9yZWYpXG4gICAgICB9XG5cbiAgICAgIGZvcihsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzLm1lc3NhZ2UubGVuZ3RoOyBpKyspe1xuICAgICAgICBsZXQgWywgY2FsbGJhY2tdID0gdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5tZXNzYWdlW2ldXG4gICAgICAgIGNhbGxiYWNrKG1zZylcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgbGVhdmVPcGVuVG9waWModG9waWMpe1xuICAgIGxldCBkdXBDaGFubmVsID0gdGhpcy5jaGFubmVscy5maW5kKGMgPT4gYy50b3BpYyA9PT0gdG9waWMgJiYgKGMuaXNKb2luZWQoKSB8fCBjLmlzSm9pbmluZygpKSlcbiAgICBpZihkdXBDaGFubmVsKXtcbiAgICAgIGlmKHRoaXMuaGFzTG9nZ2VyKCkpIHRoaXMubG9nKFwidHJhbnNwb3J0XCIsIGBsZWF2aW5nIGR1cGxpY2F0ZSB0b3BpYyBcIiR7dG9waWN9XCJgKVxuICAgICAgZHVwQ2hhbm5lbC5sZWF2ZSgpXG4gICAgfVxuICB9XG59XG4iLCAiZXhwb3J0IGNvbnN0IENPTlNFQ1VUSVZFX1JFTE9BRFMgPSBcImNvbnNlY3V0aXZlLXJlbG9hZHNcIlxuZXhwb3J0IGNvbnN0IE1BWF9SRUxPQURTID0gMTBcbmV4cG9ydCBjb25zdCBSRUxPQURfSklUVEVSX01JTiA9IDUwMDBcbmV4cG9ydCBjb25zdCBSRUxPQURfSklUVEVSX01BWCA9IDEwMDAwXG5leHBvcnQgY29uc3QgRkFJTFNBRkVfSklUVEVSID0gMzAwMDBcbmV4cG9ydCBjb25zdCBQSFhfRVZFTlRfQ0xBU1NFUyA9IFtcbiAgXCJwaHgtY2xpY2stbG9hZGluZ1wiLCBcInBoeC1jaGFuZ2UtbG9hZGluZ1wiLCBcInBoeC1zdWJtaXQtbG9hZGluZ1wiLFxuICBcInBoeC1rZXlkb3duLWxvYWRpbmdcIiwgXCJwaHgta2V5dXAtbG9hZGluZ1wiLCBcInBoeC1ibHVyLWxvYWRpbmdcIiwgXCJwaHgtZm9jdXMtbG9hZGluZ1wiLFxuICBcInBoeC1ob29rLWxvYWRpbmdcIlxuXVxuZXhwb3J0IGNvbnN0IFBIWF9DT01QT05FTlQgPSBcImRhdGEtcGh4LWNvbXBvbmVudFwiXG5leHBvcnQgY29uc3QgUEhYX0xJVkVfTElOSyA9IFwiZGF0YS1waHgtbGlua1wiXG5leHBvcnQgY29uc3QgUEhYX1RSQUNLX1NUQVRJQyA9IFwidHJhY2stc3RhdGljXCJcbmV4cG9ydCBjb25zdCBQSFhfTElOS19TVEFURSA9IFwiZGF0YS1waHgtbGluay1zdGF0ZVwiXG5leHBvcnQgY29uc3QgUEhYX1JFRl9MT0FESU5HID0gXCJkYXRhLXBoeC1yZWYtbG9hZGluZ1wiXG5leHBvcnQgY29uc3QgUEhYX1JFRl9TUkMgPSBcImRhdGEtcGh4LXJlZi1zcmNcIlxuZXhwb3J0IGNvbnN0IFBIWF9SRUZfTE9DSyA9IFwiZGF0YS1waHgtcmVmLWxvY2tcIlxuZXhwb3J0IGNvbnN0IFBIWF9QRU5ESU5HX1JFRlMgPSBcInBoeC1wZW5kaW5nLXJlZnNcIlxuZXhwb3J0IGNvbnN0IFBIWF9UUkFDS19VUExPQURTID0gXCJ0cmFjay11cGxvYWRzXCJcbmV4cG9ydCBjb25zdCBQSFhfVVBMT0FEX1JFRiA9IFwiZGF0YS1waHgtdXBsb2FkLXJlZlwiXG5leHBvcnQgY29uc3QgUEhYX1BSRUZMSUdIVEVEX1JFRlMgPSBcImRhdGEtcGh4LXByZWZsaWdodGVkLXJlZnNcIlxuZXhwb3J0IGNvbnN0IFBIWF9ET05FX1JFRlMgPSBcImRhdGEtcGh4LWRvbmUtcmVmc1wiXG5leHBvcnQgY29uc3QgUEhYX0RST1BfVEFSR0VUID0gXCJkcm9wLXRhcmdldFwiXG5leHBvcnQgY29uc3QgUEhYX0FDVElWRV9FTlRSWV9SRUZTID0gXCJkYXRhLXBoeC1hY3RpdmUtcmVmc1wiXG5leHBvcnQgY29uc3QgUEhYX0xJVkVfRklMRV9VUERBVEVEID0gXCJwaHg6bGl2ZS1maWxlOnVwZGF0ZWRcIlxuZXhwb3J0IGNvbnN0IFBIWF9TS0lQID0gXCJkYXRhLXBoeC1za2lwXCJcbmV4cG9ydCBjb25zdCBQSFhfTUFHSUNfSUQgPSBcImRhdGEtcGh4LWlkXCJcbmV4cG9ydCBjb25zdCBQSFhfUFJVTkUgPSBcImRhdGEtcGh4LXBydW5lXCJcbmV4cG9ydCBjb25zdCBQSFhfQ09OTkVDVEVEX0NMQVNTID0gXCJwaHgtY29ubmVjdGVkXCJcbmV4cG9ydCBjb25zdCBQSFhfTE9BRElOR19DTEFTUyA9IFwicGh4LWxvYWRpbmdcIlxuZXhwb3J0IGNvbnN0IFBIWF9FUlJPUl9DTEFTUyA9IFwicGh4LWVycm9yXCJcbmV4cG9ydCBjb25zdCBQSFhfQ0xJRU5UX0VSUk9SX0NMQVNTID0gXCJwaHgtY2xpZW50LWVycm9yXCJcbmV4cG9ydCBjb25zdCBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTID0gXCJwaHgtc2VydmVyLWVycm9yXCJcbmV4cG9ydCBjb25zdCBQSFhfUEFSRU5UX0lEID0gXCJkYXRhLXBoeC1wYXJlbnQtaWRcIlxuZXhwb3J0IGNvbnN0IFBIWF9NQUlOID0gXCJkYXRhLXBoeC1tYWluXCJcbmV4cG9ydCBjb25zdCBQSFhfUk9PVF9JRCA9IFwiZGF0YS1waHgtcm9vdC1pZFwiXG5leHBvcnQgY29uc3QgUEhYX1ZJRVdQT1JUX1RPUCA9IFwidmlld3BvcnQtdG9wXCJcbmV4cG9ydCBjb25zdCBQSFhfVklFV1BPUlRfQk9UVE9NID0gXCJ2aWV3cG9ydC1ib3R0b21cIlxuZXhwb3J0IGNvbnN0IFBIWF9UUklHR0VSX0FDVElPTiA9IFwidHJpZ2dlci1hY3Rpb25cIlxuZXhwb3J0IGNvbnN0IFBIWF9IQVNfRk9DVVNFRCA9IFwicGh4LWhhcy1mb2N1c2VkXCJcbmV4cG9ydCBjb25zdCBGT0NVU0FCTEVfSU5QVVRTID0gW1widGV4dFwiLCBcInRleHRhcmVhXCIsIFwibnVtYmVyXCIsIFwiZW1haWxcIiwgXCJwYXNzd29yZFwiLCBcInNlYXJjaFwiLCBcInRlbFwiLCBcInVybFwiLCBcImRhdGVcIiwgXCJ0aW1lXCIsIFwiZGF0ZXRpbWUtbG9jYWxcIiwgXCJjb2xvclwiLCBcInJhbmdlXCJdXG5leHBvcnQgY29uc3QgQ0hFQ0tBQkxFX0lOUFVUUyA9IFtcImNoZWNrYm94XCIsIFwicmFkaW9cIl1cbmV4cG9ydCBjb25zdCBQSFhfSEFTX1NVQk1JVFRFRCA9IFwicGh4LWhhcy1zdWJtaXR0ZWRcIlxuZXhwb3J0IGNvbnN0IFBIWF9TRVNTSU9OID0gXCJkYXRhLXBoeC1zZXNzaW9uXCJcbmV4cG9ydCBjb25zdCBQSFhfVklFV19TRUxFQ1RPUiA9IGBbJHtQSFhfU0VTU0lPTn1dYFxuZXhwb3J0IGNvbnN0IFBIWF9TVElDS1kgPSBcImRhdGEtcGh4LXN0aWNreVwiXG5leHBvcnQgY29uc3QgUEhYX1NUQVRJQyA9IFwiZGF0YS1waHgtc3RhdGljXCJcbmV4cG9ydCBjb25zdCBQSFhfUkVBRE9OTFkgPSBcImRhdGEtcGh4LXJlYWRvbmx5XCJcbmV4cG9ydCBjb25zdCBQSFhfRElTQUJMRUQgPSBcImRhdGEtcGh4LWRpc2FibGVkXCJcbmV4cG9ydCBjb25zdCBQSFhfRElTQUJMRV9XSVRIID0gXCJkaXNhYmxlLXdpdGhcIlxuZXhwb3J0IGNvbnN0IFBIWF9ESVNBQkxFX1dJVEhfUkVTVE9SRSA9IFwiZGF0YS1waHgtZGlzYWJsZS13aXRoLXJlc3RvcmVcIlxuZXhwb3J0IGNvbnN0IFBIWF9IT09LID0gXCJob29rXCJcbmV4cG9ydCBjb25zdCBQSFhfREVCT1VOQ0UgPSBcImRlYm91bmNlXCJcbmV4cG9ydCBjb25zdCBQSFhfVEhST1RUTEUgPSBcInRocm90dGxlXCJcbmV4cG9ydCBjb25zdCBQSFhfVVBEQVRFID0gXCJ1cGRhdGVcIlxuZXhwb3J0IGNvbnN0IFBIWF9TVFJFQU0gPSBcInN0cmVhbVwiXG5leHBvcnQgY29uc3QgUEhYX1NUUkVBTV9SRUYgPSBcImRhdGEtcGh4LXN0cmVhbVwiXG5leHBvcnQgY29uc3QgUEhYX0tFWSA9IFwia2V5XCJcbmV4cG9ydCBjb25zdCBQSFhfUFJJVkFURSA9IFwicGh4UHJpdmF0ZVwiXG5leHBvcnQgY29uc3QgUEhYX0FVVE9fUkVDT1ZFUiA9IFwiYXV0by1yZWNvdmVyXCJcbmV4cG9ydCBjb25zdCBQSFhfTFZfREVCVUcgPSBcInBoeDpsaXZlLXNvY2tldDpkZWJ1Z1wiXG5leHBvcnQgY29uc3QgUEhYX0xWX1BST0ZJTEUgPSBcInBoeDpsaXZlLXNvY2tldDpwcm9maWxpbmdcIlxuZXhwb3J0IGNvbnN0IFBIWF9MVl9MQVRFTkNZX1NJTSA9IFwicGh4OmxpdmUtc29ja2V0OmxhdGVuY3ktc2ltXCJcbmV4cG9ydCBjb25zdCBQSFhfTFZfSElTVE9SWV9QT1NJVElPTiA9IFwicGh4Om5hdi1oaXN0b3J5LXBvc2l0aW9uXCJcbmV4cG9ydCBjb25zdCBQSFhfUFJPR1JFU1MgPSBcInByb2dyZXNzXCJcbmV4cG9ydCBjb25zdCBQSFhfTU9VTlRFRCA9IFwibW91bnRlZFwiXG5leHBvcnQgY29uc3QgUEhYX1JFTE9BRF9TVEFUVVMgPSBcIl9fcGhvZW5peF9yZWxvYWRfc3RhdHVzX19cIlxuZXhwb3J0IGNvbnN0IExPQURFUl9USU1FT1VUID0gMVxuZXhwb3J0IGNvbnN0IE1BWF9DSElMRF9KT0lOX0FUVEVNUFRTID0gM1xuZXhwb3J0IGNvbnN0IEJFRk9SRV9VTkxPQURfTE9BREVSX1RJTUVPVVQgPSAyMDBcbmV4cG9ydCBjb25zdCBESVNDT05ORUNURURfVElNRU9VVCA9IDUwMFxuZXhwb3J0IGNvbnN0IEJJTkRJTkdfUFJFRklYID0gXCJwaHgtXCJcbmV4cG9ydCBjb25zdCBQVVNIX1RJTUVPVVQgPSAzMDAwMFxuZXhwb3J0IGNvbnN0IExJTktfSEVBREVSID0gXCJ4LXJlcXVlc3RlZC13aXRoXCJcbmV4cG9ydCBjb25zdCBSRVNQT05TRV9VUkxfSEVBREVSID0gXCJ4LXJlc3BvbnNlLXVybFwiXG5leHBvcnQgY29uc3QgREVCT1VOQ0VfVFJJR0dFUiA9IFwiZGVib3VuY2UtdHJpZ2dlclwiXG5leHBvcnQgY29uc3QgVEhST1RUTEVEID0gXCJ0aHJvdHRsZWRcIlxuZXhwb3J0IGNvbnN0IERFQk9VTkNFX1BSRVZfS0VZID0gXCJkZWJvdW5jZS1wcmV2LWtleVwiXG5leHBvcnQgY29uc3QgREVGQVVMVFMgPSB7XG4gIGRlYm91bmNlOiAzMDAsXG4gIHRocm90dGxlOiAzMDBcbn1cbmV4cG9ydCBjb25zdCBQSFhfUEVORElOR19BVFRSUyA9IFtQSFhfUkVGX0xPQURJTkcsIFBIWF9SRUZfU1JDLCBQSFhfUkVGX0xPQ0tdXG4vLyBSZW5kZXJlZFxuZXhwb3J0IGNvbnN0IERZTkFNSUNTID0gXCJkXCJcbmV4cG9ydCBjb25zdCBTVEFUSUMgPSBcInNcIlxuZXhwb3J0IGNvbnN0IFJPT1QgPSBcInJcIlxuZXhwb3J0IGNvbnN0IENPTVBPTkVOVFMgPSBcImNcIlxuZXhwb3J0IGNvbnN0IEVWRU5UUyA9IFwiZVwiXG5leHBvcnQgY29uc3QgUkVQTFkgPSBcInJcIlxuZXhwb3J0IGNvbnN0IFRJVExFID0gXCJ0XCJcbmV4cG9ydCBjb25zdCBURU1QTEFURVMgPSBcInBcIlxuZXhwb3J0IGNvbnN0IFNUUkVBTSA9IFwic3RyZWFtXCJcbiIsICJpbXBvcnQge1xuICBsb2dFcnJvclxufSBmcm9tIFwiLi91dGlsc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVudHJ5VXBsb2FkZXIge1xuICBjb25zdHJ1Y3RvcihlbnRyeSwgY29uZmlnLCBsaXZlU29ja2V0KXtcbiAgICBsZXQge2NodW5rX3NpemUsIGNodW5rX3RpbWVvdXR9ID0gY29uZmlnXG4gICAgdGhpcy5saXZlU29ja2V0ID0gbGl2ZVNvY2tldFxuICAgIHRoaXMuZW50cnkgPSBlbnRyeVxuICAgIHRoaXMub2Zmc2V0ID0gMFxuICAgIHRoaXMuY2h1bmtTaXplID0gY2h1bmtfc2l6ZVxuICAgIHRoaXMuY2h1bmtUaW1lb3V0ID0gY2h1bmtfdGltZW91dFxuICAgIHRoaXMuY2h1bmtUaW1lciA9IG51bGxcbiAgICB0aGlzLmVycm9yZWQgPSBmYWxzZVxuICAgIHRoaXMudXBsb2FkQ2hhbm5lbCA9IGxpdmVTb2NrZXQuY2hhbm5lbChgbHZ1OiR7ZW50cnkucmVmfWAsIHt0b2tlbjogZW50cnkubWV0YWRhdGEoKX0pXG4gIH1cblxuICBlcnJvcihyZWFzb24pe1xuICAgIGlmKHRoaXMuZXJyb3JlZCl7IHJldHVybiB9XG4gICAgdGhpcy51cGxvYWRDaGFubmVsLmxlYXZlKClcbiAgICB0aGlzLmVycm9yZWQgPSB0cnVlXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuY2h1bmtUaW1lcilcbiAgICB0aGlzLmVudHJ5LmVycm9yKHJlYXNvbilcbiAgfVxuXG4gIHVwbG9hZCgpe1xuICAgIHRoaXMudXBsb2FkQ2hhbm5lbC5vbkVycm9yKHJlYXNvbiA9PiB0aGlzLmVycm9yKHJlYXNvbikpXG4gICAgdGhpcy51cGxvYWRDaGFubmVsLmpvaW4oKVxuICAgICAgLnJlY2VpdmUoXCJva1wiLCBfZGF0YSA9PiB0aGlzLnJlYWROZXh0Q2h1bmsoKSlcbiAgICAgIC5yZWNlaXZlKFwiZXJyb3JcIiwgcmVhc29uID0+IHRoaXMuZXJyb3IocmVhc29uKSlcbiAgfVxuXG4gIGlzRG9uZSgpeyByZXR1cm4gdGhpcy5vZmZzZXQgPj0gdGhpcy5lbnRyeS5maWxlLnNpemUgfVxuXG4gIHJlYWROZXh0Q2h1bmsoKXtcbiAgICBsZXQgcmVhZGVyID0gbmV3IHdpbmRvdy5GaWxlUmVhZGVyKClcbiAgICBsZXQgYmxvYiA9IHRoaXMuZW50cnkuZmlsZS5zbGljZSh0aGlzLm9mZnNldCwgdGhpcy5jaHVua1NpemUgKyB0aGlzLm9mZnNldClcbiAgICByZWFkZXIub25sb2FkID0gKGUpID0+IHtcbiAgICAgIGlmKGUudGFyZ2V0LmVycm9yID09PSBudWxsKXtcbiAgICAgICAgdGhpcy5vZmZzZXQgKz0gZS50YXJnZXQucmVzdWx0LmJ5dGVMZW5ndGhcbiAgICAgICAgdGhpcy5wdXNoQ2h1bmsoZS50YXJnZXQucmVzdWx0KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGxvZ0Vycm9yKFwiUmVhZCBlcnJvcjogXCIgKyBlLnRhcmdldC5lcnJvcilcbiAgICAgIH1cbiAgICB9XG4gICAgcmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGJsb2IpXG4gIH1cblxuICBwdXNoQ2h1bmsoY2h1bmspe1xuICAgIGlmKCF0aGlzLnVwbG9hZENoYW5uZWwuaXNKb2luZWQoKSl7IHJldHVybiB9XG4gICAgdGhpcy51cGxvYWRDaGFubmVsLnB1c2goXCJjaHVua1wiLCBjaHVuaywgdGhpcy5jaHVua1RpbWVvdXQpXG4gICAgICAucmVjZWl2ZShcIm9rXCIsICgpID0+IHtcbiAgICAgICAgdGhpcy5lbnRyeS5wcm9ncmVzcygodGhpcy5vZmZzZXQgLyB0aGlzLmVudHJ5LmZpbGUuc2l6ZSkgKiAxMDApXG4gICAgICAgIGlmKCF0aGlzLmlzRG9uZSgpKXtcbiAgICAgICAgICB0aGlzLmNodW5rVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHRoaXMucmVhZE5leHRDaHVuaygpLCB0aGlzLmxpdmVTb2NrZXQuZ2V0TGF0ZW5jeVNpbSgpIHx8IDApXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAucmVjZWl2ZShcImVycm9yXCIsICh7cmVhc29ufSkgPT4gdGhpcy5lcnJvcihyZWFzb24pKVxuICB9XG59XG4iLCAiaW1wb3J0IHtcbiAgUEhYX1ZJRVdfU0VMRUNUT1Jcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuaW1wb3J0IEVudHJ5VXBsb2FkZXIgZnJvbSBcIi4vZW50cnlfdXBsb2FkZXJcIlxuXG5leHBvcnQgbGV0IGxvZ0Vycm9yID0gKG1zZywgb2JqKSA9PiBjb25zb2xlLmVycm9yICYmIGNvbnNvbGUuZXJyb3IobXNnLCBvYmopXG5cbmV4cG9ydCBsZXQgaXNDaWQgPSAoY2lkKSA9PiB7XG4gIGxldCB0eXBlID0gdHlwZW9mKGNpZClcbiAgcmV0dXJuIHR5cGUgPT09IFwibnVtYmVyXCIgfHwgKHR5cGUgPT09IFwic3RyaW5nXCIgJiYgL14oMHxbMS05XVxcZCopJC8udGVzdChjaWQpKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZGV0ZWN0RHVwbGljYXRlSWRzKCl7XG4gIGxldCBpZHMgPSBuZXcgU2V0KClcbiAgbGV0IGVsZW1zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcIipbaWRdXCIpXG4gIGZvcihsZXQgaSA9IDAsIGxlbiA9IGVsZW1zLmxlbmd0aDsgaSA8IGxlbjsgaSsrKXtcbiAgICBpZihpZHMuaGFzKGVsZW1zW2ldLmlkKSl7XG4gICAgICBjb25zb2xlLmVycm9yKGBNdWx0aXBsZSBJRHMgZGV0ZWN0ZWQ6ICR7ZWxlbXNbaV0uaWR9LiBFbnN1cmUgdW5pcXVlIGVsZW1lbnQgaWRzLmApXG4gICAgfSBlbHNlIHtcbiAgICAgIGlkcy5hZGQoZWxlbXNbaV0uaWQpXG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3RJbnZhbGlkU3RyZWFtSW5zZXJ0cyhpbnNlcnRzKXtcbiAgY29uc3QgZXJyb3JzID0gbmV3IFNldCgpXG4gIE9iamVjdC5rZXlzKGluc2VydHMpLmZvckVhY2goKGlkKSA9PiB7XG4gICAgY29uc3Qgc3RyZWFtRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZClcbiAgICBpZihzdHJlYW1FbCAmJiBzdHJlYW1FbC5wYXJlbnRFbGVtZW50ICYmIHN0cmVhbUVsLnBhcmVudEVsZW1lbnQuZ2V0QXR0cmlidXRlKFwicGh4LXVwZGF0ZVwiKSAhPT0gXCJzdHJlYW1cIil7XG4gICAgICBlcnJvcnMuYWRkKGBUaGUgc3RyZWFtIGNvbnRhaW5lciB3aXRoIGlkIFwiJHtzdHJlYW1FbC5wYXJlbnRFbGVtZW50LmlkfVwiIGlzIG1pc3NpbmcgdGhlIHBoeC11cGRhdGU9XCJzdHJlYW1cIiBhdHRyaWJ1dGUuIEVuc3VyZSBpdCBpcyBzZXQgZm9yIHN0cmVhbXMgdG8gd29yayBwcm9wZXJseS5gKVxuICAgIH1cbiAgfSlcbiAgZXJyb3JzLmZvckVhY2goZXJyb3IgPT4gY29uc29sZS5lcnJvcihlcnJvcikpXG59XG5cbmV4cG9ydCBsZXQgZGVidWcgPSAodmlldywga2luZCwgbXNnLCBvYmopID0+IHtcbiAgaWYodmlldy5saXZlU29ja2V0LmlzRGVidWdFbmFibGVkKCkpe1xuICAgIGNvbnNvbGUubG9nKGAke3ZpZXcuaWR9ICR7a2luZH06ICR7bXNnfSAtIGAsIG9iailcbiAgfVxufVxuXG4vLyB3cmFwcyB2YWx1ZSBpbiBjbG9zdXJlIG9yIHJldHVybnMgY2xvc3VyZVxuZXhwb3J0IGxldCBjbG9zdXJlID0gKHZhbCkgPT4gdHlwZW9mIHZhbCA9PT0gXCJmdW5jdGlvblwiID8gdmFsIDogZnVuY3Rpb24gKCl7IHJldHVybiB2YWwgfVxuXG5leHBvcnQgbGV0IGNsb25lID0gKG9iaikgPT4geyByZXR1cm4gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShvYmopKSB9XG5cbmV4cG9ydCBsZXQgY2xvc2VzdFBoeEJpbmRpbmcgPSAoZWwsIGJpbmRpbmcsIGJvcmRlckVsKSA9PiB7XG4gIGRvIHtcbiAgICBpZihlbC5tYXRjaGVzKGBbJHtiaW5kaW5nfV1gKSAmJiAhZWwuZGlzYWJsZWQpeyByZXR1cm4gZWwgfVxuICAgIGVsID0gZWwucGFyZW50RWxlbWVudCB8fCBlbC5wYXJlbnROb2RlXG4gIH0gd2hpbGUoZWwgIT09IG51bGwgJiYgZWwubm9kZVR5cGUgPT09IDEgJiYgISgoYm9yZGVyRWwgJiYgYm9yZGVyRWwuaXNTYW1lTm9kZShlbCkpIHx8IGVsLm1hdGNoZXMoUEhYX1ZJRVdfU0VMRUNUT1IpKSlcbiAgcmV0dXJuIG51bGxcbn1cblxuZXhwb3J0IGxldCBpc09iamVjdCA9IChvYmopID0+IHtcbiAgcmV0dXJuIG9iaiAhPT0gbnVsbCAmJiB0eXBlb2Ygb2JqID09PSBcIm9iamVjdFwiICYmICEob2JqIGluc3RhbmNlb2YgQXJyYXkpXG59XG5cbmV4cG9ydCBsZXQgaXNFcXVhbE9iaiA9IChvYmoxLCBvYmoyKSA9PiBKU09OLnN0cmluZ2lmeShvYmoxKSA9PT0gSlNPTi5zdHJpbmdpZnkob2JqMilcblxuZXhwb3J0IGxldCBpc0VtcHR5ID0gKG9iaikgPT4ge1xuICBmb3IobGV0IHggaW4gb2JqKXsgcmV0dXJuIGZhbHNlIH1cbiAgcmV0dXJuIHRydWVcbn1cblxuZXhwb3J0IGxldCBtYXliZSA9IChlbCwgY2FsbGJhY2spID0+IGVsICYmIGNhbGxiYWNrKGVsKVxuXG5leHBvcnQgbGV0IGNoYW5uZWxVcGxvYWRlciA9IGZ1bmN0aW9uIChlbnRyaWVzLCBvbkVycm9yLCByZXNwLCBsaXZlU29ja2V0KXtcbiAgZW50cmllcy5mb3JFYWNoKGVudHJ5ID0+IHtcbiAgICBsZXQgZW50cnlVcGxvYWRlciA9IG5ldyBFbnRyeVVwbG9hZGVyKGVudHJ5LCByZXNwLmNvbmZpZywgbGl2ZVNvY2tldClcbiAgICBlbnRyeVVwbG9hZGVyLnVwbG9hZCgpXG4gIH0pXG59XG4iLCAibGV0IEJyb3dzZXIgPSB7XG4gIGNhblB1c2hTdGF0ZSgpeyByZXR1cm4gKHR5cGVvZiAoaGlzdG9yeS5wdXNoU3RhdGUpICE9PSBcInVuZGVmaW5lZFwiKSB9LFxuXG4gIGRyb3BMb2NhbChsb2NhbFN0b3JhZ2UsIG5hbWVzcGFjZSwgc3Via2V5KXtcbiAgICByZXR1cm4gbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5sb2NhbEtleShuYW1lc3BhY2UsIHN1YmtleSkpXG4gIH0sXG5cbiAgdXBkYXRlTG9jYWwobG9jYWxTdG9yYWdlLCBuYW1lc3BhY2UsIHN1YmtleSwgaW5pdGlhbCwgZnVuYyl7XG4gICAgbGV0IGN1cnJlbnQgPSB0aGlzLmdldExvY2FsKGxvY2FsU3RvcmFnZSwgbmFtZXNwYWNlLCBzdWJrZXkpXG4gICAgbGV0IGtleSA9IHRoaXMubG9jYWxLZXkobmFtZXNwYWNlLCBzdWJrZXkpXG4gICAgbGV0IG5ld1ZhbCA9IGN1cnJlbnQgPT09IG51bGwgPyBpbml0aWFsIDogZnVuYyhjdXJyZW50KVxuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkobmV3VmFsKSlcbiAgICByZXR1cm4gbmV3VmFsXG4gIH0sXG5cbiAgZ2V0TG9jYWwobG9jYWxTdG9yYWdlLCBuYW1lc3BhY2UsIHN1YmtleSl7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UobG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5sb2NhbEtleShuYW1lc3BhY2UsIHN1YmtleSkpKVxuICB9LFxuXG4gIHVwZGF0ZUN1cnJlbnRTdGF0ZShjYWxsYmFjayl7XG4gICAgaWYoIXRoaXMuY2FuUHVzaFN0YXRlKCkpeyByZXR1cm4gfVxuICAgIGhpc3RvcnkucmVwbGFjZVN0YXRlKGNhbGxiYWNrKGhpc3Rvcnkuc3RhdGUgfHwge30pLCBcIlwiLCB3aW5kb3cubG9jYXRpb24uaHJlZilcbiAgfSxcblxuICBwdXNoU3RhdGUoa2luZCwgbWV0YSwgdG8pe1xuICAgIGlmKHRoaXMuY2FuUHVzaFN0YXRlKCkpe1xuICAgICAgaWYodG8gIT09IHdpbmRvdy5sb2NhdGlvbi5ocmVmKXtcbiAgICAgICAgaWYobWV0YS50eXBlID09IFwicmVkaXJlY3RcIiAmJiBtZXRhLnNjcm9sbCl7XG4gICAgICAgICAgLy8gSWYgd2UncmUgcmVkaXJlY3Rpbmcgc3RvcmUgdGhlIGN1cnJlbnQgc2Nyb2xsWSBmb3IgdGhlIGN1cnJlbnQgaGlzdG9yeSBzdGF0ZS5cbiAgICAgICAgICBsZXQgY3VycmVudFN0YXRlID0gaGlzdG9yeS5zdGF0ZSB8fCB7fVxuICAgICAgICAgIGN1cnJlbnRTdGF0ZS5zY3JvbGwgPSBtZXRhLnNjcm9sbFxuICAgICAgICAgIGhpc3RvcnkucmVwbGFjZVN0YXRlKGN1cnJlbnRTdGF0ZSwgXCJcIiwgd2luZG93LmxvY2F0aW9uLmhyZWYpXG4gICAgICAgIH1cblxuICAgICAgICBkZWxldGUgbWV0YS5zY3JvbGwgLy8gT25seSBzdG9yZSB0aGUgc2Nyb2xsIGluIHRoZSByZWRpcmVjdCBjYXNlLlxuICAgICAgICBoaXN0b3J5W2tpbmQgKyBcIlN0YXRlXCJdKG1ldGEsIFwiXCIsIHRvIHx8IG51bGwpIC8vIElFIHdpbGwgY29lcmNlIHVuZGVmaW5lZCB0byBzdHJpbmdcblxuICAgICAgICAvLyB3aGVuIHVzaW5nIG5hdmlnYXRlLCB3ZSdkIGNhbGwgcHVzaFN0YXRlIGltbWVkaWF0ZWx5IGJlZm9yZSBwYXRjaGluZyB0aGUgRE9NLFxuICAgICAgICAvLyBqdW1waW5nIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGUgcGFnZSwgZWZmZWN0aXZlbHkgaWdub3JpbmcgdGhlIHNjcm9sbEludG9WaWV3O1xuICAgICAgICAvLyB0aGVyZWZvcmUgd2Ugd2FpdCBmb3IgdGhlIG5leHQgZnJhbWUgKGFmdGVyIHRoZSBET00gcGF0Y2gpIGFuZCBvbmx5IHRoZW4gdHJ5XG4gICAgICAgIC8vIHRvIHNjcm9sbCB0byB0aGUgaGFzaEVsXG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgIGxldCBoYXNoRWwgPSB0aGlzLmdldEhhc2hUYXJnZXRFbCh3aW5kb3cubG9jYXRpb24uaGFzaClcbiAgXG4gICAgICAgICAgaWYoaGFzaEVsKXtcbiAgICAgICAgICAgIGhhc2hFbC5zY3JvbGxJbnRvVmlldygpXG4gICAgICAgICAgfSBlbHNlIGlmKG1ldGEudHlwZSA9PT0gXCJyZWRpcmVjdFwiKXtcbiAgICAgICAgICAgIHdpbmRvdy5zY3JvbGwoMCwgMClcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucmVkaXJlY3QodG8pXG4gICAgfVxuICB9LFxuXG4gIHNldENvb2tpZShuYW1lLCB2YWx1ZSwgbWF4QWdlU2Vjb25kcyl7XG4gICAgbGV0IGV4cGlyZXMgPSB0eXBlb2YobWF4QWdlU2Vjb25kcykgPT09IFwibnVtYmVyXCIgPyBgIG1heC1hZ2U9JHttYXhBZ2VTZWNvbmRzfTtgIDogXCJcIlxuICAgIGRvY3VtZW50LmNvb2tpZSA9IGAke25hbWV9PSR7dmFsdWV9OyR7ZXhwaXJlc30gcGF0aD0vYFxuICB9LFxuXG4gIGdldENvb2tpZShuYW1lKXtcbiAgICByZXR1cm4gZG9jdW1lbnQuY29va2llLnJlcGxhY2UobmV3IFJlZ0V4cChgKD86KD86XnwuKjtcXHMqKSR7bmFtZX1cXHMqXFw9XFxzKihbXjtdKikuKiQpfF4uKiRgKSwgXCIkMVwiKVxuICB9LFxuXG4gIGRlbGV0ZUNvb2tpZShuYW1lKXtcbiAgICBkb2N1bWVudC5jb29raWUgPSBgJHtuYW1lfT07IG1heC1hZ2U9LTE7IHBhdGg9L2BcbiAgfSxcblxuICByZWRpcmVjdCh0b1VSTCwgZmxhc2gpe1xuICAgIGlmKGZsYXNoKXsgdGhpcy5zZXRDb29raWUoXCJfX3Bob2VuaXhfZmxhc2hfX1wiLCBmbGFzaCwgNjApIH1cbiAgICB3aW5kb3cubG9jYXRpb24gPSB0b1VSTFxuICB9LFxuXG4gIGxvY2FsS2V5KG5hbWVzcGFjZSwgc3Via2V5KXsgcmV0dXJuIGAke25hbWVzcGFjZX0tJHtzdWJrZXl9YCB9LFxuXG4gIGdldEhhc2hUYXJnZXRFbChtYXliZUhhc2gpe1xuICAgIGxldCBoYXNoID0gbWF5YmVIYXNoLnRvU3RyaW5nKCkuc3Vic3RyaW5nKDEpXG4gICAgaWYoaGFzaCA9PT0gXCJcIil7IHJldHVybiB9XG4gICAgcmV0dXJuIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGhhc2gpIHx8IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYGFbbmFtZT1cIiR7aGFzaH1cIl1gKVxuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEJyb3dzZXJcbiIsICJpbXBvcnQge1xuICBDSEVDS0FCTEVfSU5QVVRTLFxuICBERUJPVU5DRV9QUkVWX0tFWSxcbiAgREVCT1VOQ0VfVFJJR0dFUixcbiAgRk9DVVNBQkxFX0lOUFVUUyxcbiAgUEhYX0NPTVBPTkVOVCxcbiAgUEhYX0hBU19GT0NVU0VELFxuICBQSFhfSEFTX1NVQk1JVFRFRCxcbiAgUEhYX01BSU4sXG4gIFBIWF9QQVJFTlRfSUQsXG4gIFBIWF9QUklWQVRFLFxuICBQSFhfUkVGX1NSQyxcbiAgUEhYX1JFRl9MT0NLLFxuICBQSFhfUEVORElOR19BVFRSUyxcbiAgUEhYX1JPT1RfSUQsXG4gIFBIWF9TRVNTSU9OLFxuICBQSFhfU1RBVElDLFxuICBQSFhfVVBMT0FEX1JFRixcbiAgUEhYX1ZJRVdfU0VMRUNUT1IsXG4gIFBIWF9TVElDS1ksXG4gIFBIWF9FVkVOVF9DTEFTU0VTLFxuICBUSFJPVFRMRUQsXG4gIFBIWF9TVFJFQU0sXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCB7XG4gIGxvZ0Vycm9yXG59IGZyb20gXCIuL3V0aWxzXCJcblxubGV0IERPTSA9IHtcbiAgYnlJZChpZCl7IHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCkgfHwgbG9nRXJyb3IoYG5vIGlkIGZvdW5kIGZvciAke2lkfWApIH0sXG5cbiAgcmVtb3ZlQ2xhc3MoZWwsIGNsYXNzTmFtZSl7XG4gICAgZWwuY2xhc3NMaXN0LnJlbW92ZShjbGFzc05hbWUpXG4gICAgaWYoZWwuY2xhc3NMaXN0Lmxlbmd0aCA9PT0gMCl7IGVsLnJlbW92ZUF0dHJpYnV0ZShcImNsYXNzXCIpIH1cbiAgfSxcblxuICBhbGwobm9kZSwgcXVlcnksIGNhbGxiYWNrKXtcbiAgICBpZighbm9kZSl7IHJldHVybiBbXSB9XG4gICAgbGV0IGFycmF5ID0gQXJyYXkuZnJvbShub2RlLnF1ZXJ5U2VsZWN0b3JBbGwocXVlcnkpKVxuICAgIHJldHVybiBjYWxsYmFjayA/IGFycmF5LmZvckVhY2goY2FsbGJhY2spIDogYXJyYXlcbiAgfSxcblxuICBjaGlsZE5vZGVMZW5ndGgoaHRtbCl7XG4gICAgbGV0IHRlbXBsYXRlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInRlbXBsYXRlXCIpXG4gICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gaHRtbFxuICAgIHJldHVybiB0ZW1wbGF0ZS5jb250ZW50LmNoaWxkRWxlbWVudENvdW50XG4gIH0sXG5cbiAgaXNVcGxvYWRJbnB1dChlbCl7IHJldHVybiBlbC50eXBlID09PSBcImZpbGVcIiAmJiBlbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpICE9PSBudWxsIH0sXG5cbiAgaXNBdXRvVXBsb2FkKGlucHV0RWwpeyByZXR1cm4gaW5wdXRFbC5oYXNBdHRyaWJ1dGUoXCJkYXRhLXBoeC1hdXRvLXVwbG9hZFwiKSB9LFxuXG4gIGZpbmRVcGxvYWRJbnB1dHMobm9kZSl7XG4gICAgY29uc3QgZm9ybUlkID0gbm9kZS5pZFxuICAgIGNvbnN0IGlucHV0c091dHNpZGVGb3JtID0gdGhpcy5hbGwoZG9jdW1lbnQsIGBpbnB1dFt0eXBlPVwiZmlsZVwiXVske1BIWF9VUExPQURfUkVGfV1bZm9ybT1cIiR7Zm9ybUlkfVwiXWApXG4gICAgcmV0dXJuIHRoaXMuYWxsKG5vZGUsIGBpbnB1dFt0eXBlPVwiZmlsZVwiXVske1BIWF9VUExPQURfUkVGfV1gKS5jb25jYXQoaW5wdXRzT3V0c2lkZUZvcm0pXG4gIH0sXG5cbiAgZmluZENvbXBvbmVudE5vZGVMaXN0KG5vZGUsIGNpZCl7XG4gICAgcmV0dXJuIHRoaXMuZmlsdGVyV2l0aGluU2FtZUxpdmVWaWV3KHRoaXMuYWxsKG5vZGUsIGBbJHtQSFhfQ09NUE9ORU5UfT1cIiR7Y2lkfVwiXWApLCBub2RlKVxuICB9LFxuXG4gIGlzUGh4RGVzdHJveWVkKG5vZGUpe1xuICAgIHJldHVybiBub2RlLmlkICYmIERPTS5wcml2YXRlKG5vZGUsIFwiZGVzdHJveWVkXCIpID8gdHJ1ZSA6IGZhbHNlXG4gIH0sXG5cbiAgd2FudHNOZXdUYWIoZSl7XG4gICAgbGV0IHdhbnRzTmV3VGFiID0gZS5jdHJsS2V5IHx8IGUuc2hpZnRLZXkgfHwgZS5tZXRhS2V5IHx8IChlLmJ1dHRvbiAmJiBlLmJ1dHRvbiA9PT0gMSlcbiAgICBsZXQgaXNEb3dubG9hZCA9IChlLnRhcmdldCBpbnN0YW5jZW9mIEhUTUxBbmNob3JFbGVtZW50ICYmIGUudGFyZ2V0Lmhhc0F0dHJpYnV0ZShcImRvd25sb2FkXCIpKVxuICAgIGxldCBpc1RhcmdldEJsYW5rID0gZS50YXJnZXQuaGFzQXR0cmlidXRlKFwidGFyZ2V0XCIpICYmIGUudGFyZ2V0LmdldEF0dHJpYnV0ZShcInRhcmdldFwiKS50b0xvd2VyQ2FzZSgpID09PSBcIl9ibGFua1wiXG4gICAgbGV0IGlzVGFyZ2V0TmFtZWRUYWIgPSBlLnRhcmdldC5oYXNBdHRyaWJ1dGUoXCJ0YXJnZXRcIikgJiYgIWUudGFyZ2V0LmdldEF0dHJpYnV0ZShcInRhcmdldFwiKS5zdGFydHNXaXRoKFwiX1wiKVxuICAgIHJldHVybiB3YW50c05ld1RhYiB8fCBpc1RhcmdldEJsYW5rIHx8IGlzRG93bmxvYWQgfHwgaXNUYXJnZXROYW1lZFRhYlxuICB9LFxuXG4gIGlzVW5sb2FkYWJsZUZvcm1TdWJtaXQoZSl7XG4gICAgLy8gSWdub3JlIGZvcm0gc3VibWlzc2lvbnMgaW50ZW5kZWQgdG8gY2xvc2UgYSBuYXRpdmUgPGRpYWxvZz4gZWxlbWVudFxuICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0hUTUwvRWxlbWVudC9kaWFsb2cjdXNhZ2Vfbm90ZXNcbiAgICBsZXQgaXNEaWFsb2dTdWJtaXQgPSAoZS50YXJnZXQgJiYgZS50YXJnZXQuZ2V0QXR0cmlidXRlKFwibWV0aG9kXCIpID09PSBcImRpYWxvZ1wiKSB8fFxuICAgICAgKGUuc3VibWl0dGVyICYmIGUuc3VibWl0dGVyLmdldEF0dHJpYnV0ZShcImZvcm1tZXRob2RcIikgPT09IFwiZGlhbG9nXCIpXG5cbiAgICBpZihpc0RpYWxvZ1N1Ym1pdCl7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICFlLmRlZmF1bHRQcmV2ZW50ZWQgJiYgIXRoaXMud2FudHNOZXdUYWIoZSlcbiAgICB9XG4gIH0sXG5cbiAgaXNOZXdQYWdlQ2xpY2soZSwgY3VycmVudExvY2F0aW9uKXtcbiAgICBsZXQgaHJlZiA9IGUudGFyZ2V0IGluc3RhbmNlb2YgSFRNTEFuY2hvckVsZW1lbnQgPyBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoXCJocmVmXCIpIDogbnVsbFxuICAgIGxldCB1cmxcblxuICAgIGlmKGUuZGVmYXVsdFByZXZlbnRlZCB8fCBocmVmID09PSBudWxsIHx8IHRoaXMud2FudHNOZXdUYWIoZSkpeyByZXR1cm4gZmFsc2UgfVxuICAgIGlmKGhyZWYuc3RhcnRzV2l0aChcIm1haWx0bzpcIikgfHwgaHJlZi5zdGFydHNXaXRoKFwidGVsOlwiKSl7IHJldHVybiBmYWxzZSB9XG4gICAgaWYoZS50YXJnZXQuaXNDb250ZW50RWRpdGFibGUpeyByZXR1cm4gZmFsc2UgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHVybCA9IG5ldyBVUkwoaHJlZilcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHVybCA9IG5ldyBVUkwoaHJlZiwgY3VycmVudExvY2F0aW9uKVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIGJhZCBVUkwsIGZhbGxiYWNrIHRvIGxldCBicm93c2VyIHRyeSBpdCBhcyBleHRlcm5hbFxuICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmKHVybC5ob3N0ID09PSBjdXJyZW50TG9jYXRpb24uaG9zdCAmJiB1cmwucHJvdG9jb2wgPT09IGN1cnJlbnRMb2NhdGlvbi5wcm90b2NvbCl7XG4gICAgICBpZih1cmwucGF0aG5hbWUgPT09IGN1cnJlbnRMb2NhdGlvbi5wYXRobmFtZSAmJiB1cmwuc2VhcmNoID09PSBjdXJyZW50TG9jYXRpb24uc2VhcmNoKXtcbiAgICAgICAgcmV0dXJuIHVybC5oYXNoID09PSBcIlwiICYmICF1cmwuaHJlZi5lbmRzV2l0aChcIiNcIilcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVybC5wcm90b2NvbC5zdGFydHNXaXRoKFwiaHR0cFwiKVxuICB9LFxuXG4gIG1hcmtQaHhDaGlsZERlc3Ryb3llZChlbCl7XG4gICAgaWYodGhpcy5pc1BoeENoaWxkKGVsKSl7IGVsLnNldEF0dHJpYnV0ZShQSFhfU0VTU0lPTiwgXCJcIikgfVxuICAgIHRoaXMucHV0UHJpdmF0ZShlbCwgXCJkZXN0cm95ZWRcIiwgdHJ1ZSlcbiAgfSxcblxuICBmaW5kUGh4Q2hpbGRyZW5JbkZyYWdtZW50KGh0bWwsIHBhcmVudElkKXtcbiAgICBsZXQgdGVtcGxhdGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwidGVtcGxhdGVcIilcbiAgICB0ZW1wbGF0ZS5pbm5lckhUTUwgPSBodG1sXG4gICAgcmV0dXJuIHRoaXMuZmluZFBoeENoaWxkcmVuKHRlbXBsYXRlLmNvbnRlbnQsIHBhcmVudElkKVxuICB9LFxuXG4gIGlzSWdub3JlZChlbCwgcGh4VXBkYXRlKXtcbiAgICByZXR1cm4gKGVsLmdldEF0dHJpYnV0ZShwaHhVcGRhdGUpIHx8IGVsLmdldEF0dHJpYnV0ZShcImRhdGEtcGh4LXVwZGF0ZVwiKSkgPT09IFwiaWdub3JlXCJcbiAgfSxcblxuICBpc1BoeFVwZGF0ZShlbCwgcGh4VXBkYXRlLCB1cGRhdGVUeXBlcyl7XG4gICAgcmV0dXJuIGVsLmdldEF0dHJpYnV0ZSAmJiB1cGRhdGVUeXBlcy5pbmRleE9mKGVsLmdldEF0dHJpYnV0ZShwaHhVcGRhdGUpKSA+PSAwXG4gIH0sXG5cbiAgZmluZFBoeFN0aWNreShlbCl7IHJldHVybiB0aGlzLmFsbChlbCwgYFske1BIWF9TVElDS1l9XWApIH0sXG5cbiAgZmluZFBoeENoaWxkcmVuKGVsLCBwYXJlbnRJZCl7XG4gICAgcmV0dXJuIHRoaXMuYWxsKGVsLCBgJHtQSFhfVklFV19TRUxFQ1RPUn1bJHtQSFhfUEFSRU5UX0lEfT1cIiR7cGFyZW50SWR9XCJdYClcbiAgfSxcblxuICBmaW5kRXhpc3RpbmdQYXJlbnRDSURzKG5vZGUsIGNpZHMpe1xuICAgIC8vIHdlIG9ubHkgd2FudCB0byBmaW5kIHBhcmVudHMgdGhhdCBleGlzdCBvbiB0aGUgcGFnZVxuICAgIC8vIGlmIGEgY2lkIGlzIG5vdCBvbiB0aGUgcGFnZSwgdGhlIG9ubHkgd2F5IGl0IGNhbiBiZSBhZGRlZCBiYWNrIHRvIHRoZSBwYWdlXG4gICAgLy8gaXMgaWYgYSBwYXJlbnQgYWRkcyBpdCBiYWNrLCB0aGVyZWZvcmUgaWYgYSBjaWQgZG9lcyBub3QgZXhpc3Qgb24gdGhlIHBhZ2UsXG4gICAgLy8gd2Ugc2hvdWxkIG5vdCB0cnkgdG8gcmVuZGVyIGl0IGJ5IGl0c2VsZiAoYmVjYXVzZSBpdCB3b3VsZCBiZSByZW5kZXJlZCB0d2ljZSxcbiAgICAvLyBvbmUgYnkgdGhlIHBhcmVudCwgYW5kIGEgc2Vjb25kIHRpbWUgYnkgaXRzZWxmKVxuICAgIGxldCBwYXJlbnRDaWRzID0gbmV3IFNldCgpXG4gICAgbGV0IGNoaWxkcmVuQ2lkcyA9IG5ldyBTZXQoKVxuXG4gICAgY2lkcy5mb3JFYWNoKGNpZCA9PiB7XG4gICAgICB0aGlzLmZpbHRlcldpdGhpblNhbWVMaXZlVmlldyh0aGlzLmFsbChub2RlLCBgWyR7UEhYX0NPTVBPTkVOVH09XCIke2NpZH1cIl1gKSwgbm9kZSkuZm9yRWFjaChwYXJlbnQgPT4ge1xuICAgICAgICBwYXJlbnRDaWRzLmFkZChjaWQpXG4gICAgICAgIHRoaXMuZmlsdGVyV2l0aGluU2FtZUxpdmVWaWV3KHRoaXMuYWxsKHBhcmVudCwgYFske1BIWF9DT01QT05FTlR9XWApLCBwYXJlbnQpXG4gICAgICAgICAgLm1hcChlbCA9PiBwYXJzZUludChlbC5nZXRBdHRyaWJ1dGUoUEhYX0NPTVBPTkVOVCkpKVxuICAgICAgICAgIC5mb3JFYWNoKGNoaWxkQ0lEID0+IGNoaWxkcmVuQ2lkcy5hZGQoY2hpbGRDSUQpKVxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgY2hpbGRyZW5DaWRzLmZvckVhY2goY2hpbGRDaWQgPT4gcGFyZW50Q2lkcy5kZWxldGUoY2hpbGRDaWQpKVxuXG4gICAgcmV0dXJuIHBhcmVudENpZHNcbiAgfSxcblxuICBmaWx0ZXJXaXRoaW5TYW1lTGl2ZVZpZXcobm9kZXMsIHBhcmVudCl7XG4gICAgaWYocGFyZW50LnF1ZXJ5U2VsZWN0b3IoUEhYX1ZJRVdfU0VMRUNUT1IpKXtcbiAgICAgIHJldHVybiBub2Rlcy5maWx0ZXIoZWwgPT4gdGhpcy53aXRoaW5TYW1lTGl2ZVZpZXcoZWwsIHBhcmVudCkpXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBub2Rlc1xuICAgIH1cbiAgfSxcblxuICB3aXRoaW5TYW1lTGl2ZVZpZXcobm9kZSwgcGFyZW50KXtcbiAgICB3aGlsZShub2RlID0gbm9kZS5wYXJlbnROb2RlKXtcbiAgICAgIGlmKG5vZGUuaXNTYW1lTm9kZShwYXJlbnQpKXsgcmV0dXJuIHRydWUgfVxuICAgICAgaWYobm9kZS5nZXRBdHRyaWJ1dGUoUEhYX1NFU1NJT04pICE9PSBudWxsKXsgcmV0dXJuIGZhbHNlIH1cbiAgICB9XG4gIH0sXG5cbiAgcHJpdmF0ZShlbCwga2V5KXsgcmV0dXJuIGVsW1BIWF9QUklWQVRFXSAmJiBlbFtQSFhfUFJJVkFURV1ba2V5XSB9LFxuXG4gIGRlbGV0ZVByaXZhdGUoZWwsIGtleSl7IGVsW1BIWF9QUklWQVRFXSAmJiBkZWxldGUgKGVsW1BIWF9QUklWQVRFXVtrZXldKSB9LFxuXG4gIHB1dFByaXZhdGUoZWwsIGtleSwgdmFsdWUpe1xuICAgIGlmKCFlbFtQSFhfUFJJVkFURV0peyBlbFtQSFhfUFJJVkFURV0gPSB7fSB9XG4gICAgZWxbUEhYX1BSSVZBVEVdW2tleV0gPSB2YWx1ZVxuICB9LFxuXG4gIHVwZGF0ZVByaXZhdGUoZWwsIGtleSwgZGVmYXVsdFZhbCwgdXBkYXRlRnVuYyl7XG4gICAgbGV0IGV4aXN0aW5nID0gdGhpcy5wcml2YXRlKGVsLCBrZXkpXG4gICAgaWYoZXhpc3RpbmcgPT09IHVuZGVmaW5lZCl7XG4gICAgICB0aGlzLnB1dFByaXZhdGUoZWwsIGtleSwgdXBkYXRlRnVuYyhkZWZhdWx0VmFsKSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5wdXRQcml2YXRlKGVsLCBrZXksIHVwZGF0ZUZ1bmMoZXhpc3RpbmcpKVxuICAgIH1cbiAgfSxcblxuICBzeW5jUGVuZGluZ0F0dHJzKGZyb21FbCwgdG9FbCl7XG4gICAgaWYoIWZyb21FbC5oYXNBdHRyaWJ1dGUoUEhYX1JFRl9TUkMpKXsgcmV0dXJuIH1cbiAgICBQSFhfRVZFTlRfQ0xBU1NFUy5mb3JFYWNoKGNsYXNzTmFtZSA9PiB7XG4gICAgICBmcm9tRWwuY2xhc3NMaXN0LmNvbnRhaW5zKGNsYXNzTmFtZSkgJiYgdG9FbC5jbGFzc0xpc3QuYWRkKGNsYXNzTmFtZSlcbiAgICB9KVxuICAgIFBIWF9QRU5ESU5HX0FUVFJTLmZpbHRlcihhdHRyID0+IGZyb21FbC5oYXNBdHRyaWJ1dGUoYXR0cikpLmZvckVhY2goYXR0ciA9PiB7XG4gICAgICB0b0VsLnNldEF0dHJpYnV0ZShhdHRyLCBmcm9tRWwuZ2V0QXR0cmlidXRlKGF0dHIpKVxuICAgIH0pXG4gIH0sXG5cbiAgY29weVByaXZhdGVzKHRhcmdldCwgc291cmNlKXtcbiAgICBpZihzb3VyY2VbUEhYX1BSSVZBVEVdKXtcbiAgICAgIHRhcmdldFtQSFhfUFJJVkFURV0gPSBzb3VyY2VbUEhYX1BSSVZBVEVdXG4gICAgfVxuICB9LFxuXG4gIHB1dFRpdGxlKHN0cil7XG4gICAgbGV0IHRpdGxlRWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwidGl0bGVcIilcbiAgICBpZih0aXRsZUVsKXtcbiAgICAgIGxldCB7cHJlZml4LCBzdWZmaXgsIGRlZmF1bHQ6IGRlZmF1bHRUaXRsZX0gPSB0aXRsZUVsLmRhdGFzZXRcbiAgICAgIGxldCBpc0VtcHR5ID0gdHlwZW9mKHN0cikgIT09IFwic3RyaW5nXCIgfHwgc3RyLnRyaW0oKSA9PT0gXCJcIlxuICAgICAgaWYoaXNFbXB0eSAmJiB0eXBlb2YoZGVmYXVsdFRpdGxlKSAhPT0gXCJzdHJpbmdcIil7IHJldHVybiB9XG5cbiAgICAgIGxldCBpbm5lciA9IGlzRW1wdHkgPyBkZWZhdWx0VGl0bGUgOiBzdHJcbiAgICAgIGRvY3VtZW50LnRpdGxlID0gYCR7cHJlZml4IHx8IFwiXCJ9JHtpbm5lciB8fCBcIlwifSR7c3VmZml4IHx8IFwiXCJ9YFxuICAgIH0gZWxzZSB7XG4gICAgICBkb2N1bWVudC50aXRsZSA9IHN0clxuICAgIH1cbiAgfSxcblxuICBkZWJvdW5jZShlbCwgZXZlbnQsIHBoeERlYm91bmNlLCBkZWZhdWx0RGVib3VuY2UsIHBoeFRocm90dGxlLCBkZWZhdWx0VGhyb3R0bGUsIGFzeW5jRmlsdGVyLCBjYWxsYmFjayl7XG4gICAgbGV0IGRlYm91bmNlID0gZWwuZ2V0QXR0cmlidXRlKHBoeERlYm91bmNlKVxuICAgIGxldCB0aHJvdHRsZSA9IGVsLmdldEF0dHJpYnV0ZShwaHhUaHJvdHRsZSlcblxuICAgIGlmKGRlYm91bmNlID09PSBcIlwiKXsgZGVib3VuY2UgPSBkZWZhdWx0RGVib3VuY2UgfVxuICAgIGlmKHRocm90dGxlID09PSBcIlwiKXsgdGhyb3R0bGUgPSBkZWZhdWx0VGhyb3R0bGUgfVxuICAgIGxldCB2YWx1ZSA9IGRlYm91bmNlIHx8IHRocm90dGxlXG4gICAgc3dpdGNoKHZhbHVlKXtcbiAgICAgIGNhc2UgbnVsbDogcmV0dXJuIGNhbGxiYWNrKClcblxuICAgICAgY2FzZSBcImJsdXJcIjpcbiAgICAgICAgdGhpcy5pbmNDeWNsZShlbCwgXCJkZWJvdW5jZS1ibHVyLWN5Y2xlXCIsICgpID0+IHtcbiAgICAgICAgICBpZihhc3luY0ZpbHRlcigpKXsgY2FsbGJhY2soKSB9XG4gICAgICAgIH0pXG4gICAgICAgIGlmKHRoaXMub25jZShlbCwgXCJkZWJvdW5jZS1ibHVyXCIpKXtcbiAgICAgICAgICBlbC5hZGRFdmVudExpc3RlbmVyKFwiYmx1clwiLCAoKSA9PiB0aGlzLnRyaWdnZXJDeWNsZShlbCwgXCJkZWJvdW5jZS1ibHVyLWN5Y2xlXCIpKVxuICAgICAgICB9XG4gICAgICAgIHJldHVyblxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsZXQgdGltZW91dCA9IHBhcnNlSW50KHZhbHVlKVxuICAgICAgICBsZXQgdHJpZ2dlciA9ICgpID0+IHRocm90dGxlID8gdGhpcy5kZWxldGVQcml2YXRlKGVsLCBUSFJPVFRMRUQpIDogY2FsbGJhY2soKVxuICAgICAgICBsZXQgY3VycmVudEN5Y2xlID0gdGhpcy5pbmNDeWNsZShlbCwgREVCT1VOQ0VfVFJJR0dFUiwgdHJpZ2dlcilcbiAgICAgICAgaWYoaXNOYU4odGltZW91dCkpeyByZXR1cm4gbG9nRXJyb3IoYGludmFsaWQgdGhyb3R0bGUvZGVib3VuY2UgdmFsdWU6ICR7dmFsdWV9YCkgfVxuICAgICAgICBpZih0aHJvdHRsZSl7XG4gICAgICAgICAgbGV0IG5ld0tleURvd24gPSBmYWxzZVxuICAgICAgICAgIGlmKGV2ZW50LnR5cGUgPT09IFwia2V5ZG93blwiKXtcbiAgICAgICAgICAgIGxldCBwcmV2S2V5ID0gdGhpcy5wcml2YXRlKGVsLCBERUJPVU5DRV9QUkVWX0tFWSlcbiAgICAgICAgICAgIHRoaXMucHV0UHJpdmF0ZShlbCwgREVCT1VOQ0VfUFJFVl9LRVksIGV2ZW50LmtleSlcbiAgICAgICAgICAgIG5ld0tleURvd24gPSBwcmV2S2V5ICE9PSBldmVudC5rZXlcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZighbmV3S2V5RG93biAmJiB0aGlzLnByaXZhdGUoZWwsIFRIUk9UVExFRCkpe1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKClcbiAgICAgICAgICAgIGNvbnN0IHQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgaWYoYXN5bmNGaWx0ZXIoKSl7IHRoaXMudHJpZ2dlckN5Y2xlKGVsLCBERUJPVU5DRV9UUklHR0VSKSB9XG4gICAgICAgICAgICB9LCB0aW1lb3V0KVxuICAgICAgICAgICAgdGhpcy5wdXRQcml2YXRlKGVsLCBUSFJPVFRMRUQsIHQpXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYoYXN5bmNGaWx0ZXIoKSl7IHRoaXMudHJpZ2dlckN5Y2xlKGVsLCBERUJPVU5DRV9UUklHR0VSLCBjdXJyZW50Q3ljbGUpIH1cbiAgICAgICAgICB9LCB0aW1lb3V0KVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGZvcm0gPSBlbC5mb3JtXG4gICAgICAgIGlmKGZvcm0gJiYgdGhpcy5vbmNlKGZvcm0sIFwiYmluZC1kZWJvdW5jZVwiKSl7XG4gICAgICAgICAgZm9ybS5hZGRFdmVudExpc3RlbmVyKFwic3VibWl0XCIsICgpID0+IHtcbiAgICAgICAgICAgIEFycmF5LmZyb20oKG5ldyBGb3JtRGF0YShmb3JtKSkuZW50cmllcygpLCAoW25hbWVdKSA9PiB7XG4gICAgICAgICAgICAgIGxldCBpbnB1dCA9IGZvcm0ucXVlcnlTZWxlY3RvcihgW25hbWU9XCIke25hbWV9XCJdYClcbiAgICAgICAgICAgICAgdGhpcy5pbmNDeWNsZShpbnB1dCwgREVCT1VOQ0VfVFJJR0dFUilcbiAgICAgICAgICAgICAgdGhpcy5kZWxldGVQcml2YXRlKGlucHV0LCBUSFJPVFRMRUQpXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgICAgaWYodGhpcy5vbmNlKGVsLCBcImJpbmQtZGVib3VuY2VcIikpe1xuICAgICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJibHVyXCIsICgpID0+IHtcbiAgICAgICAgICAgIC8vIGJlY2F1c2Ugd2UgdHJpZ2dlciB0aGUgY2FsbGJhY2sgaGVyZSxcbiAgICAgICAgICAgIC8vIHdlIGFsc28gY2xlYXIgdGhlIHRocm90dGxlIHRpbWVvdXQgdG8gcHJldmVudCB0aGUgY2FsbGJhY2tcbiAgICAgICAgICAgIC8vIGZyb20gYmVpbmcgY2FsbGVkIGFnYWluIGFmdGVyIHRoZSB0aW1lb3V0IGZpcmVzXG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5wcml2YXRlKGVsLCBUSFJPVFRMRUQpKVxuICAgICAgICAgICAgdGhpcy50cmlnZ2VyQ3ljbGUoZWwsIERFQk9VTkNFX1RSSUdHRVIpXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgIH1cbiAgfSxcblxuICB0cmlnZ2VyQ3ljbGUoZWwsIGtleSwgY3VycmVudEN5Y2xlKXtcbiAgICBsZXQgW2N5Y2xlLCB0cmlnZ2VyXSA9IHRoaXMucHJpdmF0ZShlbCwga2V5KVxuICAgIGlmKCFjdXJyZW50Q3ljbGUpeyBjdXJyZW50Q3ljbGUgPSBjeWNsZSB9XG4gICAgaWYoY3VycmVudEN5Y2xlID09PSBjeWNsZSl7XG4gICAgICB0aGlzLmluY0N5Y2xlKGVsLCBrZXkpXG4gICAgICB0cmlnZ2VyKClcbiAgICB9XG4gIH0sXG5cbiAgb25jZShlbCwga2V5KXtcbiAgICBpZih0aGlzLnByaXZhdGUoZWwsIGtleSkgPT09IHRydWUpeyByZXR1cm4gZmFsc2UgfVxuICAgIHRoaXMucHV0UHJpdmF0ZShlbCwga2V5LCB0cnVlKVxuICAgIHJldHVybiB0cnVlXG4gIH0sXG5cbiAgaW5jQ3ljbGUoZWwsIGtleSwgdHJpZ2dlciA9IGZ1bmN0aW9uICgpeyB9KXtcbiAgICBsZXQgW2N1cnJlbnRDeWNsZV0gPSB0aGlzLnByaXZhdGUoZWwsIGtleSkgfHwgWzAsIHRyaWdnZXJdXG4gICAgY3VycmVudEN5Y2xlKytcbiAgICB0aGlzLnB1dFByaXZhdGUoZWwsIGtleSwgW2N1cnJlbnRDeWNsZSwgdHJpZ2dlcl0pXG4gICAgcmV0dXJuIGN1cnJlbnRDeWNsZVxuICB9LFxuXG4gIC8vIG1haW50YWlucyBvciBhZGRzIHByaXZhdGVseSB1c2VkIGhvb2sgaW5mb3JtYXRpb25cbiAgLy8gZnJvbUVsIGFuZCB0b0VsIGNhbiBiZSB0aGUgc2FtZSBlbGVtZW50IGluIHRoZSBjYXNlIG9mIGEgbmV3bHkgYWRkZWQgbm9kZVxuICAvLyBmcm9tRWwgYW5kIHRvRWwgY2FuIGJlIGFueSBIVE1MIG5vZGUgdHlwZSwgc28gd2UgbmVlZCB0byBjaGVjayBpZiBpdCdzIGFuIGVsZW1lbnQgbm9kZVxuICBtYWludGFpblByaXZhdGVIb29rcyhmcm9tRWwsIHRvRWwsIHBoeFZpZXdwb3J0VG9wLCBwaHhWaWV3cG9ydEJvdHRvbSl7XG4gICAgLy8gbWFpbnRhaW4gdGhlIGhvb2tzIGNyZWF0ZWQgd2l0aCBjcmVhdGVIb29rXG4gICAgaWYoZnJvbUVsLmhhc0F0dHJpYnV0ZSAmJiBmcm9tRWwuaGFzQXR0cmlidXRlKFwiZGF0YS1waHgtaG9va1wiKSAmJiAhdG9FbC5oYXNBdHRyaWJ1dGUoXCJkYXRhLXBoeC1ob29rXCIpKXtcbiAgICAgIHRvRWwuc2V0QXR0cmlidXRlKFwiZGF0YS1waHgtaG9va1wiLCBmcm9tRWwuZ2V0QXR0cmlidXRlKFwiZGF0YS1waHgtaG9va1wiKSlcbiAgICB9XG4gICAgLy8gYWRkIGhvb2tzIHRvIGVsZW1lbnRzIHdpdGggdmlld3BvcnQgYXR0cmlidXRlc1xuICAgIGlmKHRvRWwuaGFzQXR0cmlidXRlICYmICh0b0VsLmhhc0F0dHJpYnV0ZShwaHhWaWV3cG9ydFRvcCkgfHwgdG9FbC5oYXNBdHRyaWJ1dGUocGh4Vmlld3BvcnRCb3R0b20pKSl7XG4gICAgICB0b0VsLnNldEF0dHJpYnV0ZShcImRhdGEtcGh4LWhvb2tcIiwgXCJQaG9lbml4LkluZmluaXRlU2Nyb2xsXCIpXG4gICAgfVxuICB9LFxuXG4gIHB1dEN1c3RvbUVsSG9vayhlbCwgaG9vayl7XG4gICAgaWYoZWwuaXNDb25uZWN0ZWQpe1xuICAgICAgZWwuc2V0QXR0cmlidXRlKFwiZGF0YS1waHgtaG9va1wiLCBcIlwiKVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBcbiAgICAgICAgaG9vayBhdHRhY2hlZCB0byBub24tY29ubmVjdGVkIERPTSBlbGVtZW50XG4gICAgICAgIGVuc3VyZSB5b3UgYXJlIGNhbGxpbmcgY3JlYXRlSG9vayB3aXRoaW4geW91ciBjb25uZWN0ZWRDYWxsYmFjay4gJHtlbC5vdXRlckhUTUx9XG4gICAgICBgKVxuICAgIH1cbiAgICB0aGlzLnB1dFByaXZhdGUoZWwsIFwiY3VzdG9tLWVsLWhvb2tcIiwgaG9vaylcbiAgfSxcblxuICBnZXRDdXN0b21FbEhvb2soZWwpeyByZXR1cm4gdGhpcy5wcml2YXRlKGVsLCBcImN1c3RvbS1lbC1ob29rXCIpIH0sXG5cbiAgaXNVc2VkSW5wdXQoZWwpe1xuICAgIHJldHVybiAoZWwubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmXG4gICAgICAodGhpcy5wcml2YXRlKGVsLCBQSFhfSEFTX0ZPQ1VTRUQpIHx8IHRoaXMucHJpdmF0ZShlbCwgUEhYX0hBU19TVUJNSVRURUQpKSlcbiAgfSxcblxuICByZXNldEZvcm0oZm9ybSl7XG4gICAgQXJyYXkuZnJvbShmb3JtLmVsZW1lbnRzKS5mb3JFYWNoKGlucHV0ID0+IHtcbiAgICAgIHRoaXMuZGVsZXRlUHJpdmF0ZShpbnB1dCwgUEhYX0hBU19GT0NVU0VEKVxuICAgICAgdGhpcy5kZWxldGVQcml2YXRlKGlucHV0LCBQSFhfSEFTX1NVQk1JVFRFRClcbiAgICB9KVxuICB9LFxuXG4gIGlzUGh4Q2hpbGQobm9kZSl7XG4gICAgcmV0dXJuIG5vZGUuZ2V0QXR0cmlidXRlICYmIG5vZGUuZ2V0QXR0cmlidXRlKFBIWF9QQVJFTlRfSUQpXG4gIH0sXG5cbiAgaXNQaHhTdGlja3kobm9kZSl7XG4gICAgcmV0dXJuIG5vZGUuZ2V0QXR0cmlidXRlICYmIG5vZGUuZ2V0QXR0cmlidXRlKFBIWF9TVElDS1kpICE9PSBudWxsXG4gIH0sXG5cbiAgaXNDaGlsZE9mQW55KGVsLCBwYXJlbnRzKXtcbiAgICByZXR1cm4gISFwYXJlbnRzLmZpbmQocGFyZW50ID0+IHBhcmVudC5jb250YWlucyhlbCkpXG4gIH0sXG5cbiAgZmlyc3RQaHhDaGlsZChlbCl7XG4gICAgcmV0dXJuIHRoaXMuaXNQaHhDaGlsZChlbCkgPyBlbCA6IHRoaXMuYWxsKGVsLCBgWyR7UEhYX1BBUkVOVF9JRH1dYClbMF1cbiAgfSxcblxuICBkaXNwYXRjaEV2ZW50KHRhcmdldCwgbmFtZSwgb3B0cyA9IHt9KXtcbiAgICBsZXQgZGVmYXVsdEJ1YmJsZSA9IHRydWVcbiAgICBsZXQgaXNVcGxvYWRUYXJnZXQgPSB0YXJnZXQubm9kZU5hbWUgPT09IFwiSU5QVVRcIiAmJiB0YXJnZXQudHlwZSA9PT0gXCJmaWxlXCJcbiAgICBpZihpc1VwbG9hZFRhcmdldCAmJiBuYW1lID09PSBcImNsaWNrXCIpe1xuICAgICAgZGVmYXVsdEJ1YmJsZSA9IGZhbHNlXG4gICAgfVxuICAgIGxldCBidWJibGVzID0gb3B0cy5idWJibGVzID09PSB1bmRlZmluZWQgPyBkZWZhdWx0QnViYmxlIDogISFvcHRzLmJ1YmJsZXNcbiAgICBsZXQgZXZlbnRPcHRzID0ge2J1YmJsZXM6IGJ1YmJsZXMsIGNhbmNlbGFibGU6IHRydWUsIGRldGFpbDogb3B0cy5kZXRhaWwgfHwge319XG4gICAgbGV0IGV2ZW50ID0gbmFtZSA9PT0gXCJjbGlja1wiID8gbmV3IE1vdXNlRXZlbnQoXCJjbGlja1wiLCBldmVudE9wdHMpIDogbmV3IEN1c3RvbUV2ZW50KG5hbWUsIGV2ZW50T3B0cylcbiAgICB0YXJnZXQuZGlzcGF0Y2hFdmVudChldmVudClcbiAgfSxcblxuICBjbG9uZU5vZGUobm9kZSwgaHRtbCl7XG4gICAgaWYodHlwZW9mIChodG1sKSA9PT0gXCJ1bmRlZmluZWRcIil7XG4gICAgICByZXR1cm4gbm9kZS5jbG9uZU5vZGUodHJ1ZSlcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IGNsb25lZCA9IG5vZGUuY2xvbmVOb2RlKGZhbHNlKVxuICAgICAgY2xvbmVkLmlubmVySFRNTCA9IGh0bWxcbiAgICAgIHJldHVybiBjbG9uZWRcbiAgICB9XG4gIH0sXG5cbiAgLy8gbWVyZ2UgYXR0cmlidXRlcyBmcm9tIHNvdXJjZSB0byB0YXJnZXRcbiAgLy8gaWYgYW4gZWxlbWVudCBpcyBpZ25vcmVkLCB3ZSBvbmx5IG1lcmdlIGRhdGEgYXR0cmlidXRlc1xuICAvLyBpbmNsdWRpbmcgcmVtb3ZpbmcgZGF0YSBhdHRyaWJ1dGVzIHRoYXQgYXJlIG5vIGxvbmdlciBpbiB0aGUgc291cmNlXG4gIG1lcmdlQXR0cnModGFyZ2V0LCBzb3VyY2UsIG9wdHMgPSB7fSl7XG4gICAgbGV0IGV4Y2x1ZGUgPSBuZXcgU2V0KG9wdHMuZXhjbHVkZSB8fCBbXSlcbiAgICBsZXQgaXNJZ25vcmVkID0gb3B0cy5pc0lnbm9yZWRcbiAgICBsZXQgc291cmNlQXR0cnMgPSBzb3VyY2UuYXR0cmlidXRlc1xuICAgIGZvcihsZXQgaSA9IHNvdXJjZUF0dHJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKXtcbiAgICAgIGxldCBuYW1lID0gc291cmNlQXR0cnNbaV0ubmFtZVxuICAgICAgaWYoIWV4Y2x1ZGUuaGFzKG5hbWUpKXtcbiAgICAgICAgY29uc3Qgc291cmNlVmFsdWUgPSBzb3VyY2UuZ2V0QXR0cmlidXRlKG5hbWUpXG4gICAgICAgIGlmKHRhcmdldC5nZXRBdHRyaWJ1dGUobmFtZSkgIT09IHNvdXJjZVZhbHVlICYmICghaXNJZ25vcmVkIHx8IChpc0lnbm9yZWQgJiYgbmFtZS5zdGFydHNXaXRoKFwiZGF0YS1cIikpKSl7XG4gICAgICAgICAgdGFyZ2V0LnNldEF0dHJpYnV0ZShuYW1lLCBzb3VyY2VWYWx1ZSlcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gV2UgZXhjbHVkZSB0aGUgdmFsdWUgZnJvbSBiZWluZyBtZXJnZWQgb24gZm9jdXNlZCBpbnB1dHMsIGJlY2F1c2UgdGhlXG4gICAgICAgIC8vIHVzZXIncyBpbnB1dCBzaG91bGQgYWx3YXlzIHdpbi5cbiAgICAgICAgLy8gV2UgY2FuIHN0aWxsIGFzc2lnbiBpdCBhcyBsb25nIGFzIHRoZSB2YWx1ZSBwcm9wZXJ0eSBpcyB0aGUgc2FtZSwgdGhvdWdoLlxuICAgICAgICAvLyBUaGlzIHByZXZlbnRzIGEgc2l0dWF0aW9uIHdoZXJlIHRoZSB1cGRhdGVkIGhvb2sgaXMgbm90IGJlaW5nIHRyaWdnZXJlZFxuICAgICAgICAvLyB3aGVuIGFuIGlucHV0IGlzIGJhY2sgaW4gaXRzIFwib3JpZ2luYWwgc3RhdGVcIiwgYmVjYXVzZSB0aGUgYXR0cmlidXRlXG4gICAgICAgIC8vIHdhcyBuZXZlciBjaGFuZ2VkLCBzZWU6XG4gICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8yMTYzXG4gICAgICAgIGlmKG5hbWUgPT09IFwidmFsdWVcIiAmJiB0YXJnZXQudmFsdWUgPT09IHNvdXJjZS52YWx1ZSl7XG4gICAgICAgICAgLy8gYWN0dWFsbHkgc2V0IHRoZSB2YWx1ZSBhdHRyaWJ1dGUgdG8gc3luYyBpdCB3aXRoIHRoZSB2YWx1ZSBwcm9wZXJ0eVxuICAgICAgICAgIHRhcmdldC5zZXRBdHRyaWJ1dGUoXCJ2YWx1ZVwiLCBzb3VyY2UuZ2V0QXR0cmlidXRlKG5hbWUpKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgbGV0IHRhcmdldEF0dHJzID0gdGFyZ2V0LmF0dHJpYnV0ZXNcbiAgICBmb3IobGV0IGkgPSB0YXJnZXRBdHRycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSl7XG4gICAgICBsZXQgbmFtZSA9IHRhcmdldEF0dHJzW2ldLm5hbWVcbiAgICAgIGlmKGlzSWdub3JlZCl7XG4gICAgICAgIGlmKG5hbWUuc3RhcnRzV2l0aChcImRhdGEtXCIpICYmICFzb3VyY2UuaGFzQXR0cmlidXRlKG5hbWUpICYmICFQSFhfUEVORElOR19BVFRSUy5pbmNsdWRlcyhuYW1lKSl7IHRhcmdldC5yZW1vdmVBdHRyaWJ1dGUobmFtZSkgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYoIXNvdXJjZS5oYXNBdHRyaWJ1dGUobmFtZSkpeyB0YXJnZXQucmVtb3ZlQXR0cmlidXRlKG5hbWUpIH1cbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgbWVyZ2VGb2N1c2VkSW5wdXQodGFyZ2V0LCBzb3VyY2Upe1xuICAgIC8vIHNraXAgc2VsZWN0cyBiZWNhdXNlIEZGIHdpbGwgcmVzZXQgaGlnaGxpZ2h0ZWQgaW5kZXggZm9yIGFueSBzZXRBdHRyaWJ1dGVcbiAgICBpZighKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSl7IERPTS5tZXJnZUF0dHJzKHRhcmdldCwgc291cmNlLCB7ZXhjbHVkZTogW1widmFsdWVcIl19KSB9XG5cbiAgICBpZihzb3VyY2UucmVhZE9ubHkpe1xuICAgICAgdGFyZ2V0LnNldEF0dHJpYnV0ZShcInJlYWRvbmx5XCIsIHRydWUpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRhcmdldC5yZW1vdmVBdHRyaWJ1dGUoXCJyZWFkb25seVwiKVxuICAgIH1cbiAgfSxcblxuICBoYXNTZWxlY3Rpb25SYW5nZShlbCl7XG4gICAgcmV0dXJuIGVsLnNldFNlbGVjdGlvblJhbmdlICYmIChlbC50eXBlID09PSBcInRleHRcIiB8fCBlbC50eXBlID09PSBcInRleHRhcmVhXCIpXG4gIH0sXG5cbiAgcmVzdG9yZUZvY3VzKGZvY3VzZWQsIHNlbGVjdGlvblN0YXJ0LCBzZWxlY3Rpb25FbmQpe1xuICAgIGlmKGZvY3VzZWQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCl7IGZvY3VzZWQuZm9jdXMoKSB9XG4gICAgaWYoIURPTS5pc1RleHR1YWxJbnB1dChmb2N1c2VkKSl7IHJldHVybiB9XG5cbiAgICBsZXQgd2FzRm9jdXNlZCA9IGZvY3VzZWQubWF0Y2hlcyhcIjpmb2N1c1wiKVxuICAgIGlmKCF3YXNGb2N1c2VkKXsgZm9jdXNlZC5mb2N1cygpIH1cbiAgICBpZih0aGlzLmhhc1NlbGVjdGlvblJhbmdlKGZvY3VzZWQpKXtcbiAgICAgIGZvY3VzZWQuc2V0U2VsZWN0aW9uUmFuZ2Uoc2VsZWN0aW9uU3RhcnQsIHNlbGVjdGlvbkVuZClcbiAgICB9XG4gIH0sXG5cbiAgaXNGb3JtSW5wdXQoZWwpeyByZXR1cm4gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWEpJC9pLnRlc3QoZWwudGFnTmFtZSkgJiYgZWwudHlwZSAhPT0gXCJidXR0b25cIiB9LFxuXG4gIHN5bmNBdHRyc1RvUHJvcHMoZWwpe1xuICAgIGlmKGVsIGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBDSEVDS0FCTEVfSU5QVVRTLmluZGV4T2YoZWwudHlwZS50b0xvY2FsZUxvd2VyQ2FzZSgpKSA+PSAwKXtcbiAgICAgIGVsLmNoZWNrZWQgPSBlbC5nZXRBdHRyaWJ1dGUoXCJjaGVja2VkXCIpICE9PSBudWxsXG4gICAgfVxuICB9LFxuXG4gIGlzVGV4dHVhbElucHV0KGVsKXsgcmV0dXJuIEZPQ1VTQUJMRV9JTlBVVFMuaW5kZXhPZihlbC50eXBlKSA+PSAwIH0sXG5cbiAgaXNOb3dUcmlnZ2VyRm9ybUV4dGVybmFsKGVsLCBwaHhUcmlnZ2VyRXh0ZXJuYWwpe1xuICAgIHJldHVybiBlbC5nZXRBdHRyaWJ1dGUgJiYgZWwuZ2V0QXR0cmlidXRlKHBoeFRyaWdnZXJFeHRlcm5hbCkgIT09IG51bGwgJiYgZG9jdW1lbnQuYm9keS5jb250YWlucyhlbClcbiAgfSxcblxuICBjbGVhbkNoaWxkTm9kZXMoY29udGFpbmVyLCBwaHhVcGRhdGUpe1xuICAgIGlmKERPTS5pc1BoeFVwZGF0ZShjb250YWluZXIsIHBoeFVwZGF0ZSwgW1wiYXBwZW5kXCIsIFwicHJlcGVuZFwiLCBQSFhfU1RSRUFNXSkpe1xuICAgICAgbGV0IHRvUmVtb3ZlID0gW11cbiAgICAgIGNvbnRhaW5lci5jaGlsZE5vZGVzLmZvckVhY2goY2hpbGROb2RlID0+IHtcbiAgICAgICAgaWYoIWNoaWxkTm9kZS5pZCl7XG4gICAgICAgICAgLy8gU2tpcCB3YXJuaW5nIGlmIGl0J3MgYW4gZW1wdHkgdGV4dCBub2RlIChlLmcuIGEgbmV3LWxpbmUpXG4gICAgICAgICAgbGV0IGlzRW1wdHlUZXh0Tm9kZSA9IGNoaWxkTm9kZS5ub2RlVHlwZSA9PT0gTm9kZS5URVhUX05PREUgJiYgY2hpbGROb2RlLm5vZGVWYWx1ZS50cmltKCkgPT09IFwiXCJcbiAgICAgICAgICBpZighaXNFbXB0eVRleHROb2RlICYmIGNoaWxkTm9kZS5ub2RlVHlwZSAhPT0gTm9kZS5DT01NRU5UX05PREUpe1xuICAgICAgICAgICAgbG9nRXJyb3IoXCJvbmx5IEhUTUwgZWxlbWVudCB0YWdzIHdpdGggYW4gaWQgYXJlIGFsbG93ZWQgaW5zaWRlIGNvbnRhaW5lcnMgd2l0aCBwaHgtdXBkYXRlLlxcblxcblwiICtcbiAgICAgICAgICAgICAgYHJlbW92aW5nIGlsbGVnYWwgbm9kZTogXCIkeyhjaGlsZE5vZGUub3V0ZXJIVE1MIHx8IGNoaWxkTm9kZS5ub2RlVmFsdWUpLnRyaW0oKX1cIlxcblxcbmApXG4gICAgICAgICAgfVxuICAgICAgICAgIHRvUmVtb3ZlLnB1c2goY2hpbGROb2RlKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgdG9SZW1vdmUuZm9yRWFjaChjaGlsZE5vZGUgPT4gY2hpbGROb2RlLnJlbW92ZSgpKVxuICAgIH1cbiAgfSxcblxuICByZXBsYWNlUm9vdENvbnRhaW5lcihjb250YWluZXIsIHRhZ05hbWUsIGF0dHJzKXtcbiAgICBsZXQgcmV0YWluZWRBdHRycyA9IG5ldyBTZXQoW1wiaWRcIiwgUEhYX1NFU1NJT04sIFBIWF9TVEFUSUMsIFBIWF9NQUlOLCBQSFhfUk9PVF9JRF0pXG4gICAgaWYoY29udGFpbmVyLnRhZ05hbWUudG9Mb3dlckNhc2UoKSA9PT0gdGFnTmFtZS50b0xvd2VyQ2FzZSgpKXtcbiAgICAgIEFycmF5LmZyb20oY29udGFpbmVyLmF0dHJpYnV0ZXMpXG4gICAgICAgIC5maWx0ZXIoYXR0ciA9PiAhcmV0YWluZWRBdHRycy5oYXMoYXR0ci5uYW1lLnRvTG93ZXJDYXNlKCkpKVxuICAgICAgICAuZm9yRWFjaChhdHRyID0+IGNvbnRhaW5lci5yZW1vdmVBdHRyaWJ1dGUoYXR0ci5uYW1lKSlcblxuICAgICAgT2JqZWN0LmtleXMoYXR0cnMpXG4gICAgICAgIC5maWx0ZXIobmFtZSA9PiAhcmV0YWluZWRBdHRycy5oYXMobmFtZS50b0xvd2VyQ2FzZSgpKSlcbiAgICAgICAgLmZvckVhY2goYXR0ciA9PiBjb250YWluZXIuc2V0QXR0cmlidXRlKGF0dHIsIGF0dHJzW2F0dHJdKSlcblxuICAgICAgcmV0dXJuIGNvbnRhaW5lclxuXG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBuZXdDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KHRhZ05hbWUpXG4gICAgICBPYmplY3Qua2V5cyhhdHRycykuZm9yRWFjaChhdHRyID0+IG5ld0NvbnRhaW5lci5zZXRBdHRyaWJ1dGUoYXR0ciwgYXR0cnNbYXR0cl0pKVxuICAgICAgcmV0YWluZWRBdHRycy5mb3JFYWNoKGF0dHIgPT4gbmV3Q29udGFpbmVyLnNldEF0dHJpYnV0ZShhdHRyLCBjb250YWluZXIuZ2V0QXR0cmlidXRlKGF0dHIpKSlcbiAgICAgIG5ld0NvbnRhaW5lci5pbm5lckhUTUwgPSBjb250YWluZXIuaW5uZXJIVE1MXG4gICAgICBjb250YWluZXIucmVwbGFjZVdpdGgobmV3Q29udGFpbmVyKVxuICAgICAgcmV0dXJuIG5ld0NvbnRhaW5lclxuICAgIH1cbiAgfSxcblxuICBnZXRTdGlja3koZWwsIG5hbWUsIGRlZmF1bHRWYWwpe1xuICAgIGxldCBvcCA9IChET00ucHJpdmF0ZShlbCwgXCJzdGlja3lcIikgfHwgW10pLmZpbmQoKFtleGlzdGluZ05hbWUsXSkgPT4gbmFtZSA9PT0gZXhpc3RpbmdOYW1lKVxuICAgIGlmKG9wKXtcbiAgICAgIGxldCBbX25hbWUsIF9vcCwgc3Rhc2hlZFJlc3VsdF0gPSBvcFxuICAgICAgcmV0dXJuIHN0YXNoZWRSZXN1bHRcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHR5cGVvZihkZWZhdWx0VmFsKSA9PT0gXCJmdW5jdGlvblwiID8gZGVmYXVsdFZhbCgpIDogZGVmYXVsdFZhbFxuICAgIH1cbiAgfSxcblxuICBkZWxldGVTdGlja3koZWwsIG5hbWUpe1xuICAgIHRoaXMudXBkYXRlUHJpdmF0ZShlbCwgXCJzdGlja3lcIiwgW10sIG9wcyA9PiB7XG4gICAgICByZXR1cm4gb3BzLmZpbHRlcigoW2V4aXN0aW5nTmFtZSwgX10pID0+IGV4aXN0aW5nTmFtZSAhPT0gbmFtZSlcbiAgICB9KVxuICB9LFxuXG4gIHB1dFN0aWNreShlbCwgbmFtZSwgb3Ape1xuICAgIGxldCBzdGFzaGVkUmVzdWx0ID0gb3AoZWwpXG4gICAgdGhpcy51cGRhdGVQcml2YXRlKGVsLCBcInN0aWNreVwiLCBbXSwgb3BzID0+IHtcbiAgICAgIGxldCBleGlzdGluZ0luZGV4ID0gb3BzLmZpbmRJbmRleCgoW2V4aXN0aW5nTmFtZSxdKSA9PiBuYW1lID09PSBleGlzdGluZ05hbWUpXG4gICAgICBpZihleGlzdGluZ0luZGV4ID49IDApe1xuICAgICAgICBvcHNbZXhpc3RpbmdJbmRleF0gPSBbbmFtZSwgb3AsIHN0YXNoZWRSZXN1bHRdXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvcHMucHVzaChbbmFtZSwgb3AsIHN0YXNoZWRSZXN1bHRdKVxuICAgICAgfVxuICAgICAgcmV0dXJuIG9wc1xuICAgIH0pXG4gIH0sXG5cbiAgYXBwbHlTdGlja3lPcGVyYXRpb25zKGVsKXtcbiAgICBsZXQgb3BzID0gRE9NLnByaXZhdGUoZWwsIFwic3RpY2t5XCIpXG4gICAgaWYoIW9wcyl7IHJldHVybiB9XG5cbiAgICBvcHMuZm9yRWFjaCgoW25hbWUsIG9wLCBfc3Rhc2hlZF0pID0+IHRoaXMucHV0U3RpY2t5KGVsLCBuYW1lLCBvcCkpXG4gIH0sXG5cbiAgaXNMb2NrZWQoZWwpe1xuICAgIHJldHVybiBlbC5oYXNBdHRyaWJ1dGUgJiYgZWwuaGFzQXR0cmlidXRlKFBIWF9SRUZfTE9DSylcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBET01cbiIsICJpbXBvcnQge1xuICBQSFhfQUNUSVZFX0VOVFJZX1JFRlMsXG4gIFBIWF9MSVZFX0ZJTEVfVVBEQVRFRCxcbiAgUEhYX1BSRUZMSUdIVEVEX1JFRlNcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuaW1wb3J0IHtcbiAgY2hhbm5lbFVwbG9hZGVyLFxuICBsb2dFcnJvclxufSBmcm9tIFwiLi91dGlsc1wiXG5cbmltcG9ydCBMaXZlVXBsb2FkZXIgZnJvbSBcIi4vbGl2ZV91cGxvYWRlclwiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFVwbG9hZEVudHJ5IHtcbiAgc3RhdGljIGlzQWN0aXZlKGZpbGVFbCwgZmlsZSl7XG4gICAgbGV0IGlzTmV3ID0gZmlsZS5fcGh4UmVmID09PSB1bmRlZmluZWRcbiAgICBsZXQgYWN0aXZlUmVmcyA9IGZpbGVFbC5nZXRBdHRyaWJ1dGUoUEhYX0FDVElWRV9FTlRSWV9SRUZTKS5zcGxpdChcIixcIilcbiAgICBsZXQgaXNBY3RpdmUgPSBhY3RpdmVSZWZzLmluZGV4T2YoTGl2ZVVwbG9hZGVyLmdlbkZpbGVSZWYoZmlsZSkpID49IDBcbiAgICByZXR1cm4gZmlsZS5zaXplID4gMCAmJiAoaXNOZXcgfHwgaXNBY3RpdmUpXG4gIH1cblxuICBzdGF0aWMgaXNQcmVmbGlnaHRlZChmaWxlRWwsIGZpbGUpe1xuICAgIGxldCBwcmVmbGlnaHRlZFJlZnMgPSBmaWxlRWwuZ2V0QXR0cmlidXRlKFBIWF9QUkVGTElHSFRFRF9SRUZTKS5zcGxpdChcIixcIilcbiAgICBsZXQgaXNQcmVmbGlnaHRlZCA9IHByZWZsaWdodGVkUmVmcy5pbmRleE9mKExpdmVVcGxvYWRlci5nZW5GaWxlUmVmKGZpbGUpKSA+PSAwXG4gICAgcmV0dXJuIGlzUHJlZmxpZ2h0ZWQgJiYgdGhpcy5pc0FjdGl2ZShmaWxlRWwsIGZpbGUpXG4gIH1cblxuICBzdGF0aWMgaXNQcmVmbGlnaHRJblByb2dyZXNzKGZpbGUpe1xuICAgIHJldHVybiBmaWxlLl9wcmVmbGlnaHRJblByb2dyZXNzID09PSB0cnVlXG4gIH1cblxuICBzdGF0aWMgbWFya1ByZWZsaWdodEluUHJvZ3Jlc3MoZmlsZSl7XG4gICAgZmlsZS5fcHJlZmxpZ2h0SW5Qcm9ncmVzcyA9IHRydWVcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGZpbGVFbCwgZmlsZSwgdmlldywgYXV0b1VwbG9hZCl7XG4gICAgdGhpcy5yZWYgPSBMaXZlVXBsb2FkZXIuZ2VuRmlsZVJlZihmaWxlKVxuICAgIHRoaXMuZmlsZUVsID0gZmlsZUVsXG4gICAgdGhpcy5maWxlID0gZmlsZVxuICAgIHRoaXMudmlldyA9IHZpZXdcbiAgICB0aGlzLm1ldGEgPSBudWxsXG4gICAgdGhpcy5faXNDYW5jZWxsZWQgPSBmYWxzZVxuICAgIHRoaXMuX2lzRG9uZSA9IGZhbHNlXG4gICAgdGhpcy5fcHJvZ3Jlc3MgPSAwXG4gICAgdGhpcy5fbGFzdFByb2dyZXNzU2VudCA9IC0xXG4gICAgdGhpcy5fb25Eb25lID0gZnVuY3Rpb24oKXsgfVxuICAgIHRoaXMuX29uRWxVcGRhdGVkID0gdGhpcy5vbkVsVXBkYXRlZC5iaW5kKHRoaXMpXG4gICAgdGhpcy5maWxlRWwuYWRkRXZlbnRMaXN0ZW5lcihQSFhfTElWRV9GSUxFX1VQREFURUQsIHRoaXMuX29uRWxVcGRhdGVkKVxuICAgIHRoaXMuYXV0b1VwbG9hZCA9IGF1dG9VcGxvYWRcbiAgfVxuXG4gIG1ldGFkYXRhKCl7IHJldHVybiB0aGlzLm1ldGEgfVxuXG4gIHByb2dyZXNzKHByb2dyZXNzKXtcbiAgICB0aGlzLl9wcm9ncmVzcyA9IE1hdGguZmxvb3IocHJvZ3Jlc3MpXG4gICAgaWYodGhpcy5fcHJvZ3Jlc3MgPiB0aGlzLl9sYXN0UHJvZ3Jlc3NTZW50KXtcbiAgICAgIGlmKHRoaXMuX3Byb2dyZXNzID49IDEwMCl7XG4gICAgICAgIHRoaXMuX3Byb2dyZXNzID0gMTAwXG4gICAgICAgIHRoaXMuX2xhc3RQcm9ncmVzc1NlbnQgPSAxMDBcbiAgICAgICAgdGhpcy5faXNEb25lID0gdHJ1ZVxuICAgICAgICB0aGlzLnZpZXcucHVzaEZpbGVQcm9ncmVzcyh0aGlzLmZpbGVFbCwgdGhpcy5yZWYsIDEwMCwgKCkgPT4ge1xuICAgICAgICAgIExpdmVVcGxvYWRlci51bnRyYWNrRmlsZSh0aGlzLmZpbGVFbCwgdGhpcy5maWxlKVxuICAgICAgICAgIHRoaXMuX29uRG9uZSgpXG4gICAgICAgIH0pXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl9sYXN0UHJvZ3Jlc3NTZW50ID0gdGhpcy5fcHJvZ3Jlc3NcbiAgICAgICAgdGhpcy52aWV3LnB1c2hGaWxlUHJvZ3Jlc3ModGhpcy5maWxlRWwsIHRoaXMucmVmLCB0aGlzLl9wcm9ncmVzcylcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpc0NhbmNlbGxlZCgpeyByZXR1cm4gdGhpcy5faXNDYW5jZWxsZWQgfVxuXG4gIGNhbmNlbCgpe1xuICAgIHRoaXMuZmlsZS5fcHJlZmxpZ2h0SW5Qcm9ncmVzcyA9IGZhbHNlXG4gICAgdGhpcy5faXNDYW5jZWxsZWQgPSB0cnVlXG4gICAgdGhpcy5faXNEb25lID0gdHJ1ZVxuICAgIHRoaXMuX29uRG9uZSgpXG4gIH1cblxuICBpc0RvbmUoKXsgcmV0dXJuIHRoaXMuX2lzRG9uZSB9XG5cbiAgZXJyb3IocmVhc29uID0gXCJmYWlsZWRcIil7XG4gICAgdGhpcy5maWxlRWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihQSFhfTElWRV9GSUxFX1VQREFURUQsIHRoaXMuX29uRWxVcGRhdGVkKVxuICAgIHRoaXMudmlldy5wdXNoRmlsZVByb2dyZXNzKHRoaXMuZmlsZUVsLCB0aGlzLnJlZiwge2Vycm9yOiByZWFzb259KVxuICAgIGlmKCF0aGlzLmlzQXV0b1VwbG9hZCgpKXsgTGl2ZVVwbG9hZGVyLmNsZWFyRmlsZXModGhpcy5maWxlRWwpIH1cbiAgfVxuXG4gIGlzQXV0b1VwbG9hZCgpeyByZXR1cm4gdGhpcy5hdXRvVXBsb2FkIH1cblxuICAvL3ByaXZhdGVcblxuICBvbkRvbmUoY2FsbGJhY2spe1xuICAgIHRoaXMuX29uRG9uZSA9ICgpID0+IHtcbiAgICAgIHRoaXMuZmlsZUVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoUEhYX0xJVkVfRklMRV9VUERBVEVELCB0aGlzLl9vbkVsVXBkYXRlZClcbiAgICAgIGNhbGxiYWNrKClcbiAgICB9XG4gIH1cblxuICBvbkVsVXBkYXRlZCgpe1xuICAgIGxldCBhY3RpdmVSZWZzID0gdGhpcy5maWxlRWwuZ2V0QXR0cmlidXRlKFBIWF9BQ1RJVkVfRU5UUllfUkVGUykuc3BsaXQoXCIsXCIpXG4gICAgaWYoYWN0aXZlUmVmcy5pbmRleE9mKHRoaXMucmVmKSA9PT0gLTEpe1xuICAgICAgTGl2ZVVwbG9hZGVyLnVudHJhY2tGaWxlKHRoaXMuZmlsZUVsLCB0aGlzLmZpbGUpXG4gICAgICB0aGlzLmNhbmNlbCgpXG4gICAgfVxuICB9XG5cbiAgdG9QcmVmbGlnaHRQYXlsb2FkKCl7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxhc3RfbW9kaWZpZWQ6IHRoaXMuZmlsZS5sYXN0TW9kaWZpZWQsXG4gICAgICBuYW1lOiB0aGlzLmZpbGUubmFtZSxcbiAgICAgIHJlbGF0aXZlX3BhdGg6IHRoaXMuZmlsZS53ZWJraXRSZWxhdGl2ZVBhdGgsXG4gICAgICBzaXplOiB0aGlzLmZpbGUuc2l6ZSxcbiAgICAgIHR5cGU6IHRoaXMuZmlsZS50eXBlLFxuICAgICAgcmVmOiB0aGlzLnJlZixcbiAgICAgIG1ldGE6IHR5cGVvZih0aGlzLmZpbGUubWV0YSkgPT09IFwiZnVuY3Rpb25cIiA/IHRoaXMuZmlsZS5tZXRhKCkgOiB1bmRlZmluZWRcbiAgICB9XG4gIH1cblxuICB1cGxvYWRlcih1cGxvYWRlcnMpe1xuICAgIGlmKHRoaXMubWV0YS51cGxvYWRlcil7XG4gICAgICBsZXQgY2FsbGJhY2sgPSB1cGxvYWRlcnNbdGhpcy5tZXRhLnVwbG9hZGVyXSB8fCBsb2dFcnJvcihgbm8gdXBsb2FkZXIgY29uZmlndXJlZCBmb3IgJHt0aGlzLm1ldGEudXBsb2FkZXJ9YClcbiAgICAgIHJldHVybiB7bmFtZTogdGhpcy5tZXRhLnVwbG9hZGVyLCBjYWxsYmFjazogY2FsbGJhY2t9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB7bmFtZTogXCJjaGFubmVsXCIsIGNhbGxiYWNrOiBjaGFubmVsVXBsb2FkZXJ9XG4gICAgfVxuICB9XG5cbiAgemlwUG9zdEZsaWdodChyZXNwKXtcbiAgICB0aGlzLm1ldGEgPSByZXNwLmVudHJpZXNbdGhpcy5yZWZdXG4gICAgaWYoIXRoaXMubWV0YSl7IGxvZ0Vycm9yKGBubyBwcmVmbGlnaHQgdXBsb2FkIHJlc3BvbnNlIHJldHVybmVkIHdpdGggcmVmICR7dGhpcy5yZWZ9YCwge2lucHV0OiB0aGlzLmZpbGVFbCwgcmVzcG9uc2U6IHJlc3B9KSB9XG4gIH1cbn1cbiIsICJpbXBvcnQge1xuICBQSFhfRE9ORV9SRUZTLFxuICBQSFhfUFJFRkxJR0hURURfUkVGUyxcbiAgUEhYX1VQTE9BRF9SRUZcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuaW1wb3J0IHtcbn0gZnJvbSBcIi4vdXRpbHNcIlxuXG5pbXBvcnQgRE9NIGZyb20gXCIuL2RvbVwiXG5pbXBvcnQgVXBsb2FkRW50cnkgZnJvbSBcIi4vdXBsb2FkX2VudHJ5XCJcblxubGV0IGxpdmVVcGxvYWRlckZpbGVSZWYgPSAwXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExpdmVVcGxvYWRlciB7XG4gIHN0YXRpYyBnZW5GaWxlUmVmKGZpbGUpe1xuICAgIGxldCByZWYgPSBmaWxlLl9waHhSZWZcbiAgICBpZihyZWYgIT09IHVuZGVmaW5lZCl7XG4gICAgICByZXR1cm4gcmVmXG4gICAgfSBlbHNlIHtcbiAgICAgIGZpbGUuX3BoeFJlZiA9IChsaXZlVXBsb2FkZXJGaWxlUmVmKyspLnRvU3RyaW5nKClcbiAgICAgIHJldHVybiBmaWxlLl9waHhSZWZcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgZ2V0RW50cnlEYXRhVVJMKGlucHV0RWwsIHJlZiwgY2FsbGJhY2spe1xuICAgIGxldCBmaWxlID0gdGhpcy5hY3RpdmVGaWxlcyhpbnB1dEVsKS5maW5kKGZpbGUgPT4gdGhpcy5nZW5GaWxlUmVmKGZpbGUpID09PSByZWYpXG4gICAgY2FsbGJhY2soVVJMLmNyZWF0ZU9iamVjdFVSTChmaWxlKSlcbiAgfVxuXG4gIHN0YXRpYyBoYXNVcGxvYWRzSW5Qcm9ncmVzcyhmb3JtRWwpe1xuICAgIGxldCBhY3RpdmUgPSAwXG4gICAgRE9NLmZpbmRVcGxvYWRJbnB1dHMoZm9ybUVsKS5mb3JFYWNoKGlucHV0ID0+IHtcbiAgICAgIGlmKGlucHV0LmdldEF0dHJpYnV0ZShQSFhfUFJFRkxJR0hURURfUkVGUykgIT09IGlucHV0LmdldEF0dHJpYnV0ZShQSFhfRE9ORV9SRUZTKSl7XG4gICAgICAgIGFjdGl2ZSsrXG4gICAgICB9XG4gICAgfSlcbiAgICByZXR1cm4gYWN0aXZlID4gMFxuICB9XG5cbiAgc3RhdGljIHNlcmlhbGl6ZVVwbG9hZHMoaW5wdXRFbCl7XG4gICAgbGV0IGZpbGVzID0gdGhpcy5hY3RpdmVGaWxlcyhpbnB1dEVsKVxuICAgIGxldCBmaWxlRGF0YSA9IHt9XG4gICAgZmlsZXMuZm9yRWFjaChmaWxlID0+IHtcbiAgICAgIGxldCBlbnRyeSA9IHtwYXRoOiBpbnB1dEVsLm5hbWV9XG4gICAgICBsZXQgdXBsb2FkUmVmID0gaW5wdXRFbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpXG4gICAgICBmaWxlRGF0YVt1cGxvYWRSZWZdID0gZmlsZURhdGFbdXBsb2FkUmVmXSB8fCBbXVxuICAgICAgZW50cnkucmVmID0gdGhpcy5nZW5GaWxlUmVmKGZpbGUpXG4gICAgICBlbnRyeS5sYXN0X21vZGlmaWVkID0gZmlsZS5sYXN0TW9kaWZpZWRcbiAgICAgIGVudHJ5Lm5hbWUgPSBmaWxlLm5hbWUgfHwgZW50cnkucmVmXG4gICAgICBlbnRyeS5yZWxhdGl2ZV9wYXRoID0gZmlsZS53ZWJraXRSZWxhdGl2ZVBhdGhcbiAgICAgIGVudHJ5LnR5cGUgPSBmaWxlLnR5cGVcbiAgICAgIGVudHJ5LnNpemUgPSBmaWxlLnNpemVcbiAgICAgIGlmKHR5cGVvZihmaWxlLm1ldGEpID09PSBcImZ1bmN0aW9uXCIpeyBlbnRyeS5tZXRhID0gZmlsZS5tZXRhKCkgfVxuICAgICAgZmlsZURhdGFbdXBsb2FkUmVmXS5wdXNoKGVudHJ5KVxuICAgIH0pXG4gICAgcmV0dXJuIGZpbGVEYXRhXG4gIH1cblxuICBzdGF0aWMgY2xlYXJGaWxlcyhpbnB1dEVsKXtcbiAgICBpbnB1dEVsLnZhbHVlID0gbnVsbFxuICAgIGlucHV0RWwucmVtb3ZlQXR0cmlidXRlKFBIWF9VUExPQURfUkVGKVxuICAgIERPTS5wdXRQcml2YXRlKGlucHV0RWwsIFwiZmlsZXNcIiwgW10pXG4gIH1cblxuICBzdGF0aWMgdW50cmFja0ZpbGUoaW5wdXRFbCwgZmlsZSl7XG4gICAgRE9NLnB1dFByaXZhdGUoaW5wdXRFbCwgXCJmaWxlc1wiLCBET00ucHJpdmF0ZShpbnB1dEVsLCBcImZpbGVzXCIpLmZpbHRlcihmID0+ICFPYmplY3QuaXMoZiwgZmlsZSkpKVxuICB9XG5cbiAgc3RhdGljIHRyYWNrRmlsZXMoaW5wdXRFbCwgZmlsZXMsIGRhdGFUcmFuc2Zlcil7XG4gICAgaWYoaW5wdXRFbC5nZXRBdHRyaWJ1dGUoXCJtdWx0aXBsZVwiKSAhPT0gbnVsbCl7XG4gICAgICBsZXQgbmV3RmlsZXMgPSBmaWxlcy5maWx0ZXIoZmlsZSA9PiAhdGhpcy5hY3RpdmVGaWxlcyhpbnB1dEVsKS5maW5kKGYgPT4gT2JqZWN0LmlzKGYsIGZpbGUpKSlcbiAgICAgIERPTS51cGRhdGVQcml2YXRlKGlucHV0RWwsIFwiZmlsZXNcIiwgW10sIChleGlzdGluZykgPT4gZXhpc3RpbmcuY29uY2F0KG5ld0ZpbGVzKSlcbiAgICAgIGlucHV0RWwudmFsdWUgPSBudWxsXG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFJlc2V0IGlucHV0RWwgZmlsZXMgdG8gYWxpZ24gb3V0cHV0IHdpdGggcHJvZ3JhbW1hdGljIGNoYW5nZXMgKGkuZS4gZHJhZyBhbmQgZHJvcClcbiAgICAgIGlmKGRhdGFUcmFuc2ZlciAmJiBkYXRhVHJhbnNmZXIuZmlsZXMubGVuZ3RoID4gMCl7IGlucHV0RWwuZmlsZXMgPSBkYXRhVHJhbnNmZXIuZmlsZXMgfVxuICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXRFbCwgXCJmaWxlc1wiLCBmaWxlcylcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYWN0aXZlRmlsZUlucHV0cyhmb3JtRWwpe1xuICAgIGxldCBmaWxlSW5wdXRzID0gRE9NLmZpbmRVcGxvYWRJbnB1dHMoZm9ybUVsKVxuICAgIHJldHVybiBBcnJheS5mcm9tKGZpbGVJbnB1dHMpLmZpbHRlcihlbCA9PiBlbC5maWxlcyAmJiB0aGlzLmFjdGl2ZUZpbGVzKGVsKS5sZW5ndGggPiAwKVxuICB9XG5cbiAgc3RhdGljIGFjdGl2ZUZpbGVzKGlucHV0KXtcbiAgICByZXR1cm4gKERPTS5wcml2YXRlKGlucHV0LCBcImZpbGVzXCIpIHx8IFtdKS5maWx0ZXIoZiA9PiBVcGxvYWRFbnRyeS5pc0FjdGl2ZShpbnB1dCwgZikpXG4gIH1cblxuICBzdGF0aWMgaW5wdXRzQXdhaXRpbmdQcmVmbGlnaHQoZm9ybUVsKXtcbiAgICBsZXQgZmlsZUlucHV0cyA9IERPTS5maW5kVXBsb2FkSW5wdXRzKGZvcm1FbClcbiAgICByZXR1cm4gQXJyYXkuZnJvbShmaWxlSW5wdXRzKS5maWx0ZXIoaW5wdXQgPT4gdGhpcy5maWxlc0F3YWl0aW5nUHJlZmxpZ2h0KGlucHV0KS5sZW5ndGggPiAwKVxuICB9XG5cbiAgc3RhdGljIGZpbGVzQXdhaXRpbmdQcmVmbGlnaHQoaW5wdXQpe1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZUZpbGVzKGlucHV0KS5maWx0ZXIoZiA9PiAhVXBsb2FkRW50cnkuaXNQcmVmbGlnaHRlZChpbnB1dCwgZikgJiYgIVVwbG9hZEVudHJ5LmlzUHJlZmxpZ2h0SW5Qcm9ncmVzcyhmKSlcbiAgfVxuXG4gIHN0YXRpYyBtYXJrUHJlZmxpZ2h0SW5Qcm9ncmVzcyhlbnRyaWVzKXtcbiAgICBlbnRyaWVzLmZvckVhY2goZW50cnkgPT4gVXBsb2FkRW50cnkubWFya1ByZWZsaWdodEluUHJvZ3Jlc3MoZW50cnkuZmlsZSkpXG4gIH1cblxuICBjb25zdHJ1Y3RvcihpbnB1dEVsLCB2aWV3LCBvbkNvbXBsZXRlKXtcbiAgICB0aGlzLmF1dG9VcGxvYWQgPSBET00uaXNBdXRvVXBsb2FkKGlucHV0RWwpXG4gICAgdGhpcy52aWV3ID0gdmlld1xuICAgIHRoaXMub25Db21wbGV0ZSA9IG9uQ29tcGxldGVcbiAgICB0aGlzLl9lbnRyaWVzID1cbiAgICAgIEFycmF5LmZyb20oTGl2ZVVwbG9hZGVyLmZpbGVzQXdhaXRpbmdQcmVmbGlnaHQoaW5wdXRFbCkgfHwgW10pXG4gICAgICAgIC5tYXAoZmlsZSA9PiBuZXcgVXBsb2FkRW50cnkoaW5wdXRFbCwgZmlsZSwgdmlldywgdGhpcy5hdXRvVXBsb2FkKSlcblxuICAgIC8vIHByZXZlbnQgc2VuZGluZyBkdXBsaWNhdGUgcHJlZmxpZ2h0IHJlcXVlc3RzXG4gICAgTGl2ZVVwbG9hZGVyLm1hcmtQcmVmbGlnaHRJblByb2dyZXNzKHRoaXMuX2VudHJpZXMpXG5cbiAgICB0aGlzLm51bUVudHJpZXNJblByb2dyZXNzID0gdGhpcy5fZW50cmllcy5sZW5ndGhcbiAgfVxuXG4gIGlzQXV0b1VwbG9hZCgpeyByZXR1cm4gdGhpcy5hdXRvVXBsb2FkIH1cblxuICBlbnRyaWVzKCl7IHJldHVybiB0aGlzLl9lbnRyaWVzIH1cblxuICBpbml0QWRhcHRlclVwbG9hZChyZXNwLCBvbkVycm9yLCBsaXZlU29ja2V0KXtcbiAgICB0aGlzLl9lbnRyaWVzID1cbiAgICAgIHRoaXMuX2VudHJpZXMubWFwKGVudHJ5ID0+IHtcbiAgICAgICAgaWYoZW50cnkuaXNDYW5jZWxsZWQoKSl7XG4gICAgICAgICAgdGhpcy5udW1FbnRyaWVzSW5Qcm9ncmVzcy0tXG4gICAgICAgICAgaWYodGhpcy5udW1FbnRyaWVzSW5Qcm9ncmVzcyA9PT0gMCl7IHRoaXMub25Db21wbGV0ZSgpIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlbnRyeS56aXBQb3N0RmxpZ2h0KHJlc3ApXG4gICAgICAgICAgZW50cnkub25Eb25lKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMubnVtRW50cmllc0luUHJvZ3Jlc3MtLVxuICAgICAgICAgICAgaWYodGhpcy5udW1FbnRyaWVzSW5Qcm9ncmVzcyA9PT0gMCl7IHRoaXMub25Db21wbGV0ZSgpIH1cbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbnRyeVxuICAgICAgfSlcblxuICAgIGxldCBncm91cGVkRW50cmllcyA9IHRoaXMuX2VudHJpZXMucmVkdWNlKChhY2MsIGVudHJ5KSA9PiB7XG4gICAgICBpZighZW50cnkubWV0YSl7IHJldHVybiBhY2MgfVxuICAgICAgbGV0IHtuYW1lLCBjYWxsYmFja30gPSBlbnRyeS51cGxvYWRlcihsaXZlU29ja2V0LnVwbG9hZGVycylcbiAgICAgIGFjY1tuYW1lXSA9IGFjY1tuYW1lXSB8fCB7Y2FsbGJhY2s6IGNhbGxiYWNrLCBlbnRyaWVzOiBbXX1cbiAgICAgIGFjY1tuYW1lXS5lbnRyaWVzLnB1c2goZW50cnkpXG4gICAgICByZXR1cm4gYWNjXG4gICAgfSwge30pXG5cbiAgICBmb3IobGV0IG5hbWUgaW4gZ3JvdXBlZEVudHJpZXMpe1xuICAgICAgbGV0IHtjYWxsYmFjaywgZW50cmllc30gPSBncm91cGVkRW50cmllc1tuYW1lXVxuICAgICAgY2FsbGJhY2soZW50cmllcywgb25FcnJvciwgcmVzcCwgbGl2ZVNvY2tldClcbiAgICB9XG4gIH1cbn1cbiIsICJsZXQgQVJJQSA9IHtcbiAgYW55T2YoaW5zdGFuY2UsIGNsYXNzZXMpeyByZXR1cm4gY2xhc3Nlcy5maW5kKG5hbWUgPT4gaW5zdGFuY2UgaW5zdGFuY2VvZiBuYW1lKSB9LFxuXG4gIGlzRm9jdXNhYmxlKGVsLCBpbnRlcmFjdGl2ZU9ubHkpe1xuICAgIHJldHVybiAoXG4gICAgICAoZWwgaW5zdGFuY2VvZiBIVE1MQW5jaG9yRWxlbWVudCAmJiBlbC5yZWwgIT09IFwiaWdub3JlXCIpIHx8XG4gICAgICAoZWwgaW5zdGFuY2VvZiBIVE1MQXJlYUVsZW1lbnQgJiYgZWwuaHJlZiAhPT0gdW5kZWZpbmVkKSB8fFxuICAgICAgKCFlbC5kaXNhYmxlZCAmJiAodGhpcy5hbnlPZihlbCwgW0hUTUxJbnB1dEVsZW1lbnQsIEhUTUxTZWxlY3RFbGVtZW50LCBIVE1MVGV4dEFyZWFFbGVtZW50LCBIVE1MQnV0dG9uRWxlbWVudF0pKSkgfHxcbiAgICAgIChlbCBpbnN0YW5jZW9mIEhUTUxJRnJhbWVFbGVtZW50KSB8fFxuICAgICAgKChlbC50YWJJbmRleCA+PSAwICYmIGVsLmdldEF0dHJpYnV0ZShcImFyaWEtaGlkZGVuXCIpICE9PSBcInRydWVcIikgfHwgKCFpbnRlcmFjdGl2ZU9ubHkgJiYgZWwuZ2V0QXR0cmlidXRlKFwidGFiaW5kZXhcIikgIT09IG51bGwgJiYgZWwuZ2V0QXR0cmlidXRlKFwiYXJpYS1oaWRkZW5cIikgIT09IFwidHJ1ZVwiKSlcbiAgICApXG4gIH0sXG5cbiAgYXR0ZW1wdEZvY3VzKGVsLCBpbnRlcmFjdGl2ZU9ubHkpe1xuICAgIGlmKHRoaXMuaXNGb2N1c2FibGUoZWwsIGludGVyYWN0aXZlT25seSkpeyB0cnkgeyBlbC5mb2N1cygpIH0gY2F0Y2gge30gfVxuICAgIHJldHVybiAhIWRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgJiYgZG9jdW1lbnQuYWN0aXZlRWxlbWVudC5pc1NhbWVOb2RlKGVsKVxuICB9LFxuXG4gIGZvY3VzRmlyc3RJbnRlcmFjdGl2ZShlbCl7XG4gICAgbGV0IGNoaWxkID0gZWwuZmlyc3RFbGVtZW50Q2hpbGRcbiAgICB3aGlsZShjaGlsZCl7XG4gICAgICBpZih0aGlzLmF0dGVtcHRGb2N1cyhjaGlsZCwgdHJ1ZSkgfHwgdGhpcy5mb2N1c0ZpcnN0SW50ZXJhY3RpdmUoY2hpbGQsIHRydWUpKXtcbiAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgIH1cbiAgICAgIGNoaWxkID0gY2hpbGQubmV4dEVsZW1lbnRTaWJsaW5nXG4gICAgfVxuICB9LFxuXG4gIGZvY3VzRmlyc3QoZWwpe1xuICAgIGxldCBjaGlsZCA9IGVsLmZpcnN0RWxlbWVudENoaWxkXG4gICAgd2hpbGUoY2hpbGQpe1xuICAgICAgaWYodGhpcy5hdHRlbXB0Rm9jdXMoY2hpbGQpIHx8IHRoaXMuZm9jdXNGaXJzdChjaGlsZCkpe1xuICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgfVxuICAgICAgY2hpbGQgPSBjaGlsZC5uZXh0RWxlbWVudFNpYmxpbmdcbiAgICB9XG4gIH0sXG5cbiAgZm9jdXNMYXN0KGVsKXtcbiAgICBsZXQgY2hpbGQgPSBlbC5sYXN0RWxlbWVudENoaWxkXG4gICAgd2hpbGUoY2hpbGQpe1xuICAgICAgaWYodGhpcy5hdHRlbXB0Rm9jdXMoY2hpbGQpIHx8IHRoaXMuZm9jdXNMYXN0KGNoaWxkKSl7XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9XG4gICAgICBjaGlsZCA9IGNoaWxkLnByZXZpb3VzRWxlbWVudFNpYmxpbmdcbiAgICB9XG4gIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEFSSUFcbiIsICJpbXBvcnQge1xuICBQSFhfQUNUSVZFX0VOVFJZX1JFRlMsXG4gIFBIWF9MSVZFX0ZJTEVfVVBEQVRFRCxcbiAgUEhYX1BSRUZMSUdIVEVEX1JFRlMsXG4gIFBIWF9VUExPQURfUkVGXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCBMaXZlVXBsb2FkZXIgZnJvbSBcIi4vbGl2ZV91cGxvYWRlclwiXG5pbXBvcnQgQVJJQSBmcm9tIFwiLi9hcmlhXCJcblxubGV0IEhvb2tzID0ge1xuICBMaXZlRmlsZVVwbG9hZDoge1xuICAgIGFjdGl2ZVJlZnMoKXsgcmV0dXJuIHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9BQ1RJVkVfRU5UUllfUkVGUykgfSxcblxuICAgIHByZWZsaWdodGVkUmVmcygpeyByZXR1cm4gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX1BSRUZMSUdIVEVEX1JFRlMpIH0sXG5cbiAgICBtb3VudGVkKCl7IHRoaXMucHJlZmxpZ2h0ZWRXYXMgPSB0aGlzLnByZWZsaWdodGVkUmVmcygpIH0sXG5cbiAgICB1cGRhdGVkKCl7XG4gICAgICBsZXQgbmV3UHJlZmxpZ2h0cyA9IHRoaXMucHJlZmxpZ2h0ZWRSZWZzKClcbiAgICAgIGlmKHRoaXMucHJlZmxpZ2h0ZWRXYXMgIT09IG5ld1ByZWZsaWdodHMpe1xuICAgICAgICB0aGlzLnByZWZsaWdodGVkV2FzID0gbmV3UHJlZmxpZ2h0c1xuICAgICAgICBpZihuZXdQcmVmbGlnaHRzID09PSBcIlwiKXtcbiAgICAgICAgICB0aGlzLl9fdmlldygpLmNhbmNlbFN1Ym1pdCh0aGlzLmVsLmZvcm0pXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYodGhpcy5hY3RpdmVSZWZzKCkgPT09IFwiXCIpeyB0aGlzLmVsLnZhbHVlID0gbnVsbCB9XG4gICAgICB0aGlzLmVsLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KFBIWF9MSVZFX0ZJTEVfVVBEQVRFRCkpXG4gICAgfVxuICB9LFxuXG4gIExpdmVJbWdQcmV2aWV3OiB7XG4gICAgbW91bnRlZCgpe1xuICAgICAgdGhpcy5yZWYgPSB0aGlzLmVsLmdldEF0dHJpYnV0ZShcImRhdGEtcGh4LWVudHJ5LXJlZlwiKVxuICAgICAgdGhpcy5pbnB1dEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpKVxuICAgICAgTGl2ZVVwbG9hZGVyLmdldEVudHJ5RGF0YVVSTCh0aGlzLmlucHV0RWwsIHRoaXMucmVmLCB1cmwgPT4ge1xuICAgICAgICB0aGlzLnVybCA9IHVybFxuICAgICAgICB0aGlzLmVsLnNyYyA9IHVybFxuICAgICAgfSlcbiAgICB9LFxuICAgIGRlc3Ryb3llZCgpe1xuICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnVybClcbiAgICB9XG4gIH0sXG4gIEZvY3VzV3JhcDoge1xuICAgIG1vdW50ZWQoKXtcbiAgICAgIHRoaXMuZm9jdXNTdGFydCA9IHRoaXMuZWwuZmlyc3RFbGVtZW50Q2hpbGRcbiAgICAgIHRoaXMuZm9jdXNFbmQgPSB0aGlzLmVsLmxhc3RFbGVtZW50Q2hpbGRcbiAgICAgIHRoaXMuZm9jdXNTdGFydC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgKGUpID0+IHtcbiAgICAgICAgaWYoIWUucmVsYXRlZFRhcmdldCB8fCAhdGhpcy5lbC5jb250YWlucyhlLnJlbGF0ZWRUYXJnZXQpKXsgXG4gICAgICAgICAgLy8gSGFuZGxlIGZvY3VzIGVudGVyaW5nIGZyb20gb3V0c2lkZSAoZS5nLiBUYWIgd2hlbiBib2R5IGlzIGZvY3VzZWQpXG4gICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3Bob2VuaXhmcmFtZXdvcmsvcGhvZW5peF9saXZlX3ZpZXcvaXNzdWVzLzM2MzZcbiAgICAgICAgICBjb25zdCBuZXh0Rm9jdXMgPSBlLnRhcmdldC5uZXh0RWxlbWVudFNpYmxpbmdcbiAgICAgICAgICBBUklBLmF0dGVtcHRGb2N1cyhuZXh0Rm9jdXMpIHx8IEFSSUEuZm9jdXNGaXJzdChuZXh0Rm9jdXMpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgQVJJQS5mb2N1c0xhc3QodGhpcy5lbClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIHRoaXMuZm9jdXNFbmQuYWRkRXZlbnRMaXN0ZW5lcihcImZvY3VzXCIsIChlKSA9PiB7XG4gICAgICAgIGlmKCFlLnJlbGF0ZWRUYXJnZXQgfHwgIXRoaXMuZWwuY29udGFpbnMoZS5yZWxhdGVkVGFyZ2V0KSl7IFxuICAgICAgICAgIC8vIEhhbmRsZSBmb2N1cyBlbnRlcmluZyBmcm9tIG91dHNpZGUgKGUuZy4gU2hpZnQrVGFiIHdoZW4gYm9keSBpcyBmb2N1c2VkKVxuICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNjM2XG4gICAgICAgICAgY29uc3QgbmV4dEZvY3VzID0gZS50YXJnZXQucHJldmlvdXNFbGVtZW50U2libGluZ1xuICAgICAgICAgIEFSSUEuYXR0ZW1wdEZvY3VzKG5leHRGb2N1cykgfHwgQVJJQS5mb2N1c0xhc3QobmV4dEZvY3VzKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIEFSSUEuZm9jdXNGaXJzdCh0aGlzLmVsKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKFwicGh4OnNob3ctZW5kXCIsICgpID0+IHRoaXMuZWwuZm9jdXMoKSlcbiAgICAgIGlmKHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHRoaXMuZWwpLmRpc3BsYXkgIT09IFwibm9uZVwiKXtcbiAgICAgICAgQVJJQS5mb2N1c0ZpcnN0KHRoaXMuZWwpXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmxldCBmaW5kU2Nyb2xsQ29udGFpbmVyID0gKGVsKSA9PiB7XG4gIC8vIHRoZSBzY3JvbGwgZXZlbnQgd29uJ3QgYmUgZmlyZWQgb24gdGhlIGh0bWwvYm9keSBlbGVtZW50IGV2ZW4gaWYgb3ZlcmZsb3cgaXMgc2V0XG4gIC8vIHRoZXJlZm9yZSB3ZSByZXR1cm4gbnVsbCB0byBpbnN0ZWFkIGxpc3RlbiBmb3Igc2Nyb2xsIGV2ZW50cyBvbiBkb2N1bWVudFxuICBpZihbXCJIVE1MXCIsIFwiQk9EWVwiXS5pbmRleE9mKGVsLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkpID49IDApIHJldHVybiBudWxsXG4gIGlmKFtcInNjcm9sbFwiLCBcImF1dG9cIl0uaW5kZXhPZihnZXRDb21wdXRlZFN0eWxlKGVsKS5vdmVyZmxvd1kpID49IDApIHJldHVybiBlbFxuICByZXR1cm4gZmluZFNjcm9sbENvbnRhaW5lcihlbC5wYXJlbnRFbGVtZW50KVxufVxuXG5sZXQgc2Nyb2xsVG9wID0gKHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBpZihzY3JvbGxDb250YWluZXIpe1xuICAgIHJldHVybiBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3AgfHwgZG9jdW1lbnQuYm9keS5zY3JvbGxUb3BcbiAgfVxufVxuXG5sZXQgYm90dG9tID0gKHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBpZihzY3JvbGxDb250YWluZXIpe1xuICAgIHJldHVybiBzY3JvbGxDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuYm90dG9tXG4gIH0gZWxzZSB7XG4gICAgLy8gd2hlbiB3ZSBoYXZlIG5vIGNvbnRhaW5lciwgdGhlIHdob2xlIHBhZ2Ugc2Nyb2xscyxcbiAgICAvLyB0aGVyZWZvcmUgdGhlIGJvdHRvbSBjb29yZGluYXRlIGlzIHRoZSB2aWV3cG9ydCBoZWlnaHRcbiAgICByZXR1cm4gd2luZG93LmlubmVySGVpZ2h0IHx8IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHRcbiAgfVxufVxuXG5sZXQgdG9wID0gKHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBpZihzY3JvbGxDb250YWluZXIpe1xuICAgIHJldHVybiBzY3JvbGxDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wXG4gIH0gZWxzZSB7XG4gICAgLy8gd2hlbiB3ZSBoYXZlIG5vIGNvbnRhaW5lciB0aGUgd2hvbGUgcGFnZSBzY3JvbGxzLFxuICAgIC8vIHRoZXJlZm9yZSB0aGUgdG9wIGNvb3JkaW5hdGUgaXMgMFxuICAgIHJldHVybiAwXG4gIH1cbn1cblxubGV0IGlzQXRWaWV3cG9ydFRvcCA9IChlbCwgc2Nyb2xsQ29udGFpbmVyKSA9PiB7XG4gIGxldCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClcbiAgcmV0dXJuIE1hdGguY2VpbChyZWN0LnRvcCkgPj0gdG9wKHNjcm9sbENvbnRhaW5lcikgJiYgTWF0aC5jZWlsKHJlY3QubGVmdCkgPj0gMCAmJiBNYXRoLmZsb29yKHJlY3QudG9wKSA8PSBib3R0b20oc2Nyb2xsQ29udGFpbmVyKVxufVxuXG5sZXQgaXNBdFZpZXdwb3J0Qm90dG9tID0gKGVsLCBzY3JvbGxDb250YWluZXIpID0+IHtcbiAgbGV0IHJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVxuICByZXR1cm4gTWF0aC5jZWlsKHJlY3QuYm90dG9tKSA+PSB0b3Aoc2Nyb2xsQ29udGFpbmVyKSAmJiBNYXRoLmNlaWwocmVjdC5sZWZ0KSA+PSAwICYmIE1hdGguZmxvb3IocmVjdC5ib3R0b20pIDw9IGJvdHRvbShzY3JvbGxDb250YWluZXIpXG59XG5cbmxldCBpc1dpdGhpblZpZXdwb3J0ID0gKGVsLCBzY3JvbGxDb250YWluZXIpID0+IHtcbiAgbGV0IHJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVxuICByZXR1cm4gTWF0aC5jZWlsKHJlY3QudG9wKSA+PSB0b3Aoc2Nyb2xsQ29udGFpbmVyKSAmJiBNYXRoLmNlaWwocmVjdC5sZWZ0KSA+PSAwICYmIE1hdGguZmxvb3IocmVjdC50b3ApIDw9IGJvdHRvbShzY3JvbGxDb250YWluZXIpXG59XG5cbkhvb2tzLkluZmluaXRlU2Nyb2xsID0ge1xuICBtb3VudGVkKCl7XG4gICAgdGhpcy5zY3JvbGxDb250YWluZXIgPSBmaW5kU2Nyb2xsQ29udGFpbmVyKHRoaXMuZWwpXG4gICAgbGV0IHNjcm9sbEJlZm9yZSA9IHNjcm9sbFRvcCh0aGlzLnNjcm9sbENvbnRhaW5lcilcbiAgICBsZXQgdG9wT3ZlcnJhbiA9IGZhbHNlXG4gICAgbGV0IHRocm90dGxlSW50ZXJ2YWwgPSA1MDBcbiAgICBsZXQgcGVuZGluZ09wID0gbnVsbFxuXG4gICAgbGV0IG9uVG9wT3ZlcnJ1biA9IHRoaXMudGhyb3R0bGUodGhyb3R0bGVJbnRlcnZhbCwgKHRvcEV2ZW50LCBmaXJzdENoaWxkKSA9PiB7XG4gICAgICBwZW5kaW5nT3AgPSAoKSA9PiB0cnVlXG4gICAgICB0aGlzLmxpdmVTb2NrZXQuZXhlY0pTSG9va1B1c2godGhpcy5lbCwgdG9wRXZlbnQsIHtpZDogZmlyc3RDaGlsZC5pZCwgX292ZXJyYW46IHRydWV9LCAoKSA9PiB7XG4gICAgICAgIHBlbmRpbmdPcCA9IG51bGxcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIGxldCBvbkZpcnN0Q2hpbGRBdFRvcCA9IHRoaXMudGhyb3R0bGUodGhyb3R0bGVJbnRlcnZhbCwgKHRvcEV2ZW50LCBmaXJzdENoaWxkKSA9PiB7XG4gICAgICBwZW5kaW5nT3AgPSAoKSA9PiBmaXJzdENoaWxkLnNjcm9sbEludG9WaWV3KHtibG9jazogXCJzdGFydFwifSlcbiAgICAgIHRoaXMubGl2ZVNvY2tldC5leGVjSlNIb29rUHVzaCh0aGlzLmVsLCB0b3BFdmVudCwge2lkOiBmaXJzdENoaWxkLmlkfSwgKCkgPT4ge1xuICAgICAgICBwZW5kaW5nT3AgPSBudWxsXG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGF0IHRoZSBET00gaXMgcGF0Y2hlZCBieSB3YWl0aW5nIGZvciB0aGUgbmV4dCB0aWNrXG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgIGlmKCFpc1dpdGhpblZpZXdwb3J0KGZpcnN0Q2hpbGQsIHRoaXMuc2Nyb2xsQ29udGFpbmVyKSl7XG4gICAgICAgICAgICBmaXJzdENoaWxkLnNjcm9sbEludG9WaWV3KHtibG9jazogXCJzdGFydFwifSlcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICB9KVxuICAgIH0pXG5cbiAgICBsZXQgb25MYXN0Q2hpbGRBdEJvdHRvbSA9IHRoaXMudGhyb3R0bGUodGhyb3R0bGVJbnRlcnZhbCwgKGJvdHRvbUV2ZW50LCBsYXN0Q2hpbGQpID0+IHtcbiAgICAgIHBlbmRpbmdPcCA9ICgpID0+IGxhc3RDaGlsZC5zY3JvbGxJbnRvVmlldyh7YmxvY2s6IFwiZW5kXCJ9KVxuICAgICAgdGhpcy5saXZlU29ja2V0LmV4ZWNKU0hvb2tQdXNoKHRoaXMuZWwsIGJvdHRvbUV2ZW50LCB7aWQ6IGxhc3RDaGlsZC5pZH0sICgpID0+IHtcbiAgICAgICAgcGVuZGluZ09wID0gbnVsbFxuICAgICAgICAvLyBtYWtlIHN1cmUgdGhhdCB0aGUgRE9NIGlzIHBhdGNoZWQgYnkgd2FpdGluZyBmb3IgdGhlIG5leHQgdGlja1xuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICBpZighaXNXaXRoaW5WaWV3cG9ydChsYXN0Q2hpbGQsIHRoaXMuc2Nyb2xsQ29udGFpbmVyKSl7XG4gICAgICAgICAgICBsYXN0Q2hpbGQuc2Nyb2xsSW50b1ZpZXcoe2Jsb2NrOiBcImVuZFwifSlcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICB9KVxuICAgIH0pXG5cbiAgICB0aGlzLm9uU2Nyb2xsID0gKF9lKSA9PiB7XG4gICAgICBsZXQgc2Nyb2xsTm93ID0gc2Nyb2xsVG9wKHRoaXMuc2Nyb2xsQ29udGFpbmVyKVxuXG4gICAgICBpZihwZW5kaW5nT3Ape1xuICAgICAgICBzY3JvbGxCZWZvcmUgPSBzY3JvbGxOb3dcbiAgICAgICAgcmV0dXJuIHBlbmRpbmdPcCgpXG4gICAgICB9XG4gICAgICBsZXQgcmVjdCA9IHRoaXMuZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClcbiAgICAgIGxldCB0b3BFdmVudCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKHRoaXMubGl2ZVNvY2tldC5iaW5kaW5nKFwidmlld3BvcnQtdG9wXCIpKVxuICAgICAgbGV0IGJvdHRvbUV2ZW50ID0gdGhpcy5lbC5nZXRBdHRyaWJ1dGUodGhpcy5saXZlU29ja2V0LmJpbmRpbmcoXCJ2aWV3cG9ydC1ib3R0b21cIikpXG4gICAgICBsZXQgbGFzdENoaWxkID0gdGhpcy5lbC5sYXN0RWxlbWVudENoaWxkXG4gICAgICBsZXQgZmlyc3RDaGlsZCA9IHRoaXMuZWwuZmlyc3RFbGVtZW50Q2hpbGRcbiAgICAgIGxldCBpc1Njcm9sbGluZ1VwID0gc2Nyb2xsTm93IDwgc2Nyb2xsQmVmb3JlXG4gICAgICBsZXQgaXNTY3JvbGxpbmdEb3duID0gc2Nyb2xsTm93ID4gc2Nyb2xsQmVmb3JlXG5cbiAgICAgIC8vIGVsIG92ZXJyYW4gd2hpbGUgc2Nyb2xsaW5nIHVwXG4gICAgICBpZihpc1Njcm9sbGluZ1VwICYmIHRvcEV2ZW50ICYmICF0b3BPdmVycmFuICYmIHJlY3QudG9wID49IDApe1xuICAgICAgICB0b3BPdmVycmFuID0gdHJ1ZVxuICAgICAgICBvblRvcE92ZXJydW4odG9wRXZlbnQsIGZpcnN0Q2hpbGQpXG4gICAgICB9IGVsc2UgaWYoaXNTY3JvbGxpbmdEb3duICYmIHRvcE92ZXJyYW4gJiYgcmVjdC50b3AgPD0gMCl7XG4gICAgICAgIHRvcE92ZXJyYW4gPSBmYWxzZVxuICAgICAgfVxuXG4gICAgICBpZih0b3BFdmVudCAmJiBpc1Njcm9sbGluZ1VwICYmIGlzQXRWaWV3cG9ydFRvcChmaXJzdENoaWxkLCB0aGlzLnNjcm9sbENvbnRhaW5lcikpe1xuICAgICAgICBvbkZpcnN0Q2hpbGRBdFRvcCh0b3BFdmVudCwgZmlyc3RDaGlsZClcbiAgICAgIH0gZWxzZSBpZihib3R0b21FdmVudCAmJiBpc1Njcm9sbGluZ0Rvd24gJiYgaXNBdFZpZXdwb3J0Qm90dG9tKGxhc3RDaGlsZCwgdGhpcy5zY3JvbGxDb250YWluZXIpKXtcbiAgICAgICAgb25MYXN0Q2hpbGRBdEJvdHRvbShib3R0b21FdmVudCwgbGFzdENoaWxkKVxuICAgICAgfVxuICAgICAgc2Nyb2xsQmVmb3JlID0gc2Nyb2xsTm93XG4gICAgfVxuXG4gICAgaWYodGhpcy5zY3JvbGxDb250YWluZXIpe1xuICAgICAgdGhpcy5zY3JvbGxDb250YWluZXIuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCB0aGlzLm9uU2Nyb2xsKVxuICAgIH0gZWxzZSB7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCB0aGlzLm9uU2Nyb2xsKVxuICAgIH1cbiAgfSxcbiAgXG4gIGRlc3Ryb3llZCgpe1xuICAgIGlmKHRoaXMuc2Nyb2xsQ29udGFpbmVyKXtcbiAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgdGhpcy5vblNjcm9sbClcbiAgICB9IGVsc2Uge1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgdGhpcy5vblNjcm9sbClcbiAgICB9XG4gIH0sXG5cbiAgdGhyb3R0bGUoaW50ZXJ2YWwsIGNhbGxiYWNrKXtcbiAgICBsZXQgbGFzdENhbGxBdCA9IDBcbiAgICBsZXQgdGltZXJcblxuICAgIHJldHVybiAoLi4uYXJncykgPT4ge1xuICAgICAgbGV0IG5vdyA9IERhdGUubm93KClcbiAgICAgIGxldCByZW1haW5pbmdUaW1lID0gaW50ZXJ2YWwgLSAobm93IC0gbGFzdENhbGxBdClcblxuICAgICAgaWYocmVtYWluaW5nVGltZSA8PSAwIHx8IHJlbWFpbmluZ1RpbWUgPiBpbnRlcnZhbCl7XG4gICAgICAgIGlmKHRpbWVyKXtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpXG4gICAgICAgICAgdGltZXIgPSBudWxsXG4gICAgICAgIH1cbiAgICAgICAgbGFzdENhbGxBdCA9IG5vd1xuICAgICAgICBjYWxsYmFjayguLi5hcmdzKVxuICAgICAgfSBlbHNlIGlmKCF0aW1lcil7XG4gICAgICAgIHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgbGFzdENhbGxBdCA9IERhdGUubm93KClcbiAgICAgICAgICB0aW1lciA9IG51bGxcbiAgICAgICAgICBjYWxsYmFjayguLi5hcmdzKVxuICAgICAgICB9LCByZW1haW5pbmdUaW1lKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuZXhwb3J0IGRlZmF1bHQgSG9va3NcbiIsICJpbXBvcnQge1xuICBQSFhfUkVGX0xPQURJTkcsXG4gIFBIWF9SRUZfTE9DSyxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9QRU5ESU5HX1JFRlMsXG4gIFBIWF9FVkVOVF9DTEFTU0VTLFxuICBQSFhfRElTQUJMRUQsXG4gIFBIWF9SRUFET05MWSxcbiAgUEhYX0RJU0FCTEVfV0lUSF9SRVNUT1JFXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCJcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRWxlbWVudFJlZiB7XG4gIHN0YXRpYyBvblVubG9jayhlbCwgY2FsbGJhY2spe1xuICAgIGlmKCFET00uaXNMb2NrZWQoZWwpICYmICFlbC5jbG9zZXN0KGBbJHtQSFhfUkVGX0xPQ0t9XWApKXsgcmV0dXJuIGNhbGxiYWNrKCkgfVxuICAgIGNvbnN0IGNsb3Nlc3RMb2NrID0gZWwuY2xvc2VzdChgWyR7UEhYX1JFRl9MT0NLfV1gKVxuICAgIGNvbnN0IHJlZiA9IGNsb3Nlc3RMb2NrLmNsb3Nlc3QoYFske1BIWF9SRUZfTE9DS31dYCkuZ2V0QXR0cmlidXRlKFBIWF9SRUZfTE9DSylcbiAgICBjbG9zZXN0TG9jay5hZGRFdmVudExpc3RlbmVyKGBwaHg6dW5kby1sb2NrOiR7cmVmfWAsICgpID0+IHtcbiAgICAgIGNhbGxiYWNrKClcbiAgICB9LCB7b25jZTogdHJ1ZX0pXG4gIH1cblxuICBjb25zdHJ1Y3RvcihlbCl7XG4gICAgdGhpcy5lbCA9IGVsXG4gICAgdGhpcy5sb2FkaW5nUmVmID0gZWwuaGFzQXR0cmlidXRlKFBIWF9SRUZfTE9BRElORykgPyBwYXJzZUludChlbC5nZXRBdHRyaWJ1dGUoUEhYX1JFRl9MT0FESU5HKSwgMTApIDogbnVsbFxuICAgIHRoaXMubG9ja1JlZiA9IGVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX0xPQ0spID8gcGFyc2VJbnQoZWwuZ2V0QXR0cmlidXRlKFBIWF9SRUZfTE9DSyksIDEwKSA6IG51bGxcbiAgfVxuXG4gIC8vIHB1YmxpY1xuXG4gIG1heWJlVW5kbyhyZWYsIHBoeEV2ZW50LCBlYWNoQ2xvbmVDYWxsYmFjayl7XG4gICAgaWYoIXRoaXMuaXNXaXRoaW4ocmVmKSl7XG4gICAgICAvLyB3ZSBjYW5ub3QgdW5kbyB0aGUgbG9jayAvIGxvYWRpbmcgbm93LCBhcyB0aGVyZSBpcyBhIG5ld2VyIG9uZSBhbHJlYWR5IHNldDtcbiAgICAgIC8vIHdlIG5lZWQgdG8gc3RvcmUgdGhlIG9yaWdpbmFsIHJlZiB3ZSB0cmllZCB0byBzZW5kIHRoZSB1bmRvIGV2ZW50IGxhdGVyXG4gICAgICBET00udXBkYXRlUHJpdmF0ZSh0aGlzLmVsLCBQSFhfUEVORElOR19SRUZTLCBbXSwgKHBlbmRpbmdSZWZzKSA9PiB7XG4gICAgICAgIHBlbmRpbmdSZWZzLnB1c2gocmVmKVxuICAgICAgICByZXR1cm4gcGVuZGluZ1JlZnNcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyB1bmRvIGxvY2tzIGFuZCBhcHBseSBjbG9uZXNcbiAgICB0aGlzLnVuZG9Mb2NrcyhyZWYsIHBoeEV2ZW50LCBlYWNoQ2xvbmVDYWxsYmFjaylcblxuICAgIC8vIHVuZG8gbG9hZGluZyBzdGF0ZXNcbiAgICB0aGlzLnVuZG9Mb2FkaW5nKHJlZiwgcGh4RXZlbnQpXG5cbiAgICAvLyBlbnN1cmUgdW5kbyBldmVudHMgYXJlIGZpcmVkIGZvciBwZW5kaW5nIHJlZnMgdGhhdFxuICAgIC8vIGFyZSByZXNvbHZlZCBieSB0aGUgY3VycmVudCByZWYsIG90aGVyd2lzZSB3ZSdkIGxlYWsgZXZlbnQgbGlzdGVuZXJzXG4gICAgRE9NLnVwZGF0ZVByaXZhdGUodGhpcy5lbCwgUEhYX1BFTkRJTkdfUkVGUywgW10sIChwZW5kaW5nUmVmcykgPT4ge1xuICAgICAgcmV0dXJuIHBlbmRpbmdSZWZzLmZpbHRlcigocGVuZGluZ1JlZikgPT4ge1xuICAgICAgICBsZXQgb3B0cyA9IHtcbiAgICAgICAgICBkZXRhaWw6IHtyZWY6IHBlbmRpbmdSZWYsIGV2ZW50OiBwaHhFdmVudH0sXG4gICAgICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgICAgICBjYW5jZWxhYmxlOiBmYWxzZSxcbiAgICAgICAgfVxuICAgICAgICBpZih0aGlzLmxvYWRpbmdSZWYgJiYgdGhpcy5sb2FkaW5nUmVmID4gcGVuZGluZ1JlZil7XG4gICAgICAgICAgdGhpcy5lbC5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IEN1c3RvbUV2ZW50KGBwaHg6dW5kby1sb2FkaW5nOiR7cGVuZGluZ1JlZn1gLCBvcHRzKSxcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgICAgaWYodGhpcy5sb2NrUmVmICYmIHRoaXMubG9ja1JlZiA+IHBlbmRpbmdSZWYpe1xuICAgICAgICAgIHRoaXMuZWwuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgIG5ldyBDdXN0b21FdmVudChgcGh4OnVuZG8tbG9jazoke3BlbmRpbmdSZWZ9YCwgb3B0cyksXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwZW5kaW5nUmVmID4gcmVmXG4gICAgICB9KVxuICAgIH0pXG5cbiAgICAvLyBjbGVhbiB1cCBpZiBmdWxseSByZXNvbHZlZFxuICAgIGlmKHRoaXMuaXNGdWxseVJlc29sdmVkQnkocmVmKSl7IHRoaXMuZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUZfU1JDKSB9XG4gIH1cblxuICAvLyBwcml2YXRlXG5cbiAgaXNXaXRoaW4ocmVmKXtcbiAgICByZXR1cm4gISgodGhpcy5sb2FkaW5nUmVmICE9PSBudWxsICYmIHRoaXMubG9hZGluZ1JlZiA+IHJlZikgJiYgKHRoaXMubG9ja1JlZiAhPT0gbnVsbCAmJiB0aGlzLmxvY2tSZWYgPiByZWYpKVxuICB9XG5cbiAgLy8gQ2hlY2sgZm9yIGNsb25lZCBQSFhfUkVGX0xPQ0sgZWxlbWVudCB0aGF0IGhhcyBiZWVuIG1vcnBoZWQgYmVoaW5kXG4gIC8vIHRoZSBzY2VuZXMgd2hpbGUgdGhpcyBlbGVtZW50IHdhcyBsb2NrZWQgaW4gdGhlIERPTS5cbiAgLy8gV2hlbiB3ZSBhcHBseSB0aGUgY2xvbmVkIHRyZWUgdG8gdGhlIGFjdGl2ZSBET00gZWxlbWVudCwgd2UgbXVzdFxuICAvL1xuICAvLyAgIDEuIGV4ZWN1dGUgcGVuZGluZyBtb3VudGVkIGhvb2tzIGZvciBub2RlcyBub3cgaW4gdGhlIERPTVxuICAvLyAgIDIuIHVuZG8gYW55IHJlZiBpbnNpZGUgdGhlIGNsb25lZCB0cmVlIHRoYXQgaGFzIHNpbmNlIGJlZW4gYWNrJ2RcbiAgdW5kb0xvY2tzKHJlZiwgcGh4RXZlbnQsIGVhY2hDbG9uZUNhbGxiYWNrKXtcbiAgICBpZighdGhpcy5pc0xvY2tVbmRvbmVCeShyZWYpKXsgcmV0dXJuIH1cblxuICAgIGxldCBjbG9uZWRUcmVlID0gRE9NLnByaXZhdGUodGhpcy5lbCwgUEhYX1JFRl9MT0NLKVxuICAgIGlmKGNsb25lZFRyZWUpe1xuICAgICAgZWFjaENsb25lQ2FsbGJhY2soY2xvbmVkVHJlZSlcbiAgICAgIERPTS5kZWxldGVQcml2YXRlKHRoaXMuZWwsIFBIWF9SRUZfTE9DSylcbiAgICB9XG4gICAgdGhpcy5lbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKVxuXG4gICAgbGV0IG9wdHMgPSB7ZGV0YWlsOiB7cmVmOiByZWYsIGV2ZW50OiBwaHhFdmVudH0sIGJ1YmJsZXM6IHRydWUsIGNhbmNlbGFibGU6IGZhbHNlfVxuICAgIHRoaXMuZWwuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoYHBoeDp1bmRvLWxvY2s6JHt0aGlzLmxvY2tSZWZ9YCwgb3B0cykpXG4gIH1cblxuICB1bmRvTG9hZGluZyhyZWYsIHBoeEV2ZW50KXtcbiAgICBpZighdGhpcy5pc0xvYWRpbmdVbmRvbmVCeShyZWYpKXtcbiAgICAgIGlmKHRoaXMuY2FuVW5kb0xvYWRpbmcocmVmKSAmJiB0aGlzLmVsLmNsYXNzTGlzdC5jb250YWlucyhcInBoeC1zdWJtaXQtbG9hZGluZ1wiKSl7XG4gICAgICAgIHRoaXMuZWwuY2xhc3NMaXN0LnJlbW92ZShcInBoeC1jaGFuZ2UtbG9hZGluZ1wiKVxuICAgICAgfVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYodGhpcy5jYW5VbmRvTG9hZGluZyhyZWYpKXtcbiAgICAgIHRoaXMuZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUZfTE9BRElORylcbiAgICAgIGxldCBkaXNhYmxlZFZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRClcbiAgICAgIGxldCByZWFkT25seVZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9SRUFET05MWSlcbiAgICAgIC8vIHJlc3RvcmUgaW5wdXRzXG4gICAgICBpZihyZWFkT25seVZhbCAhPT0gbnVsbCl7XG4gICAgICAgIHRoaXMuZWwucmVhZE9ubHkgPSByZWFkT25seVZhbCA9PT0gXCJ0cnVlXCIgPyB0cnVlIDogZmFsc2VcbiAgICAgICAgdGhpcy5lbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFQURPTkxZKVxuICAgICAgfVxuICAgICAgaWYoZGlzYWJsZWRWYWwgIT09IG51bGwpe1xuICAgICAgICB0aGlzLmVsLmRpc2FibGVkID0gZGlzYWJsZWRWYWwgPT09IFwidHJ1ZVwiID8gdHJ1ZSA6IGZhbHNlXG4gICAgICAgIHRoaXMuZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9ESVNBQkxFRClcbiAgICAgIH1cbiAgICAgIC8vIHJlc3RvcmUgZGlzYWJsZXNcbiAgICAgIGxldCBkaXNhYmxlUmVzdG9yZSA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFX1dJVEhfUkVTVE9SRSlcbiAgICAgIGlmKGRpc2FibGVSZXN0b3JlICE9PSBudWxsKXtcbiAgICAgICAgdGhpcy5lbC5pbm5lclRleHQgPSBkaXNhYmxlUmVzdG9yZVxuICAgICAgICB0aGlzLmVsLnJlbW92ZUF0dHJpYnV0ZShQSFhfRElTQUJMRV9XSVRIX1JFU1RPUkUpXG4gICAgICB9XG5cbiAgICAgIGxldCBvcHRzID0ge2RldGFpbDoge3JlZjogcmVmLCBldmVudDogcGh4RXZlbnR9LCBidWJibGVzOiB0cnVlLCBjYW5jZWxhYmxlOiBmYWxzZX1cbiAgICAgIHRoaXMuZWwuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoYHBoeDp1bmRvLWxvYWRpbmc6JHt0aGlzLmxvYWRpbmdSZWZ9YCwgb3B0cykpXG4gICAgfVxuXG4gICAgLy8gcmVtb3ZlIGNsYXNzZXNcbiAgICBQSFhfRVZFTlRfQ0xBU1NFUy5mb3JFYWNoKG5hbWUgPT4ge1xuICAgICAgaWYobmFtZSAhPT0gXCJwaHgtc3VibWl0LWxvYWRpbmdcIiB8fCB0aGlzLmNhblVuZG9Mb2FkaW5nKHJlZikpe1xuICAgICAgICBET00ucmVtb3ZlQ2xhc3ModGhpcy5lbCwgbmFtZSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgaXNMb2FkaW5nVW5kb25lQnkocmVmKXsgcmV0dXJuIHRoaXMubG9hZGluZ1JlZiA9PT0gbnVsbCA/IGZhbHNlIDogdGhpcy5sb2FkaW5nUmVmIDw9IHJlZiB9XG4gIGlzTG9ja1VuZG9uZUJ5KHJlZil7IHJldHVybiB0aGlzLmxvY2tSZWYgPT09IG51bGwgPyBmYWxzZSA6IHRoaXMubG9ja1JlZiA8PSByZWYgfVxuXG4gIGlzRnVsbHlSZXNvbHZlZEJ5KHJlZil7XG4gICAgcmV0dXJuICh0aGlzLmxvYWRpbmdSZWYgPT09IG51bGwgfHwgdGhpcy5sb2FkaW5nUmVmIDw9IHJlZikgJiYgKHRoaXMubG9ja1JlZiA9PT0gbnVsbCB8fCB0aGlzLmxvY2tSZWYgPD0gcmVmKVxuICB9XG5cbiAgLy8gb25seSByZW1vdmUgdGhlIHBoeC1zdWJtaXQtbG9hZGluZyBjbGFzcyBpZiB3ZSBhcmUgbm90IGxvY2tlZFxuICBjYW5VbmRvTG9hZGluZyhyZWYpeyByZXR1cm4gdGhpcy5sb2NrUmVmID09PSBudWxsIHx8IHRoaXMubG9ja1JlZiA8PSByZWYgfVxufVxuIiwgImltcG9ydCB7XG4gIG1heWJlXG59IGZyb20gXCIuL3V0aWxzXCJcblxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIlxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBET01Qb3N0TW9ycGhSZXN0b3JlciB7XG4gIGNvbnN0cnVjdG9yKGNvbnRhaW5lckJlZm9yZSwgY29udGFpbmVyQWZ0ZXIsIHVwZGF0ZVR5cGUpe1xuICAgIGxldCBpZHNCZWZvcmUgPSBuZXcgU2V0KClcbiAgICBsZXQgaWRzQWZ0ZXIgPSBuZXcgU2V0KFsuLi5jb250YWluZXJBZnRlci5jaGlsZHJlbl0ubWFwKGNoaWxkID0+IGNoaWxkLmlkKSlcblxuICAgIGxldCBlbGVtZW50c1RvTW9kaWZ5ID0gW11cblxuICAgIEFycmF5LmZyb20oY29udGFpbmVyQmVmb3JlLmNoaWxkcmVuKS5mb3JFYWNoKGNoaWxkID0+IHtcbiAgICAgIGlmKGNoaWxkLmlkKXsgLy8gYWxsIG9mIG91ciBjaGlsZHJlbiBzaG91bGQgYmUgZWxlbWVudHMgd2l0aCBpZHNcbiAgICAgICAgaWRzQmVmb3JlLmFkZChjaGlsZC5pZClcbiAgICAgICAgaWYoaWRzQWZ0ZXIuaGFzKGNoaWxkLmlkKSl7XG4gICAgICAgICAgbGV0IHByZXZpb3VzRWxlbWVudElkID0gY2hpbGQucHJldmlvdXNFbGVtZW50U2libGluZyAmJiBjaGlsZC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nLmlkXG4gICAgICAgICAgZWxlbWVudHNUb01vZGlmeS5wdXNoKHtlbGVtZW50SWQ6IGNoaWxkLmlkLCBwcmV2aW91c0VsZW1lbnRJZDogcHJldmlvdXNFbGVtZW50SWR9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSlcblxuICAgIHRoaXMuY29udGFpbmVySWQgPSBjb250YWluZXJBZnRlci5pZFxuICAgIHRoaXMudXBkYXRlVHlwZSA9IHVwZGF0ZVR5cGVcbiAgICB0aGlzLmVsZW1lbnRzVG9Nb2RpZnkgPSBlbGVtZW50c1RvTW9kaWZ5XG4gICAgdGhpcy5lbGVtZW50SWRzVG9BZGQgPSBbLi4uaWRzQWZ0ZXJdLmZpbHRlcihpZCA9PiAhaWRzQmVmb3JlLmhhcyhpZCkpXG4gIH1cblxuICAvLyBXZSBkbyB0aGUgZm9sbG93aW5nIHRvIG9wdGltaXplIGFwcGVuZC9wcmVwZW5kIG9wZXJhdGlvbnM6XG4gIC8vICAgMSkgVHJhY2sgaWRzIG9mIG1vZGlmaWVkIGVsZW1lbnRzICYgb2YgbmV3IGVsZW1lbnRzXG4gIC8vICAgMikgQWxsIHRoZSBtb2RpZmllZCBlbGVtZW50cyBhcmUgcHV0IGJhY2sgaW4gdGhlIGNvcnJlY3QgcG9zaXRpb24gaW4gdGhlIERPTSB0cmVlXG4gIC8vICAgICAgYnkgc3RvcmluZyB0aGUgaWQgb2YgdGhlaXIgcHJldmlvdXMgc2libGluZ1xuICAvLyAgIDMpIE5ldyBlbGVtZW50cyBhcmUgZ29pbmcgdG8gYmUgcHV0IGluIHRoZSByaWdodCBwbGFjZSBieSBtb3JwaGRvbSBkdXJpbmcgYXBwZW5kLlxuICAvLyAgICAgIEZvciBwcmVwZW5kLCB3ZSBtb3ZlIHRoZW0gdG8gdGhlIGZpcnN0IHBvc2l0aW9uIGluIHRoZSBjb250YWluZXJcbiAgcGVyZm9ybSgpe1xuICAgIGxldCBjb250YWluZXIgPSBET00uYnlJZCh0aGlzLmNvbnRhaW5lcklkKVxuICAgIHRoaXMuZWxlbWVudHNUb01vZGlmeS5mb3JFYWNoKGVsZW1lbnRUb01vZGlmeSA9PiB7XG4gICAgICBpZihlbGVtZW50VG9Nb2RpZnkucHJldmlvdXNFbGVtZW50SWQpe1xuICAgICAgICBtYXliZShkb2N1bWVudC5nZXRFbGVtZW50QnlJZChlbGVtZW50VG9Nb2RpZnkucHJldmlvdXNFbGVtZW50SWQpLCBwcmV2aW91c0VsZW0gPT4ge1xuICAgICAgICAgIG1heWJlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGVsZW1lbnRUb01vZGlmeS5lbGVtZW50SWQpLCBlbGVtID0+IHtcbiAgICAgICAgICAgIGxldCBpc0luUmlnaHRQbGFjZSA9IGVsZW0ucHJldmlvdXNFbGVtZW50U2libGluZyAmJiBlbGVtLnByZXZpb3VzRWxlbWVudFNpYmxpbmcuaWQgPT0gcHJldmlvdXNFbGVtLmlkXG4gICAgICAgICAgICBpZighaXNJblJpZ2h0UGxhY2Upe1xuICAgICAgICAgICAgICBwcmV2aW91c0VsZW0uaW5zZXJ0QWRqYWNlbnRFbGVtZW50KFwiYWZ0ZXJlbmRcIiwgZWxlbSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVGhpcyBpcyB0aGUgZmlyc3QgZWxlbWVudCBpbiB0aGUgY29udGFpbmVyXG4gICAgICAgIG1heWJlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGVsZW1lbnRUb01vZGlmeS5lbGVtZW50SWQpLCBlbGVtID0+IHtcbiAgICAgICAgICBsZXQgaXNJblJpZ2h0UGxhY2UgPSBlbGVtLnByZXZpb3VzRWxlbWVudFNpYmxpbmcgPT0gbnVsbFxuICAgICAgICAgIGlmKCFpc0luUmlnaHRQbGFjZSl7XG4gICAgICAgICAgICBjb250YWluZXIuaW5zZXJ0QWRqYWNlbnRFbGVtZW50KFwiYWZ0ZXJiZWdpblwiLCBlbGVtKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9KVxuXG4gICAgaWYodGhpcy51cGRhdGVUeXBlID09IFwicHJlcGVuZFwiKXtcbiAgICAgIHRoaXMuZWxlbWVudElkc1RvQWRkLnJldmVyc2UoKS5mb3JFYWNoKGVsZW1JZCA9PiB7XG4gICAgICAgIG1heWJlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGVsZW1JZCksIGVsZW0gPT4gY29udGFpbmVyLmluc2VydEFkamFjZW50RWxlbWVudChcImFmdGVyYmVnaW5cIiwgZWxlbSkpXG4gICAgICB9KVxuICAgIH1cbiAgfVxufVxuIiwgInZhciBET0NVTUVOVF9GUkFHTUVOVF9OT0RFID0gMTE7XG5cbmZ1bmN0aW9uIG1vcnBoQXR0cnMoZnJvbU5vZGUsIHRvTm9kZSkge1xuICAgIHZhciB0b05vZGVBdHRycyA9IHRvTm9kZS5hdHRyaWJ1dGVzO1xuICAgIHZhciBhdHRyO1xuICAgIHZhciBhdHRyTmFtZTtcbiAgICB2YXIgYXR0ck5hbWVzcGFjZVVSSTtcbiAgICB2YXIgYXR0clZhbHVlO1xuICAgIHZhciBmcm9tVmFsdWU7XG5cbiAgICAvLyBkb2N1bWVudC1mcmFnbWVudHMgZG9udCBoYXZlIGF0dHJpYnV0ZXMgc28gbGV0cyBub3QgZG8gYW55dGhpbmdcbiAgICBpZiAodG9Ob2RlLm5vZGVUeXBlID09PSBET0NVTUVOVF9GUkFHTUVOVF9OT0RFIHx8IGZyb21Ob2RlLm5vZGVUeXBlID09PSBET0NVTUVOVF9GUkFHTUVOVF9OT0RFKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gdXBkYXRlIGF0dHJpYnV0ZXMgb24gb3JpZ2luYWwgRE9NIGVsZW1lbnRcbiAgICBmb3IgKHZhciBpID0gdG9Ob2RlQXR0cnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgYXR0ciA9IHRvTm9kZUF0dHJzW2ldO1xuICAgICAgICBhdHRyTmFtZSA9IGF0dHIubmFtZTtcbiAgICAgICAgYXR0ck5hbWVzcGFjZVVSSSA9IGF0dHIubmFtZXNwYWNlVVJJO1xuICAgICAgICBhdHRyVmFsdWUgPSBhdHRyLnZhbHVlO1xuXG4gICAgICAgIGlmIChhdHRyTmFtZXNwYWNlVVJJKSB7XG4gICAgICAgICAgICBhdHRyTmFtZSA9IGF0dHIubG9jYWxOYW1lIHx8IGF0dHJOYW1lO1xuICAgICAgICAgICAgZnJvbVZhbHVlID0gZnJvbU5vZGUuZ2V0QXR0cmlidXRlTlMoYXR0ck5hbWVzcGFjZVVSSSwgYXR0ck5hbWUpO1xuXG4gICAgICAgICAgICBpZiAoZnJvbVZhbHVlICE9PSBhdHRyVmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoYXR0ci5wcmVmaXggPT09ICd4bWxucycpe1xuICAgICAgICAgICAgICAgICAgICBhdHRyTmFtZSA9IGF0dHIubmFtZTsgLy8gSXQncyBub3QgYWxsb3dlZCB0byBzZXQgYW4gYXR0cmlidXRlIHdpdGggdGhlIFhNTE5TIG5hbWVzcGFjZSB3aXRob3V0IHNwZWNpZnlpbmcgdGhlIGB4bWxuc2AgcHJlZml4XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZyb21Ob2RlLnNldEF0dHJpYnV0ZU5TKGF0dHJOYW1lc3BhY2VVUkksIGF0dHJOYW1lLCBhdHRyVmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnJvbVZhbHVlID0gZnJvbU5vZGUuZ2V0QXR0cmlidXRlKGF0dHJOYW1lKTtcblxuICAgICAgICAgICAgaWYgKGZyb21WYWx1ZSAhPT0gYXR0clZhbHVlKSB7XG4gICAgICAgICAgICAgICAgZnJvbU5vZGUuc2V0QXR0cmlidXRlKGF0dHJOYW1lLCBhdHRyVmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIGFueSBleHRyYSBhdHRyaWJ1dGVzIGZvdW5kIG9uIHRoZSBvcmlnaW5hbCBET00gZWxlbWVudCB0aGF0XG4gICAgLy8gd2VyZW4ndCBmb3VuZCBvbiB0aGUgdGFyZ2V0IGVsZW1lbnQuXG4gICAgdmFyIGZyb21Ob2RlQXR0cnMgPSBmcm9tTm9kZS5hdHRyaWJ1dGVzO1xuXG4gICAgZm9yICh2YXIgZCA9IGZyb21Ob2RlQXR0cnMubGVuZ3RoIC0gMTsgZCA+PSAwOyBkLS0pIHtcbiAgICAgICAgYXR0ciA9IGZyb21Ob2RlQXR0cnNbZF07XG4gICAgICAgIGF0dHJOYW1lID0gYXR0ci5uYW1lO1xuICAgICAgICBhdHRyTmFtZXNwYWNlVVJJID0gYXR0ci5uYW1lc3BhY2VVUkk7XG5cbiAgICAgICAgaWYgKGF0dHJOYW1lc3BhY2VVUkkpIHtcbiAgICAgICAgICAgIGF0dHJOYW1lID0gYXR0ci5sb2NhbE5hbWUgfHwgYXR0ck5hbWU7XG5cbiAgICAgICAgICAgIGlmICghdG9Ob2RlLmhhc0F0dHJpYnV0ZU5TKGF0dHJOYW1lc3BhY2VVUkksIGF0dHJOYW1lKSkge1xuICAgICAgICAgICAgICAgIGZyb21Ob2RlLnJlbW92ZUF0dHJpYnV0ZU5TKGF0dHJOYW1lc3BhY2VVUkksIGF0dHJOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghdG9Ob2RlLmhhc0F0dHJpYnV0ZShhdHRyTmFtZSkpIHtcbiAgICAgICAgICAgICAgICBmcm9tTm9kZS5yZW1vdmVBdHRyaWJ1dGUoYXR0ck5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG52YXIgcmFuZ2U7IC8vIENyZWF0ZSBhIHJhbmdlIG9iamVjdCBmb3IgZWZmaWNlbnRseSByZW5kZXJpbmcgc3RyaW5ncyB0byBlbGVtZW50cy5cbnZhciBOU19YSFRNTCA9ICdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sJztcblxudmFyIGRvYyA9IHR5cGVvZiBkb2N1bWVudCA9PT0gJ3VuZGVmaW5lZCcgPyB1bmRlZmluZWQgOiBkb2N1bWVudDtcbnZhciBIQVNfVEVNUExBVEVfU1VQUE9SVCA9ICEhZG9jICYmICdjb250ZW50JyBpbiBkb2MuY3JlYXRlRWxlbWVudCgndGVtcGxhdGUnKTtcbnZhciBIQVNfUkFOR0VfU1VQUE9SVCA9ICEhZG9jICYmIGRvYy5jcmVhdGVSYW5nZSAmJiAnY3JlYXRlQ29udGV4dHVhbEZyYWdtZW50JyBpbiBkb2MuY3JlYXRlUmFuZ2UoKTtcblxuZnVuY3Rpb24gY3JlYXRlRnJhZ21lbnRGcm9tVGVtcGxhdGUoc3RyKSB7XG4gICAgdmFyIHRlbXBsYXRlID0gZG9jLmNyZWF0ZUVsZW1lbnQoJ3RlbXBsYXRlJyk7XG4gICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gc3RyO1xuICAgIHJldHVybiB0ZW1wbGF0ZS5jb250ZW50LmNoaWxkTm9kZXNbMF07XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUZyYWdtZW50RnJvbVJhbmdlKHN0cikge1xuICAgIGlmICghcmFuZ2UpIHtcbiAgICAgICAgcmFuZ2UgPSBkb2MuY3JlYXRlUmFuZ2UoKTtcbiAgICAgICAgcmFuZ2Uuc2VsZWN0Tm9kZShkb2MuYm9keSk7XG4gICAgfVxuXG4gICAgdmFyIGZyYWdtZW50ID0gcmFuZ2UuY3JlYXRlQ29udGV4dHVhbEZyYWdtZW50KHN0cik7XG4gICAgcmV0dXJuIGZyYWdtZW50LmNoaWxkTm9kZXNbMF07XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUZyYWdtZW50RnJvbVdyYXAoc3RyKSB7XG4gICAgdmFyIGZyYWdtZW50ID0gZG9jLmNyZWF0ZUVsZW1lbnQoJ2JvZHknKTtcbiAgICBmcmFnbWVudC5pbm5lckhUTUwgPSBzdHI7XG4gICAgcmV0dXJuIGZyYWdtZW50LmNoaWxkTm9kZXNbMF07XG59XG5cbi8qKlxuICogVGhpcyBpcyBhYm91dCB0aGUgc2FtZVxuICogdmFyIGh0bWwgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKHN0ciwgJ3RleHQvaHRtbCcpO1xuICogcmV0dXJuIGh0bWwuYm9keS5maXJzdENoaWxkO1xuICpcbiAqIEBtZXRob2QgdG9FbGVtZW50XG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyXG4gKi9cbmZ1bmN0aW9uIHRvRWxlbWVudChzdHIpIHtcbiAgICBzdHIgPSBzdHIudHJpbSgpO1xuICAgIGlmIChIQVNfVEVNUExBVEVfU1VQUE9SVCkge1xuICAgICAgLy8gYXZvaWQgcmVzdHJpY3Rpb25zIG9uIGNvbnRlbnQgZm9yIHRoaW5ncyBsaWtlIGA8dHI+PHRoPkhpPC90aD48L3RyPmAgd2hpY2hcbiAgICAgIC8vIGNyZWF0ZUNvbnRleHR1YWxGcmFnbWVudCBkb2Vzbid0IHN1cHBvcnRcbiAgICAgIC8vIDx0ZW1wbGF0ZT4gc3VwcG9ydCBub3QgYXZhaWxhYmxlIGluIElFXG4gICAgICByZXR1cm4gY3JlYXRlRnJhZ21lbnRGcm9tVGVtcGxhdGUoc3RyKTtcbiAgICB9IGVsc2UgaWYgKEhBU19SQU5HRV9TVVBQT1JUKSB7XG4gICAgICByZXR1cm4gY3JlYXRlRnJhZ21lbnRGcm9tUmFuZ2Uoc3RyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3JlYXRlRnJhZ21lbnRGcm9tV3JhcChzdHIpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiB0d28gbm9kZSdzIG5hbWVzIGFyZSB0aGUgc2FtZS5cbiAqXG4gKiBOT1RFOiBXZSBkb24ndCBib3RoZXIgY2hlY2tpbmcgYG5hbWVzcGFjZVVSSWAgYmVjYXVzZSB5b3Ugd2lsbCBuZXZlciBmaW5kIHR3byBIVE1MIGVsZW1lbnRzIHdpdGggdGhlIHNhbWVcbiAqICAgICAgIG5vZGVOYW1lIGFuZCBkaWZmZXJlbnQgbmFtZXNwYWNlIFVSSXMuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBhXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGIgVGhlIHRhcmdldCBlbGVtZW50XG4gKiBAcmV0dXJuIHtib29sZWFufVxuICovXG5mdW5jdGlvbiBjb21wYXJlTm9kZU5hbWVzKGZyb21FbCwgdG9FbCkge1xuICAgIHZhciBmcm9tTm9kZU5hbWUgPSBmcm9tRWwubm9kZU5hbWU7XG4gICAgdmFyIHRvTm9kZU5hbWUgPSB0b0VsLm5vZGVOYW1lO1xuICAgIHZhciBmcm9tQ29kZVN0YXJ0LCB0b0NvZGVTdGFydDtcblxuICAgIGlmIChmcm9tTm9kZU5hbWUgPT09IHRvTm9kZU5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZnJvbUNvZGVTdGFydCA9IGZyb21Ob2RlTmFtZS5jaGFyQ29kZUF0KDApO1xuICAgIHRvQ29kZVN0YXJ0ID0gdG9Ob2RlTmFtZS5jaGFyQ29kZUF0KDApO1xuXG4gICAgLy8gSWYgdGhlIHRhcmdldCBlbGVtZW50IGlzIGEgdmlydHVhbCBET00gbm9kZSBvciBTVkcgbm9kZSB0aGVuIHdlIG1heVxuICAgIC8vIG5lZWQgdG8gbm9ybWFsaXplIHRoZSB0YWcgbmFtZSBiZWZvcmUgY29tcGFyaW5nLiBOb3JtYWwgSFRNTCBlbGVtZW50cyB0aGF0IGFyZVxuICAgIC8vIGluIHRoZSBcImh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWxcIlxuICAgIC8vIGFyZSBjb252ZXJ0ZWQgdG8gdXBwZXIgY2FzZVxuICAgIGlmIChmcm9tQ29kZVN0YXJ0IDw9IDkwICYmIHRvQ29kZVN0YXJ0ID49IDk3KSB7IC8vIGZyb20gaXMgdXBwZXIgYW5kIHRvIGlzIGxvd2VyXG4gICAgICAgIHJldHVybiBmcm9tTm9kZU5hbWUgPT09IHRvTm9kZU5hbWUudG9VcHBlckNhc2UoKTtcbiAgICB9IGVsc2UgaWYgKHRvQ29kZVN0YXJ0IDw9IDkwICYmIGZyb21Db2RlU3RhcnQgPj0gOTcpIHsgLy8gdG8gaXMgdXBwZXIgYW5kIGZyb20gaXMgbG93ZXJcbiAgICAgICAgcmV0dXJuIHRvTm9kZU5hbWUgPT09IGZyb21Ob2RlTmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGFuIGVsZW1lbnQsIG9wdGlvbmFsbHkgd2l0aCBhIGtub3duIG5hbWVzcGFjZSBVUkkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgdGhlIGVsZW1lbnQgbmFtZSwgZS5nLiAnZGl2JyBvciAnc3ZnJ1xuICogQHBhcmFtIHtzdHJpbmd9IFtuYW1lc3BhY2VVUkldIHRoZSBlbGVtZW50J3MgbmFtZXNwYWNlIFVSSSwgaS5lLiB0aGUgdmFsdWUgb2ZcbiAqIGl0cyBgeG1sbnNgIGF0dHJpYnV0ZSBvciBpdHMgaW5mZXJyZWQgbmFtZXNwYWNlLlxuICpcbiAqIEByZXR1cm4ge0VsZW1lbnR9XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUVsZW1lbnROUyhuYW1lLCBuYW1lc3BhY2VVUkkpIHtcbiAgICByZXR1cm4gIW5hbWVzcGFjZVVSSSB8fCBuYW1lc3BhY2VVUkkgPT09IE5TX1hIVE1MID9cbiAgICAgICAgZG9jLmNyZWF0ZUVsZW1lbnQobmFtZSkgOlxuICAgICAgICBkb2MuY3JlYXRlRWxlbWVudE5TKG5hbWVzcGFjZVVSSSwgbmFtZSk7XG59XG5cbi8qKlxuICogQ29waWVzIHRoZSBjaGlsZHJlbiBvZiBvbmUgRE9NIGVsZW1lbnQgdG8gYW5vdGhlciBET00gZWxlbWVudFxuICovXG5mdW5jdGlvbiBtb3ZlQ2hpbGRyZW4oZnJvbUVsLCB0b0VsKSB7XG4gICAgdmFyIGN1ckNoaWxkID0gZnJvbUVsLmZpcnN0Q2hpbGQ7XG4gICAgd2hpbGUgKGN1ckNoaWxkKSB7XG4gICAgICAgIHZhciBuZXh0Q2hpbGQgPSBjdXJDaGlsZC5uZXh0U2libGluZztcbiAgICAgICAgdG9FbC5hcHBlbmRDaGlsZChjdXJDaGlsZCk7XG4gICAgICAgIGN1ckNoaWxkID0gbmV4dENoaWxkO1xuICAgIH1cbiAgICByZXR1cm4gdG9FbDtcbn1cblxuZnVuY3Rpb24gc3luY0Jvb2xlYW5BdHRyUHJvcChmcm9tRWwsIHRvRWwsIG5hbWUpIHtcbiAgICBpZiAoZnJvbUVsW25hbWVdICE9PSB0b0VsW25hbWVdKSB7XG4gICAgICAgIGZyb21FbFtuYW1lXSA9IHRvRWxbbmFtZV07XG4gICAgICAgIGlmIChmcm9tRWxbbmFtZV0pIHtcbiAgICAgICAgICAgIGZyb21FbC5zZXRBdHRyaWJ1dGUobmFtZSwgJycpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnJvbUVsLnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxudmFyIHNwZWNpYWxFbEhhbmRsZXJzID0ge1xuICAgIE9QVElPTjogZnVuY3Rpb24oZnJvbUVsLCB0b0VsKSB7XG4gICAgICAgIHZhciBwYXJlbnROb2RlID0gZnJvbUVsLnBhcmVudE5vZGU7XG4gICAgICAgIGlmIChwYXJlbnROb2RlKSB7XG4gICAgICAgICAgICB2YXIgcGFyZW50TmFtZSA9IHBhcmVudE5vZGUubm9kZU5hbWUudG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgIGlmIChwYXJlbnROYW1lID09PSAnT1BUR1JPVVAnKSB7XG4gICAgICAgICAgICAgICAgcGFyZW50Tm9kZSA9IHBhcmVudE5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gcGFyZW50Tm9kZSAmJiBwYXJlbnROb2RlLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocGFyZW50TmFtZSA9PT0gJ1NFTEVDVCcgJiYgIXBhcmVudE5vZGUuaGFzQXR0cmlidXRlKCdtdWx0aXBsZScpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZyb21FbC5oYXNBdHRyaWJ1dGUoJ3NlbGVjdGVkJykgJiYgIXRvRWwuc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV29ya2Fyb3VuZCBmb3IgTVMgRWRnZSBidWcgd2hlcmUgdGhlICdzZWxlY3RlZCcgYXR0cmlidXRlIGNhbiBvbmx5IGJlXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZWQgaWYgc2V0IHRvIGEgbm9uLWVtcHR5IHZhbHVlOlxuICAgICAgICAgICAgICAgICAgICAvLyBodHRwczovL2RldmVsb3Blci5taWNyb3NvZnQuY29tL2VuLXVzL21pY3Jvc29mdC1lZGdlL3BsYXRmb3JtL2lzc3Vlcy8xMjA4NzY3OS9cbiAgICAgICAgICAgICAgICAgICAgZnJvbUVsLnNldEF0dHJpYnV0ZSgnc2VsZWN0ZWQnLCAnc2VsZWN0ZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgZnJvbUVsLnJlbW92ZUF0dHJpYnV0ZSgnc2VsZWN0ZWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gV2UgaGF2ZSB0byByZXNldCBzZWxlY3QgZWxlbWVudCdzIHNlbGVjdGVkSW5kZXggdG8gLTEsIG90aGVyd2lzZSBzZXR0aW5nXG4gICAgICAgICAgICAgICAgLy8gZnJvbUVsLnNlbGVjdGVkIHVzaW5nIHRoZSBzeW5jQm9vbGVhbkF0dHJQcm9wIGJlbG93IGhhcyBubyBlZmZlY3QuXG4gICAgICAgICAgICAgICAgLy8gVGhlIGNvcnJlY3Qgc2VsZWN0ZWRJbmRleCB3aWxsIGJlIHNldCBpbiB0aGUgU0VMRUNUIHNwZWNpYWwgaGFuZGxlciBiZWxvdy5cbiAgICAgICAgICAgICAgICBwYXJlbnROb2RlLnNlbGVjdGVkSW5kZXggPSAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBzeW5jQm9vbGVhbkF0dHJQcm9wKGZyb21FbCwgdG9FbCwgJ3NlbGVjdGVkJyk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBUaGUgXCJ2YWx1ZVwiIGF0dHJpYnV0ZSBpcyBzcGVjaWFsIGZvciB0aGUgPGlucHV0PiBlbGVtZW50IHNpbmNlIGl0IHNldHNcbiAgICAgKiB0aGUgaW5pdGlhbCB2YWx1ZS4gQ2hhbmdpbmcgdGhlIFwidmFsdWVcIiBhdHRyaWJ1dGUgd2l0aG91dCBjaGFuZ2luZyB0aGVcbiAgICAgKiBcInZhbHVlXCIgcHJvcGVydHkgd2lsbCBoYXZlIG5vIGVmZmVjdCBzaW5jZSBpdCBpcyBvbmx5IHVzZWQgdG8gdGhlIHNldCB0aGVcbiAgICAgKiBpbml0aWFsIHZhbHVlLiAgU2ltaWxhciBmb3IgdGhlIFwiY2hlY2tlZFwiIGF0dHJpYnV0ZSwgYW5kIFwiZGlzYWJsZWRcIi5cbiAgICAgKi9cbiAgICBJTlBVVDogZnVuY3Rpb24oZnJvbUVsLCB0b0VsKSB7XG4gICAgICAgIHN5bmNCb29sZWFuQXR0clByb3AoZnJvbUVsLCB0b0VsLCAnY2hlY2tlZCcpO1xuICAgICAgICBzeW5jQm9vbGVhbkF0dHJQcm9wKGZyb21FbCwgdG9FbCwgJ2Rpc2FibGVkJyk7XG5cbiAgICAgICAgaWYgKGZyb21FbC52YWx1ZSAhPT0gdG9FbC52YWx1ZSkge1xuICAgICAgICAgICAgZnJvbUVsLnZhbHVlID0gdG9FbC52YWx1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdG9FbC5oYXNBdHRyaWJ1dGUoJ3ZhbHVlJykpIHtcbiAgICAgICAgICAgIGZyb21FbC5yZW1vdmVBdHRyaWJ1dGUoJ3ZhbHVlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgVEVYVEFSRUE6IGZ1bmN0aW9uKGZyb21FbCwgdG9FbCkge1xuICAgICAgICB2YXIgbmV3VmFsdWUgPSB0b0VsLnZhbHVlO1xuICAgICAgICBpZiAoZnJvbUVsLnZhbHVlICE9PSBuZXdWYWx1ZSkge1xuICAgICAgICAgICAgZnJvbUVsLnZhbHVlID0gbmV3VmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZmlyc3RDaGlsZCA9IGZyb21FbC5maXJzdENoaWxkO1xuICAgICAgICBpZiAoZmlyc3RDaGlsZCkge1xuICAgICAgICAgICAgLy8gTmVlZGVkIGZvciBJRS4gQXBwYXJlbnRseSBJRSBzZXRzIHRoZSBwbGFjZWhvbGRlciBhcyB0aGVcbiAgICAgICAgICAgIC8vIG5vZGUgdmFsdWUgYW5kIHZpc2UgdmVyc2EuIFRoaXMgaWdub3JlcyBhbiBlbXB0eSB1cGRhdGUuXG4gICAgICAgICAgICB2YXIgb2xkVmFsdWUgPSBmaXJzdENoaWxkLm5vZGVWYWx1ZTtcblxuICAgICAgICAgICAgaWYgKG9sZFZhbHVlID09IG5ld1ZhbHVlIHx8ICghbmV3VmFsdWUgJiYgb2xkVmFsdWUgPT0gZnJvbUVsLnBsYWNlaG9sZGVyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZmlyc3RDaGlsZC5ub2RlVmFsdWUgPSBuZXdWYWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgU0VMRUNUOiBmdW5jdGlvbihmcm9tRWwsIHRvRWwpIHtcbiAgICAgICAgaWYgKCF0b0VsLmhhc0F0dHJpYnV0ZSgnbXVsdGlwbGUnKSkge1xuICAgICAgICAgICAgdmFyIHNlbGVjdGVkSW5kZXggPSAtMTtcbiAgICAgICAgICAgIHZhciBpID0gMDtcbiAgICAgICAgICAgIC8vIFdlIGhhdmUgdG8gbG9vcCB0aHJvdWdoIGNoaWxkcmVuIG9mIGZyb21FbCwgbm90IHRvRWwgc2luY2Ugbm9kZXMgY2FuIGJlIG1vdmVkXG4gICAgICAgICAgICAvLyBmcm9tIHRvRWwgdG8gZnJvbUVsIGRpcmVjdGx5IHdoZW4gbW9ycGhpbmcuXG4gICAgICAgICAgICAvLyBBdCB0aGUgdGltZSB0aGlzIHNwZWNpYWwgaGFuZGxlciBpcyBpbnZva2VkLCBhbGwgY2hpbGRyZW4gaGF2ZSBhbHJlYWR5IGJlZW4gbW9ycGhlZFxuICAgICAgICAgICAgLy8gYW5kIGFwcGVuZGVkIHRvIC8gcmVtb3ZlZCBmcm9tIGZyb21FbCwgc28gdXNpbmcgZnJvbUVsIGhlcmUgaXMgc2FmZSBhbmQgY29ycmVjdC5cbiAgICAgICAgICAgIHZhciBjdXJDaGlsZCA9IGZyb21FbC5maXJzdENoaWxkO1xuICAgICAgICAgICAgdmFyIG9wdGdyb3VwO1xuICAgICAgICAgICAgdmFyIG5vZGVOYW1lO1xuICAgICAgICAgICAgd2hpbGUoY3VyQ2hpbGQpIHtcbiAgICAgICAgICAgICAgICBub2RlTmFtZSA9IGN1ckNoaWxkLm5vZGVOYW1lICYmIGN1ckNoaWxkLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCk7XG4gICAgICAgICAgICAgICAgaWYgKG5vZGVOYW1lID09PSAnT1BUR1JPVVAnKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGdyb3VwID0gY3VyQ2hpbGQ7XG4gICAgICAgICAgICAgICAgICAgIGN1ckNoaWxkID0gb3B0Z3JvdXAuZmlyc3RDaGlsZDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAobm9kZU5hbWUgPT09ICdPUFRJT04nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VyQ2hpbGQuaGFzQXR0cmlidXRlKCdzZWxlY3RlZCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRJbmRleCA9IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpKys7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY3VyQ2hpbGQgPSBjdXJDaGlsZC5uZXh0U2libGluZztcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFjdXJDaGlsZCAmJiBvcHRncm91cCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY3VyQ2hpbGQgPSBvcHRncm91cC5uZXh0U2libGluZztcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZnJvbUVsLnNlbGVjdGVkSW5kZXggPSBzZWxlY3RlZEluZGV4O1xuICAgICAgICB9XG4gICAgfVxufTtcblxudmFyIEVMRU1FTlRfTk9ERSA9IDE7XG52YXIgRE9DVU1FTlRfRlJBR01FTlRfTk9ERSQxID0gMTE7XG52YXIgVEVYVF9OT0RFID0gMztcbnZhciBDT01NRU5UX05PREUgPSA4O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxuZnVuY3Rpb24gZGVmYXVsdEdldE5vZGVLZXkobm9kZSkge1xuICBpZiAobm9kZSkge1xuICAgIHJldHVybiAobm9kZS5nZXRBdHRyaWJ1dGUgJiYgbm9kZS5nZXRBdHRyaWJ1dGUoJ2lkJykpIHx8IG5vZGUuaWQ7XG4gIH1cbn1cblxuZnVuY3Rpb24gbW9ycGhkb21GYWN0b3J5KG1vcnBoQXR0cnMpIHtcblxuICByZXR1cm4gZnVuY3Rpb24gbW9ycGhkb20oZnJvbU5vZGUsIHRvTm9kZSwgb3B0aW9ucykge1xuICAgIGlmICghb3B0aW9ucykge1xuICAgICAgb3B0aW9ucyA9IHt9O1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdG9Ob2RlID09PSAnc3RyaW5nJykge1xuICAgICAgaWYgKGZyb21Ob2RlLm5vZGVOYW1lID09PSAnI2RvY3VtZW50JyB8fCBmcm9tTm9kZS5ub2RlTmFtZSA9PT0gJ0hUTUwnIHx8IGZyb21Ob2RlLm5vZGVOYW1lID09PSAnQk9EWScpIHtcbiAgICAgICAgdmFyIHRvTm9kZUh0bWwgPSB0b05vZGU7XG4gICAgICAgIHRvTm9kZSA9IGRvYy5jcmVhdGVFbGVtZW50KCdodG1sJyk7XG4gICAgICAgIHRvTm9kZS5pbm5lckhUTUwgPSB0b05vZGVIdG1sO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdG9Ob2RlID0gdG9FbGVtZW50KHRvTm9kZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0b05vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUkMSkge1xuICAgICAgdG9Ob2RlID0gdG9Ob2RlLmZpcnN0RWxlbWVudENoaWxkO1xuICAgIH1cblxuICAgIHZhciBnZXROb2RlS2V5ID0gb3B0aW9ucy5nZXROb2RlS2V5IHx8IGRlZmF1bHRHZXROb2RlS2V5O1xuICAgIHZhciBvbkJlZm9yZU5vZGVBZGRlZCA9IG9wdGlvbnMub25CZWZvcmVOb2RlQWRkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25Ob2RlQWRkZWQgPSBvcHRpb25zLm9uTm9kZUFkZGVkIHx8IG5vb3A7XG4gICAgdmFyIG9uQmVmb3JlRWxVcGRhdGVkID0gb3B0aW9ucy5vbkJlZm9yZUVsVXBkYXRlZCB8fCBub29wO1xuICAgIHZhciBvbkVsVXBkYXRlZCA9IG9wdGlvbnMub25FbFVwZGF0ZWQgfHwgbm9vcDtcbiAgICB2YXIgb25CZWZvcmVOb2RlRGlzY2FyZGVkID0gb3B0aW9ucy5vbkJlZm9yZU5vZGVEaXNjYXJkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25Ob2RlRGlzY2FyZGVkID0gb3B0aW9ucy5vbk5vZGVEaXNjYXJkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25CZWZvcmVFbENoaWxkcmVuVXBkYXRlZCA9IG9wdGlvbnMub25CZWZvcmVFbENoaWxkcmVuVXBkYXRlZCB8fCBub29wO1xuICAgIHZhciBza2lwRnJvbUNoaWxkcmVuID0gb3B0aW9ucy5za2lwRnJvbUNoaWxkcmVuIHx8IG5vb3A7XG4gICAgdmFyIGFkZENoaWxkID0gb3B0aW9ucy5hZGRDaGlsZCB8fCBmdW5jdGlvbihwYXJlbnQsIGNoaWxkKXsgcmV0dXJuIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7IH07XG4gICAgdmFyIGNoaWxkcmVuT25seSA9IG9wdGlvbnMuY2hpbGRyZW5Pbmx5ID09PSB0cnVlO1xuXG4gICAgLy8gVGhpcyBvYmplY3QgaXMgdXNlZCBhcyBhIGxvb2t1cCB0byBxdWlja2x5IGZpbmQgYWxsIGtleWVkIGVsZW1lbnRzIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZS5cbiAgICB2YXIgZnJvbU5vZGVzTG9va3VwID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB2YXIga2V5ZWRSZW1vdmFsTGlzdCA9IFtdO1xuXG4gICAgZnVuY3Rpb24gYWRkS2V5ZWRSZW1vdmFsKGtleSkge1xuICAgICAga2V5ZWRSZW1vdmFsTGlzdC5wdXNoKGtleSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMobm9kZSwgc2tpcEtleWVkTm9kZXMpIHtcbiAgICAgIGlmIChub2RlLm5vZGVUeXBlID09PSBFTEVNRU5UX05PREUpIHtcbiAgICAgICAgdmFyIGN1ckNoaWxkID0gbm9kZS5maXJzdENoaWxkO1xuICAgICAgICB3aGlsZSAoY3VyQ2hpbGQpIHtcblxuICAgICAgICAgIHZhciBrZXkgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBpZiAoc2tpcEtleWVkTm9kZXMgJiYgKGtleSA9IGdldE5vZGVLZXkoY3VyQ2hpbGQpKSkge1xuICAgICAgICAgICAgLy8gSWYgd2UgYXJlIHNraXBwaW5nIGtleWVkIG5vZGVzIHRoZW4gd2UgYWRkIHRoZSBrZXlcbiAgICAgICAgICAgIC8vIHRvIGEgbGlzdCBzbyB0aGF0IGl0IGNhbiBiZSBoYW5kbGVkIGF0IHRoZSB2ZXJ5IGVuZC5cbiAgICAgICAgICAgIGFkZEtleWVkUmVtb3ZhbChrZXkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBPbmx5IHJlcG9ydCB0aGUgbm9kZSBhcyBkaXNjYXJkZWQgaWYgaXQgaXMgbm90IGtleWVkLiBXZSBkbyB0aGlzIGJlY2F1c2VcbiAgICAgICAgICAgIC8vIGF0IHRoZSBlbmQgd2UgbG9vcCB0aHJvdWdoIGFsbCBrZXllZCBlbGVtZW50cyB0aGF0IHdlcmUgdW5tYXRjaGVkXG4gICAgICAgICAgICAvLyBhbmQgdGhlbiBkaXNjYXJkIHRoZW0gaW4gb25lIGZpbmFsIHBhc3MuXG4gICAgICAgICAgICBvbk5vZGVEaXNjYXJkZWQoY3VyQ2hpbGQpO1xuICAgICAgICAgICAgaWYgKGN1ckNoaWxkLmZpcnN0Q2hpbGQpIHtcbiAgICAgICAgICAgICAgd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMoY3VyQ2hpbGQsIHNraXBLZXllZE5vZGVzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJDaGlsZCA9IGN1ckNoaWxkLm5leHRTaWJsaW5nO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgKiBSZW1vdmVzIGEgRE9NIG5vZGUgb3V0IG9mIHRoZSBvcmlnaW5hbCBET01cbiAgICAqXG4gICAgKiBAcGFyYW0gIHtOb2RlfSBub2RlIFRoZSBub2RlIHRvIHJlbW92ZVxuICAgICogQHBhcmFtICB7Tm9kZX0gcGFyZW50Tm9kZSBUaGUgbm9kZXMgcGFyZW50XG4gICAgKiBAcGFyYW0gIHtCb29sZWFufSBza2lwS2V5ZWROb2RlcyBJZiB0cnVlIHRoZW4gZWxlbWVudHMgd2l0aCBrZXlzIHdpbGwgYmUgc2tpcHBlZCBhbmQgbm90IGRpc2NhcmRlZC5cbiAgICAqIEByZXR1cm4ge3VuZGVmaW5lZH1cbiAgICAqL1xuICAgIGZ1bmN0aW9uIHJlbW92ZU5vZGUobm9kZSwgcGFyZW50Tm9kZSwgc2tpcEtleWVkTm9kZXMpIHtcbiAgICAgIGlmIChvbkJlZm9yZU5vZGVEaXNjYXJkZWQobm9kZSkgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHBhcmVudE5vZGUpIHtcbiAgICAgICAgcGFyZW50Tm9kZS5yZW1vdmVDaGlsZChub2RlKTtcbiAgICAgIH1cblxuICAgICAgb25Ob2RlRGlzY2FyZGVkKG5vZGUpO1xuICAgICAgd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMobm9kZSwgc2tpcEtleWVkTm9kZXMpO1xuICAgIH1cblxuICAgIC8vIC8vIFRyZWVXYWxrZXIgaW1wbGVtZW50YXRpb24gaXMgbm8gZmFzdGVyLCBidXQga2VlcGluZyB0aGlzIGFyb3VuZCBpbiBjYXNlIHRoaXMgY2hhbmdlcyBpbiB0aGUgZnV0dXJlXG4gICAgLy8gZnVuY3Rpb24gaW5kZXhUcmVlKHJvb3QpIHtcbiAgICAvLyAgICAgdmFyIHRyZWVXYWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKFxuICAgIC8vICAgICAgICAgcm9vdCxcbiAgICAvLyAgICAgICAgIE5vZGVGaWx0ZXIuU0hPV19FTEVNRU5UKTtcbiAgICAvL1xuICAgIC8vICAgICB2YXIgZWw7XG4gICAgLy8gICAgIHdoaWxlKChlbCA9IHRyZWVXYWxrZXIubmV4dE5vZGUoKSkpIHtcbiAgICAvLyAgICAgICAgIHZhciBrZXkgPSBnZXROb2RlS2V5KGVsKTtcbiAgICAvLyAgICAgICAgIGlmIChrZXkpIHtcbiAgICAvLyAgICAgICAgICAgICBmcm9tTm9kZXNMb29rdXBba2V5XSA9IGVsO1xuICAgIC8vICAgICAgICAgfVxuICAgIC8vICAgICB9XG4gICAgLy8gfVxuXG4gICAgLy8gLy8gTm9kZUl0ZXJhdG9yIGltcGxlbWVudGF0aW9uIGlzIG5vIGZhc3RlciwgYnV0IGtlZXBpbmcgdGhpcyBhcm91bmQgaW4gY2FzZSB0aGlzIGNoYW5nZXMgaW4gdGhlIGZ1dHVyZVxuICAgIC8vXG4gICAgLy8gZnVuY3Rpb24gaW5kZXhUcmVlKG5vZGUpIHtcbiAgICAvLyAgICAgdmFyIG5vZGVJdGVyYXRvciA9IGRvY3VtZW50LmNyZWF0ZU5vZGVJdGVyYXRvcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCk7XG4gICAgLy8gICAgIHZhciBlbDtcbiAgICAvLyAgICAgd2hpbGUoKGVsID0gbm9kZUl0ZXJhdG9yLm5leHROb2RlKCkpKSB7XG4gICAgLy8gICAgICAgICB2YXIga2V5ID0gZ2V0Tm9kZUtleShlbCk7XG4gICAgLy8gICAgICAgICBpZiAoa2V5KSB7XG4gICAgLy8gICAgICAgICAgICAgZnJvbU5vZGVzTG9va3VwW2tleV0gPSBlbDtcbiAgICAvLyAgICAgICAgIH1cbiAgICAvLyAgICAgfVxuICAgIC8vIH1cblxuICAgIGZ1bmN0aW9uIGluZGV4VHJlZShub2RlKSB7XG4gICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFIHx8IG5vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUkMSkge1xuICAgICAgICB2YXIgY3VyQ2hpbGQgPSBub2RlLmZpcnN0Q2hpbGQ7XG4gICAgICAgIHdoaWxlIChjdXJDaGlsZCkge1xuICAgICAgICAgIHZhciBrZXkgPSBnZXROb2RlS2V5KGN1ckNoaWxkKTtcbiAgICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICBmcm9tTm9kZXNMb29rdXBba2V5XSA9IGN1ckNoaWxkO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFdhbGsgcmVjdXJzaXZlbHlcbiAgICAgICAgICBpbmRleFRyZWUoY3VyQ2hpbGQpO1xuXG4gICAgICAgICAgY3VyQ2hpbGQgPSBjdXJDaGlsZC5uZXh0U2libGluZztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGluZGV4VHJlZShmcm9tTm9kZSk7XG5cbiAgICBmdW5jdGlvbiBoYW5kbGVOb2RlQWRkZWQoZWwpIHtcbiAgICAgIG9uTm9kZUFkZGVkKGVsKTtcblxuICAgICAgdmFyIGN1ckNoaWxkID0gZWwuZmlyc3RDaGlsZDtcbiAgICAgIHdoaWxlIChjdXJDaGlsZCkge1xuICAgICAgICB2YXIgbmV4dFNpYmxpbmcgPSBjdXJDaGlsZC5uZXh0U2libGluZztcblxuICAgICAgICB2YXIga2V5ID0gZ2V0Tm9kZUtleShjdXJDaGlsZCk7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICB2YXIgdW5tYXRjaGVkRnJvbUVsID0gZnJvbU5vZGVzTG9va3VwW2tleV07XG4gICAgICAgICAgLy8gaWYgd2UgZmluZCBhIGR1cGxpY2F0ZSAjaWQgbm9kZSBpbiBjYWNoZSwgcmVwbGFjZSBgZWxgIHdpdGggY2FjaGUgdmFsdWVcbiAgICAgICAgICAvLyBhbmQgbW9ycGggaXQgdG8gdGhlIGNoaWxkIG5vZGUuXG4gICAgICAgICAgaWYgKHVubWF0Y2hlZEZyb21FbCAmJiBjb21wYXJlTm9kZU5hbWVzKGN1ckNoaWxkLCB1bm1hdGNoZWRGcm9tRWwpKSB7XG4gICAgICAgICAgICBjdXJDaGlsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZCh1bm1hdGNoZWRGcm9tRWwsIGN1ckNoaWxkKTtcbiAgICAgICAgICAgIG1vcnBoRWwodW5tYXRjaGVkRnJvbUVsLCBjdXJDaGlsZCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJDaGlsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHJlY3Vyc2l2ZWx5IGNhbGwgZm9yIGN1ckNoaWxkIGFuZCBpdCdzIGNoaWxkcmVuIHRvIHNlZSBpZiB3ZSBmaW5kIHNvbWV0aGluZyBpblxuICAgICAgICAgIC8vIGZyb21Ob2Rlc0xvb2t1cFxuICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJDaGlsZCk7XG4gICAgICAgIH1cblxuICAgICAgICBjdXJDaGlsZCA9IG5leHRTaWJsaW5nO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNsZWFudXBGcm9tRWwoZnJvbUVsLCBjdXJGcm9tTm9kZUNoaWxkLCBjdXJGcm9tTm9kZUtleSkge1xuICAgICAgLy8gV2UgaGF2ZSBwcm9jZXNzZWQgYWxsIG9mIHRoZSBcInRvIG5vZGVzXCIuIElmIGN1ckZyb21Ob2RlQ2hpbGQgaXNcbiAgICAgIC8vIG5vbi1udWxsIHRoZW4gd2Ugc3RpbGwgaGF2ZSBzb21lIGZyb20gbm9kZXMgbGVmdCBvdmVyIHRoYXQgbmVlZFxuICAgICAgLy8gdG8gYmUgcmVtb3ZlZFxuICAgICAgd2hpbGUgKGN1ckZyb21Ob2RlQ2hpbGQpIHtcbiAgICAgICAgdmFyIGZyb21OZXh0U2libGluZyA9IGN1ckZyb21Ob2RlQ2hpbGQubmV4dFNpYmxpbmc7XG4gICAgICAgIGlmICgoY3VyRnJvbU5vZGVLZXkgPSBnZXROb2RlS2V5KGN1ckZyb21Ob2RlQ2hpbGQpKSkge1xuICAgICAgICAgIC8vIFNpbmNlIHRoZSBub2RlIGlzIGtleWVkIGl0IG1pZ2h0IGJlIG1hdGNoZWQgdXAgbGF0ZXIgc28gd2UgZGVmZXJcbiAgICAgICAgICAvLyB0aGUgYWN0dWFsIHJlbW92YWwgdG8gbGF0ZXJcbiAgICAgICAgICBhZGRLZXllZFJlbW92YWwoY3VyRnJvbU5vZGVLZXkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5PVEU6IHdlIHNraXAgbmVzdGVkIGtleWVkIG5vZGVzIGZyb20gYmVpbmcgcmVtb3ZlZCBzaW5jZSB0aGVyZSBpc1xuICAgICAgICAgIC8vICAgICAgIHN0aWxsIGEgY2hhbmNlIHRoZXkgd2lsbCBiZSBtYXRjaGVkIHVwIGxhdGVyXG4gICAgICAgICAgcmVtb3ZlTm9kZShjdXJGcm9tTm9kZUNoaWxkLCBmcm9tRWwsIHRydWUgLyogc2tpcCBrZXllZCBub2RlcyAqLyk7XG4gICAgICAgIH1cbiAgICAgICAgY3VyRnJvbU5vZGVDaGlsZCA9IGZyb21OZXh0U2libGluZztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtb3JwaEVsKGZyb21FbCwgdG9FbCwgY2hpbGRyZW5Pbmx5KSB7XG4gICAgICB2YXIgdG9FbEtleSA9IGdldE5vZGVLZXkodG9FbCk7XG5cbiAgICAgIGlmICh0b0VsS2V5KSB7XG4gICAgICAgIC8vIElmIGFuIGVsZW1lbnQgd2l0aCBhbiBJRCBpcyBiZWluZyBtb3JwaGVkIHRoZW4gaXQgd2lsbCBiZSBpbiB0aGUgZmluYWxcbiAgICAgICAgLy8gRE9NIHNvIGNsZWFyIGl0IG91dCBvZiB0aGUgc2F2ZWQgZWxlbWVudHMgY29sbGVjdGlvblxuICAgICAgICBkZWxldGUgZnJvbU5vZGVzTG9va3VwW3RvRWxLZXldO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWNoaWxkcmVuT25seSkge1xuICAgICAgICAvLyBvcHRpb25hbFxuICAgICAgICB2YXIgYmVmb3JlVXBkYXRlUmVzdWx0ID0gb25CZWZvcmVFbFVwZGF0ZWQoZnJvbUVsLCB0b0VsKTtcbiAgICAgICAgaWYgKGJlZm9yZVVwZGF0ZVJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAoYmVmb3JlVXBkYXRlUmVzdWx0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgICBmcm9tRWwgPSBiZWZvcmVVcGRhdGVSZXN1bHQ7XG4gICAgICAgICAgLy8gcmVpbmRleCB0aGUgbmV3IGZyb21FbCBpbiBjYXNlIGl0J3Mgbm90IGluIHRoZSBzYW1lXG4gICAgICAgICAgLy8gdHJlZSBhcyB0aGUgb3JpZ2luYWwgZnJvbUVsXG4gICAgICAgICAgLy8gKFBob2VuaXggTGl2ZVZpZXcgc29tZXRpbWVzIHJldHVybnMgYSBjbG9uZWQgdHJlZSxcbiAgICAgICAgICAvLyAgYnV0IGtleWVkIGxvb2t1cHMgd291bGQgc3RpbGwgcG9pbnQgdG8gdGhlIG9yaWdpbmFsIHRyZWUpXG4gICAgICAgICAgaW5kZXhUcmVlKGZyb21FbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB1cGRhdGUgYXR0cmlidXRlcyBvbiBvcmlnaW5hbCBET00gZWxlbWVudCBmaXJzdFxuICAgICAgICBtb3JwaEF0dHJzKGZyb21FbCwgdG9FbCk7XG4gICAgICAgIC8vIG9wdGlvbmFsXG4gICAgICAgIG9uRWxVcGRhdGVkKGZyb21FbCk7XG5cbiAgICAgICAgaWYgKG9uQmVmb3JlRWxDaGlsZHJlblVwZGF0ZWQoZnJvbUVsLCB0b0VsKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGZyb21FbC5ub2RlTmFtZSAhPT0gJ1RFWFRBUkVBJykge1xuICAgICAgICBtb3JwaENoaWxkcmVuKGZyb21FbCwgdG9FbCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzcGVjaWFsRWxIYW5kbGVycy5URVhUQVJFQShmcm9tRWwsIHRvRWwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1vcnBoQ2hpbGRyZW4oZnJvbUVsLCB0b0VsKSB7XG4gICAgICB2YXIgc2tpcEZyb20gPSBza2lwRnJvbUNoaWxkcmVuKGZyb21FbCwgdG9FbCk7XG4gICAgICB2YXIgY3VyVG9Ob2RlQ2hpbGQgPSB0b0VsLmZpcnN0Q2hpbGQ7XG4gICAgICB2YXIgY3VyRnJvbU5vZGVDaGlsZCA9IGZyb21FbC5maXJzdENoaWxkO1xuICAgICAgdmFyIGN1clRvTm9kZUtleTtcbiAgICAgIHZhciBjdXJGcm9tTm9kZUtleTtcblxuICAgICAgdmFyIGZyb21OZXh0U2libGluZztcbiAgICAgIHZhciB0b05leHRTaWJsaW5nO1xuICAgICAgdmFyIG1hdGNoaW5nRnJvbUVsO1xuXG4gICAgICAvLyB3YWxrIHRoZSBjaGlsZHJlblxuICAgICAgb3V0ZXI6IHdoaWxlIChjdXJUb05vZGVDaGlsZCkge1xuICAgICAgICB0b05leHRTaWJsaW5nID0gY3VyVG9Ob2RlQ2hpbGQubmV4dFNpYmxpbmc7XG4gICAgICAgIGN1clRvTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyVG9Ob2RlQ2hpbGQpO1xuXG4gICAgICAgIC8vIHdhbGsgdGhlIGZyb21Ob2RlIGNoaWxkcmVuIGFsbCB0aGUgd2F5IHRocm91Z2hcbiAgICAgICAgd2hpbGUgKCFza2lwRnJvbSAmJiBjdXJGcm9tTm9kZUNoaWxkKSB7XG4gICAgICAgICAgZnJvbU5leHRTaWJsaW5nID0gY3VyRnJvbU5vZGVDaGlsZC5uZXh0U2libGluZztcblxuICAgICAgICAgIGlmIChjdXJUb05vZGVDaGlsZC5pc1NhbWVOb2RlICYmIGN1clRvTm9kZUNoaWxkLmlzU2FtZU5vZGUoY3VyRnJvbU5vZGVDaGlsZCkpIHtcbiAgICAgICAgICAgIGN1clRvTm9kZUNoaWxkID0gdG9OZXh0U2libGluZztcbiAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQgPSBmcm9tTmV4dFNpYmxpbmc7XG4gICAgICAgICAgICBjb250aW51ZSBvdXRlcjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJGcm9tTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyRnJvbU5vZGVDaGlsZCk7XG5cbiAgICAgICAgICB2YXIgY3VyRnJvbU5vZGVUeXBlID0gY3VyRnJvbU5vZGVDaGlsZC5ub2RlVHlwZTtcblxuICAgICAgICAgIC8vIHRoaXMgbWVhbnMgaWYgdGhlIGN1ckZyb21Ob2RlQ2hpbGQgZG9lc250IGhhdmUgYSBtYXRjaCB3aXRoIHRoZSBjdXJUb05vZGVDaGlsZFxuICAgICAgICAgIHZhciBpc0NvbXBhdGlibGUgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBpZiAoY3VyRnJvbU5vZGVUeXBlID09PSBjdXJUb05vZGVDaGlsZC5ub2RlVHlwZSkge1xuICAgICAgICAgICAgaWYgKGN1ckZyb21Ob2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgICAgICAgIC8vIEJvdGggbm9kZXMgYmVpbmcgY29tcGFyZWQgYXJlIEVsZW1lbnQgbm9kZXNcblxuICAgICAgICAgICAgICBpZiAoY3VyVG9Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIHRhcmdldCBub2RlIGhhcyBhIGtleSBzbyB3ZSB3YW50IHRvIG1hdGNoIGl0IHVwIHdpdGggdGhlIGNvcnJlY3QgZWxlbWVudFxuICAgICAgICAgICAgICAgIC8vIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZVxuICAgICAgICAgICAgICAgIGlmIChjdXJUb05vZGVLZXkgIT09IGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgICAvLyBUaGUgY3VycmVudCBlbGVtZW50IGluIHRoZSBvcmlnaW5hbCBET00gdHJlZSBkb2VzIG5vdCBoYXZlIGEgbWF0Y2hpbmcga2V5IHNvXG4gICAgICAgICAgICAgICAgICAvLyBsZXQncyBjaGVjayBvdXIgbG9va3VwIHRvIHNlZSBpZiB0aGVyZSBpcyBhIG1hdGNoaW5nIGVsZW1lbnQgaW4gdGhlIG9yaWdpbmFsXG4gICAgICAgICAgICAgICAgICAvLyBET00gdHJlZVxuICAgICAgICAgICAgICAgICAgaWYgKChtYXRjaGluZ0Zyb21FbCA9IGZyb21Ob2Rlc0xvb2t1cFtjdXJUb05vZGVLZXldKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZnJvbU5leHRTaWJsaW5nID09PSBtYXRjaGluZ0Zyb21FbCkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFNwZWNpYWwgY2FzZSBmb3Igc2luZ2xlIGVsZW1lbnQgcmVtb3ZhbHMuIFRvIGF2b2lkIHJlbW92aW5nIHRoZSBvcmlnaW5hbFxuICAgICAgICAgICAgICAgICAgICAgIC8vIERPTSBub2RlIG91dCBvZiB0aGUgdHJlZSAoc2luY2UgdGhhdCBjYW4gYnJlYWsgQ1NTIHRyYW5zaXRpb25zLCBldGMuKSxcbiAgICAgICAgICAgICAgICAgICAgICAvLyB3ZSB3aWxsIGluc3RlYWQgZGlzY2FyZCB0aGUgY3VycmVudCBub2RlIGFuZCB3YWl0IHVudGlsIHRoZSBuZXh0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gaXRlcmF0aW9uIHRvIHByb3Blcmx5IG1hdGNoIHVwIHRoZSBrZXllZCB0YXJnZXQgZWxlbWVudCB3aXRoIGl0cyBtYXRjaGluZ1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGVsZW1lbnQgaW4gdGhlIG9yaWdpbmFsIHRyZWVcbiAgICAgICAgICAgICAgICAgICAgICBpc0NvbXBhdGlibGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBXZSBmb3VuZCBhIG1hdGNoaW5nIGtleWVkIGVsZW1lbnQgc29tZXdoZXJlIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZS5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBMZXQncyBtb3ZlIHRoZSBvcmlnaW5hbCBET00gbm9kZSBpbnRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIGFuZCBtb3JwaFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGl0LlxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gTk9URTogV2UgdXNlIGluc2VydEJlZm9yZSBpbnN0ZWFkIG9mIHJlcGxhY2VDaGlsZCBiZWNhdXNlIHdlIHdhbnQgdG8gZ28gdGhyb3VnaFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBgcmVtb3ZlTm9kZSgpYCBmdW5jdGlvbiBmb3IgdGhlIG5vZGUgdGhhdCBpcyBiZWluZyBkaXNjYXJkZWQgc28gdGhhdFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFsbCBsaWZlY3ljbGUgaG9va3MgYXJlIGNvcnJlY3RseSBpbnZva2VkXG4gICAgICAgICAgICAgICAgICAgICAgZnJvbUVsLmluc2VydEJlZm9yZShtYXRjaGluZ0Zyb21FbCwgY3VyRnJvbU5vZGVDaGlsZCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tTmV4dFNpYmxpbmcgPSBjdXJGcm9tTm9kZUNoaWxkLm5leHRTaWJsaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTaW5jZSB0aGUgbm9kZSBpcyBrZXllZCBpdCBtaWdodCBiZSBtYXRjaGVkIHVwIGxhdGVyIHNvIHdlIGRlZmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgYWN0dWFsIHJlbW92YWwgdG8gbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZEtleWVkUmVtb3ZhbChjdXJGcm9tTm9kZUtleSk7XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5PVEU6IHdlIHNraXAgbmVzdGVkIGtleWVkIG5vZGVzIGZyb20gYmVpbmcgcmVtb3ZlZCBzaW5jZSB0aGVyZSBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgc3RpbGwgYSBjaGFuY2UgdGhleSB3aWxsIGJlIG1hdGNoZWQgdXAgbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZU5vZGUoY3VyRnJvbU5vZGVDaGlsZCwgZnJvbUVsLCB0cnVlIC8qIHNraXAga2V5ZWQgbm9kZXMgKi8pO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQgPSBtYXRjaGluZ0Zyb21FbDtcbiAgICAgICAgICAgICAgICAgICAgICBjdXJGcm9tTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyRnJvbU5vZGVDaGlsZCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSBub2RlcyBhcmUgbm90IGNvbXBhdGlibGUgc2luY2UgdGhlIFwidG9cIiBub2RlIGhhcyBhIGtleSBhbmQgdGhlcmVcbiAgICAgICAgICAgICAgICAgICAgLy8gaXMgbm8gbWF0Y2hpbmcga2V5ZWQgbm9kZSBpbiB0aGUgc291cmNlIHRyZWVcbiAgICAgICAgICAgICAgICAgICAgaXNDb21wYXRpYmxlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIG9yaWdpbmFsIGhhcyBhIGtleVxuICAgICAgICAgICAgICAgIGlzQ29tcGF0aWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgaXNDb21wYXRpYmxlID0gaXNDb21wYXRpYmxlICE9PSBmYWxzZSAmJiBjb21wYXJlTm9kZU5hbWVzKGN1ckZyb21Ob2RlQ2hpbGQsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgICAgaWYgKGlzQ29tcGF0aWJsZSkge1xuICAgICAgICAgICAgICAgIC8vIFdlIGZvdW5kIGNvbXBhdGlibGUgRE9NIGVsZW1lbnRzIHNvIHRyYW5zZm9ybVxuICAgICAgICAgICAgICAgIC8vIHRoZSBjdXJyZW50IFwiZnJvbVwiIG5vZGUgdG8gbWF0Y2ggdGhlIGN1cnJlbnRcbiAgICAgICAgICAgICAgICAvLyB0YXJnZXQgRE9NIG5vZGUuXG4gICAgICAgICAgICAgICAgLy8gTU9SUEhcbiAgICAgICAgICAgICAgICBtb3JwaEVsKGN1ckZyb21Ob2RlQ2hpbGQsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGN1ckZyb21Ob2RlVHlwZSA9PT0gVEVYVF9OT0RFIHx8IGN1ckZyb21Ob2RlVHlwZSA9PSBDT01NRU5UX05PREUpIHtcbiAgICAgICAgICAgICAgLy8gQm90aCBub2RlcyBiZWluZyBjb21wYXJlZCBhcmUgVGV4dCBvciBDb21tZW50IG5vZGVzXG4gICAgICAgICAgICAgIGlzQ29tcGF0aWJsZSA9IHRydWU7XG4gICAgICAgICAgICAgIC8vIFNpbXBseSB1cGRhdGUgbm9kZVZhbHVlIG9uIHRoZSBvcmlnaW5hbCBub2RlIHRvXG4gICAgICAgICAgICAgIC8vIGNoYW5nZSB0aGUgdGV4dCB2YWx1ZVxuICAgICAgICAgICAgICBpZiAoY3VyRnJvbU5vZGVDaGlsZC5ub2RlVmFsdWUgIT09IGN1clRvTm9kZUNoaWxkLm5vZGVWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQubm9kZVZhbHVlID0gY3VyVG9Ob2RlQ2hpbGQubm9kZVZhbHVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoaXNDb21wYXRpYmxlKSB7XG4gICAgICAgICAgICAvLyBBZHZhbmNlIGJvdGggdGhlIFwidG9cIiBjaGlsZCBhbmQgdGhlIFwiZnJvbVwiIGNoaWxkIHNpbmNlIHdlIGZvdW5kIGEgbWF0Y2hcbiAgICAgICAgICAgIC8vIE5vdGhpbmcgZWxzZSB0byBkbyBhcyB3ZSBhbHJlYWR5IHJlY3Vyc2l2ZWx5IGNhbGxlZCBtb3JwaENoaWxkcmVuIGFib3ZlXG4gICAgICAgICAgICBjdXJUb05vZGVDaGlsZCA9IHRvTmV4dFNpYmxpbmc7XG4gICAgICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgICAgICAgY29udGludWUgb3V0ZXI7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTm8gY29tcGF0aWJsZSBtYXRjaCBzbyByZW1vdmUgdGhlIG9sZCBub2RlIGZyb20gdGhlIERPTSBhbmQgY29udGludWUgdHJ5aW5nIHRvIGZpbmQgYVxuICAgICAgICAgIC8vIG1hdGNoIGluIHRoZSBvcmlnaW5hbCBET00uIEhvd2V2ZXIsIHdlIG9ubHkgZG8gdGhpcyBpZiB0aGUgZnJvbSBub2RlIGlzIG5vdCBrZXllZFxuICAgICAgICAgIC8vIHNpbmNlIGl0IGlzIHBvc3NpYmxlIHRoYXQgYSBrZXllZCBub2RlIG1pZ2h0IG1hdGNoIHVwIHdpdGggYSBub2RlIHNvbWV3aGVyZSBlbHNlIGluIHRoZVxuICAgICAgICAgIC8vIHRhcmdldCB0cmVlIGFuZCB3ZSBkb24ndCB3YW50IHRvIGRpc2NhcmQgaXQganVzdCB5ZXQgc2luY2UgaXQgc3RpbGwgbWlnaHQgZmluZCBhXG4gICAgICAgICAgLy8gaG9tZSBpbiB0aGUgZmluYWwgRE9NIHRyZWUuIEFmdGVyIGV2ZXJ5dGhpbmcgaXMgZG9uZSB3ZSB3aWxsIHJlbW92ZSBhbnkga2V5ZWQgbm9kZXNcbiAgICAgICAgICAvLyB0aGF0IGRpZG4ndCBmaW5kIGEgaG9tZVxuICAgICAgICAgIGlmIChjdXJGcm9tTm9kZUtleSkge1xuICAgICAgICAgICAgLy8gU2luY2UgdGhlIG5vZGUgaXMga2V5ZWQgaXQgbWlnaHQgYmUgbWF0Y2hlZCB1cCBsYXRlciBzbyB3ZSBkZWZlclxuICAgICAgICAgICAgLy8gdGhlIGFjdHVhbCByZW1vdmFsIHRvIGxhdGVyXG4gICAgICAgICAgICBhZGRLZXllZFJlbW92YWwoY3VyRnJvbU5vZGVLZXkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBOT1RFOiB3ZSBza2lwIG5lc3RlZCBrZXllZCBub2RlcyBmcm9tIGJlaW5nIHJlbW92ZWQgc2luY2UgdGhlcmUgaXNcbiAgICAgICAgICAgIC8vICAgICAgIHN0aWxsIGEgY2hhbmNlIHRoZXkgd2lsbCBiZSBtYXRjaGVkIHVwIGxhdGVyXG4gICAgICAgICAgICByZW1vdmVOb2RlKGN1ckZyb21Ob2RlQ2hpbGQsIGZyb21FbCwgdHJ1ZSAvKiBza2lwIGtleWVkIG5vZGVzICovKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgICB9IC8vIEVORDogd2hpbGUoY3VyRnJvbU5vZGVDaGlsZCkge31cblxuICAgICAgICAvLyBJZiB3ZSBnb3QgdGhpcyBmYXIgdGhlbiB3ZSBkaWQgbm90IGZpbmQgYSBjYW5kaWRhdGUgbWF0Y2ggZm9yXG4gICAgICAgIC8vIG91ciBcInRvIG5vZGVcIiBhbmQgd2UgZXhoYXVzdGVkIGFsbCBvZiB0aGUgY2hpbGRyZW4gXCJmcm9tXCJcbiAgICAgICAgLy8gbm9kZXMuIFRoZXJlZm9yZSwgd2Ugd2lsbCBqdXN0IGFwcGVuZCB0aGUgY3VycmVudCBcInRvXCIgbm9kZVxuICAgICAgICAvLyB0byB0aGUgZW5kXG4gICAgICAgIGlmIChjdXJUb05vZGVLZXkgJiYgKG1hdGNoaW5nRnJvbUVsID0gZnJvbU5vZGVzTG9va3VwW2N1clRvTm9kZUtleV0pICYmIGNvbXBhcmVOb2RlTmFtZXMobWF0Y2hpbmdGcm9tRWwsIGN1clRvTm9kZUNoaWxkKSkge1xuICAgICAgICAgIC8vIE1PUlBIXG4gICAgICAgICAgaWYoIXNraXBGcm9tKXsgYWRkQ2hpbGQoZnJvbUVsLCBtYXRjaGluZ0Zyb21FbCk7IH1cbiAgICAgICAgICBtb3JwaEVsKG1hdGNoaW5nRnJvbUVsLCBjdXJUb05vZGVDaGlsZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIG9uQmVmb3JlTm9kZUFkZGVkUmVzdWx0ID0gb25CZWZvcmVOb2RlQWRkZWQoY3VyVG9Ob2RlQ2hpbGQpO1xuICAgICAgICAgIGlmIChvbkJlZm9yZU5vZGVBZGRlZFJlc3VsdCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGlmIChvbkJlZm9yZU5vZGVBZGRlZFJlc3VsdCkge1xuICAgICAgICAgICAgICBjdXJUb05vZGVDaGlsZCA9IG9uQmVmb3JlTm9kZUFkZGVkUmVzdWx0O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY3VyVG9Ob2RlQ2hpbGQuYWN0dWFsaXplKSB7XG4gICAgICAgICAgICAgIGN1clRvTm9kZUNoaWxkID0gY3VyVG9Ob2RlQ2hpbGQuYWN0dWFsaXplKGZyb21FbC5vd25lckRvY3VtZW50IHx8IGRvYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhZGRDaGlsZChmcm9tRWwsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJUb05vZGVDaGlsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY3VyVG9Ob2RlQ2hpbGQgPSB0b05leHRTaWJsaW5nO1xuICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgfVxuXG4gICAgICBjbGVhbnVwRnJvbUVsKGZyb21FbCwgY3VyRnJvbU5vZGVDaGlsZCwgY3VyRnJvbU5vZGVLZXkpO1xuXG4gICAgICB2YXIgc3BlY2lhbEVsSGFuZGxlciA9IHNwZWNpYWxFbEhhbmRsZXJzW2Zyb21FbC5ub2RlTmFtZV07XG4gICAgICBpZiAoc3BlY2lhbEVsSGFuZGxlcikge1xuICAgICAgICBzcGVjaWFsRWxIYW5kbGVyKGZyb21FbCwgdG9FbCk7XG4gICAgICB9XG4gICAgfSAvLyBFTkQ6IG1vcnBoQ2hpbGRyZW4oLi4uKVxuXG4gICAgdmFyIG1vcnBoZWROb2RlID0gZnJvbU5vZGU7XG4gICAgdmFyIG1vcnBoZWROb2RlVHlwZSA9IG1vcnBoZWROb2RlLm5vZGVUeXBlO1xuICAgIHZhciB0b05vZGVUeXBlID0gdG9Ob2RlLm5vZGVUeXBlO1xuXG4gICAgaWYgKCFjaGlsZHJlbk9ubHkpIHtcbiAgICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB3ZSBhcmUgZ2l2ZW4gdHdvIERPTSBub2RlcyB0aGF0IGFyZSBub3RcbiAgICAgIC8vIGNvbXBhdGlibGUgKGUuZy4gPGRpdj4gLS0+IDxzcGFuPiBvciA8ZGl2PiAtLT4gVEVYVClcbiAgICAgIGlmIChtb3JwaGVkTm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERSkge1xuICAgICAgICBpZiAodG9Ob2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgICAgaWYgKCFjb21wYXJlTm9kZU5hbWVzKGZyb21Ob2RlLCB0b05vZGUpKSB7XG4gICAgICAgICAgICBvbk5vZGVEaXNjYXJkZWQoZnJvbU5vZGUpO1xuICAgICAgICAgICAgbW9ycGhlZE5vZGUgPSBtb3ZlQ2hpbGRyZW4oZnJvbU5vZGUsIGNyZWF0ZUVsZW1lbnROUyh0b05vZGUubm9kZU5hbWUsIHRvTm9kZS5uYW1lc3BhY2VVUkkpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gR29pbmcgZnJvbSBhbiBlbGVtZW50IG5vZGUgdG8gYSB0ZXh0IG5vZGVcbiAgICAgICAgICBtb3JwaGVkTm9kZSA9IHRvTm9kZTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChtb3JwaGVkTm9kZVR5cGUgPT09IFRFWFRfTk9ERSB8fCBtb3JwaGVkTm9kZVR5cGUgPT09IENPTU1FTlRfTk9ERSkgeyAvLyBUZXh0IG9yIGNvbW1lbnQgbm9kZVxuICAgICAgICBpZiAodG9Ob2RlVHlwZSA9PT0gbW9ycGhlZE5vZGVUeXBlKSB7XG4gICAgICAgICAgaWYgKG1vcnBoZWROb2RlLm5vZGVWYWx1ZSAhPT0gdG9Ob2RlLm5vZGVWYWx1ZSkge1xuICAgICAgICAgICAgbW9ycGhlZE5vZGUubm9kZVZhbHVlID0gdG9Ob2RlLm5vZGVWYWx1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gbW9ycGhlZE5vZGU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gVGV4dCBub2RlIHRvIHNvbWV0aGluZyBlbHNlXG4gICAgICAgICAgbW9ycGhlZE5vZGUgPSB0b05vZGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobW9ycGhlZE5vZGUgPT09IHRvTm9kZSkge1xuICAgICAgLy8gVGhlIFwidG8gbm9kZVwiIHdhcyBub3QgY29tcGF0aWJsZSB3aXRoIHRoZSBcImZyb20gbm9kZVwiIHNvIHdlIGhhZCB0b1xuICAgICAgLy8gdG9zcyBvdXQgdGhlIFwiZnJvbSBub2RlXCIgYW5kIHVzZSB0aGUgXCJ0byBub2RlXCJcbiAgICAgIG9uTm9kZURpc2NhcmRlZChmcm9tTm9kZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0b05vZGUuaXNTYW1lTm9kZSAmJiB0b05vZGUuaXNTYW1lTm9kZShtb3JwaGVkTm9kZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBtb3JwaEVsKG1vcnBoZWROb2RlLCB0b05vZGUsIGNoaWxkcmVuT25seSk7XG5cbiAgICAgIC8vIFdlIG5vdyBuZWVkIHRvIGxvb3Agb3ZlciBhbnkga2V5ZWQgbm9kZXMgdGhhdCBtaWdodCBuZWVkIHRvIGJlXG4gICAgICAvLyByZW1vdmVkLiBXZSBvbmx5IGRvIHRoZSByZW1vdmFsIGlmIHdlIGtub3cgdGhhdCB0aGUga2V5ZWQgbm9kZVxuICAgICAgLy8gbmV2ZXIgZm91bmQgYSBtYXRjaC4gV2hlbiBhIGtleWVkIG5vZGUgaXMgbWF0Y2hlZCB1cCB3ZSByZW1vdmVcbiAgICAgIC8vIGl0IG91dCBvZiBmcm9tTm9kZXNMb29rdXAgYW5kIHdlIHVzZSBmcm9tTm9kZXNMb29rdXAgdG8gZGV0ZXJtaW5lXG4gICAgICAvLyBpZiBhIGtleWVkIG5vZGUgaGFzIGJlZW4gbWF0Y2hlZCB1cCBvciBub3RcbiAgICAgIGlmIChrZXllZFJlbW92YWxMaXN0KSB7XG4gICAgICAgIGZvciAodmFyIGk9MCwgbGVuPWtleWVkUmVtb3ZhbExpc3QubGVuZ3RoOyBpPGxlbjsgaSsrKSB7XG4gICAgICAgICAgdmFyIGVsVG9SZW1vdmUgPSBmcm9tTm9kZXNMb29rdXBba2V5ZWRSZW1vdmFsTGlzdFtpXV07XG4gICAgICAgICAgaWYgKGVsVG9SZW1vdmUpIHtcbiAgICAgICAgICAgIHJlbW92ZU5vZGUoZWxUb1JlbW92ZSwgZWxUb1JlbW92ZS5wYXJlbnROb2RlLCBmYWxzZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFjaGlsZHJlbk9ubHkgJiYgbW9ycGhlZE5vZGUgIT09IGZyb21Ob2RlICYmIGZyb21Ob2RlLnBhcmVudE5vZGUpIHtcbiAgICAgIGlmIChtb3JwaGVkTm9kZS5hY3R1YWxpemUpIHtcbiAgICAgICAgbW9ycGhlZE5vZGUgPSBtb3JwaGVkTm9kZS5hY3R1YWxpemUoZnJvbU5vZGUub3duZXJEb2N1bWVudCB8fCBkb2MpO1xuICAgICAgfVxuICAgICAgLy8gSWYgd2UgaGFkIHRvIHN3YXAgb3V0IHRoZSBmcm9tIG5vZGUgd2l0aCBhIG5ldyBub2RlIGJlY2F1c2UgdGhlIG9sZFxuICAgICAgLy8gbm9kZSB3YXMgbm90IGNvbXBhdGlibGUgd2l0aCB0aGUgdGFyZ2V0IG5vZGUgdGhlbiB3ZSBuZWVkIHRvXG4gICAgICAvLyByZXBsYWNlIHRoZSBvbGQgRE9NIG5vZGUgaW4gdGhlIG9yaWdpbmFsIERPTSB0cmVlLiBUaGlzIGlzIG9ubHlcbiAgICAgIC8vIHBvc3NpYmxlIGlmIHRoZSBvcmlnaW5hbCBET00gbm9kZSB3YXMgcGFydCBvZiBhIERPTSB0cmVlIHdoaWNoXG4gICAgICAvLyB3ZSBrbm93IGlzIHRoZSBjYXNlIGlmIGl0IGhhcyBhIHBhcmVudCBub2RlLlxuICAgICAgZnJvbU5vZGUucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobW9ycGhlZE5vZGUsIGZyb21Ob2RlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbW9ycGhlZE5vZGU7XG4gIH07XG59XG5cbnZhciBtb3JwaGRvbSA9IG1vcnBoZG9tRmFjdG9yeShtb3JwaEF0dHJzKTtcblxuZXhwb3J0IGRlZmF1bHQgbW9ycGhkb207XG4iLCAiaW1wb3J0IHtcbiAgUEhYX0NPTVBPTkVOVCxcbiAgUEhYX1BSVU5FLFxuICBQSFhfUk9PVF9JRCxcbiAgUEhYX1NFU1NJT04sXG4gIFBIWF9TS0lQLFxuICBQSFhfTUFHSUNfSUQsXG4gIFBIWF9TVEFUSUMsXG4gIFBIWF9UUklHR0VSX0FDVElPTixcbiAgUEhYX1VQREFURSxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9SRUZfTE9DSyxcbiAgUEhYX1NUUkVBTSxcbiAgUEhYX1NUUkVBTV9SRUYsXG4gIFBIWF9WSUVXUE9SVF9UT1AsXG4gIFBIWF9WSUVXUE9SVF9CT1RUT00sXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCB7XG4gIGRldGVjdER1cGxpY2F0ZUlkcyxcbiAgZGV0ZWN0SW52YWxpZFN0cmVhbUluc2VydHMsXG4gIGlzQ2lkXG59IGZyb20gXCIuL3V0aWxzXCJcbmltcG9ydCBFbGVtZW50UmVmIGZyb20gXCIuL2VsZW1lbnRfcmVmXCJcbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCJcbmltcG9ydCBET01Qb3N0TW9ycGhSZXN0b3JlciBmcm9tIFwiLi9kb21fcG9zdF9tb3JwaF9yZXN0b3JlclwiXG5pbXBvcnQgbW9ycGhkb20gZnJvbSBcIm1vcnBoZG9tXCJcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRE9NUGF0Y2gge1xuICBjb25zdHJ1Y3Rvcih2aWV3LCBjb250YWluZXIsIGlkLCBodG1sLCBzdHJlYW1zLCB0YXJnZXRDSUQsIG9wdHM9e30pe1xuICAgIHRoaXMudmlldyA9IHZpZXdcbiAgICB0aGlzLmxpdmVTb2NrZXQgPSB2aWV3LmxpdmVTb2NrZXRcbiAgICB0aGlzLmNvbnRhaW5lciA9IGNvbnRhaW5lclxuICAgIHRoaXMuaWQgPSBpZFxuICAgIHRoaXMucm9vdElEID0gdmlldy5yb290LmlkXG4gICAgdGhpcy5odG1sID0gaHRtbFxuICAgIHRoaXMuc3RyZWFtcyA9IHN0cmVhbXNcbiAgICB0aGlzLnN0cmVhbUluc2VydHMgPSB7fVxuICAgIHRoaXMuc3RyZWFtQ29tcG9uZW50UmVzdG9yZSA9IHt9XG4gICAgdGhpcy50YXJnZXRDSUQgPSB0YXJnZXRDSURcbiAgICB0aGlzLmNpZFBhdGNoID0gaXNDaWQodGhpcy50YXJnZXRDSUQpXG4gICAgdGhpcy5wZW5kaW5nUmVtb3ZlcyA9IFtdXG4gICAgdGhpcy5waHhSZW1vdmUgPSB0aGlzLmxpdmVTb2NrZXQuYmluZGluZyhcInJlbW92ZVwiKVxuICAgIHRoaXMudGFyZ2V0Q29udGFpbmVyID0gdGhpcy5pc0NJRFBhdGNoKCkgPyB0aGlzLnRhcmdldENJRENvbnRhaW5lcihodG1sKSA6IGNvbnRhaW5lclxuICAgIHRoaXMuY2FsbGJhY2tzID0ge1xuICAgICAgYmVmb3JlYWRkZWQ6IFtdLCBiZWZvcmV1cGRhdGVkOiBbXSwgYmVmb3JlcGh4Q2hpbGRBZGRlZDogW10sXG4gICAgICBhZnRlcmFkZGVkOiBbXSwgYWZ0ZXJ1cGRhdGVkOiBbXSwgYWZ0ZXJkaXNjYXJkZWQ6IFtdLCBhZnRlcnBoeENoaWxkQWRkZWQ6IFtdLFxuICAgICAgYWZ0ZXJ0cmFuc2l0aW9uc0Rpc2NhcmRlZDogW11cbiAgICB9XG4gICAgdGhpcy53aXRoQ2hpbGRyZW4gPSBvcHRzLndpdGhDaGlsZHJlbiB8fCBvcHRzLnVuZG9SZWYgfHwgZmFsc2VcbiAgICB0aGlzLnVuZG9SZWYgPSBvcHRzLnVuZG9SZWZcbiAgfVxuXG4gIGJlZm9yZShraW5kLCBjYWxsYmFjayl7IHRoaXMuY2FsbGJhY2tzW2BiZWZvcmUke2tpbmR9YF0ucHVzaChjYWxsYmFjaykgfVxuICBhZnRlcihraW5kLCBjYWxsYmFjayl7IHRoaXMuY2FsbGJhY2tzW2BhZnRlciR7a2luZH1gXS5wdXNoKGNhbGxiYWNrKSB9XG5cbiAgdHJhY2tCZWZvcmUoa2luZCwgLi4uYXJncyl7XG4gICAgdGhpcy5jYWxsYmFja3NbYGJlZm9yZSR7a2luZH1gXS5mb3JFYWNoKGNhbGxiYWNrID0+IGNhbGxiYWNrKC4uLmFyZ3MpKVxuICB9XG5cbiAgdHJhY2tBZnRlcihraW5kLCAuLi5hcmdzKXtcbiAgICB0aGlzLmNhbGxiYWNrc1tgYWZ0ZXIke2tpbmR9YF0uZm9yRWFjaChjYWxsYmFjayA9PiBjYWxsYmFjayguLi5hcmdzKSlcbiAgfVxuXG4gIG1hcmtQcnVuYWJsZUNvbnRlbnRGb3JSZW1vdmFsKCl7XG4gICAgbGV0IHBoeFVwZGF0ZSA9IHRoaXMubGl2ZVNvY2tldC5iaW5kaW5nKFBIWF9VUERBVEUpXG4gICAgRE9NLmFsbCh0aGlzLmNvbnRhaW5lciwgYFske3BoeFVwZGF0ZX09YXBwZW5kXSA+ICosIFske3BoeFVwZGF0ZX09cHJlcGVuZF0gPiAqYCwgZWwgPT4ge1xuICAgICAgZWwuc2V0QXR0cmlidXRlKFBIWF9QUlVORSwgXCJcIilcbiAgICB9KVxuICB9XG5cbiAgcGVyZm9ybShpc0pvaW5QYXRjaCl7XG4gICAgbGV0IHt2aWV3LCBsaXZlU29ja2V0LCBodG1sLCBjb250YWluZXIsIHRhcmdldENvbnRhaW5lcn0gPSB0aGlzXG4gICAgaWYodGhpcy5pc0NJRFBhdGNoKCkgJiYgIXRhcmdldENvbnRhaW5lcil7IHJldHVybiB9XG5cbiAgICBsZXQgZm9jdXNlZCA9IGxpdmVTb2NrZXQuZ2V0QWN0aXZlRWxlbWVudCgpXG4gICAgbGV0IHtzZWxlY3Rpb25TdGFydCwgc2VsZWN0aW9uRW5kfSA9IGZvY3VzZWQgJiYgRE9NLmhhc1NlbGVjdGlvblJhbmdlKGZvY3VzZWQpID8gZm9jdXNlZCA6IHt9XG4gICAgbGV0IHBoeFVwZGF0ZSA9IGxpdmVTb2NrZXQuYmluZGluZyhQSFhfVVBEQVRFKVxuICAgIGxldCBwaHhWaWV3cG9ydFRvcCA9IGxpdmVTb2NrZXQuYmluZGluZyhQSFhfVklFV1BPUlRfVE9QKVxuICAgIGxldCBwaHhWaWV3cG9ydEJvdHRvbSA9IGxpdmVTb2NrZXQuYmluZGluZyhQSFhfVklFV1BPUlRfQk9UVE9NKVxuICAgIGxldCBwaHhUcmlnZ2VyRXh0ZXJuYWwgPSBsaXZlU29ja2V0LmJpbmRpbmcoUEhYX1RSSUdHRVJfQUNUSU9OKVxuICAgIGxldCBhZGRlZCA9IFtdXG4gICAgbGV0IHVwZGF0ZXMgPSBbXVxuICAgIGxldCBhcHBlbmRQcmVwZW5kVXBkYXRlcyA9IFtdXG5cbiAgICBsZXQgZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkID0gbnVsbFxuXG4gICAgZnVuY3Rpb24gbW9ycGgodGFyZ2V0Q29udGFpbmVyLCBzb3VyY2UsIHdpdGhDaGlsZHJlbj10aGlzLndpdGhDaGlsZHJlbil7XG4gICAgICBsZXQgbW9ycGhDYWxsYmFja3MgPSB7XG4gICAgICAgIC8vIG5vcm1hbGx5LCB3ZSBhcmUgcnVubmluZyB3aXRoIGNoaWxkcmVuT25seSwgYXMgdGhlIHBhdGNoIEhUTUwgZm9yIGEgTFZcbiAgICAgICAgLy8gZG9lcyBub3QgaW5jbHVkZSB0aGUgTFYgYXR0cnMgKGRhdGEtcGh4LXNlc3Npb24sIGV0Yy4pXG4gICAgICAgIC8vIHdoZW4gd2UgYXJlIHBhdGNoaW5nIGEgbGl2ZSBjb21wb25lbnQsIHdlIGRvIHdhbnQgdG8gcGF0Y2ggdGhlIHJvb3QgZWxlbWVudCBhcyB3ZWxsO1xuICAgICAgICAvLyBhbm90aGVyIGNhc2UgaXMgdGhlIHJlY3Vyc2l2ZSBwYXRjaCBvZiBhIHN0cmVhbSBpdGVtIHRoYXQgd2FzIGtlcHQgb24gcmVzZXQgKC0+IG9uQmVmb3JlTm9kZUFkZGVkKVxuICAgICAgICBjaGlsZHJlbk9ubHk6IHRhcmdldENvbnRhaW5lci5nZXRBdHRyaWJ1dGUoUEhYX0NPTVBPTkVOVCkgPT09IG51bGwgJiYgIXdpdGhDaGlsZHJlbixcbiAgICAgICAgZ2V0Tm9kZUtleTogKG5vZGUpID0+IHtcbiAgICAgICAgICBpZihET00uaXNQaHhEZXN0cm95ZWQobm9kZSkpeyByZXR1cm4gbnVsbCB9XG4gICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIGpvaW4gcGF0Y2gsIHRoZW4gYnkgZGVmaW5pdGlvbiB0aGVyZSB3YXMgbm8gUEhYX01BR0lDX0lELlxuICAgICAgICAgIC8vIFRoaXMgaXMgaW1wb3J0YW50IHRvIHJlZHVjZSB0aGUgYW1vdW50IG9mIGVsZW1lbnRzIG1vcnBoZG9tIGRpc2NhcmRzLlxuICAgICAgICAgIGlmKGlzSm9pblBhdGNoKXsgcmV0dXJuIG5vZGUuaWQgfVxuICAgICAgICAgIHJldHVybiBub2RlLmlkIHx8IChub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZShQSFhfTUFHSUNfSUQpKVxuICAgICAgICB9LFxuICAgICAgICAvLyBza2lwIGluZGV4aW5nIGZyb20gY2hpbGRyZW4gd2hlbiBjb250YWluZXIgaXMgc3RyZWFtXG4gICAgICAgIHNraXBGcm9tQ2hpbGRyZW46IChmcm9tKSA9PiB7IHJldHVybiBmcm9tLmdldEF0dHJpYnV0ZShwaHhVcGRhdGUpID09PSBQSFhfU1RSRUFNIH0sXG4gICAgICAgIC8vIHRlbGwgbW9ycGhkb20gaG93IHRvIGFkZCBhIGNoaWxkXG4gICAgICAgIGFkZENoaWxkOiAocGFyZW50LCBjaGlsZCkgPT4ge1xuICAgICAgICAgIGxldCB7cmVmLCBzdHJlYW1BdH0gPSB0aGlzLmdldFN0cmVhbUluc2VydChjaGlsZClcbiAgICAgICAgICBpZihyZWYgPT09IHVuZGVmaW5lZCl7IHJldHVybiBwYXJlbnQuYXBwZW5kQ2hpbGQoY2hpbGQpIH1cblxuICAgICAgICAgIHRoaXMuc2V0U3RyZWFtUmVmKGNoaWxkLCByZWYpXG5cbiAgICAgICAgICAvLyBzdHJlYW1pbmdcbiAgICAgICAgICBpZihzdHJlYW1BdCA9PT0gMCl7XG4gICAgICAgICAgICBwYXJlbnQuaW5zZXJ0QWRqYWNlbnRFbGVtZW50KFwiYWZ0ZXJiZWdpblwiLCBjaGlsZClcbiAgICAgICAgICB9IGVsc2UgaWYoc3RyZWFtQXQgPT09IC0xKXtcbiAgICAgICAgICAgIGxldCBsYXN0Q2hpbGQgPSBwYXJlbnQubGFzdEVsZW1lbnRDaGlsZFxuICAgICAgICAgICAgaWYobGFzdENoaWxkICYmICFsYXN0Q2hpbGQuaGFzQXR0cmlidXRlKFBIWF9TVFJFQU1fUkVGKSl7XG4gICAgICAgICAgICAgIGxldCBub25TdHJlYW1DaGlsZCA9IEFycmF5LmZyb20ocGFyZW50LmNoaWxkcmVuKS5maW5kKGMgPT4gIWMuaGFzQXR0cmlidXRlKFBIWF9TVFJFQU1fUkVGKSlcbiAgICAgICAgICAgICAgcGFyZW50Lmluc2VydEJlZm9yZShjaGlsZCwgbm9uU3RyZWFtQ2hpbGQpXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBwYXJlbnQuYXBwZW5kQ2hpbGQoY2hpbGQpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmKHN0cmVhbUF0ID4gMCl7XG4gICAgICAgICAgICBsZXQgc2libGluZyA9IEFycmF5LmZyb20ocGFyZW50LmNoaWxkcmVuKVtzdHJlYW1BdF1cbiAgICAgICAgICAgIHBhcmVudC5pbnNlcnRCZWZvcmUoY2hpbGQsIHNpYmxpbmcpXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBvbkJlZm9yZU5vZGVBZGRlZDogKGVsKSA9PiB7XG4gICAgICAgICAgRE9NLm1haW50YWluUHJpdmF0ZUhvb2tzKGVsLCBlbCwgcGh4Vmlld3BvcnRUb3AsIHBoeFZpZXdwb3J0Qm90dG9tKVxuICAgICAgICAgIHRoaXMudHJhY2tCZWZvcmUoXCJhZGRlZFwiLCBlbClcblxuICAgICAgICAgIGxldCBtb3JwaGVkRWwgPSBlbFxuICAgICAgICAgIC8vIHRoaXMgaXMgYSBzdHJlYW0gaXRlbSB0aGF0IHdhcyBrZXB0IG9uIHJlc2V0LCByZWN1cnNpdmVseSBtb3JwaCBpdFxuICAgICAgICAgIGlmKHRoaXMuc3RyZWFtQ29tcG9uZW50UmVzdG9yZVtlbC5pZF0pe1xuICAgICAgICAgICAgbW9ycGhlZEVsID0gdGhpcy5zdHJlYW1Db21wb25lbnRSZXN0b3JlW2VsLmlkXVxuICAgICAgICAgICAgZGVsZXRlIHRoaXMuc3RyZWFtQ29tcG9uZW50UmVzdG9yZVtlbC5pZF1cbiAgICAgICAgICAgIG1vcnBoLmNhbGwodGhpcywgbW9ycGhlZEVsLCBlbCwgdHJ1ZSlcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gbW9ycGhlZEVsXG4gICAgICAgIH0sXG4gICAgICAgIG9uTm9kZUFkZGVkOiAoZWwpID0+IHtcbiAgICAgICAgICBpZihlbC5nZXRBdHRyaWJ1dGUpeyB0aGlzLm1heWJlUmVPcmRlclN0cmVhbShlbCwgdHJ1ZSkgfVxuXG4gICAgICAgICAgLy8gaGFjayB0byBmaXggU2FmYXJpIGhhbmRsaW5nIG9mIGltZyBzcmNzZXQgYW5kIHZpZGVvIHRhZ3NcbiAgICAgICAgICBpZihlbCBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgJiYgZWwuc3Jjc2V0KXtcbiAgICAgICAgICAgIGVsLnNyY3NldCA9IGVsLnNyY3NldFxuICAgICAgICAgIH0gZWxzZSBpZihlbCBpbnN0YW5jZW9mIEhUTUxWaWRlb0VsZW1lbnQgJiYgZWwuYXV0b3BsYXkpe1xuICAgICAgICAgICAgZWwucGxheSgpXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKERPTS5pc05vd1RyaWdnZXJGb3JtRXh0ZXJuYWwoZWwsIHBoeFRyaWdnZXJFeHRlcm5hbCkpe1xuICAgICAgICAgICAgZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkID0gZWxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBuZXN0ZWQgdmlldyBoYW5kbGluZ1xuICAgICAgICAgIGlmKChET00uaXNQaHhDaGlsZChlbCkgJiYgdmlldy5vd25zRWxlbWVudChlbCkpIHx8IERPTS5pc1BoeFN0aWNreShlbCkgJiYgdmlldy5vd25zRWxlbWVudChlbC5wYXJlbnROb2RlKSl7XG4gICAgICAgICAgICB0aGlzLnRyYWNrQWZ0ZXIoXCJwaHhDaGlsZEFkZGVkXCIsIGVsKVxuICAgICAgICAgIH1cbiAgICAgICAgICBhZGRlZC5wdXNoKGVsKVxuICAgICAgICB9LFxuICAgICAgICBvbk5vZGVEaXNjYXJkZWQ6IChlbCkgPT4gdGhpcy5vbk5vZGVEaXNjYXJkZWQoZWwpLFxuICAgICAgICBvbkJlZm9yZU5vZGVEaXNjYXJkZWQ6IChlbCkgPT4ge1xuICAgICAgICAgIGlmKGVsLmdldEF0dHJpYnV0ZSAmJiBlbC5nZXRBdHRyaWJ1dGUoUEhYX1BSVU5FKSAhPT0gbnVsbCl7IHJldHVybiB0cnVlIH1cbiAgICAgICAgICBpZihlbC5wYXJlbnRFbGVtZW50ICE9PSBudWxsICYmIGVsLmlkICYmXG4gICAgICAgICAgICBET00uaXNQaHhVcGRhdGUoZWwucGFyZW50RWxlbWVudCwgcGh4VXBkYXRlLCBbUEhYX1NUUkVBTSwgXCJhcHBlbmRcIiwgXCJwcmVwZW5kXCJdKSl7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYodGhpcy5tYXliZVBlbmRpbmdSZW1vdmUoZWwpKXsgcmV0dXJuIGZhbHNlIH1cbiAgICAgICAgICBpZih0aGlzLnNraXBDSURTaWJsaW5nKGVsKSl7IHJldHVybiBmYWxzZSB9XG5cbiAgICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBvbkVsVXBkYXRlZDogKGVsKSA9PiB7XG4gICAgICAgICAgaWYoRE9NLmlzTm93VHJpZ2dlckZvcm1FeHRlcm5hbChlbCwgcGh4VHJpZ2dlckV4dGVybmFsKSl7XG4gICAgICAgICAgICBleHRlcm5hbEZvcm1UcmlnZ2VyZWQgPSBlbFxuICAgICAgICAgIH1cbiAgICAgICAgICB1cGRhdGVzLnB1c2goZWwpXG4gICAgICAgICAgdGhpcy5tYXliZVJlT3JkZXJTdHJlYW0oZWwsIGZhbHNlKVxuICAgICAgICB9LFxuICAgICAgICBvbkJlZm9yZUVsVXBkYXRlZDogKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgICAgIC8vIGlmIHdlIGFyZSBwYXRjaGluZyB0aGUgcm9vdCB0YXJnZXQgY29udGFpbmVyIGFuZCB0aGUgaWQgaGFzIGNoYW5nZWQsIHRyZWF0IGl0IGFzIGEgbmV3IG5vZGVcbiAgICAgICAgICAvLyBieSByZXBsYWNpbmcgdGhlIGZyb21FbCB3aXRoIHRoZSB0b0VsLCB3aGljaCBlbnN1cmVzIGhvb2tzIGFyZSB0b3JuIGRvd24gYW5kIHJlLWNyZWF0ZWRcbiAgICAgICAgICBpZihmcm9tRWwuaWQgJiYgZnJvbUVsLmlzU2FtZU5vZGUodGFyZ2V0Q29udGFpbmVyKSAmJiBmcm9tRWwuaWQgIT09IHRvRWwuaWQpe1xuICAgICAgICAgICAgbW9ycGhDYWxsYmFja3Mub25Ob2RlRGlzY2FyZGVkKGZyb21FbClcbiAgICAgICAgICAgIGZyb21FbC5yZXBsYWNlV2l0aCh0b0VsKVxuICAgICAgICAgICAgcmV0dXJuIG1vcnBoQ2FsbGJhY2tzLm9uTm9kZUFkZGVkKHRvRWwpXG4gICAgICAgICAgfVxuICAgICAgICAgIERPTS5zeW5jUGVuZGluZ0F0dHJzKGZyb21FbCwgdG9FbClcbiAgICAgICAgICBET00ubWFpbnRhaW5Qcml2YXRlSG9va3MoZnJvbUVsLCB0b0VsLCBwaHhWaWV3cG9ydFRvcCwgcGh4Vmlld3BvcnRCb3R0b20pXG4gICAgICAgICAgRE9NLmNsZWFuQ2hpbGROb2Rlcyh0b0VsLCBwaHhVcGRhdGUpXG4gICAgICAgICAgaWYodGhpcy5za2lwQ0lEU2libGluZyh0b0VsKSl7XG4gICAgICAgICAgICAvLyBpZiB0aGlzIGlzIGEgbGl2ZSBjb21wb25lbnQgdXNlZCBpbiBhIHN0cmVhbSwgd2UgbWF5IG5lZWQgdG8gcmVvcmRlciBpdFxuICAgICAgICAgICAgdGhpcy5tYXliZVJlT3JkZXJTdHJlYW0oZnJvbUVsKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKERPTS5pc1BoeFN0aWNreShmcm9tRWwpKXtcbiAgICAgICAgICAgIFtQSFhfU0VTU0lPTiwgUEhYX1NUQVRJQywgUEhYX1JPT1RfSURdXG4gICAgICAgICAgICAgIC5tYXAoYXR0ciA9PiBbYXR0ciwgZnJvbUVsLmdldEF0dHJpYnV0ZShhdHRyKSwgdG9FbC5nZXRBdHRyaWJ1dGUoYXR0cildKVxuICAgICAgICAgICAgICAuZm9yRWFjaCgoW2F0dHIsIGZyb21WYWwsIHRvVmFsXSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmKHRvVmFsICYmIGZyb21WYWwgIT09IHRvVmFsKXsgZnJvbUVsLnNldEF0dHJpYnV0ZShhdHRyLCB0b1ZhbCkgfVxuICAgICAgICAgICAgICB9KVxuXG4gICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoRE9NLmlzSWdub3JlZChmcm9tRWwsIHBoeFVwZGF0ZSkgfHwgKGZyb21FbC5mb3JtICYmIGZyb21FbC5mb3JtLmlzU2FtZU5vZGUoZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkKSkpe1xuICAgICAgICAgICAgdGhpcy50cmFja0JlZm9yZShcInVwZGF0ZWRcIiwgZnJvbUVsLCB0b0VsKVxuICAgICAgICAgICAgRE9NLm1lcmdlQXR0cnMoZnJvbUVsLCB0b0VsLCB7aXNJZ25vcmVkOiBET00uaXNJZ25vcmVkKGZyb21FbCwgcGh4VXBkYXRlKX0pXG4gICAgICAgICAgICB1cGRhdGVzLnB1c2goZnJvbUVsKVxuICAgICAgICAgICAgRE9NLmFwcGx5U3RpY2t5T3BlcmF0aW9ucyhmcm9tRWwpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoZnJvbUVsLnR5cGUgPT09IFwibnVtYmVyXCIgJiYgKGZyb21FbC52YWxpZGl0eSAmJiBmcm9tRWwudmFsaWRpdHkuYmFkSW5wdXQpKXsgcmV0dXJuIGZhbHNlIH1cbiAgICAgICAgICAvLyBJZiB0aGUgZWxlbWVudCBoYXMgUEhYX1JFRl9TUkMsIGl0IGlzIGxvYWRpbmcgb3IgbG9ja2VkIGFuZCBhd2FpdGluZyBhbiBhY2suXG4gICAgICAgICAgLy8gSWYgaXQncyBsb2NrZWQsIHdlIGNsb25lIHRoZSBmcm9tRWwgdHJlZSBhbmQgaW5zdHJ1Y3QgbW9ycGhkb20gdG8gdXNlXG4gICAgICAgICAgLy8gdGhlIGNsb25lZCB0cmVlIGFzIHRoZSBzb3VyY2Ugb2YgdGhlIG1vcnBoIGZvciB0aGlzIGJyYW5jaCBmcm9tIGhlcmUgb24gb3V0LlxuICAgICAgICAgIC8vIFdlIGtlZXAgYSByZWZlcmVuY2UgdG8gdGhlIGNsb25lZCB0cmVlIGluIHRoZSBlbGVtZW50J3MgcHJpdmF0ZSBkYXRhLCBhbmRcbiAgICAgICAgICAvLyBvbiBhY2sgKHZpZXcudW5kb1JlZnMpLCB3ZSBtb3JwaCB0aGUgY2xvbmVkIHRyZWUgd2l0aCB0aGUgdHJ1ZSBmcm9tRWwgaW4gdGhlIERPTSB0b1xuICAgICAgICAgIC8vIGFwcGx5IGFueSBjaGFuZ2VzIHRoYXQgaGFwcGVuZWQgd2hpbGUgdGhlIGVsZW1lbnQgd2FzIGxvY2tlZC5cbiAgICAgICAgICBsZXQgaXNGb2N1c2VkRm9ybUVsID0gZm9jdXNlZCAmJiBmcm9tRWwuaXNTYW1lTm9kZShmb2N1c2VkKSAmJiBET00uaXNGb3JtSW5wdXQoZnJvbUVsKVxuICAgICAgICAgIGxldCBmb2N1c2VkU2VsZWN0Q2hhbmdlZCA9IGlzRm9jdXNlZEZvcm1FbCAmJiB0aGlzLmlzQ2hhbmdlZFNlbGVjdChmcm9tRWwsIHRvRWwpXG4gICAgICAgICAgaWYoZnJvbUVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX1NSQykpe1xuICAgICAgICAgICAgY29uc3QgcmVmID0gbmV3IEVsZW1lbnRSZWYoZnJvbUVsKVxuICAgICAgICAgICAgLy8gb25seSBwZXJmb3JtIHRoZSBjbG9uZSBzdGVwIGlmIHRoaXMgaXMgbm90IGEgcGF0Y2ggdGhhdCB1bmxvY2tzXG4gICAgICAgICAgICBpZihyZWYubG9ja1JlZiAmJiAoIXRoaXMudW5kb1JlZiB8fCAhcmVmLmlzTG9ja1VuZG9uZUJ5KHRoaXMudW5kb1JlZikpKXtcbiAgICAgICAgICAgICAgaWYoRE9NLmlzVXBsb2FkSW5wdXQoZnJvbUVsKSl7XG4gICAgICAgICAgICAgICAgRE9NLm1lcmdlQXR0cnMoZnJvbUVsLCB0b0VsLCB7aXNJZ25vcmVkOiB0cnVlfSlcbiAgICAgICAgICAgICAgICB0aGlzLnRyYWNrQmVmb3JlKFwidXBkYXRlZFwiLCBmcm9tRWwsIHRvRWwpXG4gICAgICAgICAgICAgICAgdXBkYXRlcy5wdXNoKGZyb21FbClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBET00uYXBwbHlTdGlja3lPcGVyYXRpb25zKGZyb21FbClcbiAgICAgICAgICAgICAgbGV0IGlzTG9ja2VkID0gZnJvbUVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX0xPQ0spXG4gICAgICAgICAgICAgIGxldCBjbG9uZSA9IGlzTG9ja2VkID8gRE9NLnByaXZhdGUoZnJvbUVsLCBQSFhfUkVGX0xPQ0spIHx8IGZyb21FbC5jbG9uZU5vZGUodHJ1ZSkgOiBudWxsXG4gICAgICAgICAgICAgIGlmKGNsb25lKXtcbiAgICAgICAgICAgICAgICBET00ucHV0UHJpdmF0ZShmcm9tRWwsIFBIWF9SRUZfTE9DSywgY2xvbmUpXG4gICAgICAgICAgICAgICAgaWYoIWlzRm9jdXNlZEZvcm1FbCl7XG4gICAgICAgICAgICAgICAgICBmcm9tRWwgPSBjbG9uZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIG5lc3RlZCB2aWV3IGhhbmRsaW5nXG4gICAgICAgICAgaWYoRE9NLmlzUGh4Q2hpbGQodG9FbCkpe1xuICAgICAgICAgICAgbGV0IHByZXZTZXNzaW9uID0gZnJvbUVsLmdldEF0dHJpYnV0ZShQSFhfU0VTU0lPTilcbiAgICAgICAgICAgIERPTS5tZXJnZUF0dHJzKGZyb21FbCwgdG9FbCwge2V4Y2x1ZGU6IFtQSFhfU1RBVElDXX0pXG4gICAgICAgICAgICBpZihwcmV2U2Vzc2lvbiAhPT0gXCJcIil7IGZyb21FbC5zZXRBdHRyaWJ1dGUoUEhYX1NFU1NJT04sIHByZXZTZXNzaW9uKSB9XG4gICAgICAgICAgICBmcm9tRWwuc2V0QXR0cmlidXRlKFBIWF9ST09UX0lELCB0aGlzLnJvb3RJRClcbiAgICAgICAgICAgIERPTS5hcHBseVN0aWNreU9wZXJhdGlvbnMoZnJvbUVsKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gaWYgd2UgYXJlIHVuZG9pbmcgYSBsb2NrLCBjb3B5IHBvdGVudGlhbGx5IG5lc3RlZCBjbG9uZXMgb3ZlclxuICAgICAgICAgIGlmKHRoaXMudW5kb1JlZiAmJiBET00ucHJpdmF0ZSh0b0VsLCBQSFhfUkVGX0xPQ0spKXtcbiAgICAgICAgICAgIERPTS5wdXRQcml2YXRlKGZyb21FbCwgUEhYX1JFRl9MT0NLLCBET00ucHJpdmF0ZSh0b0VsLCBQSFhfUkVGX0xPQ0spKVxuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBub3cgY29weSByZWd1bGFyIERPTS5wcml2YXRlIGRhdGFcbiAgICAgICAgICBET00uY29weVByaXZhdGVzKHRvRWwsIGZyb21FbClcblxuICAgICAgICAgIC8vIHNraXAgcGF0Y2hpbmcgZm9jdXNlZCBpbnB1dHMgdW5sZXNzIGZvY3VzIGlzIGEgc2VsZWN0IHRoYXQgaGFzIGNoYW5nZWQgb3B0aW9uc1xuICAgICAgICAgIGlmKGlzRm9jdXNlZEZvcm1FbCAmJiBmcm9tRWwudHlwZSAhPT0gXCJoaWRkZW5cIiAmJiAhZm9jdXNlZFNlbGVjdENoYW5nZWQpe1xuICAgICAgICAgICAgdGhpcy50cmFja0JlZm9yZShcInVwZGF0ZWRcIiwgZnJvbUVsLCB0b0VsKVxuICAgICAgICAgICAgRE9NLm1lcmdlRm9jdXNlZElucHV0KGZyb21FbCwgdG9FbClcbiAgICAgICAgICAgIERPTS5zeW5jQXR0cnNUb1Byb3BzKGZyb21FbClcbiAgICAgICAgICAgIHVwZGF0ZXMucHVzaChmcm9tRWwpXG4gICAgICAgICAgICBET00uYXBwbHlTdGlja3lPcGVyYXRpb25zKGZyb21FbClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBibHVyIGZvY3VzZWQgc2VsZWN0IGlmIGl0IGNoYW5nZWQgc28gbmF0aXZlIFVJIGlzIHVwZGF0ZWQgKGllIHNhZmFyaSB3b24ndCB1cGRhdGUgdmlzaWJsZSBvcHRpb25zKVxuICAgICAgICAgICAgaWYoZm9jdXNlZFNlbGVjdENoYW5nZWQpeyBmcm9tRWwuYmx1cigpIH1cbiAgICAgICAgICAgIGlmKERPTS5pc1BoeFVwZGF0ZSh0b0VsLCBwaHhVcGRhdGUsIFtcImFwcGVuZFwiLCBcInByZXBlbmRcIl0pKXtcbiAgICAgICAgICAgICAgYXBwZW5kUHJlcGVuZFVwZGF0ZXMucHVzaChuZXcgRE9NUG9zdE1vcnBoUmVzdG9yZXIoZnJvbUVsLCB0b0VsLCB0b0VsLmdldEF0dHJpYnV0ZShwaHhVcGRhdGUpKSlcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgRE9NLnN5bmNBdHRyc1RvUHJvcHModG9FbClcbiAgICAgICAgICAgIERPTS5hcHBseVN0aWNreU9wZXJhdGlvbnModG9FbClcbiAgICAgICAgICAgIHRoaXMudHJhY2tCZWZvcmUoXCJ1cGRhdGVkXCIsIGZyb21FbCwgdG9FbClcbiAgICAgICAgICAgIHJldHVybiBmcm9tRWxcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIG1vcnBoZG9tKHRhcmdldENvbnRhaW5lciwgc291cmNlLCBtb3JwaENhbGxiYWNrcylcbiAgICB9XG5cbiAgICB0aGlzLnRyYWNrQmVmb3JlKFwiYWRkZWRcIiwgY29udGFpbmVyKVxuICAgIHRoaXMudHJhY2tCZWZvcmUoXCJ1cGRhdGVkXCIsIGNvbnRhaW5lciwgY29udGFpbmVyKVxuXG4gICAgbGl2ZVNvY2tldC50aW1lKFwibW9ycGhkb21cIiwgKCkgPT4ge1xuICAgICAgdGhpcy5zdHJlYW1zLmZvckVhY2goKFtyZWYsIGluc2VydHMsIGRlbGV0ZUlkcywgcmVzZXRdKSA9PiB7XG4gICAgICAgIGluc2VydHMuZm9yRWFjaCgoW2tleSwgc3RyZWFtQXQsIGxpbWl0XSkgPT4ge1xuICAgICAgICAgIHRoaXMuc3RyZWFtSW5zZXJ0c1trZXldID0ge3JlZiwgc3RyZWFtQXQsIGxpbWl0LCByZXNldH1cbiAgICAgICAgfSlcbiAgICAgICAgaWYocmVzZXQgIT09IHVuZGVmaW5lZCl7XG4gICAgICAgICAgRE9NLmFsbChjb250YWluZXIsIGBbJHtQSFhfU1RSRUFNX1JFRn09XCIke3JlZn1cIl1gLCBjaGlsZCA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVN0cmVhbUNoaWxkRWxlbWVudChjaGlsZClcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICAgIGRlbGV0ZUlkcy5mb3JFYWNoKGlkID0+IHtcbiAgICAgICAgICBsZXQgY2hpbGQgPSBjb250YWluZXIucXVlcnlTZWxlY3RvcihgW2lkPVwiJHtpZH1cIl1gKVxuICAgICAgICAgIGlmKGNoaWxkKXsgdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQpIH1cbiAgICAgICAgfSlcbiAgICAgIH0pXG5cbiAgICAgIC8vIGNsZWFyIHN0cmVhbSBpdGVtcyBmcm9tIHRoZSBkZWFkIHJlbmRlciBpZiB0aGV5IGFyZSBub3QgaW5zZXJ0ZWQgYWdhaW5cbiAgICAgIGlmKGlzSm9pblBhdGNoKXtcbiAgICAgICAgRE9NLmFsbCh0aGlzLmNvbnRhaW5lciwgYFske3BoeFVwZGF0ZX09JHtQSFhfU1RSRUFNfV1gKVxuICAgICAgICAgIC8vIGl0IGlzIGltcG9ydGFudCB0byBmaWx0ZXIgdGhlIGVsZW1lbnQgYmVmb3JlIHJlbW92aW5nIHRoZW0sIGFzXG4gICAgICAgICAgLy8gaXQgbWF5IGhhcHBlbiB0aGF0IHN0cmVhbXMgYXJlIG5lc3RlZCBhbmQgdGhlIG93bmVyIGNoZWNrIGZhaWxzIGlmXG4gICAgICAgICAgLy8gYSBwYXJlbnQgaXMgcmVtb3ZlZCBiZWZvcmUgYSBjaGlsZFxuICAgICAgICAgIC5maWx0ZXIoZWwgPT4gdGhpcy52aWV3Lm93bnNFbGVtZW50KGVsKSlcbiAgICAgICAgICAuZm9yRWFjaChlbCA9PiB7XG4gICAgICAgICAgICBBcnJheS5mcm9tKGVsLmNoaWxkcmVuKS5mb3JFYWNoKGNoaWxkID0+IHtcbiAgICAgICAgICAgICAgLy8gd2UgYWxyZWFkeSBwZXJmb3JtZWQgdGhlIG93bmVyIGNoZWNrLCBlYWNoIGNoaWxkIGlzIGd1YXJhbnRlZWQgdG8gYmUgb3duZWRcbiAgICAgICAgICAgICAgLy8gYnkgdGhlIHZpZXcuIFRvIHByZXZlbnQgdGhlIG5lc3RlZCBvd25lciBjaGVjayBmcm9tIGZhaWxpbmcgaW4gY2FzZSBvZiBuZXN0ZWRcbiAgICAgICAgICAgICAgLy8gc3RyZWFtcyB3aGVyZSB0aGUgcGFyZW50IGlzIHJlbW92ZWQgYmVmb3JlIHRoZSBjaGlsZCwgd2UgZm9yY2UgdGhlIHJlbW92YWxcbiAgICAgICAgICAgICAgdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQsIHRydWUpXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIG1vcnBoLmNhbGwodGhpcywgdGFyZ2V0Q29udGFpbmVyLCBodG1sKVxuICAgIH0pXG5cbiAgICBpZihsaXZlU29ja2V0LmlzRGVidWdFbmFibGVkKCkpe1xuICAgICAgZGV0ZWN0RHVwbGljYXRlSWRzKClcbiAgICAgIGRldGVjdEludmFsaWRTdHJlYW1JbnNlcnRzKHRoaXMuc3RyZWFtSW5zZXJ0cylcbiAgICAgIC8vIHdhcm4gaWYgdGhlcmUgYXJlIGFueSBpbnB1dHMgbmFtZWQgXCJpZFwiXG4gICAgICBBcnJheS5mcm9tKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCJpbnB1dFtuYW1lPWlkXVwiKSkuZm9yRWFjaChub2RlID0+IHtcbiAgICAgICAgaWYobm9kZS5mb3JtKXtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRGV0ZWN0ZWQgYW4gaW5wdXQgd2l0aCBuYW1lPVxcXCJpZFxcXCIgaW5zaWRlIGEgZm9ybSEgVGhpcyB3aWxsIGNhdXNlIHByb2JsZW1zIHdoZW4gcGF0Y2hpbmcgdGhlIERPTS5cXG5cIiwgbm9kZSlcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG5cbiAgICBpZihhcHBlbmRQcmVwZW5kVXBkYXRlcy5sZW5ndGggPiAwKXtcbiAgICAgIGxpdmVTb2NrZXQudGltZShcInBvc3QtbW9ycGggYXBwZW5kL3ByZXBlbmQgcmVzdG9yYXRpb25cIiwgKCkgPT4ge1xuICAgICAgICBhcHBlbmRQcmVwZW5kVXBkYXRlcy5mb3JFYWNoKHVwZGF0ZSA9PiB1cGRhdGUucGVyZm9ybSgpKVxuICAgICAgfSlcbiAgICB9XG5cbiAgICBsaXZlU29ja2V0LnNpbGVuY2VFdmVudHMoKCkgPT4gRE9NLnJlc3RvcmVGb2N1cyhmb2N1c2VkLCBzZWxlY3Rpb25TdGFydCwgc2VsZWN0aW9uRW5kKSlcbiAgICBET00uZGlzcGF0Y2hFdmVudChkb2N1bWVudCwgXCJwaHg6dXBkYXRlXCIpXG4gICAgYWRkZWQuZm9yRWFjaChlbCA9PiB0aGlzLnRyYWNrQWZ0ZXIoXCJhZGRlZFwiLCBlbCkpXG4gICAgdXBkYXRlcy5mb3JFYWNoKGVsID0+IHRoaXMudHJhY2tBZnRlcihcInVwZGF0ZWRcIiwgZWwpKVxuXG4gICAgdGhpcy50cmFuc2l0aW9uUGVuZGluZ1JlbW92ZXMoKVxuXG4gICAgaWYoZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkKXtcbiAgICAgIGxpdmVTb2NrZXQudW5sb2FkKClcbiAgICAgIC8vIGNoZWNrIGZvciBzdWJtaXR0ZXIgYW5kIGluamVjdCBpdCBhcyBoaWRkZW4gaW5wdXQgZm9yIGV4dGVybmFsIHN1Ym1pdDtcbiAgICAgIC8vIEluIHRoZW9yeSwgaXQgY291bGQgaGFwcGVuIHRoYXQgdGhlIHN0b3JlZCBzdWJtaXR0ZXIgaXMgb3V0ZGF0ZWQgYW5kIGRvZXNuJ3RcbiAgICAgIC8vIGV4aXN0IGluIHRoZSBET00gYW55IG1vcmUsIGJ1dCB0aGlzIGlzIHVubGlrZWx5LCBzbyB3ZSBqdXN0IGFjY2VwdCBpdCBmb3Igbm93LlxuICAgICAgY29uc3Qgc3VibWl0dGVyID0gRE9NLnByaXZhdGUoZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkLCBcInN1Ym1pdHRlclwiKVxuICAgICAgaWYoc3VibWl0dGVyICYmIHN1Ym1pdHRlci5uYW1lICYmIHRhcmdldENvbnRhaW5lci5jb250YWlucyhzdWJtaXR0ZXIpKXtcbiAgICAgICAgY29uc3QgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIilcbiAgICAgICAgaW5wdXQudHlwZSA9IFwiaGlkZGVuXCJcbiAgICAgICAgY29uc3QgZm9ybUlkID0gc3VibWl0dGVyLmdldEF0dHJpYnV0ZShcImZvcm1cIilcbiAgICAgICAgaWYoZm9ybUlkKXtcbiAgICAgICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoXCJmb3JtXCIsIGZvcm1JZClcbiAgICAgICAgfVxuICAgICAgICBpbnB1dC5uYW1lID0gc3VibWl0dGVyLm5hbWVcbiAgICAgICAgaW5wdXQudmFsdWUgPSBzdWJtaXR0ZXIudmFsdWVcbiAgICAgICAgc3VibWl0dGVyLnBhcmVudEVsZW1lbnQuaW5zZXJ0QmVmb3JlKGlucHV0LCBzdWJtaXR0ZXIpXG4gICAgICB9XG4gICAgICAvLyB1c2UgcHJvdG90eXBlJ3Mgc3VibWl0IGluIGNhc2UgdGhlcmUncyBhIGZvcm0gY29udHJvbCB3aXRoIG5hbWUgb3IgaWQgb2YgXCJzdWJtaXRcIlxuICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0hUTUxGb3JtRWxlbWVudC9zdWJtaXRcbiAgICAgIE9iamVjdC5nZXRQcm90b3R5cGVPZihleHRlcm5hbEZvcm1UcmlnZ2VyZWQpLnN1Ym1pdC5jYWxsKGV4dGVybmFsRm9ybVRyaWdnZXJlZClcbiAgICB9XG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIG9uTm9kZURpc2NhcmRlZChlbCl7XG4gICAgLy8gbmVzdGVkIHZpZXcgaGFuZGxpbmdcbiAgICBpZihET00uaXNQaHhDaGlsZChlbCkgfHwgRE9NLmlzUGh4U3RpY2t5KGVsKSl7IHRoaXMubGl2ZVNvY2tldC5kZXN0cm95Vmlld0J5RWwoZWwpIH1cbiAgICB0aGlzLnRyYWNrQWZ0ZXIoXCJkaXNjYXJkZWRcIiwgZWwpXG4gIH1cblxuICBtYXliZVBlbmRpbmdSZW1vdmUobm9kZSl7XG4gICAgaWYobm9kZS5nZXRBdHRyaWJ1dGUgJiYgbm9kZS5nZXRBdHRyaWJ1dGUodGhpcy5waHhSZW1vdmUpICE9PSBudWxsKXtcbiAgICAgIHRoaXMucGVuZGluZ1JlbW92ZXMucHVzaChub2RlKVxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlU3RyZWFtQ2hpbGRFbGVtZW50KGNoaWxkLCBmb3JjZT1mYWxzZSl7XG4gICAgLy8gbWFrZSBzdXJlIHRvIG9ubHkgcmVtb3ZlIGVsZW1lbnRzIG93bmVkIGJ5IHRoZSBjdXJyZW50IHZpZXdcbiAgICAvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3Bob2VuaXhmcmFtZXdvcmsvcGhvZW5peF9saXZlX3ZpZXcvaXNzdWVzLzMwNDdcbiAgICAvLyBhbmQgaHR0cHM6Ly9naXRodWIuY29tL3Bob2VuaXhmcmFtZXdvcmsvcGhvZW5peF9saXZlX3ZpZXcvaXNzdWVzLzM2ODFcbiAgICBpZighZm9yY2UgJiYgIXRoaXMudmlldy5vd25zRWxlbWVudChjaGlsZCkpeyByZXR1cm4gfVxuXG4gICAgLy8gd2UgbmVlZCB0byBzdG9yZSB0aGUgbm9kZSBpZiBpdCBpcyBhY3R1YWxseSByZS1hZGRlZCBpbiB0aGUgc2FtZSBwYXRjaFxuICAgIC8vIHdlIGRvIE5PVCB3YW50IHRvIGV4ZWN1dGUgcGh4LXJlbW92ZSwgd2UgZG8gTk9UIHdhbnQgdG8gY2FsbCBvbk5vZGVEaXNjYXJkZWRcbiAgICBpZih0aGlzLnN0cmVhbUluc2VydHNbY2hpbGQuaWRdKXtcbiAgICAgIHRoaXMuc3RyZWFtQ29tcG9uZW50UmVzdG9yZVtjaGlsZC5pZF0gPSBjaGlsZFxuICAgICAgY2hpbGQucmVtb3ZlKClcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gb25seSByZW1vdmUgdGhlIGVsZW1lbnQgbm93IGlmIGl0IGhhcyBubyBwaHgtcmVtb3ZlIGJpbmRpbmdcbiAgICAgIGlmKCF0aGlzLm1heWJlUGVuZGluZ1JlbW92ZShjaGlsZCkpe1xuICAgICAgICBjaGlsZC5yZW1vdmUoKVxuICAgICAgICB0aGlzLm9uTm9kZURpc2NhcmRlZChjaGlsZClcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRTdHJlYW1JbnNlcnQoZWwpe1xuICAgIGxldCBpbnNlcnQgPSBlbC5pZCA/IHRoaXMuc3RyZWFtSW5zZXJ0c1tlbC5pZF0gOiB7fVxuICAgIHJldHVybiBpbnNlcnQgfHwge31cbiAgfVxuXG4gIHNldFN0cmVhbVJlZihlbCwgcmVmKXtcbiAgICBET00ucHV0U3RpY2t5KGVsLCBQSFhfU1RSRUFNX1JFRiwgZWwgPT4gZWwuc2V0QXR0cmlidXRlKFBIWF9TVFJFQU1fUkVGLCByZWYpKVxuICB9XG5cbiAgbWF5YmVSZU9yZGVyU3RyZWFtKGVsLCBpc05ldyl7XG4gICAgbGV0IHtyZWYsIHN0cmVhbUF0LCByZXNldH0gPSB0aGlzLmdldFN0cmVhbUluc2VydChlbClcbiAgICBpZihzdHJlYW1BdCA9PT0gdW5kZWZpbmVkKXsgcmV0dXJuIH1cblxuICAgIC8vIHdlIG5lZWQgdG8gc2V0IHRoZSBQSFhfU1RSRUFNX1JFRiBoZXJlIGFzIHdlbGwgYXMgYWRkQ2hpbGQgaXMgaW52b2tlZCBvbmx5IGZvciBwYXJlbnRzXG4gICAgdGhpcy5zZXRTdHJlYW1SZWYoZWwsIHJlZilcblxuICAgIGlmKCFyZXNldCAmJiAhaXNOZXcpe1xuICAgICAgLy8gd2Ugb25seSByZW9yZGVyIGlmIHRoZSBlbGVtZW50IGlzIG5ldyBvciBpdCdzIGEgc3RyZWFtIHJlc2V0XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBjaGVjayBpZiB0aGUgZWxlbWVudCBoYXMgYSBwYXJlbnQgZWxlbWVudDtcbiAgICAvLyBpdCBkb2Vzbid0IGlmIHdlIGFyZSBjdXJyZW50bHkgcmVjdXJzaXZlbHkgbW9ycGhpbmcgKHJlc3RvcmluZyBhIHNhdmVkIHN0cmVhbSBjaGlsZClcbiAgICAvLyBiZWNhdXNlIHRoZSBlbGVtZW50IGlzIG5vdCB5ZXQgYWRkZWQgdG8gdGhlIHJlYWwgZG9tO1xuICAgIC8vIHJlb3JkZXJpbmcgZG9lcyBub3QgbWFrZSBzZW5zZSBpbiB0aGF0IGNhc2UgYW55d2F5XG4gICAgaWYoIWVsLnBhcmVudEVsZW1lbnQpeyByZXR1cm4gfVxuXG4gICAgaWYoc3RyZWFtQXQgPT09IDApe1xuICAgICAgZWwucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUoZWwsIGVsLnBhcmVudEVsZW1lbnQuZmlyc3RFbGVtZW50Q2hpbGQpXG4gICAgfSBlbHNlIGlmKHN0cmVhbUF0ID4gMCl7XG4gICAgICBsZXQgY2hpbGRyZW4gPSBBcnJheS5mcm9tKGVsLnBhcmVudEVsZW1lbnQuY2hpbGRyZW4pXG4gICAgICBsZXQgb2xkSW5kZXggPSBjaGlsZHJlbi5pbmRleE9mKGVsKVxuICAgICAgaWYoc3RyZWFtQXQgPj0gY2hpbGRyZW4ubGVuZ3RoIC0gMSl7XG4gICAgICAgIGVsLnBhcmVudEVsZW1lbnQuYXBwZW5kQ2hpbGQoZWwpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgc2libGluZyA9IGNoaWxkcmVuW3N0cmVhbUF0XVxuICAgICAgICBpZihvbGRJbmRleCA+IHN0cmVhbUF0KXtcbiAgICAgICAgICBlbC5wYXJlbnRFbGVtZW50Lmluc2VydEJlZm9yZShlbCwgc2libGluZylcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlbC5wYXJlbnRFbGVtZW50Lmluc2VydEJlZm9yZShlbCwgc2libGluZy5uZXh0RWxlbWVudFNpYmxpbmcpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLm1heWJlTGltaXRTdHJlYW0oZWwpXG4gIH1cblxuICBtYXliZUxpbWl0U3RyZWFtKGVsKXtcbiAgICBsZXQge2xpbWl0fSA9IHRoaXMuZ2V0U3RyZWFtSW5zZXJ0KGVsKVxuICAgIGxldCBjaGlsZHJlbiA9IGxpbWl0ICE9PSBudWxsICYmIEFycmF5LmZyb20oZWwucGFyZW50RWxlbWVudC5jaGlsZHJlbilcbiAgICBpZihsaW1pdCAmJiBsaW1pdCA8IDAgJiYgY2hpbGRyZW4ubGVuZ3RoID4gbGltaXQgKiAtMSl7XG4gICAgICBjaGlsZHJlbi5zbGljZSgwLCBjaGlsZHJlbi5sZW5ndGggKyBsaW1pdCkuZm9yRWFjaChjaGlsZCA9PiB0aGlzLnJlbW92ZVN0cmVhbUNoaWxkRWxlbWVudChjaGlsZCkpXG4gICAgfSBlbHNlIGlmKGxpbWl0ICYmIGxpbWl0ID49IDAgJiYgY2hpbGRyZW4ubGVuZ3RoID4gbGltaXQpe1xuICAgICAgY2hpbGRyZW4uc2xpY2UobGltaXQpLmZvckVhY2goY2hpbGQgPT4gdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQpKVxuICAgIH1cbiAgfVxuXG4gIHRyYW5zaXRpb25QZW5kaW5nUmVtb3Zlcygpe1xuICAgIGxldCB7cGVuZGluZ1JlbW92ZXMsIGxpdmVTb2NrZXR9ID0gdGhpc1xuICAgIGlmKHBlbmRpbmdSZW1vdmVzLmxlbmd0aCA+IDApe1xuICAgICAgbGl2ZVNvY2tldC50cmFuc2l0aW9uUmVtb3ZlcyhwZW5kaW5nUmVtb3ZlcywgKCkgPT4ge1xuICAgICAgICBwZW5kaW5nUmVtb3Zlcy5mb3JFYWNoKGVsID0+IHtcbiAgICAgICAgICBsZXQgY2hpbGQgPSBET00uZmlyc3RQaHhDaGlsZChlbClcbiAgICAgICAgICBpZihjaGlsZCl7IGxpdmVTb2NrZXQuZGVzdHJveVZpZXdCeUVsKGNoaWxkKSB9XG4gICAgICAgICAgZWwucmVtb3ZlKClcbiAgICAgICAgfSlcbiAgICAgICAgdGhpcy50cmFja0FmdGVyKFwidHJhbnNpdGlvbnNEaXNjYXJkZWRcIiwgcGVuZGluZ1JlbW92ZXMpXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGlzQ2hhbmdlZFNlbGVjdChmcm9tRWwsIHRvRWwpe1xuICAgIGlmKCEoZnJvbUVsIGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQpIHx8IGZyb21FbC5tdWx0aXBsZSl7IHJldHVybiBmYWxzZSB9XG4gICAgaWYoZnJvbUVsLm9wdGlvbnMubGVuZ3RoICE9PSB0b0VsLm9wdGlvbnMubGVuZ3RoKXsgcmV0dXJuIHRydWUgfVxuXG4gICAgLy8ga2VlcCB0aGUgY3VycmVudCB2YWx1ZVxuICAgIHRvRWwudmFsdWUgPSBmcm9tRWwudmFsdWVcblxuICAgIC8vIGluIGdlbmVyYWwgd2UgaGF2ZSB0byBiZSB2ZXJ5IGNhcmVmdWwgd2l0aCB1c2luZyBpc0VxdWFsTm9kZSBhcyBpdCBkb2VzIG5vdCBhIHJlbGlhYmxlXG4gICAgLy8gRE9NIHRyZWUgZXF1YWxpdHkgY2hlY2ssIGJ1dCBmb3Igc2VsZWN0aW9uIGF0dHJpYnV0ZXMgYW5kIG9wdGlvbnMgaXQgd29ya3MgZmluZVxuICAgIHJldHVybiAhZnJvbUVsLmlzRXF1YWxOb2RlKHRvRWwpXG4gIH1cblxuICBpc0NJRFBhdGNoKCl7IHJldHVybiB0aGlzLmNpZFBhdGNoIH1cblxuICBza2lwQ0lEU2libGluZyhlbCl7XG4gICAgcmV0dXJuIGVsLm5vZGVUeXBlID09PSBOb2RlLkVMRU1FTlRfTk9ERSAmJiBlbC5oYXNBdHRyaWJ1dGUoUEhYX1NLSVApXG4gIH1cblxuICB0YXJnZXRDSURDb250YWluZXIoaHRtbCl7XG4gICAgaWYoIXRoaXMuaXNDSURQYXRjaCgpKXsgcmV0dXJuIH1cbiAgICBsZXQgW2ZpcnN0LCAuLi5yZXN0XSA9IERPTS5maW5kQ29tcG9uZW50Tm9kZUxpc3QodGhpcy5jb250YWluZXIsIHRoaXMudGFyZ2V0Q0lEKVxuICAgIGlmKHJlc3QubGVuZ3RoID09PSAwICYmIERPTS5jaGlsZE5vZGVMZW5ndGgoaHRtbCkgPT09IDEpe1xuICAgICAgcmV0dXJuIGZpcnN0XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmaXJzdCAmJiBmaXJzdC5wYXJlbnROb2RlXG4gICAgfVxuICB9XG5cbiAgaW5kZXhPZihwYXJlbnQsIGNoaWxkKXsgcmV0dXJuIEFycmF5LmZyb20ocGFyZW50LmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKSB9XG59XG4iLCAiaW1wb3J0IHtcbiAgQ09NUE9ORU5UUyxcbiAgRFlOQU1JQ1MsXG4gIFRFTVBMQVRFUyxcbiAgRVZFTlRTLFxuICBQSFhfQ09NUE9ORU5ULFxuICBQSFhfU0tJUCxcbiAgUEhYX01BR0lDX0lELFxuICBSRVBMWSxcbiAgU1RBVElDLFxuICBUSVRMRSxcbiAgU1RSRUFNLFxuICBST09ULFxufSBmcm9tIFwiLi9jb25zdGFudHNcIlxuXG5pbXBvcnQge1xuICBpc09iamVjdCxcbiAgbG9nRXJyb3IsXG4gIGlzQ2lkLFxufSBmcm9tIFwiLi91dGlsc1wiXG5cbmNvbnN0IFZPSURfVEFHUyA9IG5ldyBTZXQoW1xuICBcImFyZWFcIixcbiAgXCJiYXNlXCIsXG4gIFwiYnJcIixcbiAgXCJjb2xcIixcbiAgXCJjb21tYW5kXCIsXG4gIFwiZW1iZWRcIixcbiAgXCJoclwiLFxuICBcImltZ1wiLFxuICBcImlucHV0XCIsXG4gIFwia2V5Z2VuXCIsXG4gIFwibGlua1wiLFxuICBcIm1ldGFcIixcbiAgXCJwYXJhbVwiLFxuICBcInNvdXJjZVwiLFxuICBcInRyYWNrXCIsXG4gIFwid2JyXCJcbl0pXG5jb25zdCBxdW90ZUNoYXJzID0gbmV3IFNldChbXCInXCIsIFwiXFxcIlwiXSlcblxuZXhwb3J0IGxldCBtb2RpZnlSb290ID0gKGh0bWwsIGF0dHJzLCBjbGVhcklubmVySFRNTCkgPT4ge1xuICBsZXQgaSA9IDBcbiAgbGV0IGluc2lkZUNvbW1lbnQgPSBmYWxzZVxuICBsZXQgYmVmb3JlVGFnLCBhZnRlclRhZywgdGFnLCB0YWdOYW1lRW5kc0F0LCBpZCwgbmV3SFRNTFxuXG4gIGxldCBsb29rYWhlYWQgPSBodG1sLm1hdGNoKC9eKFxccyooPzo8IS0tLio/LS0+XFxzKikqKTwoW15cXHNcXC8+XSspLylcbiAgaWYobG9va2FoZWFkID09PSBudWxsKXsgdGhyb3cgbmV3IEVycm9yKGBtYWxmb3JtZWQgaHRtbCAke2h0bWx9YCkgfVxuXG4gIGkgPSBsb29rYWhlYWRbMF0ubGVuZ3RoXG4gIGJlZm9yZVRhZyA9IGxvb2thaGVhZFsxXVxuICB0YWcgPSBsb29rYWhlYWRbMl1cbiAgdGFnTmFtZUVuZHNBdCA9IGlcblxuICAvLyBTY2FuIHRoZSBvcGVuaW5nIHRhZyBmb3IgaWQsIGlmIHRoZXJlIGlzIGFueVxuICBmb3IoaTsgaSA8IGh0bWwubGVuZ3RoOyBpKyspe1xuICAgIGlmKGh0bWwuY2hhckF0KGkpID09PSBcIj5cIiApeyBicmVhayB9XG4gICAgaWYoaHRtbC5jaGFyQXQoaSkgPT09IFwiPVwiKXtcbiAgICAgIGxldCBpc0lkID0gaHRtbC5zbGljZShpIC0gMywgaSkgPT09IFwiIGlkXCJcbiAgICAgIGkrK1xuICAgICAgbGV0IGNoYXIgPSBodG1sLmNoYXJBdChpKVxuICAgICAgaWYocXVvdGVDaGFycy5oYXMoY2hhcikpe1xuICAgICAgICBsZXQgYXR0clN0YXJ0c0F0ID0gaVxuICAgICAgICBpKytcbiAgICAgICAgZm9yKGk7IGkgPCBodG1sLmxlbmd0aDsgaSsrKXtcbiAgICAgICAgICBpZihodG1sLmNoYXJBdChpKSA9PT0gY2hhcil7IGJyZWFrIH1cbiAgICAgICAgfVxuICAgICAgICBpZihpc0lkKXtcbiAgICAgICAgICBpZCA9IGh0bWwuc2xpY2UoYXR0clN0YXJ0c0F0ICsgMSwgaSlcbiAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgbGV0IGNsb3NlQXQgPSBodG1sLmxlbmd0aCAtIDFcbiAgaW5zaWRlQ29tbWVudCA9IGZhbHNlXG4gIHdoaWxlKGNsb3NlQXQgPj0gYmVmb3JlVGFnLmxlbmd0aCArIHRhZy5sZW5ndGgpe1xuICAgIGxldCBjaGFyID0gaHRtbC5jaGFyQXQoY2xvc2VBdClcbiAgICBpZihpbnNpZGVDb21tZW50KXtcbiAgICAgIGlmKGNoYXIgPT09IFwiLVwiICYmIGh0bWwuc2xpY2UoY2xvc2VBdCAtIDMsIGNsb3NlQXQpID09PSBcIjwhLVwiKXtcbiAgICAgICAgaW5zaWRlQ29tbWVudCA9IGZhbHNlXG4gICAgICAgIGNsb3NlQXQgLT0gNFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2xvc2VBdCAtPSAxXG4gICAgICB9XG4gICAgfSBlbHNlIGlmKGNoYXIgPT09IFwiPlwiICYmIGh0bWwuc2xpY2UoY2xvc2VBdCAtIDIsIGNsb3NlQXQpID09PSBcIi0tXCIpe1xuICAgICAgaW5zaWRlQ29tbWVudCA9IHRydWVcbiAgICAgIGNsb3NlQXQgLT0gM1xuICAgIH0gZWxzZSBpZihjaGFyID09PSBcIj5cIil7XG4gICAgICBicmVha1xuICAgIH0gZWxzZSB7XG4gICAgICBjbG9zZUF0IC09IDFcbiAgICB9XG4gIH1cbiAgYWZ0ZXJUYWcgPSBodG1sLnNsaWNlKGNsb3NlQXQgKyAxLCBodG1sLmxlbmd0aClcblxuICBsZXQgYXR0cnNTdHIgPVxuICAgIE9iamVjdC5rZXlzKGF0dHJzKVxuICAgICAgLm1hcChhdHRyID0+IGF0dHJzW2F0dHJdID09PSB0cnVlID8gYXR0ciA6IGAke2F0dHJ9PVwiJHthdHRyc1thdHRyXX1cImApXG4gICAgICAuam9pbihcIiBcIilcblxuICBpZihjbGVhcklubmVySFRNTCl7XG4gICAgLy8gS2VlcCB0aGUgaWQgaWYgYW55XG4gICAgbGV0IGlkQXR0clN0ciA9IGlkID8gYCBpZD1cIiR7aWR9XCJgIDogXCJcIlxuICAgIGlmKFZPSURfVEFHUy5oYXModGFnKSl7XG4gICAgICBuZXdIVE1MID0gYDwke3RhZ30ke2lkQXR0clN0cn0ke2F0dHJzU3RyID09PSBcIlwiID8gXCJcIiA6IFwiIFwifSR7YXR0cnNTdHJ9Lz5gXG4gICAgfSBlbHNlIHtcbiAgICAgIG5ld0hUTUwgPSBgPCR7dGFnfSR7aWRBdHRyU3RyfSR7YXR0cnNTdHIgPT09IFwiXCIgPyBcIlwiIDogXCIgXCJ9JHthdHRyc1N0cn0+PC8ke3RhZ30+YFxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBsZXQgcmVzdCA9IGh0bWwuc2xpY2UodGFnTmFtZUVuZHNBdCwgY2xvc2VBdCArIDEpXG4gICAgbmV3SFRNTCA9IGA8JHt0YWd9JHthdHRyc1N0ciA9PT0gXCJcIiA/IFwiXCIgOiBcIiBcIn0ke2F0dHJzU3RyfSR7cmVzdH1gXG4gIH1cblxuICByZXR1cm4gW25ld0hUTUwsIGJlZm9yZVRhZywgYWZ0ZXJUYWddXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJlbmRlcmVkIHtcbiAgc3RhdGljIGV4dHJhY3QoZGlmZil7XG4gICAgbGV0IHtbUkVQTFldOiByZXBseSwgW0VWRU5UU106IGV2ZW50cywgW1RJVExFXTogdGl0bGV9ID0gZGlmZlxuICAgIGRlbGV0ZSBkaWZmW1JFUExZXVxuICAgIGRlbGV0ZSBkaWZmW0VWRU5UU11cbiAgICBkZWxldGUgZGlmZltUSVRMRV1cbiAgICByZXR1cm4ge2RpZmYsIHRpdGxlLCByZXBseTogcmVwbHkgfHwgbnVsbCwgZXZlbnRzOiBldmVudHMgfHwgW119XG4gIH1cblxuICBjb25zdHJ1Y3Rvcih2aWV3SWQsIHJlbmRlcmVkKXtcbiAgICB0aGlzLnZpZXdJZCA9IHZpZXdJZFxuICAgIHRoaXMucmVuZGVyZWQgPSB7fVxuICAgIHRoaXMubWFnaWNJZCA9IDBcbiAgICB0aGlzLm1lcmdlRGlmZihyZW5kZXJlZClcbiAgfVxuXG4gIHBhcmVudFZpZXdJZCgpeyByZXR1cm4gdGhpcy52aWV3SWQgfVxuXG4gIHRvU3RyaW5nKG9ubHlDaWRzKXtcbiAgICBsZXQgW3N0ciwgc3RyZWFtc10gPSB0aGlzLnJlY3Vyc2l2ZVRvU3RyaW5nKHRoaXMucmVuZGVyZWQsIHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU10sIG9ubHlDaWRzLCB0cnVlLCB7fSlcbiAgICByZXR1cm4gW3N0ciwgc3RyZWFtc11cbiAgfVxuXG4gIHJlY3Vyc2l2ZVRvU3RyaW5nKHJlbmRlcmVkLCBjb21wb25lbnRzID0gcmVuZGVyZWRbQ09NUE9ORU5UU10sIG9ubHlDaWRzLCBjaGFuZ2VUcmFja2luZywgcm9vdEF0dHJzKXtcbiAgICBvbmx5Q2lkcyA9IG9ubHlDaWRzID8gbmV3IFNldChvbmx5Q2lkcykgOiBudWxsXG4gICAgbGV0IG91dHB1dCA9IHtidWZmZXI6IFwiXCIsIGNvbXBvbmVudHM6IGNvbXBvbmVudHMsIG9ubHlDaWRzOiBvbmx5Q2lkcywgc3RyZWFtczogbmV3IFNldCgpfVxuICAgIHRoaXMudG9PdXRwdXRCdWZmZXIocmVuZGVyZWQsIG51bGwsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcsIHJvb3RBdHRycylcbiAgICByZXR1cm4gW291dHB1dC5idWZmZXIsIG91dHB1dC5zdHJlYW1zXVxuICB9XG5cbiAgY29tcG9uZW50Q0lEcyhkaWZmKXsgcmV0dXJuIE9iamVjdC5rZXlzKGRpZmZbQ09NUE9ORU5UU10gfHwge30pLm1hcChpID0+IHBhcnNlSW50KGkpKSB9XG5cbiAgaXNDb21wb25lbnRPbmx5RGlmZihkaWZmKXtcbiAgICBpZighZGlmZltDT01QT05FTlRTXSl7IHJldHVybiBmYWxzZSB9XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKGRpZmYpLmxlbmd0aCA9PT0gMVxuICB9XG5cbiAgZ2V0Q29tcG9uZW50KGRpZmYsIGNpZCl7IHJldHVybiBkaWZmW0NPTVBPTkVOVFNdW2NpZF0gfVxuXG4gIHJlc2V0UmVuZGVyKGNpZCl7XG4gICAgLy8gd2UgYXJlIHJhY2luZyBhIGNvbXBvbmVudCBkZXN0cm95LCBpdCBjb3VsZCBub3QgZXhpc3QsIHNvXG4gICAgLy8gbWFrZSBzdXJlIHRoYXQgd2UgZG9uJ3QgdHJ5IHRvIHNldCByZXNldCBvbiB1bmRlZmluZWRcbiAgICBpZih0aGlzLnJlbmRlcmVkW0NPTVBPTkVOVFNdW2NpZF0pe1xuICAgICAgdGhpcy5yZW5kZXJlZFtDT01QT05FTlRTXVtjaWRdLnJlc2V0ID0gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIG1lcmdlRGlmZihkaWZmKXtcbiAgICBsZXQgbmV3YyA9IGRpZmZbQ09NUE9ORU5UU11cbiAgICBsZXQgY2FjaGUgPSB7fVxuICAgIGRlbGV0ZSBkaWZmW0NPTVBPTkVOVFNdXG4gICAgdGhpcy5yZW5kZXJlZCA9IHRoaXMubXV0YWJsZU1lcmdlKHRoaXMucmVuZGVyZWQsIGRpZmYpXG4gICAgdGhpcy5yZW5kZXJlZFtDT01QT05FTlRTXSA9IHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU10gfHwge31cblxuICAgIGlmKG5ld2Mpe1xuICAgICAgbGV0IG9sZGMgPSB0aGlzLnJlbmRlcmVkW0NPTVBPTkVOVFNdXG5cbiAgICAgIGZvcihsZXQgY2lkIGluIG5ld2Mpe1xuICAgICAgICBuZXdjW2NpZF0gPSB0aGlzLmNhY2hlZEZpbmRDb21wb25lbnQoY2lkLCBuZXdjW2NpZF0sIG9sZGMsIG5ld2MsIGNhY2hlKVxuICAgICAgfVxuXG4gICAgICBmb3IobGV0IGNpZCBpbiBuZXdjKXsgb2xkY1tjaWRdID0gbmV3Y1tjaWRdIH1cbiAgICAgIGRpZmZbQ09NUE9ORU5UU10gPSBuZXdjXG4gICAgfVxuICB9XG5cbiAgY2FjaGVkRmluZENvbXBvbmVudChjaWQsIGNkaWZmLCBvbGRjLCBuZXdjLCBjYWNoZSl7XG4gICAgaWYoY2FjaGVbY2lkXSl7XG4gICAgICByZXR1cm4gY2FjaGVbY2lkXVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgbmRpZmYsIHN0YXQsIHNjaWQgPSBjZGlmZltTVEFUSUNdXG5cbiAgICAgIGlmKGlzQ2lkKHNjaWQpKXtcbiAgICAgICAgbGV0IHRkaWZmXG5cbiAgICAgICAgaWYoc2NpZCA+IDApe1xuICAgICAgICAgIHRkaWZmID0gdGhpcy5jYWNoZWRGaW5kQ29tcG9uZW50KHNjaWQsIG5ld2Nbc2NpZF0sIG9sZGMsIG5ld2MsIGNhY2hlKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRkaWZmID0gb2xkY1stc2NpZF1cbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXQgPSB0ZGlmZltTVEFUSUNdXG4gICAgICAgIG5kaWZmID0gdGhpcy5jbG9uZU1lcmdlKHRkaWZmLCBjZGlmZiwgdHJ1ZSlcbiAgICAgICAgbmRpZmZbU1RBVElDXSA9IHN0YXRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5kaWZmID0gY2RpZmZbU1RBVElDXSAhPT0gdW5kZWZpbmVkIHx8IG9sZGNbY2lkXSA9PT0gdW5kZWZpbmVkID9cbiAgICAgICAgICBjZGlmZiA6IHRoaXMuY2xvbmVNZXJnZShvbGRjW2NpZF0sIGNkaWZmLCBmYWxzZSlcbiAgICAgIH1cblxuICAgICAgY2FjaGVbY2lkXSA9IG5kaWZmXG4gICAgICByZXR1cm4gbmRpZmZcbiAgICB9XG4gIH1cblxuICBtdXRhYmxlTWVyZ2UodGFyZ2V0LCBzb3VyY2Upe1xuICAgIGlmKHNvdXJjZVtTVEFUSUNdICE9PSB1bmRlZmluZWQpe1xuICAgICAgcmV0dXJuIHNvdXJjZVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRvTXV0YWJsZU1lcmdlKHRhcmdldCwgc291cmNlKVxuICAgICAgcmV0dXJuIHRhcmdldFxuICAgIH1cbiAgfVxuXG4gIGRvTXV0YWJsZU1lcmdlKHRhcmdldCwgc291cmNlKXtcbiAgICBmb3IobGV0IGtleSBpbiBzb3VyY2Upe1xuICAgICAgbGV0IHZhbCA9IHNvdXJjZVtrZXldXG4gICAgICBsZXQgdGFyZ2V0VmFsID0gdGFyZ2V0W2tleV1cbiAgICAgIGxldCBpc09ialZhbCA9IGlzT2JqZWN0KHZhbClcbiAgICAgIGlmKGlzT2JqVmFsICYmIHZhbFtTVEFUSUNdID09PSB1bmRlZmluZWQgJiYgaXNPYmplY3QodGFyZ2V0VmFsKSl7XG4gICAgICAgIHRoaXMuZG9NdXRhYmxlTWVyZ2UodGFyZ2V0VmFsLCB2YWwpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0YXJnZXRba2V5XSA9IHZhbFxuICAgICAgfVxuICAgIH1cbiAgICBpZih0YXJnZXRbUk9PVF0pe1xuICAgICAgdGFyZ2V0Lm5ld1JlbmRlciA9IHRydWVcbiAgICB9XG4gIH1cblxuICAvLyBNZXJnZXMgY2lkIHRyZWVzIHRvZ2V0aGVyLCBjb3B5aW5nIHN0YXRpY3MgZnJvbSBzb3VyY2UgdHJlZS5cbiAgLy9cbiAgLy8gVGhlIGBwcnVuZU1hZ2ljSWRgIGlzIHBhc3NlZCB0byBjb250cm9sIHBydW5pbmcgdGhlIG1hZ2ljSWQgb2YgdGhlXG4gIC8vIHRhcmdldC4gV2UgbXVzdCBhbHdheXMgcHJ1bmUgdGhlIG1hZ2ljSWQgd2hlbiB3ZSBhcmUgc2hhcmluZyBzdGF0aWNzXG4gIC8vIGZyb20gYW5vdGhlciBjb21wb25lbnQuIElmIG5vdCBwcnVuaW5nLCB3ZSByZXBsaWNhdGUgdGhlIGxvZ2ljIGZyb21cbiAgLy8gbXV0YWJsZU1lcmdlLCB3aGVyZSB3ZSBzZXQgbmV3UmVuZGVyIHRvIHRydWUgaWYgdGhlcmUgaXMgYSByb290XG4gIC8vIChlZmZlY3RpdmVseSBmb3JjaW5nIHRoZSBuZXcgdmVyc2lvbiB0byBiZSByZW5kZXJlZCBpbnN0ZWFkIG9mIHNraXBwZWQpXG4gIC8vXG4gIGNsb25lTWVyZ2UodGFyZ2V0LCBzb3VyY2UsIHBydW5lTWFnaWNJZCl7XG4gICAgbGV0IG1lcmdlZCA9IHsuLi50YXJnZXQsIC4uLnNvdXJjZX1cbiAgICBmb3IobGV0IGtleSBpbiBtZXJnZWQpe1xuICAgICAgbGV0IHZhbCA9IHNvdXJjZVtrZXldXG4gICAgICBsZXQgdGFyZ2V0VmFsID0gdGFyZ2V0W2tleV1cbiAgICAgIGlmKGlzT2JqZWN0KHZhbCkgJiYgdmFsW1NUQVRJQ10gPT09IHVuZGVmaW5lZCAmJiBpc09iamVjdCh0YXJnZXRWYWwpKXtcbiAgICAgICAgbWVyZ2VkW2tleV0gPSB0aGlzLmNsb25lTWVyZ2UodGFyZ2V0VmFsLCB2YWwsIHBydW5lTWFnaWNJZClcbiAgICAgIH0gZWxzZSBpZih2YWwgPT09IHVuZGVmaW5lZCAmJiBpc09iamVjdCh0YXJnZXRWYWwpKXtcbiAgICAgICAgbWVyZ2VkW2tleV0gPSB0aGlzLmNsb25lTWVyZ2UodGFyZ2V0VmFsLCB7fSwgcHJ1bmVNYWdpY0lkKVxuICAgICAgfVxuICAgIH1cbiAgICBpZihwcnVuZU1hZ2ljSWQpe1xuICAgICAgZGVsZXRlIG1lcmdlZC5tYWdpY0lkXG4gICAgICBkZWxldGUgbWVyZ2VkLm5ld1JlbmRlclxuICAgIH0gZWxzZSBpZih0YXJnZXRbUk9PVF0pe1xuICAgICAgbWVyZ2VkLm5ld1JlbmRlciA9IHRydWVcbiAgICB9XG4gICAgcmV0dXJuIG1lcmdlZFxuICB9XG5cbiAgY29tcG9uZW50VG9TdHJpbmcoY2lkKXtcbiAgICBsZXQgW3N0ciwgc3RyZWFtc10gPSB0aGlzLnJlY3Vyc2l2ZUNJRFRvU3RyaW5nKHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU10sIGNpZCwgbnVsbClcbiAgICBsZXQgW3N0cmlwcGVkSFRNTCwgX2JlZm9yZSwgX2FmdGVyXSA9IG1vZGlmeVJvb3Qoc3RyLCB7fSlcbiAgICByZXR1cm4gW3N0cmlwcGVkSFRNTCwgc3RyZWFtc11cbiAgfVxuXG4gIHBydW5lQ0lEcyhjaWRzKXtcbiAgICBjaWRzLmZvckVhY2goY2lkID0+IGRlbGV0ZSB0aGlzLnJlbmRlcmVkW0NPTVBPTkVOVFNdW2NpZF0pXG4gIH1cblxuICAvLyBwcml2YXRlXG5cbiAgZ2V0KCl7IHJldHVybiB0aGlzLnJlbmRlcmVkIH1cblxuICBpc05ld0ZpbmdlcnByaW50KGRpZmYgPSB7fSl7IHJldHVybiAhIWRpZmZbU1RBVElDXSB9XG5cbiAgdGVtcGxhdGVTdGF0aWMocGFydCwgdGVtcGxhdGVzKXtcbiAgICBpZih0eXBlb2YgKHBhcnQpID09PSBcIm51bWJlclwiKXtcbiAgICAgIHJldHVybiB0ZW1wbGF0ZXNbcGFydF1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHBhcnRcbiAgICB9XG4gIH1cblxuICBuZXh0TWFnaWNJRCgpe1xuICAgIHRoaXMubWFnaWNJZCsrXG4gICAgcmV0dXJuIGBtJHt0aGlzLm1hZ2ljSWR9LSR7dGhpcy5wYXJlbnRWaWV3SWQoKX1gXG4gIH1cblxuICAvLyBDb252ZXJ0cyByZW5kZXJlZCB0cmVlIHRvIG91dHB1dCBidWZmZXIuXG4gIC8vXG4gIC8vIGNoYW5nZVRyYWNraW5nIGNvbnRyb2xzIGlmIHdlIGNhbiBhcHBseSB0aGUgUEhYX1NLSVAgb3B0aW1pemF0aW9uLlxuICAvLyBJdCBpcyBkaXNhYmxlZCBmb3IgY29tcHJlaGVuc2lvbnMgc2luY2Ugd2UgbXVzdCByZS1yZW5kZXIgdGhlIGVudGlyZSBjb2xsZWN0aW9uXG4gIC8vIGFuZCBubyBpbmRpdmlkdWFsIGVsZW1lbnQgaXMgdHJhY2tlZCBpbnNpZGUgdGhlIGNvbXByZWhlbnNpb24uXG4gIHRvT3V0cHV0QnVmZmVyKHJlbmRlcmVkLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcsIHJvb3RBdHRycyA9IHt9KXtcbiAgICBpZihyZW5kZXJlZFtEWU5BTUlDU10peyByZXR1cm4gdGhpcy5jb21wcmVoZW5zaW9uVG9CdWZmZXIocmVuZGVyZWQsIHRlbXBsYXRlcywgb3V0cHV0KSB9XG4gICAgbGV0IHtbU1RBVElDXTogc3RhdGljc30gPSByZW5kZXJlZFxuICAgIHN0YXRpY3MgPSB0aGlzLnRlbXBsYXRlU3RhdGljKHN0YXRpY3MsIHRlbXBsYXRlcylcbiAgICBsZXQgaXNSb290ID0gcmVuZGVyZWRbUk9PVF1cbiAgICBsZXQgcHJldkJ1ZmZlciA9IG91dHB1dC5idWZmZXJcbiAgICBpZihpc1Jvb3QpeyBvdXRwdXQuYnVmZmVyID0gXCJcIiB9XG5cbiAgICAvLyB0aGlzIGNvbmRpdGlvbiBpcyBjYWxsZWQgd2hlbiBmaXJzdCByZW5kZXJpbmcgYW4gb3B0aW1pemFibGUgZnVuY3Rpb24gY29tcG9uZW50LlxuICAgIC8vIExDIGhhdmUgdGhlaXIgbWFnaWNJZCBwcmV2aW91c2x5IHNldFxuICAgIGlmKGNoYW5nZVRyYWNraW5nICYmIGlzUm9vdCAmJiAhcmVuZGVyZWQubWFnaWNJZCl7XG4gICAgICByZW5kZXJlZC5uZXdSZW5kZXIgPSB0cnVlXG4gICAgICByZW5kZXJlZC5tYWdpY0lkID0gdGhpcy5uZXh0TWFnaWNJRCgpXG4gICAgfVxuXG4gICAgb3V0cHV0LmJ1ZmZlciArPSBzdGF0aWNzWzBdXG4gICAgZm9yKGxldCBpID0gMTsgaSA8IHN0YXRpY3MubGVuZ3RoOyBpKyspe1xuICAgICAgdGhpcy5keW5hbWljVG9CdWZmZXIocmVuZGVyZWRbaSAtIDFdLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcpXG4gICAgICBvdXRwdXQuYnVmZmVyICs9IHN0YXRpY3NbaV1cbiAgICB9XG5cbiAgICAvLyBBcHBsaWVzIHRoZSByb290IHRhZyBcInNraXBcIiBvcHRpbWl6YXRpb24gaWYgc3VwcG9ydGVkLCB3aGljaCBjbGVhcnNcbiAgICAvLyB0aGUgcm9vdCB0YWcgYXR0cmlidXRlcyBhbmQgaW5uZXJIVE1MLCBhbmQgb25seSBtYWludGFpbnMgdGhlIG1hZ2ljSWQuXG4gICAgLy8gV2UgY2FuIG9ubHkgc2tpcCB3aGVuIGNoYW5nZVRyYWNraW5nIGlzIHN1cHBvcnRlZCAob3V0c2lkZSBvZiBhIGNvbXByZWhlbnNpb24pLFxuICAgIC8vIGFuZCB3aGVuIHRoZSByb290IGVsZW1lbnQgaGFzbid0IGV4cGVyaWVuY2VkIGFuIHVucmVuZGVyZWQgbWVyZ2UgKG5ld1JlbmRlciB0cnVlKS5cbiAgICBpZihpc1Jvb3Qpe1xuICAgICAgbGV0IHNraXAgPSBmYWxzZVxuICAgICAgbGV0IGF0dHJzXG4gICAgICAvLyBXaGVuIGEgTEMgaXMgcmUtYWRkZWQgdG8gdGhlIHBhZ2UsIHdlIG5lZWQgdG8gcmUtcmVuZGVyIHRoZSBlbnRpcmUgTEMgdHJlZSxcbiAgICAgIC8vIHRoZXJlZm9yZSBjaGFuZ2VUcmFja2luZyBpcyBmYWxzZTsgaG93ZXZlciwgd2UgbmVlZCB0byBrZWVwIGFsbCB0aGUgbWFnaWNJZHNcbiAgICAgIC8vIGZyb20gYW55IGZ1bmN0aW9uIGNvbXBvbmVudCBzbyB0aGUgbmV4dCB0aW1lIHRoZSBMQyBpcyB1cGRhdGVkLCB3ZSBjYW4gYXBwbHlcbiAgICAgIC8vIHRoZSBza2lwIG9wdGltaXphdGlvblxuICAgICAgaWYoY2hhbmdlVHJhY2tpbmcgfHwgcmVuZGVyZWQubWFnaWNJZCl7XG4gICAgICAgIHNraXAgPSBjaGFuZ2VUcmFja2luZyAmJiAhcmVuZGVyZWQubmV3UmVuZGVyXG4gICAgICAgIGF0dHJzID0ge1tQSFhfTUFHSUNfSURdOiByZW5kZXJlZC5tYWdpY0lkLCAuLi5yb290QXR0cnN9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhdHRycyA9IHJvb3RBdHRyc1xuICAgICAgfVxuICAgICAgaWYoc2tpcCl7IGF0dHJzW1BIWF9TS0lQXSA9IHRydWUgfVxuICAgICAgbGV0IFtuZXdSb290LCBjb21tZW50QmVmb3JlLCBjb21tZW50QWZ0ZXJdID0gbW9kaWZ5Um9vdChvdXRwdXQuYnVmZmVyLCBhdHRycywgc2tpcClcbiAgICAgIHJlbmRlcmVkLm5ld1JlbmRlciA9IGZhbHNlXG4gICAgICBvdXRwdXQuYnVmZmVyID0gcHJldkJ1ZmZlciArIGNvbW1lbnRCZWZvcmUgKyBuZXdSb290ICsgY29tbWVudEFmdGVyXG4gICAgfVxuICB9XG5cbiAgY29tcHJlaGVuc2lvblRvQnVmZmVyKHJlbmRlcmVkLCB0ZW1wbGF0ZXMsIG91dHB1dCl7XG4gICAgbGV0IHtbRFlOQU1JQ1NdOiBkeW5hbWljcywgW1NUQVRJQ106IHN0YXRpY3MsIFtTVFJFQU1dOiBzdHJlYW19ID0gcmVuZGVyZWRcbiAgICBsZXQgW19yZWYsIF9pbnNlcnRzLCBkZWxldGVJZHMsIHJlc2V0XSA9IHN0cmVhbSB8fCBbbnVsbCwge30sIFtdLCBudWxsXVxuICAgIHN0YXRpY3MgPSB0aGlzLnRlbXBsYXRlU3RhdGljKHN0YXRpY3MsIHRlbXBsYXRlcylcbiAgICBsZXQgY29tcFRlbXBsYXRlcyA9IHRlbXBsYXRlcyB8fCByZW5kZXJlZFtURU1QTEFURVNdXG4gICAgZm9yKGxldCBkID0gMDsgZCA8IGR5bmFtaWNzLmxlbmd0aDsgZCsrKXtcbiAgICAgIGxldCBkeW5hbWljID0gZHluYW1pY3NbZF1cbiAgICAgIG91dHB1dC5idWZmZXIgKz0gc3RhdGljc1swXVxuICAgICAgZm9yKGxldCBpID0gMTsgaSA8IHN0YXRpY3MubGVuZ3RoOyBpKyspe1xuICAgICAgICAvLyBJbnNpZGUgYSBjb21wcmVoZW5zaW9uLCB3ZSBkb24ndCB0cmFjayBob3cgZHluYW1pY3MgY2hhbmdlXG4gICAgICAgIC8vIG92ZXIgdGltZSAoYW5kIGZlYXR1cmVzIGxpa2Ugc3RyZWFtcyB3b3VsZCBtYWtlIHRoYXQgaW1wb3NzaWJsZVxuICAgICAgICAvLyB1bmxlc3Mgd2UgbW92ZSB0aGUgc3RyZWFtIGRpZmZpbmcgYXdheSBmcm9tIG1vcnBoZG9tKSxcbiAgICAgICAgLy8gc28gd2UgY2FuJ3QgcGVyZm9ybSByb290IGNoYW5nZSB0cmFja2luZy5cbiAgICAgICAgbGV0IGNoYW5nZVRyYWNraW5nID0gZmFsc2VcbiAgICAgICAgdGhpcy5keW5hbWljVG9CdWZmZXIoZHluYW1pY1tpIC0gMV0sIGNvbXBUZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcpXG4gICAgICAgIG91dHB1dC5idWZmZXIgKz0gc3RhdGljc1tpXVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmKHN0cmVhbSAhPT0gdW5kZWZpbmVkICYmIChyZW5kZXJlZFtEWU5BTUlDU10ubGVuZ3RoID4gMCB8fCBkZWxldGVJZHMubGVuZ3RoID4gMCB8fCByZXNldCkpe1xuICAgICAgZGVsZXRlIHJlbmRlcmVkW1NUUkVBTV1cbiAgICAgIHJlbmRlcmVkW0RZTkFNSUNTXSA9IFtdXG4gICAgICBvdXRwdXQuc3RyZWFtcy5hZGQoc3RyZWFtKVxuICAgIH1cbiAgfVxuXG4gIGR5bmFtaWNUb0J1ZmZlcihyZW5kZXJlZCwgdGVtcGxhdGVzLCBvdXRwdXQsIGNoYW5nZVRyYWNraW5nKXtcbiAgICBpZih0eXBlb2YgKHJlbmRlcmVkKSA9PT0gXCJudW1iZXJcIil7XG4gICAgICBsZXQgW3N0ciwgc3RyZWFtc10gPSB0aGlzLnJlY3Vyc2l2ZUNJRFRvU3RyaW5nKG91dHB1dC5jb21wb25lbnRzLCByZW5kZXJlZCwgb3V0cHV0Lm9ubHlDaWRzKVxuICAgICAgb3V0cHV0LmJ1ZmZlciArPSBzdHJcbiAgICAgIG91dHB1dC5zdHJlYW1zID0gbmV3IFNldChbLi4ub3V0cHV0LnN0cmVhbXMsIC4uLnN0cmVhbXNdKVxuICAgIH0gZWxzZSBpZihpc09iamVjdChyZW5kZXJlZCkpe1xuICAgICAgdGhpcy50b091dHB1dEJ1ZmZlcihyZW5kZXJlZCwgdGVtcGxhdGVzLCBvdXRwdXQsIGNoYW5nZVRyYWNraW5nLCB7fSlcbiAgICB9IGVsc2Uge1xuICAgICAgb3V0cHV0LmJ1ZmZlciArPSByZW5kZXJlZFxuICAgIH1cbiAgfVxuXG4gIHJlY3Vyc2l2ZUNJRFRvU3RyaW5nKGNvbXBvbmVudHMsIGNpZCwgb25seUNpZHMpe1xuICAgIGxldCBjb21wb25lbnQgPSBjb21wb25lbnRzW2NpZF0gfHwgbG9nRXJyb3IoYG5vIGNvbXBvbmVudCBmb3IgQ0lEICR7Y2lkfWAsIGNvbXBvbmVudHMpXG4gICAgbGV0IGF0dHJzID0ge1tQSFhfQ09NUE9ORU5UXTogY2lkfVxuICAgIGxldCBza2lwID0gb25seUNpZHMgJiYgIW9ubHlDaWRzLmhhcyhjaWQpXG4gICAgLy8gVHdvIG9wdGltaXphdGlvbiBwYXRocyBhcHBseSBoZXJlOlxuICAgIC8vXG4gICAgLy8gICAxLiBUaGUgb25seUNpZHMgb3B0aW1pemF0aW9uIHdvcmtzIGJ5IHRoZSBzZXJ2ZXIgZGlmZiB0ZWxsaW5nIHVzIG9ubHkgc3BlY2lmaWNcbiAgICAvLyAgICAgY2lkJ3MgaGF2ZSBjaGFuZ2VkLiBUaGlzIGFsbG93cyB1cyB0byBza2lwIHJlbmRlcmluZyBhbnkgY29tcG9uZW50IHRoYXQgaGFzbid0IGNoYW5nZWQsXG4gICAgLy8gICAgIHdoaWNoIHVsdGltYXRlbHkgc2V0cyBQSFhfU0tJUCByb290IGF0dHJpYnV0ZSBhbmQgYXZvaWRzIHJlbmRlcmluZyB0aGUgaW5uZXJIVE1MLlxuICAgIC8vXG4gICAgLy8gICAyLiBUaGUgcm9vdCBQSFhfU0tJUCBvcHRpbWl6YXRpb24gZ2VuZXJhbGl6ZXMgdG8gYWxsIEhFRXggZnVuY3Rpb24gY29tcG9uZW50cywgYW5kXG4gICAgLy8gICAgIHdvcmtzIGluIHRoZSBzYW1lIFBIWF9TS0lQIGF0dHJpYnV0ZSBmYXNoaW9uIGFzIDEsIGJ1dCB0aGUgbmV3UmVuZGVyIHRyYWNraW5nIGlzIGRvbmVcbiAgICAvLyAgICAgYXQgdGhlIGdlbmVyYWwgZGlmZiBtZXJnZSBsZXZlbC4gSWYgd2UgbWVyZ2UgYSBkaWZmIHdpdGggbmV3IGR5bmFtaWNzLCB3ZSBuZWNlc3NhcmlseSBoYXZlXG4gICAgLy8gICAgIGV4cGVyaWVuY2VkIGEgY2hhbmdlIHdoaWNoIG11c3QgYmUgYSBuZXdSZW5kZXIsIGFuZCB0aHVzIHdlIGNhbid0IHNraXAgdGhlIHJlbmRlci5cbiAgICAvL1xuICAgIC8vIEJvdGggb3B0aW1pemF0aW9uIGZsb3dzIGFwcGx5IGhlcmUuIG5ld1JlbmRlciBpcyBzZXQgYmFzZWQgb24gdGhlIG9ubHlDaWRzIG9wdGltaXphdGlvbiwgYW5kXG4gICAgLy8gd2UgdHJhY2sgYSBkZXRlcm1pbmlzdGljIG1hZ2ljSWQgYmFzZWQgb24gdGhlIGNpZC5cbiAgICAvL1xuICAgIC8vIGNoYW5nZVRyYWNraW5nIGlzIGFib3V0IHRoZSBlbnRpcmUgdHJlZVxuICAgIC8vIG5ld1JlbmRlciBpcyBhYm91dCB0aGUgY3VycmVudCByb290IGluIHRoZSB0cmVlXG4gICAgLy9cbiAgICAvLyBCeSBkZWZhdWx0IGNoYW5nZVRyYWNraW5nIGlzIGVuYWJsZWQsIGJ1dCB3ZSBzcGVjaWFsIGNhc2UgdGhlIGZsb3cgd2hlcmUgdGhlIGNsaWVudCBpcyBwcnVuaW5nXG4gICAgLy8gY2lkcyBhbmQgdGhlIHNlcnZlciBhZGRzIHRoZSBjb21wb25lbnQgYmFjay4gSW4gc3VjaCBjYXNlcywgd2UgZXhwbGljaXRseSBkaXNhYmxlIGNoYW5nZVRyYWNraW5nXG4gICAgLy8gd2l0aCByZXNldFJlbmRlciBmb3IgdGhpcyBjaWQsIHRoZW4gcmUtZW5hYmxlIGl0IGFmdGVyIHRoZSByZWN1cnNpdmUgY2FsbCB0byBza2lwIHRoZSBvcHRpbWl6YXRpb25cbiAgICAvLyBmb3IgdGhlIGVudGlyZSBjb21wb25lbnQgdHJlZS5cbiAgICBjb21wb25lbnQubmV3UmVuZGVyID0gIXNraXBcbiAgICBjb21wb25lbnQubWFnaWNJZCA9IGBjJHtjaWR9LSR7dGhpcy5wYXJlbnRWaWV3SWQoKX1gXG4gICAgLy8gZW5hYmxlIGNoYW5nZSB0cmFja2luZyBhcyBsb25nIGFzIHRoZSBjb21wb25lbnQgaGFzbid0IGJlZW4gcmVzZXRcbiAgICBsZXQgY2hhbmdlVHJhY2tpbmcgPSAhY29tcG9uZW50LnJlc2V0XG4gICAgbGV0IFtodG1sLCBzdHJlYW1zXSA9IHRoaXMucmVjdXJzaXZlVG9TdHJpbmcoY29tcG9uZW50LCBjb21wb25lbnRzLCBvbmx5Q2lkcywgY2hhbmdlVHJhY2tpbmcsIGF0dHJzKVxuICAgIC8vIGRpc2FibGUgcmVzZXQgYWZ0ZXIgd2UndmUgcmVuZGVyZWRcbiAgICBkZWxldGUgY29tcG9uZW50LnJlc2V0XG5cbiAgICByZXR1cm4gW2h0bWwsIHN0cmVhbXNdXG4gIH1cbn1cbiIsICJpbXBvcnQgRE9NIGZyb20gXCIuL2RvbVwiXG5pbXBvcnQgQVJJQSBmcm9tIFwiLi9hcmlhXCJcblxubGV0IGZvY3VzU3RhY2sgPSBbXVxubGV0IGRlZmF1bHRfdHJhbnNpdGlvbl90aW1lID0gMjAwXG5cbmxldCBKUyA9IHtcbiAgLy8gcHJpdmF0ZVxuICBleGVjKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBkZWZhdWx0cyl7XG4gICAgbGV0IFtkZWZhdWx0S2luZCwgZGVmYXVsdEFyZ3NdID0gZGVmYXVsdHMgfHwgW251bGwsIHtjYWxsYmFjazogZGVmYXVsdHMgJiYgZGVmYXVsdHMuY2FsbGJhY2t9XVxuICAgIGxldCBjb21tYW5kcyA9IHBoeEV2ZW50LmNoYXJBdCgwKSA9PT0gXCJbXCIgP1xuICAgICAgSlNPTi5wYXJzZShwaHhFdmVudCkgOiBbW2RlZmF1bHRLaW5kLCBkZWZhdWx0QXJnc11dXG5cbiAgICBjb21tYW5kcy5mb3JFYWNoKChba2luZCwgYXJnc10pID0+IHtcbiAgICAgIGlmKGtpbmQgPT09IGRlZmF1bHRLaW5kKXtcbiAgICAgICAgLy8gYWx3YXlzIHByZWZlciB0aGUgYXJncywgYnV0IGtlZXAgZXhpc3Rpbmcga2V5cyBmcm9tIHRoZSBkZWZhdWx0QXJnc1xuICAgICAgICBhcmdzID0gey4uLmRlZmF1bHRBcmdzLCAuLi5hcmdzfVxuICAgICAgICBhcmdzLmNhbGxiYWNrID0gYXJncy5jYWxsYmFjayB8fCBkZWZhdWx0QXJncy5jYWxsYmFja1xuICAgICAgfVxuICAgICAgdGhpcy5maWx0ZXJUb0Vscyh2aWV3LmxpdmVTb2NrZXQsIHNvdXJjZUVsLCBhcmdzKS5mb3JFYWNoKGVsID0+IHtcbiAgICAgICAgdGhpc1tgZXhlY18ke2tpbmR9YF0oZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCBhcmdzKVxuICAgICAgfSlcbiAgICB9KVxuICB9LFxuXG4gIGlzVmlzaWJsZShlbCl7XG4gICAgcmV0dXJuICEhKGVsLm9mZnNldFdpZHRoIHx8IGVsLm9mZnNldEhlaWdodCB8fCBlbC5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCA+IDApXG4gIH0sXG5cbiAgLy8gcmV0dXJucyB0cnVlIGlmIGFueSBwYXJ0IG9mIHRoZSBlbGVtZW50IGlzIGluc2lkZSB0aGUgdmlld3BvcnRcbiAgaXNJblZpZXdwb3J0KGVsKXtcbiAgICBjb25zdCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClcbiAgICBjb25zdCB3aW5kb3dIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodFxuICAgIGNvbnN0IHdpbmRvd1dpZHRoID0gd2luZG93LmlubmVyV2lkdGggfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoXG5cbiAgICByZXR1cm4gKFxuICAgICAgcmVjdC5yaWdodCA+IDAgJiZcbiAgICAgIHJlY3QuYm90dG9tID4gMCAmJlxuICAgICAgcmVjdC5sZWZ0IDwgd2luZG93V2lkdGggJiZcbiAgICAgIHJlY3QudG9wIDwgd2luZG93SGVpZ2h0XG4gICAgKVxuICB9LFxuXG4gIC8vIHByaXZhdGVcblxuICAvLyBjb21tYW5kc1xuXG4gIGV4ZWNfZXhlYyhlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwsIHthdHRyLCB0b30pe1xuICAgIGxldCBlbmNvZGVkSlMgPSBlbC5nZXRBdHRyaWJ1dGUoYXR0cilcbiAgICBpZighZW5jb2RlZEpTKXsgdGhyb3cgbmV3IEVycm9yKGBleHBlY3RlZCAke2F0dHJ9IHRvIGNvbnRhaW4gSlMgY29tbWFuZCBvbiBcIiR7dG99XCJgKSB9XG4gICAgdmlldy5saXZlU29ja2V0LmV4ZWNKUyhlbCwgZW5jb2RlZEpTLCBldmVudFR5cGUpXG4gIH0sXG5cbiAgZXhlY19kaXNwYXRjaChlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwsIHtldmVudCwgZGV0YWlsLCBidWJibGVzfSl7XG4gICAgZGV0YWlsID0gZGV0YWlsIHx8IHt9XG4gICAgZGV0YWlsLmRpc3BhdGNoZXIgPSBzb3VyY2VFbFxuICAgIERPTS5kaXNwYXRjaEV2ZW50KGVsLCBldmVudCwge2RldGFpbCwgYnViYmxlc30pXG4gIH0sXG5cbiAgZXhlY19wdXNoKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwgYXJncyl7XG4gICAgbGV0IHtldmVudCwgZGF0YSwgdGFyZ2V0LCBwYWdlX2xvYWRpbmcsIGxvYWRpbmcsIHZhbHVlLCBkaXNwYXRjaGVyLCBjYWxsYmFja30gPSBhcmdzXG4gICAgbGV0IHB1c2hPcHRzID0ge2xvYWRpbmcsIHZhbHVlLCB0YXJnZXQsIHBhZ2VfbG9hZGluZzogISFwYWdlX2xvYWRpbmd9XG4gICAgbGV0IHRhcmdldFNyYyA9IGV2ZW50VHlwZSA9PT0gXCJjaGFuZ2VcIiAmJiBkaXNwYXRjaGVyID8gZGlzcGF0Y2hlciA6IHNvdXJjZUVsXG4gICAgbGV0IHBoeFRhcmdldCA9IHRhcmdldCB8fCB0YXJnZXRTcmMuZ2V0QXR0cmlidXRlKHZpZXcuYmluZGluZyhcInRhcmdldFwiKSkgfHwgdGFyZ2V0U3JjXG4gICAgY29uc3QgaGFuZGxlciA9ICh0YXJnZXRWaWV3LCB0YXJnZXRDdHgpID0+IHtcbiAgICAgIGlmKCF0YXJnZXRWaWV3LmlzQ29ubmVjdGVkKCkpeyByZXR1cm4gfVxuICAgICAgaWYoZXZlbnRUeXBlID09PSBcImNoYW5nZVwiKXtcbiAgICAgICAgbGV0IHtuZXdDaWQsIF90YXJnZXR9ID0gYXJnc1xuICAgICAgICBfdGFyZ2V0ID0gX3RhcmdldCB8fCAoRE9NLmlzRm9ybUlucHV0KHNvdXJjZUVsKSA/IHNvdXJjZUVsLm5hbWUgOiB1bmRlZmluZWQpXG4gICAgICAgIGlmKF90YXJnZXQpeyBwdXNoT3B0cy5fdGFyZ2V0ID0gX3RhcmdldCB9XG4gICAgICAgIHRhcmdldFZpZXcucHVzaElucHV0KHNvdXJjZUVsLCB0YXJnZXRDdHgsIG5ld0NpZCwgZXZlbnQgfHwgcGh4RXZlbnQsIHB1c2hPcHRzLCBjYWxsYmFjaylcbiAgICAgIH0gZWxzZSBpZihldmVudFR5cGUgPT09IFwic3VibWl0XCIpe1xuICAgICAgICBsZXQge3N1Ym1pdHRlcn0gPSBhcmdzXG4gICAgICAgIHRhcmdldFZpZXcuc3VibWl0Rm9ybShzb3VyY2VFbCwgdGFyZ2V0Q3R4LCBldmVudCB8fCBwaHhFdmVudCwgc3VibWl0dGVyLCBwdXNoT3B0cywgY2FsbGJhY2spXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0YXJnZXRWaWV3LnB1c2hFdmVudChldmVudFR5cGUsIHNvdXJjZUVsLCB0YXJnZXRDdHgsIGV2ZW50IHx8IHBoeEV2ZW50LCBkYXRhLCBwdXNoT3B0cywgY2FsbGJhY2spXG4gICAgICB9XG4gICAgfVxuICAgIC8vIGluIGNhc2Ugb2YgZm9ybVJlY292ZXJ5LCB0YXJnZXRWaWV3IGFuZCB0YXJnZXRDdHggYXJlIHBhc3NlZCBhcyBhcmd1bWVudFxuICAgIC8vIGFzIHRoZXkgYXJlIGxvb2tlZCB1cCBpbiBhIHRlbXBsYXRlIGVsZW1lbnQsIG5vdCB0aGUgcmVhbCBET01cbiAgICBpZihhcmdzLnRhcmdldFZpZXcgJiYgYXJncy50YXJnZXRDdHgpe1xuICAgICAgaGFuZGxlcihhcmdzLnRhcmdldFZpZXcsIGFyZ3MudGFyZ2V0Q3R4KVxuICAgIH0gZWxzZSB7XG4gICAgICB2aWV3LndpdGhpblRhcmdldHMocGh4VGFyZ2V0LCBoYW5kbGVyKVxuICAgIH1cbiAgfSxcblxuICBleGVjX25hdmlnYXRlKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge2hyZWYsIHJlcGxhY2V9KXtcbiAgICB2aWV3LmxpdmVTb2NrZXQuaGlzdG9yeVJlZGlyZWN0KGUsIGhyZWYsIHJlcGxhY2UgPyBcInJlcGxhY2VcIiA6IFwicHVzaFwiLCBudWxsLCBzb3VyY2VFbClcbiAgfSxcblxuICBleGVjX3BhdGNoKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge2hyZWYsIHJlcGxhY2V9KXtcbiAgICB2aWV3LmxpdmVTb2NrZXQucHVzaEhpc3RvcnlQYXRjaChlLCBocmVmLCByZXBsYWNlID8gXCJyZXBsYWNlXCIgOiBcInB1c2hcIiwgc291cmNlRWwpXG4gIH0sXG5cbiAgZXhlY19mb2N1cyhlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwpe1xuICAgIEFSSUEuYXR0ZW1wdEZvY3VzKGVsKVxuICAgIC8vIGluIGNhc2UgdGhlIEpTLmZvY3VzIGNvbW1hbmQgaXMgaW4gYSBKUy5zaG93L2hpZGUvdG9nZ2xlIGNoYWluLCBmb3Igc2hvdyB3ZSBuZWVkXG4gICAgLy8gdG8gd2FpdCBmb3IgSlMuc2hvdyB0byBoYXZlIHVwZGF0ZWQgdGhlIGVsZW1lbnQncyBkaXNwbGF5IHByb3BlcnR5IChzZWUgZXhlY190b2dnbGUpXG4gICAgLy8gYnV0IHRoYXQgcnVuIGluIG5lc3RlZCBhbmltYXRpb24gZnJhbWVzLCB0aGVyZWZvcmUgd2UgbmVlZCB0byB1c2UgdGhlbSBoZXJlIGFzIHdlbGxcbiAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gQVJJQS5hdHRlbXB0Rm9jdXMoZWwpKVxuICAgIH0pXG4gIH0sXG5cbiAgZXhlY19mb2N1c19maXJzdChlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwpe1xuICAgIEFSSUEuZm9jdXNGaXJzdEludGVyYWN0aXZlKGVsKSB8fCBBUklBLmZvY3VzRmlyc3QoZWwpXG4gICAgLy8gaWYgeW91IHdvbmRlciBhYm91dCB0aGUgbmVzdGVkIGFuaW1hdGlvbiBmcmFtZXMsIHNlZSBleGVjX2ZvY3VzXG4gICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IEFSSUEuZm9jdXNGaXJzdEludGVyYWN0aXZlKGVsKSB8fCBBUklBLmZvY3VzRmlyc3QoZWwpKVxuICAgIH0pXG4gIH0sXG5cbiAgZXhlY19wdXNoX2ZvY3VzKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCl7XG4gICAgZm9jdXNTdGFjay5wdXNoKGVsIHx8IHNvdXJjZUVsKVxuICB9LFxuXG4gIGV4ZWNfcG9wX2ZvY3VzKF9lLCBfZXZlbnRUeXBlLCBfcGh4RXZlbnQsIF92aWV3LCBfc291cmNlRWwsIF9lbCl7XG4gICAgY29uc3QgZWwgPSBmb2N1c1N0YWNrLnBvcCgpXG4gICAgaWYoZWwpe1xuICAgICAgZWwuZm9jdXMoKVxuICAgICAgLy8gaWYgeW91IHdvbmRlciBhYm91dCB0aGUgbmVzdGVkIGFuaW1hdGlvbiBmcmFtZXMsIHNlZSBleGVjX2ZvY3VzXG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiBlbC5mb2N1cygpKVxuICAgICAgfSlcbiAgICB9XG4gIH0sXG5cbiAgZXhlY19hZGRfY2xhc3MoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7bmFtZXMsIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nfSl7XG4gICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIG5hbWVzLCBbXSwgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpXG4gIH0sXG5cbiAgZXhlY19yZW1vdmVfY2xhc3MoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7bmFtZXMsIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nfSl7XG4gICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIFtdLCBuYW1lcywgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpXG4gIH0sXG5cbiAgZXhlY190b2dnbGVfY2xhc3MoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7bmFtZXMsIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nfSl7XG4gICAgdGhpcy50b2dnbGVDbGFzc2VzKGVsLCBuYW1lcywgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpXG4gIH0sXG5cbiAgZXhlY190b2dnbGVfYXR0cihlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwsIHthdHRyOiBbYXR0ciwgdmFsMSwgdmFsMl19KXtcbiAgICB0aGlzLnRvZ2dsZUF0dHIoZWwsIGF0dHIsIHZhbDEsIHZhbDIpXG4gIH0sXG5cbiAgZXhlY190cmFuc2l0aW9uKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge3RpbWUsIHRyYW5zaXRpb24sIGJsb2NraW5nfSl7XG4gICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIFtdLCBbXSwgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpXG4gIH0sXG5cbiAgZXhlY190b2dnbGUoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7ZGlzcGxheSwgaW5zLCBvdXRzLCB0aW1lLCBibG9ja2luZ30pe1xuICAgIHRoaXMudG9nZ2xlKGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIGlucywgb3V0cywgdGltZSwgYmxvY2tpbmcpXG4gIH0sXG5cbiAgZXhlY19zaG93KGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge2Rpc3BsYXksIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nfSl7XG4gICAgdGhpcy5zaG93KGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nKVxuICB9LFxuXG4gIGV4ZWNfaGlkZShlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwsIHtkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZ30pe1xuICAgIHRoaXMuaGlkZShldmVudFR5cGUsIHZpZXcsIGVsLCBkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZylcbiAgfSxcblxuICBleGVjX3NldF9hdHRyKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge2F0dHI6IFthdHRyLCB2YWxdfSl7XG4gICAgdGhpcy5zZXRPclJlbW92ZUF0dHJzKGVsLCBbW2F0dHIsIHZhbF1dLCBbXSlcbiAgfSxcblxuICBleGVjX3JlbW92ZV9hdHRyKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwge2F0dHJ9KXtcbiAgICB0aGlzLnNldE9yUmVtb3ZlQXR0cnMoZWwsIFtdLCBbYXR0cl0pXG4gIH0sXG5cbiAgLy8gdXRpbHMgZm9yIGNvbW1hbmRzXG5cbiAgc2hvdyhldmVudFR5cGUsIHZpZXcsIGVsLCBkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyl7XG4gICAgaWYoIXRoaXMuaXNWaXNpYmxlKGVsKSl7XG4gICAgICB0aGlzLnRvZ2dsZShldmVudFR5cGUsIHZpZXcsIGVsLCBkaXNwbGF5LCB0cmFuc2l0aW9uLCBudWxsLCB0aW1lLCBibG9ja2luZylcbiAgICB9XG4gIH0sXG5cbiAgaGlkZShldmVudFR5cGUsIHZpZXcsIGVsLCBkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyl7XG4gICAgaWYodGhpcy5pc1Zpc2libGUoZWwpKXtcbiAgICAgIHRoaXMudG9nZ2xlKGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIG51bGwsIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nKVxuICAgIH1cbiAgfSxcblxuICB0b2dnbGUoZXZlbnRUeXBlLCB2aWV3LCBlbCwgZGlzcGxheSwgaW5zLCBvdXRzLCB0aW1lLCBibG9ja2luZyl7XG4gICAgdGltZSA9IHRpbWUgfHwgZGVmYXVsdF90cmFuc2l0aW9uX3RpbWVcbiAgICBsZXQgW2luQ2xhc3NlcywgaW5TdGFydENsYXNzZXMsIGluRW5kQ2xhc3Nlc10gPSBpbnMgfHwgW1tdLCBbXSwgW11dXG4gICAgbGV0IFtvdXRDbGFzc2VzLCBvdXRTdGFydENsYXNzZXMsIG91dEVuZENsYXNzZXNdID0gb3V0cyB8fCBbW10sIFtdLCBbXV1cbiAgICBpZihpbkNsYXNzZXMubGVuZ3RoID4gMCB8fCBvdXRDbGFzc2VzLmxlbmd0aCA+IDApe1xuICAgICAgaWYodGhpcy5pc1Zpc2libGUoZWwpKXtcbiAgICAgICAgbGV0IG9uU3RhcnQgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIG91dFN0YXJ0Q2xhc3NlcywgaW5DbGFzc2VzLmNvbmNhdChpblN0YXJ0Q2xhc3NlcykuY29uY2F0KGluRW5kQ2xhc3NlcykpXG4gICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgb3V0Q2xhc3NlcywgW10pXG4gICAgICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBvdXRFbmRDbGFzc2VzLCBvdXRTdGFydENsYXNzZXMpKVxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgICAgbGV0IG9uRW5kID0gKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBbXSwgb3V0Q2xhc3Nlcy5jb25jYXQob3V0RW5kQ2xhc3NlcykpXG4gICAgICAgICAgRE9NLnB1dFN0aWNreShlbCwgXCJ0b2dnbGVcIiwgY3VycmVudEVsID0+IGN1cnJlbnRFbC5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCIpXG4gICAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6aGlkZS1lbmRcIikpXG4gICAgICAgIH1cbiAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6aGlkZS1zdGFydFwiKSlcbiAgICAgICAgaWYoYmxvY2tpbmcgPT09IGZhbHNlKXtcbiAgICAgICAgICBvblN0YXJ0KClcbiAgICAgICAgICBzZXRUaW1lb3V0KG9uRW5kLCB0aW1lKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZpZXcudHJhbnNpdGlvbih0aW1lLCBvblN0YXJ0LCBvbkVuZClcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYoZXZlbnRUeXBlID09PSBcInJlbW92ZVwiKXsgcmV0dXJuIH1cbiAgICAgICAgbGV0IG9uU3RhcnQgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIGluU3RhcnRDbGFzc2VzLCBvdXRDbGFzc2VzLmNvbmNhdChvdXRTdGFydENsYXNzZXMpLmNvbmNhdChvdXRFbmRDbGFzc2VzKSlcbiAgICAgICAgICBjb25zdCBzdGlja3lEaXNwbGF5ID0gZGlzcGxheSB8fCB0aGlzLmRlZmF1bHREaXNwbGF5KGVsKVxuICAgICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgICAgLy8gZmlyc3QgYWRkIHRoZSBzdGFydGluZyArIGFjdGl2ZSBjbGFzcywgVEhFTiBtYWtlIHRoZSBlbGVtZW50IHZpc2libGVcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSBpZiB3ZSB0b2dnbGVkIHRoZSB2aXNpYmlsaXR5IGVhcmxpZXIgY3NzIGFuaW1hdGlvbnNcbiAgICAgICAgICAgIC8vIHdvdWxkIGZsaWNrZXIsIGFzIHRoZSBlbGVtZW50IGJlY29tZXMgdmlzaWJsZSBiZWZvcmUgdGhlIGFjdGl2ZSBhbmltYXRpb25cbiAgICAgICAgICAgIC8vIGNsYXNzIGlzIHNldCAoc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNDU2KVxuICAgICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIGluQ2xhc3NlcywgW10pXG4gICAgICAgICAgICAvLyBhZGRPclJlbW92ZUNsYXNzZXMgdXNlcyBhIHJlcXVlc3RBbmltYXRpb25GcmFtZSBpdHNlbGYsIHRoZXJlZm9yZSB3ZSBuZWVkIHRvIG1vdmUgdGhlIHB1dFN0aWNreVxuICAgICAgICAgICAgLy8gaW50byB0aGUgbmV4dCByZXF1ZXN0QW5pbWF0aW9uRnJhbWUuLi5cbiAgICAgICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgICAgICBET00ucHV0U3RpY2t5KGVsLCBcInRvZ2dsZVwiLCBjdXJyZW50RWwgPT4gY3VycmVudEVsLnN0eWxlLmRpc3BsYXkgPSBzdGlja3lEaXNwbGF5KVxuICAgICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgaW5FbmRDbGFzc2VzLCBpblN0YXJ0Q2xhc3NlcylcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgICBsZXQgb25FbmQgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIFtdLCBpbkNsYXNzZXMuY29uY2F0KGluRW5kQ2xhc3NlcykpXG4gICAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1lbmRcIikpXG4gICAgICAgIH1cbiAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1zdGFydFwiKSlcbiAgICAgICAgaWYoYmxvY2tpbmcgPT09IGZhbHNlKXtcbiAgICAgICAgICBvblN0YXJ0KClcbiAgICAgICAgICBzZXRUaW1lb3V0KG9uRW5kLCB0aW1lKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZpZXcudHJhbnNpdGlvbih0aW1lLCBvblN0YXJ0LCBvbkVuZClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZih0aGlzLmlzVmlzaWJsZShlbCkpe1xuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICBlbC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudChcInBoeDpoaWRlLXN0YXJ0XCIpKVxuICAgICAgICAgIERPTS5wdXRTdGlja3koZWwsIFwidG9nZ2xlXCIsIGN1cnJlbnRFbCA9PiBjdXJyZW50RWwuc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiKVxuICAgICAgICAgIGVsLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwicGh4OmhpZGUtZW5kXCIpKVxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1zdGFydFwiKSlcbiAgICAgICAgICBsZXQgc3RpY2t5RGlzcGxheSA9IGRpc3BsYXkgfHwgdGhpcy5kZWZhdWx0RGlzcGxheShlbClcbiAgICAgICAgICBET00ucHV0U3RpY2t5KGVsLCBcInRvZ2dsZVwiLCBjdXJyZW50RWwgPT4gY3VycmVudEVsLnN0eWxlLmRpc3BsYXkgPSBzdGlja3lEaXNwbGF5KVxuICAgICAgICAgIGVsLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwicGh4OnNob3ctZW5kXCIpKVxuICAgICAgICB9KVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICB0b2dnbGVDbGFzc2VzKGVsLCBjbGFzc2VzLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZyl7XG4gICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICBsZXQgW3ByZXZBZGRzLCBwcmV2UmVtb3Zlc10gPSBET00uZ2V0U3RpY2t5KGVsLCBcImNsYXNzZXNcIiwgW1tdLCBbXV0pXG4gICAgICBsZXQgbmV3QWRkcyA9IGNsYXNzZXMuZmlsdGVyKG5hbWUgPT4gcHJldkFkZHMuaW5kZXhPZihuYW1lKSA8IDAgJiYgIWVsLmNsYXNzTGlzdC5jb250YWlucyhuYW1lKSlcbiAgICAgIGxldCBuZXdSZW1vdmVzID0gY2xhc3Nlcy5maWx0ZXIobmFtZSA9PiBwcmV2UmVtb3Zlcy5pbmRleE9mKG5hbWUpIDwgMCAmJiBlbC5jbGFzc0xpc3QuY29udGFpbnMobmFtZSkpXG4gICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgbmV3QWRkcywgbmV3UmVtb3ZlcywgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpXG4gICAgfSlcbiAgfSxcblxuICB0b2dnbGVBdHRyKGVsLCBhdHRyLCB2YWwxLCB2YWwyKXtcbiAgICBpZihlbC5oYXNBdHRyaWJ1dGUoYXR0cikpe1xuICAgICAgaWYodmFsMiAhPT0gdW5kZWZpbmVkKXtcbiAgICAgICAgLy8gdG9nZ2xlIGJldHdlZW4gdmFsMSBhbmQgdmFsMlxuICAgICAgICBpZihlbC5nZXRBdHRyaWJ1dGUoYXR0cikgPT09IHZhbDEpe1xuICAgICAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWwyXV0sIFtdKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWwxXV0sIFtdKVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyByZW1vdmUgYXR0clxuICAgICAgICB0aGlzLnNldE9yUmVtb3ZlQXR0cnMoZWwsIFtdLCBbYXR0cl0pXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWwxXV0sIFtdKVxuICAgIH1cbiAgfSxcblxuICBhZGRPclJlbW92ZUNsYXNzZXMoZWwsIGFkZHMsIHJlbW92ZXMsIHRyYW5zaXRpb24sIHRpbWUsIHZpZXcsIGJsb2NraW5nKXtcbiAgICB0aW1lID0gdGltZSB8fCBkZWZhdWx0X3RyYW5zaXRpb25fdGltZVxuICAgIGxldCBbdHJhbnNpdGlvblJ1biwgdHJhbnNpdGlvblN0YXJ0LCB0cmFuc2l0aW9uRW5kXSA9IHRyYW5zaXRpb24gfHwgW1tdLCBbXSwgW11dXG4gICAgaWYodHJhbnNpdGlvblJ1bi5sZW5ndGggPiAwKXtcbiAgICAgIGxldCBvblN0YXJ0ID0gKCkgPT4ge1xuICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgdHJhbnNpdGlvblN0YXJ0LCBbXS5jb25jYXQodHJhbnNpdGlvblJ1bikuY29uY2F0KHRyYW5zaXRpb25FbmQpKVxuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgdHJhbnNpdGlvblJ1biwgW10pXG4gICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgdHJhbnNpdGlvbkVuZCwgdHJhbnNpdGlvblN0YXJ0KSlcbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICAgIGxldCBvbkRvbmUgPSAoKSA9PiB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgYWRkcy5jb25jYXQodHJhbnNpdGlvbkVuZCksIHJlbW92ZXMuY29uY2F0KHRyYW5zaXRpb25SdW4pLmNvbmNhdCh0cmFuc2l0aW9uU3RhcnQpKVxuICAgICAgaWYoYmxvY2tpbmcgPT09IGZhbHNlKXtcbiAgICAgICAgb25TdGFydCgpXG4gICAgICAgIHNldFRpbWVvdXQob25Eb25lLCB0aW1lKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmlldy50cmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRG9uZSlcbiAgICAgIH1cbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgbGV0IFtwcmV2QWRkcywgcHJldlJlbW92ZXNdID0gRE9NLmdldFN0aWNreShlbCwgXCJjbGFzc2VzXCIsIFtbXSwgW11dKVxuICAgICAgbGV0IGtlZXBBZGRzID0gYWRkcy5maWx0ZXIobmFtZSA9PiBwcmV2QWRkcy5pbmRleE9mKG5hbWUpIDwgMCAmJiAhZWwuY2xhc3NMaXN0LmNvbnRhaW5zKG5hbWUpKVxuICAgICAgbGV0IGtlZXBSZW1vdmVzID0gcmVtb3Zlcy5maWx0ZXIobmFtZSA9PiBwcmV2UmVtb3Zlcy5pbmRleE9mKG5hbWUpIDwgMCAmJiBlbC5jbGFzc0xpc3QuY29udGFpbnMobmFtZSkpXG4gICAgICBsZXQgbmV3QWRkcyA9IHByZXZBZGRzLmZpbHRlcihuYW1lID0+IHJlbW92ZXMuaW5kZXhPZihuYW1lKSA8IDApLmNvbmNhdChrZWVwQWRkcylcbiAgICAgIGxldCBuZXdSZW1vdmVzID0gcHJldlJlbW92ZXMuZmlsdGVyKG5hbWUgPT4gYWRkcy5pbmRleE9mKG5hbWUpIDwgMCkuY29uY2F0KGtlZXBSZW1vdmVzKVxuXG4gICAgICBET00ucHV0U3RpY2t5KGVsLCBcImNsYXNzZXNcIiwgY3VycmVudEVsID0+IHtcbiAgICAgICAgY3VycmVudEVsLmNsYXNzTGlzdC5yZW1vdmUoLi4ubmV3UmVtb3ZlcylcbiAgICAgICAgY3VycmVudEVsLmNsYXNzTGlzdC5hZGQoLi4ubmV3QWRkcylcbiAgICAgICAgcmV0dXJuIFtuZXdBZGRzLCBuZXdSZW1vdmVzXVxuICAgICAgfSlcbiAgICB9KVxuICB9LFxuXG4gIHNldE9yUmVtb3ZlQXR0cnMoZWwsIHNldHMsIHJlbW92ZXMpe1xuICAgIGxldCBbcHJldlNldHMsIHByZXZSZW1vdmVzXSA9IERPTS5nZXRTdGlja3koZWwsIFwiYXR0cnNcIiwgW1tdLCBbXV0pXG5cbiAgICBsZXQgYWx0ZXJlZEF0dHJzID0gc2V0cy5tYXAoKFthdHRyLCBfdmFsXSkgPT4gYXR0cikuY29uY2F0KHJlbW92ZXMpXG4gICAgbGV0IG5ld1NldHMgPSBwcmV2U2V0cy5maWx0ZXIoKFthdHRyLCBfdmFsXSkgPT4gIWFsdGVyZWRBdHRycy5pbmNsdWRlcyhhdHRyKSkuY29uY2F0KHNldHMpXG4gICAgbGV0IG5ld1JlbW92ZXMgPSBwcmV2UmVtb3Zlcy5maWx0ZXIoKGF0dHIpID0+ICFhbHRlcmVkQXR0cnMuaW5jbHVkZXMoYXR0cikpLmNvbmNhdChyZW1vdmVzKVxuXG4gICAgRE9NLnB1dFN0aWNreShlbCwgXCJhdHRyc1wiLCBjdXJyZW50RWwgPT4ge1xuICAgICAgbmV3UmVtb3Zlcy5mb3JFYWNoKGF0dHIgPT4gY3VycmVudEVsLnJlbW92ZUF0dHJpYnV0ZShhdHRyKSlcbiAgICAgIG5ld1NldHMuZm9yRWFjaCgoW2F0dHIsIHZhbF0pID0+IGN1cnJlbnRFbC5zZXRBdHRyaWJ1dGUoYXR0ciwgdmFsKSlcbiAgICAgIHJldHVybiBbbmV3U2V0cywgbmV3UmVtb3Zlc11cbiAgICB9KVxuICB9LFxuXG4gIGhhc0FsbENsYXNzZXMoZWwsIGNsYXNzZXMpeyByZXR1cm4gY2xhc3Nlcy5ldmVyeShuYW1lID0+IGVsLmNsYXNzTGlzdC5jb250YWlucyhuYW1lKSkgfSxcblxuICBpc1RvZ2dsZWRPdXQoZWwsIG91dENsYXNzZXMpe1xuICAgIHJldHVybiAhdGhpcy5pc1Zpc2libGUoZWwpIHx8IHRoaXMuaGFzQWxsQ2xhc3NlcyhlbCwgb3V0Q2xhc3NlcylcbiAgfSxcblxuICBmaWx0ZXJUb0VscyhsaXZlU29ja2V0LCBzb3VyY2VFbCwge3RvfSl7XG4gICAgbGV0IGRlZmF1bHRRdWVyeSA9ICgpID0+IHtcbiAgICAgIGlmKHR5cGVvZih0bykgPT09IFwic3RyaW5nXCIpe1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCh0bylcbiAgICAgIH0gZWxzZSBpZih0by5jbG9zZXN0KXtcbiAgICAgICAgbGV0IHRvRWwgPSBzb3VyY2VFbC5jbG9zZXN0KHRvLmNsb3Nlc3QpXG4gICAgICAgIHJldHVybiB0b0VsID8gW3RvRWxdIDogW11cbiAgICAgIH0gZWxzZSBpZih0by5pbm5lcil7XG4gICAgICAgIHJldHVybiBzb3VyY2VFbC5xdWVyeVNlbGVjdG9yQWxsKHRvLmlubmVyKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdG8gPyBsaXZlU29ja2V0LmpzUXVlcnlTZWxlY3RvckFsbChzb3VyY2VFbCwgdG8sIGRlZmF1bHRRdWVyeSkgOiBbc291cmNlRWxdXG4gIH0sXG5cbiAgZGVmYXVsdERpc3BsYXkoZWwpe1xuICAgIHJldHVybiB7dHI6IFwidGFibGUtcm93XCIsIHRkOiBcInRhYmxlLWNlbGxcIn1bZWwudGFnTmFtZS50b0xvd2VyQ2FzZSgpXSB8fCBcImJsb2NrXCJcbiAgfSxcblxuICB0cmFuc2l0aW9uQ2xhc3Nlcyh2YWwpe1xuICAgIGlmKCF2YWwpeyByZXR1cm4gbnVsbCB9XG5cbiAgICBsZXQgW3RyYW5zLCB0U3RhcnQsIHRFbmRdID0gQXJyYXkuaXNBcnJheSh2YWwpID8gdmFsIDogW3ZhbC5zcGxpdChcIiBcIiksIFtdLCBbXV1cbiAgICB0cmFucyA9IEFycmF5LmlzQXJyYXkodHJhbnMpID8gdHJhbnMgOiB0cmFucy5zcGxpdChcIiBcIilcbiAgICB0U3RhcnQgPSBBcnJheS5pc0FycmF5KHRTdGFydCkgPyB0U3RhcnQgOiB0U3RhcnQuc3BsaXQoXCIgXCIpXG4gICAgdEVuZCA9IEFycmF5LmlzQXJyYXkodEVuZCkgPyB0RW5kIDogdEVuZC5zcGxpdChcIiBcIilcbiAgICByZXR1cm4gW3RyYW5zLCB0U3RhcnQsIHRFbmRdXG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgSlNcbiIsICJpbXBvcnQgSlMgZnJvbSBcIi4vanNcIlxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIlxuXG5jb25zdCBIT09LX0lEID0gXCJob29rSWRcIlxuXG5sZXQgdmlld0hvb2tJRCA9IDFcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZpZXdIb29rIHtcbiAgc3RhdGljIG1ha2VJRCgpeyByZXR1cm4gdmlld0hvb2tJRCsrIH1cbiAgc3RhdGljIGVsZW1lbnRJRChlbCl7IHJldHVybiBET00ucHJpdmF0ZShlbCwgSE9PS19JRCkgfVxuXG4gIGNvbnN0cnVjdG9yKHZpZXcsIGVsLCBjYWxsYmFja3Mpe1xuICAgIHRoaXMuZWwgPSBlbFxuICAgIHRoaXMuX19hdHRhY2hWaWV3KHZpZXcpXG4gICAgdGhpcy5fX2NhbGxiYWNrcyA9IGNhbGxiYWNrc1xuICAgIHRoaXMuX19saXN0ZW5lcnMgPSBuZXcgU2V0KClcbiAgICB0aGlzLl9faXNEaXNjb25uZWN0ZWQgPSBmYWxzZVxuICAgIERPTS5wdXRQcml2YXRlKHRoaXMuZWwsIEhPT0tfSUQsIHRoaXMuY29uc3RydWN0b3IubWFrZUlEKCkpXG4gICAgZm9yKGxldCBrZXkgaW4gdGhpcy5fX2NhbGxiYWNrcyl7IHRoaXNba2V5XSA9IHRoaXMuX19jYWxsYmFja3Nba2V5XSB9XG4gIH1cblxuICBfX2F0dGFjaFZpZXcodmlldyl7XG4gICAgaWYodmlldyl7XG4gICAgICB0aGlzLl9fdmlldyA9ICgpID0+IHZpZXdcbiAgICAgIHRoaXMubGl2ZVNvY2tldCA9IHZpZXcubGl2ZVNvY2tldFxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9fdmlldyA9ICgpID0+IHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBob29rIG5vdCB5ZXQgYXR0YWNoZWQgdG8gYSBsaXZlIHZpZXc6ICR7dGhpcy5lbC5vdXRlckhUTUx9YClcbiAgICAgIH1cbiAgICAgIHRoaXMubGl2ZVNvY2tldCA9IG51bGxcbiAgICB9XG4gIH1cblxuICBfX21vdW50ZWQoKXsgdGhpcy5tb3VudGVkICYmIHRoaXMubW91bnRlZCgpIH1cbiAgX191cGRhdGVkKCl7IHRoaXMudXBkYXRlZCAmJiB0aGlzLnVwZGF0ZWQoKSB9XG4gIF9fYmVmb3JlVXBkYXRlKCl7IHRoaXMuYmVmb3JlVXBkYXRlICYmIHRoaXMuYmVmb3JlVXBkYXRlKCkgfVxuICBfX2Rlc3Ryb3llZCgpe1xuICAgIHRoaXMuZGVzdHJveWVkICYmIHRoaXMuZGVzdHJveWVkKClcbiAgICBET00uZGVsZXRlUHJpdmF0ZSh0aGlzLmVsLCBIT09LX0lEKSAvLyBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMzQ5NlxuICB9XG4gIF9fcmVjb25uZWN0ZWQoKXtcbiAgICBpZih0aGlzLl9faXNEaXNjb25uZWN0ZWQpe1xuICAgICAgdGhpcy5fX2lzRGlzY29ubmVjdGVkID0gZmFsc2VcbiAgICAgIHRoaXMucmVjb25uZWN0ZWQgJiYgdGhpcy5yZWNvbm5lY3RlZCgpXG4gICAgfVxuICB9XG4gIF9fZGlzY29ubmVjdGVkKCl7XG4gICAgdGhpcy5fX2lzRGlzY29ubmVjdGVkID0gdHJ1ZVxuICAgIHRoaXMuZGlzY29ubmVjdGVkICYmIHRoaXMuZGlzY29ubmVjdGVkKClcbiAgfVxuXG4gIC8qKlxuICAgKiBCaW5kcyB0aGUgaG9vayB0byBKUyBjb21tYW5kcy5cbiAgICpcbiAgICogQHBhcmFtIHtWaWV3SG9va30gaG9vayAtIFRoZSBWaWV3SG9vayBpbnN0YW5jZSB0byBiaW5kLlxuICAgKlxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3Qgd2l0aCBtZXRob2RzIHRvIG1hbmlwdWxhdGUgdGhlIERPTSBhbmQgZXhlY3V0ZSBKYXZhU2NyaXB0LlxuICAgKi9cbiAganMoKXtcbiAgICBsZXQgaG9vayA9IHRoaXNcblxuICAgIHJldHVybiB7XG4gICAgICAvKipcbiAgICAgICAqIEV4ZWN1dGVzIGVuY29kZWQgSmF2YVNjcmlwdCBpbiB0aGUgY29udGV4dCBvZiB0aGUgaG9vayBlbGVtZW50LlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGVkSlMgLSBUaGUgZW5jb2RlZCBKYXZhU2NyaXB0IHN0cmluZyB0byBleGVjdXRlLlxuICAgICAgICovXG4gICAgICBleGVjKGVuY29kZWRKUyl7XG4gICAgICAgIGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5leGVjSlMoaG9vay5lbCwgZW5jb2RlZEpTLCBcImhvb2tcIilcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogU2hvd3MgYW4gZWxlbWVudC5cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIFRoZSBlbGVtZW50IHRvIHNob3cuXG4gICAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9e31dIC0gT3B0aW9uYWwgc2V0dGluZ3MuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuZGlzcGxheV0gLSBUaGUgQ1NTIGRpc3BsYXkgdmFsdWUgdG8gc2V0LiBEZWZhdWx0cyBcImJsb2NrXCIuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMudHJhbnNpdGlvbl0gLSBUaGUgQ1NTIHRyYW5zaXRpb24gY2xhc3NlcyB0byBzZXQgd2hlbiBzaG93aW5nLlxuICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLnRpbWVdIC0gVGhlIHRyYW5zaXRpb24gZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzLiBEZWZhdWx0cyAyMDAuXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmJsb2NraW5nXSAtIFRoZSBib29sZWFuIGZsYWcgdG8gYmxvY2sgdGhlIFVJIGR1cmluZyB0aGUgdHJhbnNpdGlvbi5cbiAgICAgICAqICBEZWZhdWx0cyBgdHJ1ZWAuXG4gICAgICAgKi9cbiAgICAgIHNob3coZWwsIG9wdHMgPSB7fSl7XG4gICAgICAgIGxldCBvd25lciA9IGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5vd25lcihlbClcbiAgICAgICAgSlMuc2hvdyhcImhvb2tcIiwgb3duZXIsIGVsLCBvcHRzLmRpc3BsYXksIG9wdHMudHJhbnNpdGlvbiwgb3B0cy50aW1lLCBvcHRzLmJsb2NraW5nKVxuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBIaWRlcyBhbiBlbGVtZW50LlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIC0gVGhlIGVsZW1lbnQgdG8gaGlkZS5cbiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy50cmFuc2l0aW9uXSAtIFRoZSBDU1MgdHJhbnNpdGlvbiBjbGFzc2VzIHRvIHNldCB3aGVuIGhpZGluZy5cbiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lXSAtIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy4gRGVmYXVsdHMgMjAwLlxuICAgICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5ibG9ja2luZ10gLSBUaGUgYm9vbGVhbiBmbGFnIHRvIGJsb2NrIHRoZSBVSSBkdXJpbmcgdGhlIHRyYW5zaXRpb24uXG4gICAgICAgKiAgIERlZmF1bHRzIGB0cnVlYC5cbiAgICAgICAqL1xuICAgICAgaGlkZShlbCwgb3B0cyA9IHt9KXtcbiAgICAgICAgbGV0IG93bmVyID0gaG9vay5fX3ZpZXcoKS5saXZlU29ja2V0Lm93bmVyKGVsKVxuICAgICAgICBKUy5oaWRlKFwiaG9va1wiLCBvd25lciwgZWwsIG51bGwsIG9wdHMudHJhbnNpdGlvbiwgb3B0cy50aW1lLCBvcHRzLmJsb2NraW5nKVxuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBUb2dnbGVzIHRoZSB2aXNpYmlsaXR5IG9mIGFuIGVsZW1lbnQuXG4gICAgICAgKlxuICAgICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWwgLSBUaGUgZWxlbWVudCB0byB0b2dnbGUuXG4gICAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9e31dIC0gT3B0aW9uYWwgc2V0dGluZ3MuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuZGlzcGxheV0gLSBUaGUgQ1NTIGRpc3BsYXkgdmFsdWUgdG8gc2V0LiBEZWZhdWx0cyBcImJsb2NrXCIuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuaW5dIC0gVGhlIENTUyB0cmFuc2l0aW9uIGNsYXNzZXMgZm9yIHNob3dpbmcuXG4gICAgICAgKiAgIEFjY2VwdHMgZWl0aGVyIHRoZSBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRvZ2dsaW5nIGluLCBvclxuICAgICAgICogICBhIDMtdHVwbGUgY29udGFpbmluZyB0aGUgdHJhbnNpdGlvbiBjbGFzcywgdGhlIGNsYXNzIHRvIGFwcGx5XG4gICAgICAgKiAgIHRvIHN0YXJ0IHRoZSB0cmFuc2l0aW9uLCBhbmQgdGhlIGVuZGluZyB0cmFuc2l0aW9uIGNsYXNzLCBzdWNoIGFzOlxuICAgICAgICpcbiAgICAgICAqICAgICAgIFtcImVhc2Utb3V0IGR1cmF0aW9uLTMwMFwiLCBcIm9wYWNpdHktMFwiLCBcIm9wYWNpdHktMTAwXCJdXG4gICAgICAgKlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm91dF0gLSBUaGUgQ1NTIHRyYW5zaXRpb24gY2xhc3NlcyBmb3IgaGlkaW5nLlxuICAgICAgICogICBBY2NlcHRzIGVpdGhlciBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRvZ2dsaW5nIG91dCwgb3JcbiAgICAgICAqICAgYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgICAgICogICB0byBzdGFydCB0aGUgdHJhbnNpdGlvbiwgYW5kIHRoZSBlbmRpbmcgdHJhbnNpdGlvbiBjbGFzcywgc3VjaCBhczpcbiAgICAgICAqXG4gICAgICAgKiAgICAgICBbXCJlYXNlLW91dCBkdXJhdGlvbi0zMDBcIiwgXCJvcGFjaXR5LTEwMFwiLCBcIm9wYWNpdHktMFwiXVxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lXSAtIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy5cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmJsb2NraW5nXSAtIFRoZSBib29sZWFuIGZsYWcgdG8gYmxvY2sgdGhlIFVJIGR1cmluZyB0aGUgdHJhbnNpdGlvbi5cbiAgICAgICAqICAgRGVmYXVsdHMgYHRydWVgLlxuICAgICAgICovXG4gICAgICB0b2dnbGUoZWwsIG9wdHMgPSB7fSl7XG4gICAgICAgIGxldCBvd25lciA9IGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5vd25lcihlbClcbiAgICAgICAgb3B0cy5pbiA9IEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMuaW4pXG4gICAgICAgIG9wdHMub3V0ID0gSlMudHJhbnNpdGlvbkNsYXNzZXMob3B0cy5vdXQpXG4gICAgICAgIEpTLnRvZ2dsZShcImhvb2tcIiwgb3duZXIsIGVsLCBvcHRzLmRpc3BsYXksIG9wdHMuaW4sIG9wdHMub3V0LCBvcHRzLnRpbWUsIG9wdHMuYmxvY2tpbmcpXG4gICAgICB9LFxuXG4gICAgICAvKipcbiAgICAgICAqIEFkZHMgQ1NTIGNsYXNzZXMgdG8gYW4gZWxlbWVudC5cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIFRoZSBlbGVtZW50IHRvIGFkZCBjbGFzc2VzIHRvLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IG5hbWVzIC0gVGhlIGNsYXNzIG5hbWUocykgdG8gYWRkLlxuICAgICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRzPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdzLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLnRyYW5zaXRpb25dIC0gVGhlIENTUyB0cmFuc2l0aW9uIHByb3BlcnR5IHRvIHNldC5cbiAgICAgICAqICAgQWNjZXB0cyBhIHN0cmluZyBvZiBjbGFzc2VzIHRvIGFwcGx5IHdoZW4gYWRkaW5nIGNsYXNzZXMgb3JcbiAgICAgICAqICAgYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgICAgICogICB0byBzdGFydCB0aGUgdHJhbnNpdGlvbiwgYW5kIHRoZSBlbmRpbmcgdHJhbnNpdGlvbiBjbGFzcywgc3VjaCBhczpcbiAgICAgICAqXG4gICAgICAgKiAgICAgICBbXCJlYXNlLW91dCBkdXJhdGlvbi0zMDBcIiwgXCJvcGFjaXR5LTBcIiwgXCJvcGFjaXR5LTEwMFwiXVxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lXSAtIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy5cbiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuYmxvY2tpbmddIC0gVGhlIGJvb2xlYW4gZmxhZyB0byBibG9jayB0aGUgVUkgZHVyaW5nIHRoZSB0cmFuc2l0aW9uLlxuICAgICAgICogICBEZWZhdWx0cyBgdHJ1ZWAuXG4gICAgICAgKi9cbiAgICAgIGFkZENsYXNzKGVsLCBuYW1lcywgb3B0cyA9IHt9KXtcbiAgICAgICAgbmFtZXMgPSBBcnJheS5pc0FycmF5KG5hbWVzKSA/IG5hbWVzIDogbmFtZXMuc3BsaXQoXCIgXCIpXG4gICAgICAgIGxldCBvd25lciA9IGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5vd25lcihlbClcbiAgICAgICAgSlMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBuYW1lcywgW10sIG9wdHMudHJhbnNpdGlvbiwgb3B0cy50aW1lLCBvd25lciwgb3B0cy5ibG9ja2luZylcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogUmVtb3ZlcyBDU1MgY2xhc3NlcyBmcm9tIGFuIGVsZW1lbnQuXG4gICAgICAgKlxuICAgICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWwgLSBUaGUgZWxlbWVudCB0byByZW1vdmUgY2xhc3NlcyBmcm9tLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IG5hbWVzIC0gVGhlIGNsYXNzIG5hbWUocykgdG8gcmVtb3ZlLlxuICAgICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRzPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdzLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLnRyYW5zaXRpb25dIC0gVGhlIENTUyB0cmFuc2l0aW9uIGNsYXNzZXMgdG8gc2V0LlxuICAgICAgICogICBBY2NlcHRzIGEgc3RyaW5nIG9mIGNsYXNzZXMgdG8gYXBwbHkgd2hlbiByZW1vdmluZyBjbGFzc2VzIG9yXG4gICAgICAgKiAgIGEgMy10dXBsZSBjb250YWluaW5nIHRoZSB0cmFuc2l0aW9uIGNsYXNzLCB0aGUgY2xhc3MgdG8gYXBwbHlcbiAgICAgICAqICAgdG8gc3RhcnQgdGhlIHRyYW5zaXRpb24sIGFuZCB0aGUgZW5kaW5nIHRyYW5zaXRpb24gY2xhc3MsIHN1Y2ggYXM6XG4gICAgICAgKlxuICAgICAgICogICAgICAgW1wiZWFzZS1vdXQgZHVyYXRpb24tMzAwXCIsIFwib3BhY2l0eS0xMDBcIiwgXCJvcGFjaXR5LTBcIl1cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdHMudGltZV0gLSBUaGUgdHJhbnNpdGlvbiBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMuXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmJsb2NraW5nXSAtIFRoZSBib29sZWFuIGZsYWcgdG8gYmxvY2sgdGhlIFVJIGR1cmluZyB0aGUgdHJhbnNpdGlvbi5cbiAgICAgICAqICAgRGVmYXVsdHMgYHRydWVgLlxuICAgICAgICovXG4gICAgICByZW1vdmVDbGFzcyhlbCwgbmFtZXMsIG9wdHMgPSB7fSl7XG4gICAgICAgIG9wdHMudHJhbnNpdGlvbiA9IEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMudHJhbnNpdGlvbilcbiAgICAgICAgbmFtZXMgPSBBcnJheS5pc0FycmF5KG5hbWVzKSA/IG5hbWVzIDogbmFtZXMuc3BsaXQoXCIgXCIpXG4gICAgICAgIGxldCBvd25lciA9IGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5vd25lcihlbClcbiAgICAgICAgSlMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBbXSwgbmFtZXMsIG9wdHMudHJhbnNpdGlvbiwgb3B0cy50aW1lLCBvd25lciwgb3B0cy5ibG9ja2luZylcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogVG9nZ2xlcyBDU1MgY2xhc3NlcyBvbiBhbiBlbGVtZW50LlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIC0gVGhlIGVsZW1lbnQgdG8gdG9nZ2xlIGNsYXNzZXMgb24uXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gbmFtZXMgLSBUaGUgY2xhc3MgbmFtZShzKSB0byB0b2dnbGUuXG4gICAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9e31dIC0gT3B0aW9uYWwgc2V0dGluZ3MuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMudHJhbnNpdGlvbl0gLSBUaGUgQ1NTIHRyYW5zaXRpb24gY2xhc3NlcyB0byBzZXQuXG4gICAgICAgKiAgIEFjY2VwdHMgYSBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRvZ2dsaW5nIGNsYXNzZXMgb3JcbiAgICAgICAqICAgYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgICAgICogICB0byBzdGFydCB0aGUgdHJhbnNpdGlvbiwgYW5kIHRoZSBlbmRpbmcgdHJhbnNpdGlvbiBjbGFzcywgc3VjaCBhczpcbiAgICAgICAqXG4gICAgICAgKiAgICAgICBbXCJlYXNlLW91dCBkdXJhdGlvbi0zMDBcIiwgXCJvcGFjaXR5LTEwMFwiLCBcIm9wYWNpdHktMFwiXVxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lXSAtIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy5cbiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuYmxvY2tpbmddIC0gVGhlIGJvb2xlYW4gZmxhZyB0byBibG9jayB0aGUgVUkgZHVyaW5nIHRoZSB0cmFuc2l0aW9uLlxuICAgICAgICogICBEZWZhdWx0cyBgdHJ1ZWAuXG4gICAgICAgKi9cbiAgICAgIHRvZ2dsZUNsYXNzKGVsLCBuYW1lcywgb3B0cyA9IHt9KXtcbiAgICAgICAgb3B0cy50cmFuc2l0aW9uID0gSlMudHJhbnNpdGlvbkNsYXNzZXMob3B0cy50cmFuc2l0aW9uKVxuICAgICAgICBuYW1lcyA9IEFycmF5LmlzQXJyYXkobmFtZXMpID8gbmFtZXMgOiBuYW1lcy5zcGxpdChcIiBcIilcbiAgICAgICAgbGV0IG93bmVyID0gaG9vay5fX3ZpZXcoKS5saXZlU29ja2V0Lm93bmVyKGVsKVxuICAgICAgICBKUy50b2dnbGVDbGFzc2VzKGVsLCBuYW1lcywgb3B0cy50cmFuc2l0aW9uLCBvcHRzLnRpbWUsIG93bmVyLCBvcHRzLmJsb2NraW5nKVxuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBBcHBsaWVzIGEgQ1NTIHRyYW5zaXRpb24gdG8gYW4gZWxlbWVudC5cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIFRoZSBlbGVtZW50IHRvIGFwcGx5IHRoZSB0cmFuc2l0aW9uIHRvLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IHRyYW5zaXRpb24gLSBUaGUgdHJhbnNpdGlvbiBjbGFzcyhlcykgdG8gYXBwbHkuXG4gICAgICAgKiAgIEFjY2VwdHMgYSBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRyYW5zaXRpb25pbmcgb3JcbiAgICAgICAqICAgYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgICAgICogICB0byBzdGFydCB0aGUgdHJhbnNpdGlvbiwgYW5kIHRoZSBlbmRpbmcgdHJhbnNpdGlvbiBjbGFzcywgc3VjaCBhczpcbiAgICAgICAqXG4gICAgICAgKiAgICAgICBbXCJlYXNlLW91dCBkdXJhdGlvbi0zMDBcIiwgXCJvcGFjaXR5LTEwMFwiLCBcIm9wYWNpdHktMFwiXVxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lXSAtIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy5cbiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuYmxvY2tpbmddIC0gVGhlIGJvb2xlYW4gZmxhZyB0byBibG9jayB0aGUgVUkgZHVyaW5nIHRoZSB0cmFuc2l0aW9uLlxuICAgICAgICogICBEZWZhdWx0cyBgdHJ1ZWAuXG4gICAgICAgKi9cbiAgICAgIHRyYW5zaXRpb24oZWwsIHRyYW5zaXRpb24sIG9wdHMgPSB7fSl7XG4gICAgICAgIGxldCBvd25lciA9IGhvb2suX192aWV3KCkubGl2ZVNvY2tldC5vd25lcihlbClcbiAgICAgICAgSlMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBbXSwgW10sIEpTLnRyYW5zaXRpb25DbGFzc2VzKHRyYW5zaXRpb24pLCBvcHRzLnRpbWUsIG93bmVyLCBvcHRzLmJsb2NraW5nKVxuICAgICAgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBTZXRzIGFuIGF0dHJpYnV0ZSBvbiBhbiBlbGVtZW50LlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIC0gVGhlIGVsZW1lbnQgdG8gc2V0IHRoZSBhdHRyaWJ1dGUgb24uXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYXR0ciAtIFRoZSBhdHRyaWJ1dGUgbmFtZSB0byBzZXQuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsIC0gVGhlIHZhbHVlIHRvIHNldCBmb3IgdGhlIGF0dHJpYnV0ZS5cbiAgICAgICAqL1xuICAgICAgc2V0QXR0cmlidXRlKGVsLCBhdHRyLCB2YWwpeyBKUy5zZXRPclJlbW92ZUF0dHJzKGVsLCBbW2F0dHIsIHZhbF1dLCBbXSkgfSxcblxuICAgICAgLyoqXG4gICAgICAgKiBSZW1vdmVzIGFuIGF0dHJpYnV0ZSBmcm9tIGFuIGVsZW1lbnQuXG4gICAgICAgKlxuICAgICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWwgLSBUaGUgZWxlbWVudCB0byByZW1vdmUgdGhlIGF0dHJpYnV0ZSBmcm9tLlxuICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGF0dHIgLSBUaGUgYXR0cmlidXRlIG5hbWUgdG8gcmVtb3ZlLlxuICAgICAgICovXG4gICAgICByZW1vdmVBdHRyaWJ1dGUoZWwsIGF0dHIpeyBKUy5zZXRPclJlbW92ZUF0dHJzKGVsLCBbXSwgW2F0dHJdKSB9LFxuXG4gICAgICAvKipcbiAgICAgICAqIFRvZ2dsZXMgYW4gYXR0cmlidXRlIG9uIGFuIGVsZW1lbnQgYmV0d2VlbiB0d28gdmFsdWVzLlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIC0gVGhlIGVsZW1lbnQgdG8gdG9nZ2xlIHRoZSBhdHRyaWJ1dGUgb24uXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYXR0ciAtIFRoZSBhdHRyaWJ1dGUgbmFtZSB0byB0b2dnbGUuXG4gICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsMSAtIFRoZSBmaXJzdCB2YWx1ZSB0byB0b2dnbGUgYmV0d2Vlbi5cbiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWwyIC0gVGhlIHNlY29uZCB2YWx1ZSB0byB0b2dnbGUgYmV0d2Vlbi5cbiAgICAgICAqL1xuICAgICAgdG9nZ2xlQXR0cmlidXRlKGVsLCBhdHRyLCB2YWwxLCB2YWwyKXsgSlMudG9nZ2xlQXR0cihlbCwgYXR0ciwgdmFsMSwgdmFsMikgfSxcbiAgICB9XG4gIH1cblxuICBwdXNoRXZlbnQoZXZlbnQsIHBheWxvYWQgPSB7fSwgb25SZXBseSl7XG4gICAgaWYob25SZXBseSA9PT0gdW5kZWZpbmVkKXtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVmID0gdGhpcy5fX3ZpZXcoKS5wdXNoSG9va0V2ZW50KHRoaXMuZWwsIG51bGwsIGV2ZW50LCBwYXlsb2FkLCAocmVwbHksIF9yZWYpID0+IHJlc29sdmUocmVwbHkpKVxuICAgICAgICAgIGlmKHJlZiA9PT0gZmFsc2Upe1xuICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihcInVuYWJsZSB0byBwdXNoIGhvb2sgZXZlbnQuIExpdmVWaWV3IG5vdCBjb25uZWN0ZWRcIikpXG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcil7XG4gICAgICAgICAgcmVqZWN0KGVycm9yKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fX3ZpZXcoKS5wdXNoSG9va0V2ZW50KHRoaXMuZWwsIG51bGwsIGV2ZW50LCBwYXlsb2FkLCBvblJlcGx5KVxuICB9XG5cbiAgcHVzaEV2ZW50VG8ocGh4VGFyZ2V0LCBldmVudCwgcGF5bG9hZCA9IHt9LCBvblJlcGx5KXtcbiAgICBpZihvblJlcGx5ID09PSB1bmRlZmluZWQpe1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLl9fdmlldygpLndpdGhpblRhcmdldHMocGh4VGFyZ2V0LCAodmlldywgdGFyZ2V0Q3R4KSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZWYgPSB2aWV3LnB1c2hIb29rRXZlbnQodGhpcy5lbCwgdGFyZ2V0Q3R4LCBldmVudCwgcGF5bG9hZCwgKHJlcGx5LCBfcmVmKSA9PiByZXNvbHZlKHJlcGx5KSlcbiAgICAgICAgICAgIGlmKHJlZiA9PT0gZmFsc2Upe1xuICAgICAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwidW5hYmxlIHRvIHB1c2ggaG9vayBldmVudC4gTGl2ZVZpZXcgbm90IGNvbm5lY3RlZFwiKSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICB9IGNhdGNoIChlcnJvcil7XG4gICAgICAgICAgcmVqZWN0KGVycm9yKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fX3ZpZXcoKS53aXRoaW5UYXJnZXRzKHBoeFRhcmdldCwgKHZpZXcsIHRhcmdldEN0eCkgPT4ge1xuICAgICAgcmV0dXJuIHZpZXcucHVzaEhvb2tFdmVudCh0aGlzLmVsLCB0YXJnZXRDdHgsIGV2ZW50LCBwYXlsb2FkLCBvblJlcGx5KVxuICAgIH0pXG4gIH1cblxuICBoYW5kbGVFdmVudChldmVudCwgY2FsbGJhY2spe1xuICAgIGxldCBjYWxsYmFja1JlZiA9IChjdXN0b21FdmVudCwgYnlwYXNzKSA9PiBieXBhc3MgPyBldmVudCA6IGNhbGxiYWNrKGN1c3RvbUV2ZW50LmRldGFpbClcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihgcGh4OiR7ZXZlbnR9YCwgY2FsbGJhY2tSZWYpXG4gICAgdGhpcy5fX2xpc3RlbmVycy5hZGQoY2FsbGJhY2tSZWYpXG4gICAgcmV0dXJuIGNhbGxiYWNrUmVmXG4gIH1cblxuICByZW1vdmVIYW5kbGVFdmVudChjYWxsYmFja1JlZil7XG4gICAgbGV0IGV2ZW50ID0gY2FsbGJhY2tSZWYobnVsbCwgdHJ1ZSlcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihgcGh4OiR7ZXZlbnR9YCwgY2FsbGJhY2tSZWYpXG4gICAgdGhpcy5fX2xpc3RlbmVycy5kZWxldGUoY2FsbGJhY2tSZWYpXG4gIH1cblxuICB1cGxvYWQobmFtZSwgZmlsZXMpe1xuICAgIHJldHVybiB0aGlzLl9fdmlldygpLmRpc3BhdGNoVXBsb2FkcyhudWxsLCBuYW1lLCBmaWxlcylcbiAgfVxuXG4gIHVwbG9hZFRvKHBoeFRhcmdldCwgbmFtZSwgZmlsZXMpe1xuICAgIHJldHVybiB0aGlzLl9fdmlldygpLndpdGhpblRhcmdldHMocGh4VGFyZ2V0LCAodmlldywgdGFyZ2V0Q3R4KSA9PiB7XG4gICAgICB2aWV3LmRpc3BhdGNoVXBsb2Fkcyh0YXJnZXRDdHgsIG5hbWUsIGZpbGVzKVxuICAgIH0pXG4gIH1cblxuICBfX2NsZWFudXBfXygpe1xuICAgIHRoaXMuX19saXN0ZW5lcnMuZm9yRWFjaChjYWxsYmFja1JlZiA9PiB0aGlzLnJlbW92ZUhhbmRsZUV2ZW50KGNhbGxiYWNrUmVmKSlcbiAgfVxufVxuIiwgImltcG9ydCB7XG4gIEJFRk9SRV9VTkxPQURfTE9BREVSX1RJTUVPVVQsXG4gIENIRUNLQUJMRV9JTlBVVFMsXG4gIENPTlNFQ1VUSVZFX1JFTE9BRFMsXG4gIFBIWF9BVVRPX1JFQ09WRVIsXG4gIFBIWF9DT01QT05FTlQsXG4gIFBIWF9DT05ORUNURURfQ0xBU1MsXG4gIFBIWF9ESVNBQkxFX1dJVEgsXG4gIFBIWF9ESVNBQkxFX1dJVEhfUkVTVE9SRSxcbiAgUEhYX0RJU0FCTEVELFxuICBQSFhfTE9BRElOR19DTEFTUyxcbiAgUEhYX0VSUk9SX0NMQVNTLFxuICBQSFhfQ0xJRU5UX0VSUk9SX0NMQVNTLFxuICBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTLFxuICBQSFhfSEFTX0ZPQ1VTRUQsXG4gIFBIWF9IQVNfU1VCTUlUVEVELFxuICBQSFhfSE9PSyxcbiAgUEhYX1BBUkVOVF9JRCxcbiAgUEhYX1BST0dSRVNTLFxuICBQSFhfUkVBRE9OTFksXG4gIFBIWF9SRUZfTE9BRElORyxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9SRUZfTE9DSyxcbiAgUEhYX1JPT1RfSUQsXG4gIFBIWF9TRVNTSU9OLFxuICBQSFhfU1RBVElDLFxuICBQSFhfU1RJQ0tZLFxuICBQSFhfVFJBQ0tfU1RBVElDLFxuICBQSFhfVFJBQ0tfVVBMT0FEUyxcbiAgUEhYX1VQREFURSxcbiAgUEhYX1VQTE9BRF9SRUYsXG4gIFBIWF9WSUVXX1NFTEVDVE9SLFxuICBQSFhfTUFJTixcbiAgUEhYX01PVU5URUQsXG4gIFBVU0hfVElNRU9VVCxcbiAgUEhYX1ZJRVdQT1JUX1RPUCxcbiAgUEhYX1ZJRVdQT1JUX0JPVFRPTSxcbiAgTUFYX0NISUxEX0pPSU5fQVRURU1QVFNcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuaW1wb3J0IHtcbiAgY2xvbmUsXG4gIGNsb3Nlc3RQaHhCaW5kaW5nLFxuICBpc0VtcHR5LFxuICBpc0VxdWFsT2JqLFxuICBsb2dFcnJvcixcbiAgbWF5YmUsXG4gIGlzQ2lkLFxufSBmcm9tIFwiLi91dGlsc1wiXG5cbmltcG9ydCBCcm93c2VyIGZyb20gXCIuL2Jyb3dzZXJcIlxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIlxuaW1wb3J0IEVsZW1lbnRSZWYgZnJvbSBcIi4vZWxlbWVudF9yZWZcIlxuaW1wb3J0IERPTVBhdGNoIGZyb20gXCIuL2RvbV9wYXRjaFwiXG5pbXBvcnQgTGl2ZVVwbG9hZGVyIGZyb20gXCIuL2xpdmVfdXBsb2FkZXJcIlxuaW1wb3J0IFJlbmRlcmVkIGZyb20gXCIuL3JlbmRlcmVkXCJcbmltcG9ydCBWaWV3SG9vayBmcm9tIFwiLi92aWV3X2hvb2tcIlxuaW1wb3J0IEpTIGZyb20gXCIuL2pzXCJcblxuaW1wb3J0IG1vcnBoZG9tIGZyb20gXCJtb3JwaGRvbVwiXG5cbmV4cG9ydCBsZXQgcHJlcGVuZEZvcm1EYXRhS2V5ID0gKGtleSwgcHJlZml4KSA9PiB7XG4gIGxldCBpc0FycmF5ID0ga2V5LmVuZHNXaXRoKFwiW11cIilcbiAgLy8gUmVtb3ZlIHRoZSBcIltdXCIgaWYgaXQncyBhbiBhcnJheVxuICBsZXQgYmFzZUtleSA9IGlzQXJyYXkgPyBrZXkuc2xpY2UoMCwgLTIpIDoga2V5XG4gIC8vIFJlcGxhY2UgbGFzdCBvY2N1cnJlbmNlIG9mIGtleSBiZWZvcmUgYSBjbG9zaW5nIGJyYWNrZXQgb3IgdGhlIGVuZCB3aXRoIGtleSBwbHVzIHN1ZmZpeFxuICBiYXNlS2V5ID0gYmFzZUtleS5yZXBsYWNlKC8oW15cXFtcXF1dKykoXFxdPyQpLywgYCR7cHJlZml4fSQxJDJgKVxuICAvLyBBZGQgYmFjayB0aGUgXCJbXVwiIGlmIGl0IHdhcyBhbiBhcnJheVxuICBpZihpc0FycmF5KXsgYmFzZUtleSArPSBcIltdXCIgfVxuICByZXR1cm4gYmFzZUtleVxufVxuXG5sZXQgc2VyaWFsaXplRm9ybSA9IChmb3JtLCBvcHRzLCBvbmx5TmFtZXMgPSBbXSkgPT4ge1xuICBjb25zdCB7c3VibWl0dGVyfSA9IG9wdHNcblxuICAvLyBXZSBtdXN0IGluamVjdCB0aGUgc3VibWl0dGVyIGluIHRoZSBvcmRlciB0aGF0IGl0IGV4aXN0cyBpbiB0aGUgRE9NXG4gIC8vIHJlbGF0aXZlIHRvIG90aGVyIGlucHV0cy4gRm9yIGV4YW1wbGUsIGZvciBjaGVja2JveCBncm91cHMsIHRoZSBvcmRlciBtdXN0IGJlIG1haW50YWluZWQuXG4gIGxldCBpbmplY3RlZEVsZW1lbnRcbiAgaWYoc3VibWl0dGVyICYmIHN1Ym1pdHRlci5uYW1lKXtcbiAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiKVxuICAgIGlucHV0LnR5cGUgPSBcImhpZGRlblwiXG4gICAgLy8gc2V0IHRoZSBmb3JtIGF0dHJpYnV0ZSBpZiB0aGUgc3VibWl0dGVyIGhhcyBvbmU7XG4gICAgLy8gdGhpcyBjYW4gaGFwcGVuIGlmIHRoZSBlbGVtZW50IGlzIG91dHNpZGUgdGhlIGFjdHVhbCBmb3JtIGVsZW1lbnRcbiAgICBjb25zdCBmb3JtSWQgPSBzdWJtaXR0ZXIuZ2V0QXR0cmlidXRlKFwiZm9ybVwiKVxuICAgIGlmKGZvcm1JZCl7XG4gICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoXCJmb3JtXCIsIGZvcm1JZClcbiAgICB9XG4gICAgaW5wdXQubmFtZSA9IHN1Ym1pdHRlci5uYW1lXG4gICAgaW5wdXQudmFsdWUgPSBzdWJtaXR0ZXIudmFsdWVcbiAgICBzdWJtaXR0ZXIucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUoaW5wdXQsIHN1Ym1pdHRlcilcbiAgICBpbmplY3RlZEVsZW1lbnQgPSBpbnB1dFxuICB9XG5cbiAgY29uc3QgZm9ybURhdGEgPSBuZXcgRm9ybURhdGEoZm9ybSlcbiAgY29uc3QgdG9SZW1vdmUgPSBbXVxuXG4gIGZvcm1EYXRhLmZvckVhY2goKHZhbCwga2V5LCBfaW5kZXgpID0+IHtcbiAgICBpZih2YWwgaW5zdGFuY2VvZiBGaWxlKXsgdG9SZW1vdmUucHVzaChrZXkpIH1cbiAgfSlcblxuICAvLyBDbGVhbnVwIGFmdGVyIGJ1aWxkaW5nIGZpbGVEYXRhXG4gIHRvUmVtb3ZlLmZvckVhY2goa2V5ID0+IGZvcm1EYXRhLmRlbGV0ZShrZXkpKVxuXG4gIGNvbnN0IHBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoKVxuXG4gIGNvbnN0IHtpbnB1dHNVbnVzZWQsIG9ubHlIaWRkZW5JbnB1dHN9ID0gQXJyYXkuZnJvbShmb3JtLmVsZW1lbnRzKS5yZWR1Y2UoKGFjYywgaW5wdXQpID0+IHtcbiAgICBjb25zdCB7aW5wdXRzVW51c2VkLCBvbmx5SGlkZGVuSW5wdXRzfSA9IGFjY1xuICAgIGNvbnN0IGtleSA9IGlucHV0Lm5hbWVcbiAgICBpZigha2V5KXsgcmV0dXJuIGFjYyB9XG5cbiAgICBpZihpbnB1dHNVbnVzZWRba2V5XSA9PT0gdW5kZWZpbmVkKXsgaW5wdXRzVW51c2VkW2tleV0gPSB0cnVlIH1cbiAgICBpZihvbmx5SGlkZGVuSW5wdXRzW2tleV0gPT09IHVuZGVmaW5lZCl7IG9ubHlIaWRkZW5JbnB1dHNba2V5XSA9IHRydWUgfVxuXG4gICAgY29uc3QgaXNVc2VkID0gRE9NLnByaXZhdGUoaW5wdXQsIFBIWF9IQVNfRk9DVVNFRCkgfHwgRE9NLnByaXZhdGUoaW5wdXQsIFBIWF9IQVNfU1VCTUlUVEVEKVxuICAgIGNvbnN0IGlzSGlkZGVuID0gaW5wdXQudHlwZSA9PT0gXCJoaWRkZW5cIlxuICAgIGlucHV0c1VudXNlZFtrZXldID0gaW5wdXRzVW51c2VkW2tleV0gJiYgIWlzVXNlZFxuICAgIG9ubHlIaWRkZW5JbnB1dHNba2V5XSA9IG9ubHlIaWRkZW5JbnB1dHNba2V5XSAmJiBpc0hpZGRlblxuXG4gICAgcmV0dXJuIGFjY1xuICB9LCB7aW5wdXRzVW51c2VkOiB7fSwgb25seUhpZGRlbklucHV0czoge319KVxuXG4gIGZvcihsZXQgW2tleSwgdmFsXSBvZiBmb3JtRGF0YS5lbnRyaWVzKCkpe1xuICAgIGlmKG9ubHlOYW1lcy5sZW5ndGggPT09IDAgfHwgb25seU5hbWVzLmluZGV4T2Yoa2V5KSA+PSAwKXtcbiAgICAgIGxldCBpc1VudXNlZCA9IGlucHV0c1VudXNlZFtrZXldXG4gICAgICBsZXQgaGlkZGVuID0gb25seUhpZGRlbklucHV0c1trZXldXG4gICAgICBpZihpc1VudXNlZCAmJiAhKHN1Ym1pdHRlciAmJiBzdWJtaXR0ZXIubmFtZSA9PSBrZXkpICYmICFoaWRkZW4pe1xuICAgICAgICBwYXJhbXMuYXBwZW5kKHByZXBlbmRGb3JtRGF0YUtleShrZXksIFwiX3VudXNlZF9cIiksIFwiXCIpXG4gICAgICB9XG4gICAgICBwYXJhbXMuYXBwZW5kKGtleSwgdmFsKVxuICAgIH1cbiAgfVxuXG4gIC8vIHJlbW92ZSB0aGUgaW5qZWN0ZWQgZWxlbWVudCBhZ2FpblxuICAvLyAoaXQgd291bGQgYmUgcmVtb3ZlZCBieSB0aGUgbmV4dCBkb20gcGF0Y2ggYW55d2F5LCBidXQgdGhpcyBpcyBjbGVhbmVyKVxuICBpZihzdWJtaXR0ZXIgJiYgaW5qZWN0ZWRFbGVtZW50KXtcbiAgICBzdWJtaXR0ZXIucGFyZW50RWxlbWVudC5yZW1vdmVDaGlsZChpbmplY3RlZEVsZW1lbnQpXG4gIH1cblxuICByZXR1cm4gcGFyYW1zLnRvU3RyaW5nKClcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVmlldyB7XG4gIHN0YXRpYyBjbG9zZXN0VmlldyhlbCl7XG4gICAgbGV0IGxpdmVWaWV3RWwgPSBlbC5jbG9zZXN0KFBIWF9WSUVXX1NFTEVDVE9SKVxuICAgIHJldHVybiBsaXZlVmlld0VsID8gRE9NLnByaXZhdGUobGl2ZVZpZXdFbCwgXCJ2aWV3XCIpIDogbnVsbFxuICB9XG5cbiAgY29uc3RydWN0b3IoZWwsIGxpdmVTb2NrZXQsIHBhcmVudFZpZXcsIGZsYXNoLCBsaXZlUmVmZXJlcil7XG4gICAgdGhpcy5pc0RlYWQgPSBmYWxzZVxuICAgIHRoaXMubGl2ZVNvY2tldCA9IGxpdmVTb2NrZXRcbiAgICB0aGlzLmZsYXNoID0gZmxhc2hcbiAgICB0aGlzLnBhcmVudCA9IHBhcmVudFZpZXdcbiAgICB0aGlzLnJvb3QgPSBwYXJlbnRWaWV3ID8gcGFyZW50Vmlldy5yb290IDogdGhpc1xuICAgIHRoaXMuZWwgPSBlbFxuICAgIERPTS5wdXRQcml2YXRlKHRoaXMuZWwsIFwidmlld1wiLCB0aGlzKVxuICAgIHRoaXMuaWQgPSB0aGlzLmVsLmlkXG4gICAgdGhpcy5yZWYgPSAwXG4gICAgdGhpcy5sYXN0QWNrUmVmID0gbnVsbFxuICAgIHRoaXMuY2hpbGRKb2lucyA9IDBcbiAgICB0aGlzLmxvYWRlclRpbWVyID0gbnVsbFxuICAgIHRoaXMuZGlzY29ubmVjdGVkVGltZXIgPSBudWxsXG4gICAgdGhpcy5wZW5kaW5nRGlmZnMgPSBbXVxuICAgIHRoaXMucGVuZGluZ0Zvcm1zID0gbmV3IFNldCgpXG4gICAgdGhpcy5yZWRpcmVjdCA9IGZhbHNlXG4gICAgdGhpcy5ocmVmID0gbnVsbFxuICAgIHRoaXMuam9pbkNvdW50ID0gdGhpcy5wYXJlbnQgPyB0aGlzLnBhcmVudC5qb2luQ291bnQgLSAxIDogMFxuICAgIHRoaXMuam9pbkF0dGVtcHRzID0gMFxuICAgIHRoaXMuam9pblBlbmRpbmcgPSB0cnVlXG4gICAgdGhpcy5kZXN0cm95ZWQgPSBmYWxzZVxuICAgIHRoaXMuam9pbkNhbGxiYWNrID0gZnVuY3Rpb24ob25Eb25lKXsgb25Eb25lICYmIG9uRG9uZSgpIH1cbiAgICB0aGlzLnN0b3BDYWxsYmFjayA9IGZ1bmN0aW9uKCl7IH1cbiAgICB0aGlzLnBlbmRpbmdKb2luT3BzID0gdGhpcy5wYXJlbnQgPyBudWxsIDogW11cbiAgICB0aGlzLnZpZXdIb29rcyA9IHt9XG4gICAgdGhpcy5mb3JtU3VibWl0cyA9IFtdXG4gICAgdGhpcy5jaGlsZHJlbiA9IHRoaXMucGFyZW50ID8gbnVsbCA6IHt9XG4gICAgdGhpcy5yb290LmNoaWxkcmVuW3RoaXMuaWRdID0ge31cbiAgICB0aGlzLmZvcm1zRm9yUmVjb3ZlcnkgPSB7fVxuICAgIHRoaXMuY2hhbm5lbCA9IHRoaXMubGl2ZVNvY2tldC5jaGFubmVsKGBsdjoke3RoaXMuaWR9YCwgKCkgPT4ge1xuICAgICAgbGV0IHVybCA9IHRoaXMuaHJlZiAmJiB0aGlzLmV4cGFuZFVSTCh0aGlzLmhyZWYpXG4gICAgICByZXR1cm4ge1xuICAgICAgICByZWRpcmVjdDogdGhpcy5yZWRpcmVjdCA/IHVybCA6IHVuZGVmaW5lZCxcbiAgICAgICAgdXJsOiB0aGlzLnJlZGlyZWN0ID8gdW5kZWZpbmVkIDogdXJsIHx8IHVuZGVmaW5lZCxcbiAgICAgICAgcGFyYW1zOiB0aGlzLmNvbm5lY3RQYXJhbXMobGl2ZVJlZmVyZXIpLFxuICAgICAgICBzZXNzaW9uOiB0aGlzLmdldFNlc3Npb24oKSxcbiAgICAgICAgc3RhdGljOiB0aGlzLmdldFN0YXRpYygpLFxuICAgICAgICBmbGFzaDogdGhpcy5mbGFzaCxcbiAgICAgICAgc3RpY2t5OiB0aGlzLmVsLmhhc0F0dHJpYnV0ZShQSFhfU1RJQ0tZKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBzZXRIcmVmKGhyZWYpeyB0aGlzLmhyZWYgPSBocmVmIH1cblxuICBzZXRSZWRpcmVjdChocmVmKXtcbiAgICB0aGlzLnJlZGlyZWN0ID0gdHJ1ZVxuICAgIHRoaXMuaHJlZiA9IGhyZWZcbiAgfVxuXG4gIGlzTWFpbigpeyByZXR1cm4gdGhpcy5lbC5oYXNBdHRyaWJ1dGUoUEhYX01BSU4pIH1cblxuICBjb25uZWN0UGFyYW1zKGxpdmVSZWZlcmVyKXtcbiAgICBsZXQgcGFyYW1zID0gdGhpcy5saXZlU29ja2V0LnBhcmFtcyh0aGlzLmVsKVxuICAgIGxldCBtYW5pZmVzdCA9XG4gICAgICBET00uYWxsKGRvY3VtZW50LCBgWyR7dGhpcy5iaW5kaW5nKFBIWF9UUkFDS19TVEFUSUMpfV1gKVxuICAgICAgICAubWFwKG5vZGUgPT4gbm9kZS5zcmMgfHwgbm9kZS5ocmVmKS5maWx0ZXIodXJsID0+IHR5cGVvZiAodXJsKSA9PT0gXCJzdHJpbmdcIilcblxuICAgIGlmKG1hbmlmZXN0Lmxlbmd0aCA+IDApeyBwYXJhbXNbXCJfdHJhY2tfc3RhdGljXCJdID0gbWFuaWZlc3QgfVxuICAgIHBhcmFtc1tcIl9tb3VudHNcIl0gPSB0aGlzLmpvaW5Db3VudFxuICAgIHBhcmFtc1tcIl9tb3VudF9hdHRlbXB0c1wiXSA9IHRoaXMuam9pbkF0dGVtcHRzXG4gICAgcGFyYW1zW1wiX2xpdmVfcmVmZXJlclwiXSA9IGxpdmVSZWZlcmVyXG4gICAgdGhpcy5qb2luQXR0ZW1wdHMrK1xuXG4gICAgcmV0dXJuIHBhcmFtc1xuICB9XG5cbiAgaXNDb25uZWN0ZWQoKXsgcmV0dXJuIHRoaXMuY2hhbm5lbC5jYW5QdXNoKCkgfVxuXG4gIGdldFNlc3Npb24oKXsgcmV0dXJuIHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9TRVNTSU9OKSB9XG5cbiAgZ2V0U3RhdGljKCl7XG4gICAgbGV0IHZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9TVEFUSUMpXG4gICAgcmV0dXJuIHZhbCA9PT0gXCJcIiA/IG51bGwgOiB2YWxcbiAgfVxuXG4gIGRlc3Ryb3koY2FsbGJhY2sgPSBmdW5jdGlvbiAoKXsgfSl7XG4gICAgdGhpcy5kZXN0cm95QWxsQ2hpbGRyZW4oKVxuICAgIHRoaXMuZGVzdHJveWVkID0gdHJ1ZVxuICAgIGRlbGV0ZSB0aGlzLnJvb3QuY2hpbGRyZW5bdGhpcy5pZF1cbiAgICBpZih0aGlzLnBhcmVudCl7IGRlbGV0ZSB0aGlzLnJvb3QuY2hpbGRyZW5bdGhpcy5wYXJlbnQuaWRdW3RoaXMuaWRdIH1cbiAgICBjbGVhclRpbWVvdXQodGhpcy5sb2FkZXJUaW1lcilcbiAgICBsZXQgb25GaW5pc2hlZCA9ICgpID0+IHtcbiAgICAgIGNhbGxiYWNrKClcbiAgICAgIGZvcihsZXQgaWQgaW4gdGhpcy52aWV3SG9va3Mpe1xuICAgICAgICB0aGlzLmRlc3Ryb3lIb29rKHRoaXMudmlld0hvb2tzW2lkXSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICBET00ubWFya1BoeENoaWxkRGVzdHJveWVkKHRoaXMuZWwpXG5cbiAgICB0aGlzLmxvZyhcImRlc3Ryb3llZFwiLCAoKSA9PiBbXCJ0aGUgY2hpbGQgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIHRoZSBwYXJlbnRcIl0pXG4gICAgdGhpcy5jaGFubmVsLmxlYXZlKClcbiAgICAgIC5yZWNlaXZlKFwib2tcIiwgb25GaW5pc2hlZClcbiAgICAgIC5yZWNlaXZlKFwiZXJyb3JcIiwgb25GaW5pc2hlZClcbiAgICAgIC5yZWNlaXZlKFwidGltZW91dFwiLCBvbkZpbmlzaGVkKVxuICB9XG5cbiAgc2V0Q29udGFpbmVyQ2xhc3NlcyguLi5jbGFzc2VzKXtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdC5yZW1vdmUoXG4gICAgICBQSFhfQ09OTkVDVEVEX0NMQVNTLFxuICAgICAgUEhYX0xPQURJTkdfQ0xBU1MsXG4gICAgICBQSFhfRVJST1JfQ0xBU1MsXG4gICAgICBQSFhfQ0xJRU5UX0VSUk9SX0NMQVNTLFxuICAgICAgUEhYX1NFUlZFUl9FUlJPUl9DTEFTU1xuICAgIClcbiAgICB0aGlzLmVsLmNsYXNzTGlzdC5hZGQoLi4uY2xhc3NlcylcbiAgfVxuXG4gIHNob3dMb2FkZXIodGltZW91dCl7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMubG9hZGVyVGltZXIpXG4gICAgaWYodGltZW91dCl7XG4gICAgICB0aGlzLmxvYWRlclRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB0aGlzLnNob3dMb2FkZXIoKSwgdGltZW91dClcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yKGxldCBpZCBpbiB0aGlzLnZpZXdIb29rcyl7IHRoaXMudmlld0hvb2tzW2lkXS5fX2Rpc2Nvbm5lY3RlZCgpIH1cbiAgICAgIHRoaXMuc2V0Q29udGFpbmVyQ2xhc3NlcyhQSFhfTE9BRElOR19DTEFTUylcbiAgICB9XG4gIH1cblxuICBleGVjQWxsKGJpbmRpbmcpe1xuICAgIERPTS5hbGwodGhpcy5lbCwgYFske2JpbmRpbmd9XWAsIGVsID0+IHRoaXMubGl2ZVNvY2tldC5leGVjSlMoZWwsIGVsLmdldEF0dHJpYnV0ZShiaW5kaW5nKSkpXG4gIH1cblxuICBoaWRlTG9hZGVyKCl7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMubG9hZGVyVGltZXIpXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuZGlzY29ubmVjdGVkVGltZXIpXG4gICAgdGhpcy5zZXRDb250YWluZXJDbGFzc2VzKFBIWF9DT05ORUNURURfQ0xBU1MpXG4gICAgdGhpcy5leGVjQWxsKHRoaXMuYmluZGluZyhcImNvbm5lY3RlZFwiKSlcbiAgfVxuXG4gIHRyaWdnZXJSZWNvbm5lY3RlZCgpe1xuICAgIGZvcihsZXQgaWQgaW4gdGhpcy52aWV3SG9va3MpeyB0aGlzLnZpZXdIb29rc1tpZF0uX19yZWNvbm5lY3RlZCgpIH1cbiAgfVxuXG4gIGxvZyhraW5kLCBtc2dDYWxsYmFjayl7XG4gICAgdGhpcy5saXZlU29ja2V0LmxvZyh0aGlzLCBraW5kLCBtc2dDYWxsYmFjaylcbiAgfVxuXG4gIHRyYW5zaXRpb24odGltZSwgb25TdGFydCwgb25Eb25lID0gZnVuY3Rpb24oKXt9KXtcbiAgICB0aGlzLmxpdmVTb2NrZXQudHJhbnNpdGlvbih0aW1lLCBvblN0YXJ0LCBvbkRvbmUpXG4gIH1cblxuICAvLyBjYWxscyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgdmlldyBhbmQgdGFyZ2V0IGVsZW1lbnQgZm9yIHRoZSBnaXZlbiBwaHhUYXJnZXRcbiAgLy8gdGFyZ2V0cyBjYW4gYmU6XG4gIC8vICAqIGFuIGVsZW1lbnQgaXRzZWxmLCB0aGVuIGl0IGlzIHNpbXBseSBwYXNzZWQgdG8gbGl2ZVNvY2tldC5vd25lcjtcbiAgLy8gICogYSBDSUQgKENvbXBvbmVudCBJRCksIHRoZW4gd2UgZmlyc3Qgc2VhcmNoIHRoZSBjb21wb25lbnQncyBlbGVtZW50IGluIHRoZSBET01cbiAgLy8gICogYSBzZWxlY3RvciwgdGhlbiB3ZSBzZWFyY2ggdGhlIHNlbGVjdG9yIGluIHRoZSBET00gYW5kIGNhbGwgdGhlIGNhbGxiYWNrXG4gIC8vICAgIGZvciBlYWNoIGVsZW1lbnQgZm91bmQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBvd25lciB2aWV3XG4gIHdpdGhpblRhcmdldHMocGh4VGFyZ2V0LCBjYWxsYmFjaywgZG9tID0gZG9jdW1lbnQsIHZpZXdFbCl7XG4gICAgLy8gaW4gdGhlIGZvcm0gcmVjb3ZlcnkgY2FzZSB3ZSBzZWFyY2ggaW4gYSB0ZW1wbGF0ZSBmcmFnbWVudCBpbnN0ZWFkIG9mXG4gICAgLy8gdGhlIHJlYWwgZG9tLCB0aGVyZWZvcmUgd2Ugb3B0aW9uYWxseSBwYXNzIGRvbSBhbmQgdmlld0VsXG5cbiAgICBpZihwaHhUYXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCB8fCBwaHhUYXJnZXQgaW5zdGFuY2VvZiBTVkdFbGVtZW50KXtcbiAgICAgIHJldHVybiB0aGlzLmxpdmVTb2NrZXQub3duZXIocGh4VGFyZ2V0LCB2aWV3ID0+IGNhbGxiYWNrKHZpZXcsIHBoeFRhcmdldCkpXG4gICAgfVxuXG4gICAgaWYoaXNDaWQocGh4VGFyZ2V0KSl7XG4gICAgICBsZXQgdGFyZ2V0cyA9IERPTS5maW5kQ29tcG9uZW50Tm9kZUxpc3Qodmlld0VsIHx8IHRoaXMuZWwsIHBoeFRhcmdldClcbiAgICAgIGlmKHRhcmdldHMubGVuZ3RoID09PSAwKXtcbiAgICAgICAgbG9nRXJyb3IoYG5vIGNvbXBvbmVudCBmb3VuZCBtYXRjaGluZyBwaHgtdGFyZ2V0IG9mICR7cGh4VGFyZ2V0fWApXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYWxsYmFjayh0aGlzLCBwYXJzZUludChwaHhUYXJnZXQpKVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgdGFyZ2V0cyA9IEFycmF5LmZyb20oZG9tLnF1ZXJ5U2VsZWN0b3JBbGwocGh4VGFyZ2V0KSlcbiAgICAgIGlmKHRhcmdldHMubGVuZ3RoID09PSAwKXsgbG9nRXJyb3IoYG5vdGhpbmcgZm91bmQgbWF0Y2hpbmcgdGhlIHBoeC10YXJnZXQgc2VsZWN0b3IgXCIke3BoeFRhcmdldH1cImApIH1cbiAgICAgIHRhcmdldHMuZm9yRWFjaCh0YXJnZXQgPT4gdGhpcy5saXZlU29ja2V0Lm93bmVyKHRhcmdldCwgdmlldyA9PiBjYWxsYmFjayh2aWV3LCB0YXJnZXQpKSlcbiAgICB9XG4gIH1cblxuICBhcHBseURpZmYodHlwZSwgcmF3RGlmZiwgY2FsbGJhY2spe1xuICAgIHRoaXMubG9nKHR5cGUsICgpID0+IFtcIlwiLCBjbG9uZShyYXdEaWZmKV0pXG4gICAgbGV0IHtkaWZmLCByZXBseSwgZXZlbnRzLCB0aXRsZX0gPSBSZW5kZXJlZC5leHRyYWN0KHJhd0RpZmYpXG4gICAgY2FsbGJhY2soe2RpZmYsIHJlcGx5LCBldmVudHN9KVxuICAgIGlmKHR5cGVvZiB0aXRsZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlID09IFwibW91bnRcIil7IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gRE9NLnB1dFRpdGxlKHRpdGxlKSkgfVxuICB9XG5cbiAgb25Kb2luKHJlc3Ape1xuICAgIGxldCB7cmVuZGVyZWQsIGNvbnRhaW5lciwgbGl2ZXZpZXdfdmVyc2lvbn0gPSByZXNwXG4gICAgaWYoY29udGFpbmVyKXtcbiAgICAgIGxldCBbdGFnLCBhdHRyc10gPSBjb250YWluZXJcbiAgICAgIHRoaXMuZWwgPSBET00ucmVwbGFjZVJvb3RDb250YWluZXIodGhpcy5lbCwgdGFnLCBhdHRycylcbiAgICB9XG4gICAgdGhpcy5jaGlsZEpvaW5zID0gMFxuICAgIHRoaXMuam9pblBlbmRpbmcgPSB0cnVlXG4gICAgdGhpcy5mbGFzaCA9IG51bGxcbiAgICBpZih0aGlzLnJvb3QgPT09IHRoaXMpe1xuICAgICAgdGhpcy5mb3Jtc0ZvclJlY292ZXJ5ID0gdGhpcy5nZXRGb3Jtc0ZvclJlY292ZXJ5KClcbiAgICB9XG4gICAgaWYodGhpcy5pc01haW4oKSAmJiB3aW5kb3cuaGlzdG9yeS5zdGF0ZSA9PT0gbnVsbCl7XG4gICAgICAvLyBzZXQgaW5pdGlhbCBoaXN0b3J5IGVudHJ5IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHBhZ2UgbG9hZCAobm8gaGlzdG9yeSlcbiAgICAgIEJyb3dzZXIucHVzaFN0YXRlKFwicmVwbGFjZVwiLCB7XG4gICAgICAgIHR5cGU6IFwicGF0Y2hcIixcbiAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLmxpdmVTb2NrZXQuY3VycmVudEhpc3RvcnlQb3NpdGlvblxuICAgICAgfSlcbiAgICB9XG5cbiAgICBpZihsaXZldmlld192ZXJzaW9uICE9PSB0aGlzLmxpdmVTb2NrZXQudmVyc2lvbigpKXtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYExpdmVWaWV3IGFzc2V0IHZlcnNpb24gbWlzbWF0Y2guIEphdmFTY3JpcHQgdmVyc2lvbiAke3RoaXMubGl2ZVNvY2tldC52ZXJzaW9uKCl9IHZzLiBzZXJ2ZXIgJHtsaXZldmlld192ZXJzaW9ufS4gVG8gYXZvaWQgaXNzdWVzLCBwbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBhc3NldHMgdXNlIHRoZSBzYW1lIHZlcnNpb24gYXMgdGhlIHNlcnZlci5gKVxuICAgIH1cblxuICAgIEJyb3dzZXIuZHJvcExvY2FsKHRoaXMubGl2ZVNvY2tldC5sb2NhbFN0b3JhZ2UsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSwgQ09OU0VDVVRJVkVfUkVMT0FEUylcbiAgICB0aGlzLmFwcGx5RGlmZihcIm1vdW50XCIsIHJlbmRlcmVkLCAoe2RpZmYsIGV2ZW50c30pID0+IHtcbiAgICAgIHRoaXMucmVuZGVyZWQgPSBuZXcgUmVuZGVyZWQodGhpcy5pZCwgZGlmZilcbiAgICAgIGxldCBbaHRtbCwgc3RyZWFtc10gPSB0aGlzLnJlbmRlckNvbnRhaW5lcihudWxsLCBcImpvaW5cIilcbiAgICAgIHRoaXMuZHJvcFBlbmRpbmdSZWZzKClcbiAgICAgIHRoaXMuam9pbkNvdW50KytcbiAgICAgIHRoaXMuam9pbkF0dGVtcHRzID0gMFxuXG4gICAgICB0aGlzLm1heWJlUmVjb3ZlckZvcm1zKGh0bWwsICgpID0+IHtcbiAgICAgICAgdGhpcy5vbkpvaW5Db21wbGV0ZShyZXNwLCBodG1sLCBzdHJlYW1zLCBldmVudHMpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICBkcm9wUGVuZGluZ1JlZnMoKXtcbiAgICBET00uYWxsKGRvY3VtZW50LCBgWyR7UEhYX1JFRl9TUkN9PVwiJHt0aGlzLnJlZlNyYygpfVwiXWAsIGVsID0+IHtcbiAgICAgIGVsLnJlbW92ZUF0dHJpYnV0ZShQSFhfUkVGX0xPQURJTkcpXG4gICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFRl9TUkMpXG4gICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKVxuICAgIH0pXG4gIH1cblxuICBvbkpvaW5Db21wbGV0ZSh7bGl2ZV9wYXRjaH0sIGh0bWwsIHN0cmVhbXMsIGV2ZW50cyl7XG4gICAgLy8gSW4gb3JkZXIgdG8gcHJvdmlkZSBhIGJldHRlciBleHBlcmllbmNlLCB3ZSB3YW50IHRvIGpvaW5cbiAgICAvLyBhbGwgTGl2ZVZpZXdzIGZpcnN0IGFuZCBvbmx5IHRoZW4gYXBwbHkgdGhlaXIgcGF0Y2hlcy5cbiAgICBpZih0aGlzLmpvaW5Db3VudCA+IDEgfHwgKHRoaXMucGFyZW50ICYmICF0aGlzLnBhcmVudC5pc0pvaW5QZW5kaW5nKCkpKXtcbiAgICAgIHJldHVybiB0aGlzLmFwcGx5Sm9pblBhdGNoKGxpdmVfcGF0Y2gsIGh0bWwsIHN0cmVhbXMsIGV2ZW50cylcbiAgICB9XG5cbiAgICAvLyBPbmUgZG93bnNpZGUgb2YgdGhpcyBhcHByb2FjaCBpcyB0aGF0IHdlIG5lZWQgdG8gZmluZCBwaHhDaGlsZHJlblxuICAgIC8vIGluIHRoZSBodG1sIGZyYWdtZW50LCBpbnN0ZWFkIG9mIGRpcmVjdGx5IG9uIHRoZSBET00uIFRoZSBmcmFnbWVudFxuICAgIC8vIGFsc28gZG9lcyBub3QgaW5jbHVkZSBQSFhfU1RBVElDLCBzbyB3ZSBuZWVkIHRvIGNvcHkgaXQgb3ZlciBmcm9tXG4gICAgLy8gdGhlIERPTS5cbiAgICBsZXQgbmV3Q2hpbGRyZW4gPSBET00uZmluZFBoeENoaWxkcmVuSW5GcmFnbWVudChodG1sLCB0aGlzLmlkKS5maWx0ZXIodG9FbCA9PiB7XG4gICAgICBsZXQgZnJvbUVsID0gdG9FbC5pZCAmJiB0aGlzLmVsLnF1ZXJ5U2VsZWN0b3IoYFtpZD1cIiR7dG9FbC5pZH1cIl1gKVxuICAgICAgbGV0IHBoeFN0YXRpYyA9IGZyb21FbCAmJiBmcm9tRWwuZ2V0QXR0cmlidXRlKFBIWF9TVEFUSUMpXG4gICAgICBpZihwaHhTdGF0aWMpeyB0b0VsLnNldEF0dHJpYnV0ZShQSFhfU1RBVElDLCBwaHhTdGF0aWMpIH1cbiAgICAgIC8vIHNldCBQSFhfUk9PVF9JRCB0byBwcmV2ZW50IGV2ZW50cyBmcm9tIGJlaW5nIGRpc3BhdGNoZWQgdG8gdGhlIHJvb3Qgdmlld1xuICAgICAgLy8gd2hpbGUgdGhlIGNoaWxkIGpvaW4gaXMgc3RpbGwgcGVuZGluZ1xuICAgICAgaWYoZnJvbUVsKXsgZnJvbUVsLnNldEF0dHJpYnV0ZShQSFhfUk9PVF9JRCwgdGhpcy5yb290LmlkKSB9XG4gICAgICByZXR1cm4gdGhpcy5qb2luQ2hpbGQodG9FbClcbiAgICB9KVxuXG4gICAgaWYobmV3Q2hpbGRyZW4ubGVuZ3RoID09PSAwKXtcbiAgICAgIGlmKHRoaXMucGFyZW50KXtcbiAgICAgICAgdGhpcy5yb290LnBlbmRpbmdKb2luT3BzLnB1c2goW3RoaXMsICgpID0+IHRoaXMuYXBwbHlKb2luUGF0Y2gobGl2ZV9wYXRjaCwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKV0pXG4gICAgICAgIHRoaXMucGFyZW50LmFja0pvaW4odGhpcylcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMub25BbGxDaGlsZEpvaW5zQ29tcGxldGUoKVxuICAgICAgICB0aGlzLmFwcGx5Sm9pblBhdGNoKGxpdmVfcGF0Y2gsIGh0bWwsIHN0cmVhbXMsIGV2ZW50cylcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yb290LnBlbmRpbmdKb2luT3BzLnB1c2goW3RoaXMsICgpID0+IHRoaXMuYXBwbHlKb2luUGF0Y2gobGl2ZV9wYXRjaCwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKV0pXG4gICAgfVxuICB9XG5cbiAgYXR0YWNoVHJ1ZURvY0VsKCl7XG4gICAgdGhpcy5lbCA9IERPTS5ieUlkKHRoaXMuaWQpXG4gICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoUEhYX1JPT1RfSUQsIHRoaXMucm9vdC5pZClcbiAgfVxuXG4gIC8vIHRoaXMgaXMgaW52b2tlZCBmb3IgZGVhZCBhbmQgbGl2ZSB2aWV3cywgc28gd2UgbXVzdCBmaWx0ZXIgYnlcbiAgLy8gYnkgb3duZXIgdG8gZW5zdXJlIHdlIGFyZW4ndCBkdXBsaWNhdGluZyBob29rcyBhY3Jvc3MgZGlzY29ubmVjdFxuICAvLyBhbmQgY29ubmVjdGVkIHN0YXRlcy4gVGhpcyBhbHNvIGhhbmRsZXMgY2FzZXMgd2hlcmUgaG9va3MgZXhpc3RcbiAgLy8gaW4gYSByb290IGxheW91dCB3aXRoIGEgTFYgaW4gdGhlIGJvZHlcbiAgZXhlY05ld01vdW50ZWQocGFyZW50ID0gdGhpcy5lbCl7XG4gICAgbGV0IHBoeFZpZXdwb3J0VG9wID0gdGhpcy5iaW5kaW5nKFBIWF9WSUVXUE9SVF9UT1ApXG4gICAgbGV0IHBoeFZpZXdwb3J0Qm90dG9tID0gdGhpcy5iaW5kaW5nKFBIWF9WSUVXUE9SVF9CT1RUT00pXG4gICAgRE9NLmFsbChwYXJlbnQsIGBbJHtwaHhWaWV3cG9ydFRvcH1dLCBbJHtwaHhWaWV3cG9ydEJvdHRvbX1dYCwgaG9va0VsID0+IHtcbiAgICAgIGlmKHRoaXMub3duc0VsZW1lbnQoaG9va0VsKSl7XG4gICAgICAgIERPTS5tYWludGFpblByaXZhdGVIb29rcyhob29rRWwsIGhvb2tFbCwgcGh4Vmlld3BvcnRUb3AsIHBoeFZpZXdwb3J0Qm90dG9tKVxuICAgICAgICB0aGlzLm1heWJlQWRkTmV3SG9vayhob29rRWwpXG4gICAgICB9XG4gICAgfSlcbiAgICBET00uYWxsKHBhcmVudCwgYFske3RoaXMuYmluZGluZyhQSFhfSE9PSyl9XSwgW2RhdGEtcGh4LSR7UEhYX0hPT0t9XWAsIGhvb2tFbCA9PiB7XG4gICAgICBpZih0aGlzLm93bnNFbGVtZW50KGhvb2tFbCkpe1xuICAgICAgICB0aGlzLm1heWJlQWRkTmV3SG9vayhob29rRWwpXG4gICAgICB9XG4gICAgfSlcbiAgICBET00uYWxsKHBhcmVudCwgYFske3RoaXMuYmluZGluZyhQSFhfTU9VTlRFRCl9XWAsIGVsID0+IHtcbiAgICAgIGlmKHRoaXMub3duc0VsZW1lbnQoZWwpKXtcbiAgICAgICAgdGhpcy5tYXliZU1vdW50ZWQoZWwpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIGFwcGx5Sm9pblBhdGNoKGxpdmVfcGF0Y2gsIGh0bWwsIHN0cmVhbXMsIGV2ZW50cyl7XG4gICAgdGhpcy5hdHRhY2hUcnVlRG9jRWwoKVxuICAgIGxldCBwYXRjaCA9IG5ldyBET01QYXRjaCh0aGlzLCB0aGlzLmVsLCB0aGlzLmlkLCBodG1sLCBzdHJlYW1zLCBudWxsKVxuICAgIHBhdGNoLm1hcmtQcnVuYWJsZUNvbnRlbnRGb3JSZW1vdmFsKClcbiAgICB0aGlzLnBlcmZvcm1QYXRjaChwYXRjaCwgZmFsc2UsIHRydWUpXG4gICAgdGhpcy5qb2luTmV3Q2hpbGRyZW4oKVxuICAgIHRoaXMuZXhlY05ld01vdW50ZWQoKVxuXG4gICAgdGhpcy5qb2luUGVuZGluZyA9IGZhbHNlXG4gICAgdGhpcy5saXZlU29ja2V0LmRpc3BhdGNoRXZlbnRzKGV2ZW50cylcbiAgICB0aGlzLmFwcGx5UGVuZGluZ1VwZGF0ZXMoKVxuXG4gICAgaWYobGl2ZV9wYXRjaCl7XG4gICAgICBsZXQge2tpbmQsIHRvfSA9IGxpdmVfcGF0Y2hcbiAgICAgIHRoaXMubGl2ZVNvY2tldC5oaXN0b3J5UGF0Y2godG8sIGtpbmQpXG4gICAgfVxuICAgIHRoaXMuaGlkZUxvYWRlcigpXG4gICAgaWYodGhpcy5qb2luQ291bnQgPiAxKXsgdGhpcy50cmlnZ2VyUmVjb25uZWN0ZWQoKSB9XG4gICAgdGhpcy5zdG9wQ2FsbGJhY2soKVxuICB9XG5cbiAgdHJpZ2dlckJlZm9yZVVwZGF0ZUhvb2soZnJvbUVsLCB0b0VsKXtcbiAgICB0aGlzLmxpdmVTb2NrZXQudHJpZ2dlckRPTShcIm9uQmVmb3JlRWxVcGRhdGVkXCIsIFtmcm9tRWwsIHRvRWxdKVxuICAgIGxldCBob29rID0gdGhpcy5nZXRIb29rKGZyb21FbClcbiAgICBsZXQgaXNJZ25vcmVkID0gaG9vayAmJiBET00uaXNJZ25vcmVkKGZyb21FbCwgdGhpcy5iaW5kaW5nKFBIWF9VUERBVEUpKVxuICAgIGlmKGhvb2sgJiYgIWZyb21FbC5pc0VxdWFsTm9kZSh0b0VsKSAmJiAhKGlzSWdub3JlZCAmJiBpc0VxdWFsT2JqKGZyb21FbC5kYXRhc2V0LCB0b0VsLmRhdGFzZXQpKSl7XG4gICAgICBob29rLl9fYmVmb3JlVXBkYXRlKClcbiAgICAgIHJldHVybiBob29rXG4gICAgfVxuICB9XG5cbiAgbWF5YmVNb3VudGVkKGVsKXtcbiAgICBsZXQgcGh4TW91bnRlZCA9IGVsLmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoUEhYX01PVU5URUQpKVxuICAgIGxldCBoYXNCZWVuSW52b2tlZCA9IHBoeE1vdW50ZWQgJiYgRE9NLnByaXZhdGUoZWwsIFwibW91bnRlZFwiKVxuICAgIGlmKHBoeE1vdW50ZWQgJiYgIWhhc0JlZW5JbnZva2VkKXtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC5leGVjSlMoZWwsIHBoeE1vdW50ZWQpXG4gICAgICBET00ucHV0UHJpdmF0ZShlbCwgXCJtb3VudGVkXCIsIHRydWUpXG4gICAgfVxuICB9XG5cbiAgbWF5YmVBZGROZXdIb29rKGVsKXtcbiAgICBsZXQgbmV3SG9vayA9IHRoaXMuYWRkSG9vayhlbClcbiAgICBpZihuZXdIb29rKXsgbmV3SG9vay5fX21vdW50ZWQoKSB9XG4gIH1cblxuICBwZXJmb3JtUGF0Y2gocGF0Y2gsIHBydW5lQ2lkcywgaXNKb2luUGF0Y2ggPSBmYWxzZSl7XG4gICAgbGV0IHJlbW92ZWRFbHMgPSBbXVxuICAgIGxldCBwaHhDaGlsZHJlbkFkZGVkID0gZmFsc2VcbiAgICBsZXQgdXBkYXRlZEhvb2tJZHMgPSBuZXcgU2V0KClcblxuICAgIHRoaXMubGl2ZVNvY2tldC50cmlnZ2VyRE9NKFwib25QYXRjaFN0YXJ0XCIsIFtwYXRjaC50YXJnZXRDb250YWluZXJdKVxuXG4gICAgcGF0Y2guYWZ0ZXIoXCJhZGRlZFwiLCBlbCA9PiB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQudHJpZ2dlckRPTShcIm9uTm9kZUFkZGVkXCIsIFtlbF0pXG4gICAgICBsZXQgcGh4Vmlld3BvcnRUb3AgPSB0aGlzLmJpbmRpbmcoUEhYX1ZJRVdQT1JUX1RPUClcbiAgICAgIGxldCBwaHhWaWV3cG9ydEJvdHRvbSA9IHRoaXMuYmluZGluZyhQSFhfVklFV1BPUlRfQk9UVE9NKVxuICAgICAgRE9NLm1haW50YWluUHJpdmF0ZUhvb2tzKGVsLCBlbCwgcGh4Vmlld3BvcnRUb3AsIHBoeFZpZXdwb3J0Qm90dG9tKVxuICAgICAgdGhpcy5tYXliZUFkZE5ld0hvb2soZWwpXG4gICAgICBpZihlbC5nZXRBdHRyaWJ1dGUpeyB0aGlzLm1heWJlTW91bnRlZChlbCkgfVxuICAgIH0pXG5cbiAgICBwYXRjaC5hZnRlcihcInBoeENoaWxkQWRkZWRcIiwgZWwgPT4ge1xuICAgICAgaWYoRE9NLmlzUGh4U3RpY2t5KGVsKSl7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5qb2luUm9vdFZpZXdzKClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBoeENoaWxkcmVuQWRkZWQgPSB0cnVlXG4gICAgICB9XG4gICAgfSlcblxuICAgIHBhdGNoLmJlZm9yZShcInVwZGF0ZWRcIiwgKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgbGV0IGhvb2sgPSB0aGlzLnRyaWdnZXJCZWZvcmVVcGRhdGVIb29rKGZyb21FbCwgdG9FbClcbiAgICAgIGlmKGhvb2speyB1cGRhdGVkSG9va0lkcy5hZGQoZnJvbUVsLmlkKSB9XG4gICAgfSlcblxuICAgIHBhdGNoLmFmdGVyKFwidXBkYXRlZFwiLCBlbCA9PiB7XG4gICAgICBpZih1cGRhdGVkSG9va0lkcy5oYXMoZWwuaWQpKXsgdGhpcy5nZXRIb29rKGVsKS5fX3VwZGF0ZWQoKSB9XG4gICAgfSlcblxuICAgIHBhdGNoLmFmdGVyKFwiZGlzY2FyZGVkXCIsIChlbCkgPT4ge1xuICAgICAgaWYoZWwubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFKXsgcmVtb3ZlZEVscy5wdXNoKGVsKSB9XG4gICAgfSlcblxuICAgIHBhdGNoLmFmdGVyKFwidHJhbnNpdGlvbnNEaXNjYXJkZWRcIiwgZWxzID0+IHRoaXMuYWZ0ZXJFbGVtZW50c1JlbW92ZWQoZWxzLCBwcnVuZUNpZHMpKVxuICAgIHBhdGNoLnBlcmZvcm0oaXNKb2luUGF0Y2gpXG4gICAgdGhpcy5hZnRlckVsZW1lbnRzUmVtb3ZlZChyZW1vdmVkRWxzLCBwcnVuZUNpZHMpXG5cbiAgICB0aGlzLmxpdmVTb2NrZXQudHJpZ2dlckRPTShcIm9uUGF0Y2hFbmRcIiwgW3BhdGNoLnRhcmdldENvbnRhaW5lcl0pXG4gICAgcmV0dXJuIHBoeENoaWxkcmVuQWRkZWRcbiAgfVxuXG4gIGFmdGVyRWxlbWVudHNSZW1vdmVkKGVsZW1lbnRzLCBwcnVuZUNpZHMpe1xuICAgIGxldCBkZXN0cm95ZWRDSURzID0gW11cbiAgICBlbGVtZW50cy5mb3JFYWNoKHBhcmVudCA9PiB7XG4gICAgICBsZXQgY29tcG9uZW50cyA9IERPTS5hbGwocGFyZW50LCBgWyR7UEhYX0NPTVBPTkVOVH1dYClcbiAgICAgIGxldCBob29rcyA9IERPTS5hbGwocGFyZW50LCBgWyR7dGhpcy5iaW5kaW5nKFBIWF9IT09LKX1dLCBbZGF0YS1waHgtaG9va11gKVxuICAgICAgY29tcG9uZW50cy5jb25jYXQocGFyZW50KS5mb3JFYWNoKGVsID0+IHtcbiAgICAgICAgbGV0IGNpZCA9IHRoaXMuY29tcG9uZW50SUQoZWwpXG4gICAgICAgIGlmKGlzQ2lkKGNpZCkgJiYgZGVzdHJveWVkQ0lEcy5pbmRleE9mKGNpZCkgPT09IC0xKXsgZGVzdHJveWVkQ0lEcy5wdXNoKGNpZCkgfVxuICAgICAgfSlcbiAgICAgIGhvb2tzLmNvbmNhdChwYXJlbnQpLmZvckVhY2goaG9va0VsID0+IHtcbiAgICAgICAgbGV0IGhvb2sgPSB0aGlzLmdldEhvb2soaG9va0VsKVxuICAgICAgICBob29rICYmIHRoaXMuZGVzdHJveUhvb2soaG9vaylcbiAgICAgIH0pXG4gICAgfSlcbiAgICAvLyBXZSBzaG91bGQgbm90IHBydW5lQ2lkcyBvbiBqb2lucy4gT3RoZXJ3aXNlLCBpbiBjYXNlIG9mXG4gICAgLy8gcmVqb2lucywgd2UgbWF5IG5vdGlmeSBjaWRzIHRoYXQgbm8gbG9uZ2VyIGJlbG9uZyB0byB0aGVcbiAgICAvLyBjdXJyZW50IExpdmVWaWV3IHRvIGJlIHJlbW92ZWQuXG4gICAgaWYocHJ1bmVDaWRzKXtcbiAgICAgIHRoaXMubWF5YmVQdXNoQ29tcG9uZW50c0Rlc3Ryb3llZChkZXN0cm95ZWRDSURzKVxuICAgIH1cbiAgfVxuXG4gIGpvaW5OZXdDaGlsZHJlbigpe1xuICAgIERPTS5maW5kUGh4Q2hpbGRyZW4odGhpcy5lbCwgdGhpcy5pZCkuZm9yRWFjaChlbCA9PiB0aGlzLmpvaW5DaGlsZChlbCkpXG4gIH1cblxuICBtYXliZVJlY292ZXJGb3JtcyhodG1sLCBjYWxsYmFjayl7XG4gICAgY29uc3QgcGh4Q2hhbmdlID0gdGhpcy5iaW5kaW5nKFwiY2hhbmdlXCIpXG4gICAgY29uc3Qgb2xkRm9ybXMgPSB0aGlzLnJvb3QuZm9ybXNGb3JSZWNvdmVyeVxuICAgIC8vIFNvIHdoeSBkbyB3ZSBjcmVhdGUgYSB0ZW1wbGF0ZSBlbGVtZW50IGhlcmU/XG4gICAgLy8gT25lIHdheSB0byByZWNvdmVyIGZvcm1zIHdvdWxkIGJlIHRvIGltbWVkaWF0ZWx5IGFwcGx5IHRoZSBtb3VudFxuICAgIC8vIHBhdGNoIGFuZCB0aGVuIGFmdGVyd2FyZHMgcmVjb3ZlciB0aGUgZm9ybXMuIEhvd2V2ZXIsIHRoaXMgd291bGRcbiAgICAvLyBjYXVzZSBhIGZsaWNrZXIsIGJlY2F1c2UgdGhlIG1vdW50IHBhdGNoIHdvdWxkIHJlbW92ZSB0aGUgZm9ybSBjb250ZW50XG4gICAgLy8gdW50aWwgaXQgaXMgcmVzdG9yZWQuIFRoZXJlZm9yZSBMViBkZWNpZGVkIHRvIGRvIGZvcm0gcmVjb3Zlcnkgd2l0aCB0aGVcbiAgICAvLyByYXcgSFRNTCBiZWZvcmUgaXQgaXMgYXBwbGllZCBhbmQgZGVsYXkgdGhlIG1vdW50IHBhdGNoIHVudGlsIHRoZSBmb3JtXG4gICAgLy8gcmVjb3ZlcnkgZXZlbnRzIGFyZSBkb25lLlxuICAgIGxldCB0ZW1wbGF0ZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0ZW1wbGF0ZVwiKVxuICAgIHRlbXBsYXRlLmlubmVySFRNTCA9IGh0bWxcbiAgICAvLyBiZWNhdXNlIHdlIHdvcmsgd2l0aCBhIHRlbXBsYXRlIGVsZW1lbnQsIHdlIG11c3QgbWFudWFsbHkgY29weSB0aGUgYXR0cmlidXRlc1xuICAgIC8vIG90aGVyd2lzZSB0aGUgb3duZXIgLyB0YXJnZXQgaGVscGVycyBkb24ndCB3b3JrIHByb3Blcmx5XG4gICAgY29uc3Qgcm9vdEVsID0gdGVtcGxhdGUuY29udGVudC5maXJzdEVsZW1lbnRDaGlsZFxuICAgIHJvb3RFbC5pZCA9IHRoaXMuaWRcbiAgICByb290RWwuc2V0QXR0cmlidXRlKFBIWF9ST09UX0lELCB0aGlzLnJvb3QuaWQpXG4gICAgcm9vdEVsLnNldEF0dHJpYnV0ZShQSFhfU0VTU0lPTiwgdGhpcy5nZXRTZXNzaW9uKCkpXG4gICAgcm9vdEVsLnNldEF0dHJpYnV0ZShQSFhfU1RBVElDLCB0aGlzLmdldFN0YXRpYygpKVxuICAgIHJvb3RFbC5zZXRBdHRyaWJ1dGUoUEhYX1BBUkVOVF9JRCwgdGhpcy5wYXJlbnQgPyB0aGlzLnBhcmVudC5pZCA6IG51bGwpXG5cbiAgICAvLyB3ZSBnbyBvdmVyIGFsbCBmb3JtIGVsZW1lbnRzIGluIHRoZSBuZXcgSFRNTCBmb3IgdGhlIExWXG4gICAgLy8gYW5kIGxvb2sgZm9yIG9sZCBmb3JtcyBpbiB0aGUgYGZvcm1zRm9yUmVjb3ZlcnlgIG9iamVjdDtcbiAgICAvLyB0aGUgZm9ybXNGb3JSZWNvdmVyeSBjYW4gYWxzbyBjb250YWluIGZvcm1zIGZyb20gY2hpbGQgdmlld3NcbiAgICBjb25zdCBmb3Jtc1RvUmVjb3ZlciA9XG4gICAgICAvLyB3ZSBnbyBvdmVyIGFsbCBmb3JtcyBpbiB0aGUgbmV3IERPTTsgYmVjYXVzZSB0aGlzIGlzIG9ubHkgdGhlIEhUTUwgZm9yIHRoZSBjdXJyZW50XG4gICAgICAvLyB2aWV3LCB3ZSBjYW4gYmUgc3VyZSB0aGF0IGFsbCBmb3JtcyBhcmUgb3duZWQgYnkgdGhpcyB2aWV3OlxuICAgICAgRE9NLmFsbCh0ZW1wbGF0ZS5jb250ZW50LCBcImZvcm1cIilcbiAgICAgICAgLy8gb25seSByZWNvdmVyIGZvcm1zIHRoYXQgaGF2ZSBhbiBpZCBhbmQgYXJlIGluIHRoZSBvbGQgRE9NXG4gICAgICAgIC5maWx0ZXIobmV3Rm9ybSA9PiBuZXdGb3JtLmlkICYmIG9sZEZvcm1zW25ld0Zvcm0uaWRdKVxuICAgICAgICAvLyBhYmFuZG9uIGZvcm1zIHdlIGFscmVhZHkgdHJpZWQgdG8gcmVjb3ZlciB0byBwcmV2ZW50IGxvb3BpbmcgYSBmYWlsZWQgc3RhdGVcbiAgICAgICAgLmZpbHRlcihuZXdGb3JtID0+ICF0aGlzLnBlbmRpbmdGb3Jtcy5oYXMobmV3Rm9ybS5pZCkpXG4gICAgICAgIC8vIG9ubHkgcmVjb3ZlciBpZiB0aGUgZm9ybSBoYXMgdGhlIHNhbWUgcGh4LWNoYW5nZSB2YWx1ZVxuICAgICAgICAuZmlsdGVyKG5ld0Zvcm0gPT4gb2xkRm9ybXNbbmV3Rm9ybS5pZF0uZ2V0QXR0cmlidXRlKHBoeENoYW5nZSkgPT09IG5ld0Zvcm0uZ2V0QXR0cmlidXRlKHBoeENoYW5nZSkpXG4gICAgICAgIC5tYXAobmV3Rm9ybSA9PiB7XG4gICAgICAgICAgcmV0dXJuIFtvbGRGb3Jtc1tuZXdGb3JtLmlkXSwgbmV3Rm9ybV1cbiAgICAgICAgfSlcblxuICAgIGlmKGZvcm1zVG9SZWNvdmVyLmxlbmd0aCA9PT0gMCl7XG4gICAgICByZXR1cm4gY2FsbGJhY2soKVxuICAgIH1cblxuICAgIGZvcm1zVG9SZWNvdmVyLmZvckVhY2goKFtvbGRGb3JtLCBuZXdGb3JtXSwgaSkgPT4ge1xuICAgICAgdGhpcy5wZW5kaW5nRm9ybXMuYWRkKG5ld0Zvcm0uaWQpXG4gICAgICAvLyBpdCBpcyBpbXBvcnRhbnQgdG8gdXNlIHRoZSBmaXJzdEVsZW1lbnRDaGlsZCBvZiB0aGUgdGVtcGxhdGUgY29udGVudFxuICAgICAgLy8gYmVjYXVzZSB3aGVuIHRyYXZlcnNpbmcgYSBkb2N1bWVudEZyYWdtZW50IHVzaW5nIHBhcmVudE5vZGUsIHdlIHdvbid0IGV2ZXIgYXJyaXZlIGF0XG4gICAgICAvLyB0aGUgZnJhZ21lbnQ7IGFzIHRoZSB0ZW1wbGF0ZSBpcyBhbHdheXMgYSBMaXZlVmlldywgd2UgY2FuIGJlIHN1cmUgdGhhdCB0aGVyZSBpcyBvbmx5XG4gICAgICAvLyBvbmUgY2hpbGQgb24gdGhlIHJvb3QgbGV2ZWxcbiAgICAgIHRoaXMucHVzaEZvcm1SZWNvdmVyeShvbGRGb3JtLCBuZXdGb3JtLCB0ZW1wbGF0ZS5jb250ZW50LmZpcnN0RWxlbWVudENoaWxkLCAoKSA9PiB7XG4gICAgICAgIHRoaXMucGVuZGluZ0Zvcm1zLmRlbGV0ZShuZXdGb3JtLmlkKVxuICAgICAgICAvLyB3ZSBvbmx5IGNhbGwgdGhlIGNhbGxiYWNrIG9uY2UgYWxsIGZvcm1zIGhhdmUgYmVlbiByZWNvdmVyZWRcbiAgICAgICAgaWYoaSA9PT0gZm9ybXNUb1JlY292ZXIubGVuZ3RoIC0gMSl7XG4gICAgICAgICAgY2FsbGJhY2soKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICBnZXRDaGlsZEJ5SWQoaWQpeyByZXR1cm4gdGhpcy5yb290LmNoaWxkcmVuW3RoaXMuaWRdW2lkXSB9XG5cbiAgZ2V0RGVzY2VuZGVudEJ5RWwoZWwpe1xuICAgIGlmKGVsLmlkID09PSB0aGlzLmlkKXtcbiAgICAgIHJldHVybiB0aGlzXG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0aGlzLmNoaWxkcmVuW2VsLmdldEF0dHJpYnV0ZShQSFhfUEFSRU5UX0lEKV0/LltlbC5pZF1cbiAgICB9XG4gIH1cblxuICBkZXN0cm95RGVzY2VuZGVudChpZCl7XG4gICAgZm9yKGxldCBwYXJlbnRJZCBpbiB0aGlzLnJvb3QuY2hpbGRyZW4pe1xuICAgICAgZm9yKGxldCBjaGlsZElkIGluIHRoaXMucm9vdC5jaGlsZHJlbltwYXJlbnRJZF0pe1xuICAgICAgICBpZihjaGlsZElkID09PSBpZCl7IHJldHVybiB0aGlzLnJvb3QuY2hpbGRyZW5bcGFyZW50SWRdW2NoaWxkSWRdLmRlc3Ryb3koKSB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgam9pbkNoaWxkKGVsKXtcbiAgICBsZXQgY2hpbGQgPSB0aGlzLmdldENoaWxkQnlJZChlbC5pZClcbiAgICBpZighY2hpbGQpe1xuICAgICAgbGV0IHZpZXcgPSBuZXcgVmlldyhlbCwgdGhpcy5saXZlU29ja2V0LCB0aGlzKVxuICAgICAgdGhpcy5yb290LmNoaWxkcmVuW3RoaXMuaWRdW3ZpZXcuaWRdID0gdmlld1xuICAgICAgdmlldy5qb2luKClcbiAgICAgIHRoaXMuY2hpbGRKb2lucysrXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIGlzSm9pblBlbmRpbmcoKXsgcmV0dXJuIHRoaXMuam9pblBlbmRpbmcgfVxuXG4gIGFja0pvaW4oX2NoaWxkKXtcbiAgICB0aGlzLmNoaWxkSm9pbnMtLVxuXG4gICAgaWYodGhpcy5jaGlsZEpvaW5zID09PSAwKXtcbiAgICAgIGlmKHRoaXMucGFyZW50KXtcbiAgICAgICAgdGhpcy5wYXJlbnQuYWNrSm9pbih0aGlzKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5vbkFsbENoaWxkSm9pbnNDb21wbGV0ZSgpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgb25BbGxDaGlsZEpvaW5zQ29tcGxldGUoKXtcbiAgICAvLyB3ZSBjYW4gY2xlYXIgcGVuZGluZyBmb3JtIHJlY292ZXJpZXMgbm93IHRoYXQgd2UndmUgam9pbmVkLlxuICAgIC8vIFRoZXkgZWl0aGVyIGFsbCByZXNvbHZlZCBvciB3ZXJlIGFiYW5kb25lZFxuICAgIHRoaXMucGVuZGluZ0Zvcm1zLmNsZWFyKClcbiAgICAvLyB3ZSBjYW4gYWxzbyBjbGVhciB0aGUgZm9ybXNGb3JSZWNvdmVyeSBvYmplY3QgdG8gbm90IGtlZXAgb2xkIGZvcm0gZWxlbWVudHMgYXJvdW5kXG4gICAgdGhpcy5mb3Jtc0ZvclJlY292ZXJ5ID0ge31cbiAgICB0aGlzLmpvaW5DYWxsYmFjaygoKSA9PiB7XG4gICAgICB0aGlzLnBlbmRpbmdKb2luT3BzLmZvckVhY2goKFt2aWV3LCBvcF0pID0+IHtcbiAgICAgICAgaWYoIXZpZXcuaXNEZXN0cm95ZWQoKSl7IG9wKCkgfVxuICAgICAgfSlcbiAgICAgIHRoaXMucGVuZGluZ0pvaW5PcHMgPSBbXVxuICAgIH0pXG4gIH1cblxuICB1cGRhdGUoZGlmZiwgZXZlbnRzKXtcbiAgICBpZih0aGlzLmlzSm9pblBlbmRpbmcoKSB8fCAodGhpcy5saXZlU29ja2V0Lmhhc1BlbmRpbmdMaW5rKCkgJiYgdGhpcy5yb290LmlzTWFpbigpKSl7XG4gICAgICByZXR1cm4gdGhpcy5wZW5kaW5nRGlmZnMucHVzaCh7ZGlmZiwgZXZlbnRzfSlcbiAgICB9XG5cbiAgICB0aGlzLnJlbmRlcmVkLm1lcmdlRGlmZihkaWZmKVxuICAgIGxldCBwaHhDaGlsZHJlbkFkZGVkID0gZmFsc2VcblxuICAgIC8vIFdoZW4gdGhlIGRpZmYgb25seSBjb250YWlucyBjb21wb25lbnQgZGlmZnMsIHRoZW4gd2FsayBjb21wb25lbnRzXG4gICAgLy8gYW5kIHBhdGNoIG9ubHkgdGhlIHBhcmVudCBjb21wb25lbnQgY29udGFpbmVycyBmb3VuZCBpbiB0aGUgZGlmZi5cbiAgICAvLyBPdGhlcndpc2UsIHBhdGNoIGVudGlyZSBMViBjb250YWluZXIuXG4gICAgaWYodGhpcy5yZW5kZXJlZC5pc0NvbXBvbmVudE9ubHlEaWZmKGRpZmYpKXtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC50aW1lKFwiY29tcG9uZW50IHBhdGNoIGNvbXBsZXRlXCIsICgpID0+IHtcbiAgICAgICAgbGV0IHBhcmVudENpZHMgPSBET00uZmluZEV4aXN0aW5nUGFyZW50Q0lEcyh0aGlzLmVsLCB0aGlzLnJlbmRlcmVkLmNvbXBvbmVudENJRHMoZGlmZikpXG4gICAgICAgIHBhcmVudENpZHMuZm9yRWFjaChwYXJlbnRDSUQgPT4ge1xuICAgICAgICAgIGlmKHRoaXMuY29tcG9uZW50UGF0Y2godGhpcy5yZW5kZXJlZC5nZXRDb21wb25lbnQoZGlmZiwgcGFyZW50Q0lEKSwgcGFyZW50Q0lEKSl7IHBoeENoaWxkcmVuQWRkZWQgPSB0cnVlIH1cbiAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfSBlbHNlIGlmKCFpc0VtcHR5KGRpZmYpKXtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC50aW1lKFwiZnVsbCBwYXRjaCBjb21wbGV0ZVwiLCAoKSA9PiB7XG4gICAgICAgIGxldCBbaHRtbCwgc3RyZWFtc10gPSB0aGlzLnJlbmRlckNvbnRhaW5lcihkaWZmLCBcInVwZGF0ZVwiKVxuICAgICAgICBsZXQgcGF0Y2ggPSBuZXcgRE9NUGF0Y2godGhpcywgdGhpcy5lbCwgdGhpcy5pZCwgaHRtbCwgc3RyZWFtcywgbnVsbClcbiAgICAgICAgcGh4Q2hpbGRyZW5BZGRlZCA9IHRoaXMucGVyZm9ybVBhdGNoKHBhdGNoLCB0cnVlKVxuICAgICAgfSlcbiAgICB9XG5cbiAgICB0aGlzLmxpdmVTb2NrZXQuZGlzcGF0Y2hFdmVudHMoZXZlbnRzKVxuICAgIGlmKHBoeENoaWxkcmVuQWRkZWQpeyB0aGlzLmpvaW5OZXdDaGlsZHJlbigpIH1cbiAgfVxuXG4gIHJlbmRlckNvbnRhaW5lcihkaWZmLCBraW5kKXtcbiAgICByZXR1cm4gdGhpcy5saXZlU29ja2V0LnRpbWUoYHRvU3RyaW5nIGRpZmYgKCR7a2luZH0pYCwgKCkgPT4ge1xuICAgICAgbGV0IHRhZyA9IHRoaXMuZWwudGFnTmFtZVxuICAgICAgLy8gRG9uJ3Qgc2tpcCBhbnkgY29tcG9uZW50IGluIHRoZSBkaWZmIG5vciBhbnkgbWFya2VkIGFzIHBydW5lZFxuICAgICAgLy8gKGFzIHRoZXkgbWF5IGhhdmUgYmVlbiBhZGRlZCBiYWNrKVxuICAgICAgbGV0IGNpZHMgPSBkaWZmID8gdGhpcy5yZW5kZXJlZC5jb21wb25lbnRDSURzKGRpZmYpIDogbnVsbFxuICAgICAgbGV0IFtodG1sLCBzdHJlYW1zXSA9IHRoaXMucmVuZGVyZWQudG9TdHJpbmcoY2lkcylcbiAgICAgIHJldHVybiBbYDwke3RhZ30+JHtodG1sfTwvJHt0YWd9PmAsIHN0cmVhbXNdXG4gICAgfSlcbiAgfVxuXG4gIGNvbXBvbmVudFBhdGNoKGRpZmYsIGNpZCl7XG4gICAgaWYoaXNFbXB0eShkaWZmKSkgcmV0dXJuIGZhbHNlXG4gICAgbGV0IFtodG1sLCBzdHJlYW1zXSA9IHRoaXMucmVuZGVyZWQuY29tcG9uZW50VG9TdHJpbmcoY2lkKVxuICAgIGxldCBwYXRjaCA9IG5ldyBET01QYXRjaCh0aGlzLCB0aGlzLmVsLCB0aGlzLmlkLCBodG1sLCBzdHJlYW1zLCBjaWQpXG4gICAgbGV0IGNoaWxkcmVuQWRkZWQgPSB0aGlzLnBlcmZvcm1QYXRjaChwYXRjaCwgdHJ1ZSlcbiAgICByZXR1cm4gY2hpbGRyZW5BZGRlZFxuICB9XG5cbiAgZ2V0SG9vayhlbCl7IHJldHVybiB0aGlzLnZpZXdIb29rc1tWaWV3SG9vay5lbGVtZW50SUQoZWwpXSB9XG5cbiAgYWRkSG9vayhlbCl7XG4gICAgbGV0IGhvb2tFbElkID0gVmlld0hvb2suZWxlbWVudElEKGVsKVxuXG4gICAgLy8gb25seSBldmVyIHRyeSB0byBhZGQgaG9va3MgdG8gZWxlbWVudHMgb3duZWQgYnkgdGhpcyB2aWV3XG4gICAgaWYoZWwuZ2V0QXR0cmlidXRlICYmICF0aGlzLm93bnNFbGVtZW50KGVsKSl7IHJldHVybiB9XG5cbiAgICBpZihob29rRWxJZCAmJiAhdGhpcy52aWV3SG9va3NbaG9va0VsSWRdKXtcbiAgICAgIC8vIGhvb2sgY3JlYXRlZCwgYnV0IG5vdCBhdHRhY2hlZCAoY3JlYXRlSG9vayBmb3Igd2ViIGNvbXBvbmVudClcbiAgICAgIGxldCBob29rID0gRE9NLmdldEN1c3RvbUVsSG9vayhlbCkgfHwgbG9nRXJyb3IoYG5vIGhvb2sgZm91bmQgZm9yIGN1c3RvbSBlbGVtZW50OiAke2VsLmlkfWApXG4gICAgICB0aGlzLnZpZXdIb29rc1tob29rRWxJZF0gPSBob29rXG4gICAgICBob29rLl9fYXR0YWNoVmlldyh0aGlzKVxuICAgICAgcmV0dXJuIGhvb2tcbiAgICB9XG4gICAgZWxzZSBpZihob29rRWxJZCB8fCAhZWwuZ2V0QXR0cmlidXRlKXtcbiAgICAgIC8vIG5vIGhvb2sgZm91bmRcbiAgICAgIHJldHVyblxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBuZXcgaG9vayBmb3VuZCB3aXRoIHBoeC1ob29rIGF0dHJpYnV0ZVxuICAgICAgbGV0IGhvb2tOYW1lID0gZWwuZ2V0QXR0cmlidXRlKGBkYXRhLXBoeC0ke1BIWF9IT09LfWApIHx8IGVsLmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoUEhYX0hPT0spKVxuICAgICAgbGV0IGNhbGxiYWNrcyA9IHRoaXMubGl2ZVNvY2tldC5nZXRIb29rQ2FsbGJhY2tzKGhvb2tOYW1lKVxuXG4gICAgICBpZihjYWxsYmFja3Mpe1xuICAgICAgICBpZighZWwuaWQpeyBsb2dFcnJvcihgbm8gRE9NIElEIGZvciBob29rIFwiJHtob29rTmFtZX1cIi4gSG9va3MgcmVxdWlyZSBhIHVuaXF1ZSBJRCBvbiBlYWNoIGVsZW1lbnQuYCwgZWwpIH1cbiAgICAgICAgbGV0IGhvb2sgPSBuZXcgVmlld0hvb2sodGhpcywgZWwsIGNhbGxiYWNrcylcbiAgICAgICAgdGhpcy52aWV3SG9va3NbVmlld0hvb2suZWxlbWVudElEKGhvb2suZWwpXSA9IGhvb2tcbiAgICAgICAgcmV0dXJuIGhvb2tcbiAgICAgIH0gZWxzZSBpZihob29rTmFtZSAhPT0gbnVsbCl7XG4gICAgICAgIGxvZ0Vycm9yKGB1bmtub3duIGhvb2sgZm91bmQgZm9yIFwiJHtob29rTmFtZX1cImAsIGVsKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGRlc3Ryb3lIb29rKGhvb2spe1xuICAgIC8vIF9fZGVzdHJveWVkIGNsZWFycyB0aGUgZWxlbWVudElEIGZyb20gdGhlIGhvb2ssIHRoZXJlZm9yZVxuICAgIC8vIHdlIG5lZWQgdG8gZ2V0IGl0IGJlZm9yZSBjYWxsaW5nIF9fZGVzdHJveWVkXG4gICAgY29uc3QgaG9va0lkID0gVmlld0hvb2suZWxlbWVudElEKGhvb2suZWwpXG4gICAgaG9vay5fX2Rlc3Ryb3llZCgpXG4gICAgaG9vay5fX2NsZWFudXBfXygpXG4gICAgZGVsZXRlIHRoaXMudmlld0hvb2tzW2hvb2tJZF1cbiAgfVxuXG4gIGFwcGx5UGVuZGluZ1VwZGF0ZXMoKXtcbiAgICAvLyBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyB3aGVyZSB3ZSBtaWdodCBzdGlsbCBiZSBwZW5kaW5nIGEgbmV3XG4gICAgLy8gbmF2aWdhdGlvbiBhZnRlciBhcHBseWluZyB0aGUgY3VycmVudCBvbmU7XG4gICAgLy8gaWYgd2UgY2FsbCB1cGRhdGUgYW5kIGEgcGVuZGluZ0RpZmYgaXMgbm90IGFwcGxpZWQsIGl0IHdvdWxkXG4gICAgLy8gYmUgc2lsZW50bHkgZHJvcHBlZCBvdGhlcndpc2UsIGFzIHVwZGF0ZSB3b3VsZCBwdXNoIGl0IGJhY2sgdG9cbiAgICAvLyBwZW5kaW5nRGlmZnMsIGJ1dCB3ZSBjbGVhciBpdCBpbW1lZGlhdGVseSBhZnRlclxuICAgIGlmKHRoaXMubGl2ZVNvY2tldC5oYXNQZW5kaW5nTGluaygpICYmIHRoaXMucm9vdC5pc01haW4oKSl7IHJldHVybiB9XG4gICAgdGhpcy5wZW5kaW5nRGlmZnMuZm9yRWFjaCgoe2RpZmYsIGV2ZW50c30pID0+IHRoaXMudXBkYXRlKGRpZmYsIGV2ZW50cykpXG4gICAgdGhpcy5wZW5kaW5nRGlmZnMgPSBbXVxuICAgIHRoaXMuZWFjaENoaWxkKGNoaWxkID0+IGNoaWxkLmFwcGx5UGVuZGluZ1VwZGF0ZXMoKSlcbiAgfVxuXG4gIGVhY2hDaGlsZChjYWxsYmFjayl7XG4gICAgbGV0IGNoaWxkcmVuID0gdGhpcy5yb290LmNoaWxkcmVuW3RoaXMuaWRdIHx8IHt9XG4gICAgZm9yKGxldCBpZCBpbiBjaGlsZHJlbil7IGNhbGxiYWNrKHRoaXMuZ2V0Q2hpbGRCeUlkKGlkKSkgfVxuICB9XG5cbiAgb25DaGFubmVsKGV2ZW50LCBjYil7XG4gICAgdGhpcy5saXZlU29ja2V0Lm9uQ2hhbm5lbCh0aGlzLmNoYW5uZWwsIGV2ZW50LCByZXNwID0+IHtcbiAgICAgIGlmKHRoaXMuaXNKb2luUGVuZGluZygpKXtcbiAgICAgICAgdGhpcy5yb290LnBlbmRpbmdKb2luT3BzLnB1c2goW3RoaXMsICgpID0+IGNiKHJlc3ApXSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IGNiKHJlc3ApKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBiaW5kQ2hhbm5lbCgpe1xuICAgIC8vIFRoZSBkaWZmIGV2ZW50IHNob3VsZCBiZSBoYW5kbGVkIGJ5IHRoZSByZWd1bGFyIHVwZGF0ZSBvcGVyYXRpb25zLlxuICAgIC8vIEFsbCBvdGhlciBvcGVyYXRpb25zIGFyZSBxdWV1ZWQgdG8gYmUgYXBwbGllZCBvbmx5IGFmdGVyIGpvaW4uXG4gICAgdGhpcy5saXZlU29ja2V0Lm9uQ2hhbm5lbCh0aGlzLmNoYW5uZWwsIFwiZGlmZlwiLCAocmF3RGlmZikgPT4ge1xuICAgICAgdGhpcy5saXZlU29ja2V0LnJlcXVlc3RET01VcGRhdGUoKCkgPT4ge1xuICAgICAgICB0aGlzLmFwcGx5RGlmZihcInVwZGF0ZVwiLCByYXdEaWZmLCAoe2RpZmYsIGV2ZW50c30pID0+IHRoaXMudXBkYXRlKGRpZmYsIGV2ZW50cykpXG4gICAgICB9KVxuICAgIH0pXG4gICAgdGhpcy5vbkNoYW5uZWwoXCJyZWRpcmVjdFwiLCAoe3RvLCBmbGFzaH0pID0+IHRoaXMub25SZWRpcmVjdCh7dG8sIGZsYXNofSkpXG4gICAgdGhpcy5vbkNoYW5uZWwoXCJsaXZlX3BhdGNoXCIsIChyZWRpcikgPT4gdGhpcy5vbkxpdmVQYXRjaChyZWRpcikpXG4gICAgdGhpcy5vbkNoYW5uZWwoXCJsaXZlX3JlZGlyZWN0XCIsIChyZWRpcikgPT4gdGhpcy5vbkxpdmVSZWRpcmVjdChyZWRpcikpXG4gICAgdGhpcy5jaGFubmVsLm9uRXJyb3IocmVhc29uID0+IHRoaXMub25FcnJvcihyZWFzb24pKVxuICAgIHRoaXMuY2hhbm5lbC5vbkNsb3NlKHJlYXNvbiA9PiB0aGlzLm9uQ2xvc2UocmVhc29uKSlcbiAgfVxuXG4gIGRlc3Ryb3lBbGxDaGlsZHJlbigpeyB0aGlzLmVhY2hDaGlsZChjaGlsZCA9PiBjaGlsZC5kZXN0cm95KCkpIH1cblxuICBvbkxpdmVSZWRpcmVjdChyZWRpcil7XG4gICAgbGV0IHt0bywga2luZCwgZmxhc2h9ID0gcmVkaXJcbiAgICBsZXQgdXJsID0gdGhpcy5leHBhbmRVUkwodG8pXG4gICAgbGV0IGUgPSBuZXcgQ3VzdG9tRXZlbnQoXCJwaHg6c2VydmVyLW5hdmlnYXRlXCIsIHtkZXRhaWw6IHt0bywga2luZCwgZmxhc2h9fSlcbiAgICB0aGlzLmxpdmVTb2NrZXQuaGlzdG9yeVJlZGlyZWN0KGUsIHVybCwga2luZCwgZmxhc2gpXG4gIH1cblxuICBvbkxpdmVQYXRjaChyZWRpcil7XG4gICAgbGV0IHt0bywga2luZH0gPSByZWRpclxuICAgIHRoaXMuaHJlZiA9IHRoaXMuZXhwYW5kVVJMKHRvKVxuICAgIHRoaXMubGl2ZVNvY2tldC5oaXN0b3J5UGF0Y2godG8sIGtpbmQpXG4gIH1cblxuICBleHBhbmRVUkwodG8pe1xuICAgIHJldHVybiB0by5zdGFydHNXaXRoKFwiL1wiKSA/IGAke3dpbmRvdy5sb2NhdGlvbi5wcm90b2NvbH0vLyR7d2luZG93LmxvY2F0aW9uLmhvc3R9JHt0b31gIDogdG9cbiAgfVxuXG4gIG9uUmVkaXJlY3Qoe3RvLCBmbGFzaCwgcmVsb2FkVG9rZW59KXsgdGhpcy5saXZlU29ja2V0LnJlZGlyZWN0KHRvLCBmbGFzaCwgcmVsb2FkVG9rZW4pIH1cblxuICBpc0Rlc3Ryb3llZCgpeyByZXR1cm4gdGhpcy5kZXN0cm95ZWQgfVxuXG4gIGpvaW5EZWFkKCl7IHRoaXMuaXNEZWFkID0gdHJ1ZSB9XG5cbiAgam9pblB1c2goKXtcbiAgICB0aGlzLmpvaW5QdXNoID0gdGhpcy5qb2luUHVzaCB8fCB0aGlzLmNoYW5uZWwuam9pbigpXG4gICAgcmV0dXJuIHRoaXMuam9pblB1c2hcbiAgfVxuXG4gIGpvaW4oY2FsbGJhY2spe1xuICAgIHRoaXMuc2hvd0xvYWRlcih0aGlzLmxpdmVTb2NrZXQubG9hZGVyVGltZW91dClcbiAgICB0aGlzLmJpbmRDaGFubmVsKClcbiAgICBpZih0aGlzLmlzTWFpbigpKXtcbiAgICAgIHRoaXMuc3RvcENhbGxiYWNrID0gdGhpcy5saXZlU29ja2V0LndpdGhQYWdlTG9hZGluZyh7dG86IHRoaXMuaHJlZiwga2luZDogXCJpbml0aWFsXCJ9KVxuICAgIH1cbiAgICB0aGlzLmpvaW5DYWxsYmFjayA9IChvbkRvbmUpID0+IHtcbiAgICAgIG9uRG9uZSA9IG9uRG9uZSB8fCBmdW5jdGlvbigpe31cbiAgICAgIGNhbGxiYWNrID8gY2FsbGJhY2sodGhpcy5qb2luQ291bnQsIG9uRG9uZSkgOiBvbkRvbmUoKVxuICAgIH1cblxuICAgIHRoaXMud3JhcFB1c2goKCkgPT4gdGhpcy5jaGFubmVsLmpvaW4oKSwge1xuICAgICAgb2s6IChyZXNwKSA9PiB0aGlzLmxpdmVTb2NrZXQucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB0aGlzLm9uSm9pbihyZXNwKSksXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB0aGlzLm9uSm9pbkVycm9yKGVycm9yKSxcbiAgICAgIHRpbWVvdXQ6ICgpID0+IHRoaXMub25Kb2luRXJyb3Ioe3JlYXNvbjogXCJ0aW1lb3V0XCJ9KVxuICAgIH0pXG4gIH1cblxuICBvbkpvaW5FcnJvcihyZXNwKXtcbiAgICBpZihyZXNwLnJlYXNvbiA9PT0gXCJyZWxvYWRcIil7XG4gICAgICB0aGlzLmxvZyhcImVycm9yXCIsICgpID0+IFtgZmFpbGVkIG1vdW50IHdpdGggJHtyZXNwLnN0YXR1c30uIEZhbGxpbmcgYmFjayB0byBwYWdlIHJlbG9hZGAsIHJlc3BdKVxuICAgICAgdGhpcy5vblJlZGlyZWN0KHt0bzogdGhpcy5yb290LmhyZWYsIHJlbG9hZFRva2VuOiByZXNwLnRva2VufSlcbiAgICAgIHJldHVyblxuICAgIH0gZWxzZSBpZihyZXNwLnJlYXNvbiA9PT0gXCJ1bmF1dGhvcml6ZWRcIiB8fCByZXNwLnJlYXNvbiA9PT0gXCJzdGFsZVwiKXtcbiAgICAgIHRoaXMubG9nKFwiZXJyb3JcIiwgKCkgPT4gW1widW5hdXRob3JpemVkIGxpdmVfcmVkaXJlY3QuIEZhbGxpbmcgYmFjayB0byBwYWdlIHJlcXVlc3RcIiwgcmVzcF0pXG4gICAgICB0aGlzLm9uUmVkaXJlY3Qoe3RvOiB0aGlzLnJvb3QuaHJlZiwgZmxhc2g6IHRoaXMuZmxhc2h9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGlmKHJlc3AucmVkaXJlY3QgfHwgcmVzcC5saXZlX3JlZGlyZWN0KXtcbiAgICAgIHRoaXMuam9pblBlbmRpbmcgPSBmYWxzZVxuICAgICAgdGhpcy5jaGFubmVsLmxlYXZlKClcbiAgICB9XG4gICAgaWYocmVzcC5yZWRpcmVjdCl7IHJldHVybiB0aGlzLm9uUmVkaXJlY3QocmVzcC5yZWRpcmVjdCkgfVxuICAgIGlmKHJlc3AubGl2ZV9yZWRpcmVjdCl7IHJldHVybiB0aGlzLm9uTGl2ZVJlZGlyZWN0KHJlc3AubGl2ZV9yZWRpcmVjdCkgfVxuICAgIHRoaXMubG9nKFwiZXJyb3JcIiwgKCkgPT4gW1widW5hYmxlIHRvIGpvaW5cIiwgcmVzcF0pXG4gICAgaWYodGhpcy5pc01haW4oKSl7XG4gICAgICB0aGlzLmRpc3BsYXlFcnJvcihbUEhYX0xPQURJTkdfQ0xBU1MsIFBIWF9FUlJPUl9DTEFTUywgUEhYX1NFUlZFUl9FUlJPUl9DTEFTU10pXG4gICAgICBpZih0aGlzLmxpdmVTb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMubGl2ZVNvY2tldC5yZWxvYWRXaXRoSml0dGVyKHRoaXMpIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYodGhpcy5qb2luQXR0ZW1wdHMgPj0gTUFYX0NISUxEX0pPSU5fQVRURU1QVFMpe1xuICAgICAgICAvLyBwdXQgdGhlIHJvb3QgcmV2aWV3IGludG8gcGVybWFuZW50IGVycm9yIHN0YXRlLCBidXQgZG9uJ3QgZGVzdHJveSBpdCBhcyBpdCBjYW4gcmVtYWluIGFjdGl2ZVxuICAgICAgICB0aGlzLnJvb3QuZGlzcGxheUVycm9yKFtQSFhfTE9BRElOR19DTEFTUywgUEhYX0VSUk9SX0NMQVNTLCBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTXSlcbiAgICAgICAgdGhpcy5sb2coXCJlcnJvclwiLCAoKSA9PiBbYGdpdmluZyB1cCB0cnlpbmcgdG8gbW91bnQgYWZ0ZXIgJHtNQVhfQ0hJTERfSk9JTl9BVFRFTVBUU30gdHJpZXNgLCByZXNwXSlcbiAgICAgICAgdGhpcy5kZXN0cm95KClcbiAgICAgIH1cbiAgICAgIGxldCB0cnVlQ2hpbGRFbCA9IERPTS5ieUlkKHRoaXMuZWwuaWQpXG4gICAgICBpZih0cnVlQ2hpbGRFbCl7XG4gICAgICAgIERPTS5tZXJnZUF0dHJzKHRydWVDaGlsZEVsLCB0aGlzLmVsKVxuICAgICAgICB0aGlzLmRpc3BsYXlFcnJvcihbUEhYX0xPQURJTkdfQ0xBU1MsIFBIWF9FUlJPUl9DTEFTUywgUEhYX1NFUlZFUl9FUlJPUl9DTEFTU10pXG4gICAgICAgIHRoaXMuZWwgPSB0cnVlQ2hpbGRFbFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5kZXN0cm95KClcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBvbkNsb3NlKHJlYXNvbil7XG4gICAgaWYodGhpcy5pc0Rlc3Ryb3llZCgpKXsgcmV0dXJuIH1cbiAgICBpZih0aGlzLmlzTWFpbigpICYmIHRoaXMubGl2ZVNvY2tldC5oYXNQZW5kaW5nTGluaygpICYmIHJlYXNvbiAhPT0gXCJsZWF2ZVwiKXtcbiAgICAgIHJldHVybiB0aGlzLmxpdmVTb2NrZXQucmVsb2FkV2l0aEppdHRlcih0aGlzKVxuICAgIH1cbiAgICB0aGlzLmRlc3Ryb3lBbGxDaGlsZHJlbigpXG4gICAgdGhpcy5saXZlU29ja2V0LmRyb3BBY3RpdmVFbGVtZW50KHRoaXMpXG4gICAgLy8gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBjYW4gYmUgbnVsbCBpbiBJbnRlcm5ldCBFeHBsb3JlciAxMVxuICAgIGlmKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpeyBkb2N1bWVudC5hY3RpdmVFbGVtZW50LmJsdXIoKSB9XG4gICAgaWYodGhpcy5saXZlU29ja2V0LmlzVW5sb2FkZWQoKSl7XG4gICAgICB0aGlzLnNob3dMb2FkZXIoQkVGT1JFX1VOTE9BRF9MT0FERVJfVElNRU9VVClcbiAgICB9XG4gIH1cblxuICBvbkVycm9yKHJlYXNvbil7XG4gICAgdGhpcy5vbkNsb3NlKHJlYXNvbilcbiAgICBpZih0aGlzLmxpdmVTb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMubG9nKFwiZXJyb3JcIiwgKCkgPT4gW1widmlldyBjcmFzaGVkXCIsIHJlYXNvbl0pIH1cbiAgICBpZighdGhpcy5saXZlU29ja2V0LmlzVW5sb2FkZWQoKSl7XG4gICAgICBpZih0aGlzLmxpdmVTb2NrZXQuaXNDb25uZWN0ZWQoKSl7XG4gICAgICAgIHRoaXMuZGlzcGxheUVycm9yKFtQSFhfTE9BRElOR19DTEFTUywgUEhYX0VSUk9SX0NMQVNTLCBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTXSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuZGlzcGxheUVycm9yKFtQSFhfTE9BRElOR19DTEFTUywgUEhYX0VSUk9SX0NMQVNTLCBQSFhfQ0xJRU5UX0VSUk9SX0NMQVNTXSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBkaXNwbGF5RXJyb3IoY2xhc3Nlcyl7XG4gICAgaWYodGhpcy5pc01haW4oKSl7IERPTS5kaXNwYXRjaEV2ZW50KHdpbmRvdywgXCJwaHg6cGFnZS1sb2FkaW5nLXN0YXJ0XCIsIHtkZXRhaWw6IHt0bzogdGhpcy5ocmVmLCBraW5kOiBcImVycm9yXCJ9fSkgfVxuICAgIHRoaXMuc2hvd0xvYWRlcigpXG4gICAgdGhpcy5zZXRDb250YWluZXJDbGFzc2VzKC4uLmNsYXNzZXMpXG4gICAgdGhpcy5kZWxheWVkRGlzY29ubmVjdGVkKClcbiAgfVxuXG4gIGRlbGF5ZWREaXNjb25uZWN0ZWQoKXtcbiAgICB0aGlzLmRpc2Nvbm5lY3RlZFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmV4ZWNBbGwodGhpcy5iaW5kaW5nKFwiZGlzY29ubmVjdGVkXCIpKVxuICAgIH0sIHRoaXMubGl2ZVNvY2tldC5kaXNjb25uZWN0ZWRUaW1lb3V0KVxuICB9XG5cbiAgd3JhcFB1c2goY2FsbGVyUHVzaCwgcmVjZWl2ZXMpe1xuICAgIGxldCBsYXRlbmN5ID0gdGhpcy5saXZlU29ja2V0LmdldExhdGVuY3lTaW0oKVxuICAgIGxldCB3aXRoTGF0ZW5jeSA9IGxhdGVuY3kgP1xuICAgICAgKGNiKSA9PiBzZXRUaW1lb3V0KCgpID0+ICF0aGlzLmlzRGVzdHJveWVkKCkgJiYgY2IoKSwgbGF0ZW5jeSkgOlxuICAgICAgKGNiKSA9PiAhdGhpcy5pc0Rlc3Ryb3llZCgpICYmIGNiKClcblxuICAgIHdpdGhMYXRlbmN5KCgpID0+IHtcbiAgICAgIGNhbGxlclB1c2goKVxuICAgICAgICAucmVjZWl2ZShcIm9rXCIsIHJlc3AgPT4gd2l0aExhdGVuY3koKCkgPT4gcmVjZWl2ZXMub2sgJiYgcmVjZWl2ZXMub2socmVzcCkpKVxuICAgICAgICAucmVjZWl2ZShcImVycm9yXCIsIHJlYXNvbiA9PiB3aXRoTGF0ZW5jeSgoKSA9PiByZWNlaXZlcy5lcnJvciAmJiByZWNlaXZlcy5lcnJvcihyZWFzb24pKSlcbiAgICAgICAgLnJlY2VpdmUoXCJ0aW1lb3V0XCIsICgpID0+IHdpdGhMYXRlbmN5KCgpID0+IHJlY2VpdmVzLnRpbWVvdXQgJiYgcmVjZWl2ZXMudGltZW91dCgpKSlcbiAgICB9KVxuICB9XG5cbiAgcHVzaFdpdGhSZXBseShyZWZHZW5lcmF0b3IsIGV2ZW50LCBwYXlsb2FkKXtcbiAgICBpZighdGhpcy5pc0Nvbm5lY3RlZCgpKXsgcmV0dXJuIFByb21pc2UucmVqZWN0KHtlcnJvcjogXCJub2Nvbm5lY3Rpb25cIn0pIH1cblxuICAgIGxldCBbcmVmLCBbZWxdLCBvcHRzXSA9IHJlZkdlbmVyYXRvciA/IHJlZkdlbmVyYXRvcigpIDogW251bGwsIFtdLCB7fV1cbiAgICBsZXQgb2xkSm9pbkNvdW50ID0gdGhpcy5qb2luQ291bnRcbiAgICBsZXQgb25Mb2FkaW5nRG9uZSA9IGZ1bmN0aW9uKCl7fVxuICAgIGlmKG9wdHMucGFnZV9sb2FkaW5nKXtcbiAgICAgIG9uTG9hZGluZ0RvbmUgPSB0aGlzLmxpdmVTb2NrZXQud2l0aFBhZ2VMb2FkaW5nKHtraW5kOiBcImVsZW1lbnRcIiwgdGFyZ2V0OiBlbH0pXG4gICAgfVxuXG4gICAgaWYodHlwZW9mIChwYXlsb2FkLmNpZCkgIT09IFwibnVtYmVyXCIpeyBkZWxldGUgcGF5bG9hZC5jaWQgfVxuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMud3JhcFB1c2goKCkgPT4gdGhpcy5jaGFubmVsLnB1c2goZXZlbnQsIHBheWxvYWQsIFBVU0hfVElNRU9VVCksIHtcbiAgICAgICAgb2s6IChyZXNwKSA9PiB7XG4gICAgICAgICAgaWYocmVmICE9PSBudWxsKXsgdGhpcy5sYXN0QWNrUmVmID0gcmVmIH1cbiAgICAgICAgICBsZXQgZmluaXNoID0gKGhvb2tSZXBseSkgPT4ge1xuICAgICAgICAgICAgaWYocmVzcC5yZWRpcmVjdCl7IHRoaXMub25SZWRpcmVjdChyZXNwLnJlZGlyZWN0KSB9XG4gICAgICAgICAgICBpZihyZXNwLmxpdmVfcGF0Y2gpeyB0aGlzLm9uTGl2ZVBhdGNoKHJlc3AubGl2ZV9wYXRjaCkgfVxuICAgICAgICAgICAgaWYocmVzcC5saXZlX3JlZGlyZWN0KXsgdGhpcy5vbkxpdmVSZWRpcmVjdChyZXNwLmxpdmVfcmVkaXJlY3QpIH1cbiAgICAgICAgICAgIG9uTG9hZGluZ0RvbmUoKVxuICAgICAgICAgICAgcmVzb2x2ZSh7cmVzcDogcmVzcCwgcmVwbHk6IGhvb2tSZXBseX0pXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKHJlc3AuZGlmZil7XG4gICAgICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuYXBwbHlEaWZmKFwidXBkYXRlXCIsIHJlc3AuZGlmZiwgKHtkaWZmLCByZXBseSwgZXZlbnRzfSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmKHJlZiAhPT0gbnVsbCl7XG4gICAgICAgICAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGF5bG9hZC5ldmVudClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGUoZGlmZiwgZXZlbnRzKVxuICAgICAgICAgICAgICAgIGZpbmlzaChyZXBseSlcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmKHJlZiAhPT0gbnVsbCl7IHRoaXMudW5kb1JlZnMocmVmLCBwYXlsb2FkLmV2ZW50KSB9XG4gICAgICAgICAgICBmaW5pc2gobnVsbClcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGVycm9yOiAocmVhc29uKSA9PiByZWplY3Qoe2Vycm9yOiByZWFzb259KSxcbiAgICAgICAgdGltZW91dDogKCkgPT4ge1xuICAgICAgICAgIHJlamVjdCh7dGltZW91dDogdHJ1ZX0pXG4gICAgICAgICAgaWYodGhpcy5qb2luQ291bnQgPT09IG9sZEpvaW5Db3VudCl7XG4gICAgICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVsb2FkV2l0aEppdHRlcih0aGlzLCAoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMubG9nKFwidGltZW91dFwiLCAoKSA9PiBbXCJyZWNlaXZlZCB0aW1lb3V0IHdoaWxlIGNvbW11bmljYXRpbmcgd2l0aCBzZXJ2ZXIuIEZhbGxpbmcgYmFjayB0byBoYXJkIHJlZnJlc2ggZm9yIHJlY292ZXJ5XCJdKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSlcbiAgfVxuXG4gIHVuZG9SZWZzKHJlZiwgcGh4RXZlbnQsIG9ubHlFbHMpe1xuICAgIGlmKCF0aGlzLmlzQ29ubmVjdGVkKCkpeyByZXR1cm4gfSAvLyBleGl0IGlmIGV4dGVybmFsIGZvcm0gdHJpZ2dlcmVkXG4gICAgbGV0IHNlbGVjdG9yID0gYFske1BIWF9SRUZfU1JDfT1cIiR7dGhpcy5yZWZTcmMoKX1cIl1gXG5cbiAgICBpZihvbmx5RWxzKXtcbiAgICAgIG9ubHlFbHMgPSBuZXcgU2V0KG9ubHlFbHMpXG4gICAgICBET00uYWxsKGRvY3VtZW50LCBzZWxlY3RvciwgcGFyZW50ID0+IHtcbiAgICAgICAgaWYob25seUVscyAmJiAhb25seUVscy5oYXMocGFyZW50KSl7IHJldHVybiB9XG4gICAgICAgIC8vIHVuZG8gYW55IGNoaWxkIHJlZnMgd2l0aGluIHBhcmVudCBmaXJzdFxuICAgICAgICBET00uYWxsKHBhcmVudCwgc2VsZWN0b3IsIGNoaWxkID0+IHRoaXMudW5kb0VsUmVmKGNoaWxkLCByZWYsIHBoeEV2ZW50KSlcbiAgICAgICAgdGhpcy51bmRvRWxSZWYocGFyZW50LCByZWYsIHBoeEV2ZW50KVxuICAgICAgfSlcbiAgICB9IGVsc2Uge1xuICAgICAgRE9NLmFsbChkb2N1bWVudCwgc2VsZWN0b3IsIGVsID0+IHRoaXMudW5kb0VsUmVmKGVsLCByZWYsIHBoeEV2ZW50KSlcbiAgICB9XG4gIH1cblxuICB1bmRvRWxSZWYoZWwsIHJlZiwgcGh4RXZlbnQpe1xuICAgIGxldCBlbFJlZiA9IG5ldyBFbGVtZW50UmVmKGVsKVxuXG4gICAgZWxSZWYubWF5YmVVbmRvKHJlZiwgcGh4RXZlbnQsIGNsb25lZFRyZWUgPT4ge1xuICAgICAgLy8gd2UgbmVlZCB0byBwZXJmb3JtIGEgZnVsbCBwYXRjaCBvbiB1bmxvY2tlZCBlbGVtZW50c1xuICAgICAgLy8gdG8gcGVyZm9ybSBhbGwgdGhlIG5lY2Vzc2FyeSBsb2dpYyAobGlrZSBjYWxsaW5nIHVwZGF0ZWQgZm9yIGhvb2tzLCBldGMuKVxuICAgICAgbGV0IHBhdGNoID0gbmV3IERPTVBhdGNoKHRoaXMsIGVsLCB0aGlzLmlkLCBjbG9uZWRUcmVlLCBbXSwgbnVsbCwge3VuZG9SZWY6IHJlZn0pXG4gICAgICBjb25zdCBwaHhDaGlsZHJlbkFkZGVkID0gdGhpcy5wZXJmb3JtUGF0Y2gocGF0Y2gsIHRydWUpXG4gICAgICBET00uYWxsKGVsLCBgWyR7UEhYX1JFRl9TUkN9PVwiJHt0aGlzLnJlZlNyYygpfVwiXWAsIGNoaWxkID0+IHRoaXMudW5kb0VsUmVmKGNoaWxkLCByZWYsIHBoeEV2ZW50KSlcbiAgICAgIGlmKHBoeENoaWxkcmVuQWRkZWQpeyB0aGlzLmpvaW5OZXdDaGlsZHJlbigpIH1cbiAgICB9KVxuICB9XG5cbiAgcmVmU3JjKCl7IHJldHVybiB0aGlzLmVsLmlkIH1cblxuICBwdXRSZWYoZWxlbWVudHMsIHBoeEV2ZW50LCBldmVudFR5cGUsIG9wdHMgPSB7fSl7XG4gICAgbGV0IG5ld1JlZiA9IHRoaXMucmVmKytcbiAgICBsZXQgZGlzYWJsZVdpdGggPSB0aGlzLmJpbmRpbmcoUEhYX0RJU0FCTEVfV0lUSClcbiAgICBpZihvcHRzLmxvYWRpbmcpe1xuICAgICAgbGV0IGxvYWRpbmdFbHMgPSBET00uYWxsKGRvY3VtZW50LCBvcHRzLmxvYWRpbmcpLm1hcChlbCA9PiB7XG4gICAgICAgIHJldHVybiB7ZWwsIGxvY2s6IHRydWUsIGxvYWRpbmc6IHRydWV9XG4gICAgICB9KVxuICAgICAgZWxlbWVudHMgPSBlbGVtZW50cy5jb25jYXQobG9hZGluZ0VscylcbiAgICB9XG5cbiAgICBmb3IobGV0IHtlbCwgbG9jaywgbG9hZGluZ30gb2YgZWxlbWVudHMpe1xuICAgICAgaWYoIWxvY2sgJiYgIWxvYWRpbmcpeyB0aHJvdyBuZXcgRXJyb3IoXCJwdXRSZWYgcmVxdWlyZXMgbG9jayBvciBsb2FkaW5nXCIpIH1cbiAgICAgIGVsLnNldEF0dHJpYnV0ZShQSFhfUkVGX1NSQywgdGhpcy5yZWZTcmMoKSlcbiAgICAgIGlmKGxvYWRpbmcpeyBlbC5zZXRBdHRyaWJ1dGUoUEhYX1JFRl9MT0FESU5HLCBuZXdSZWYpIH1cbiAgICAgIGlmKGxvY2speyBlbC5zZXRBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLLCBuZXdSZWYpIH1cblxuICAgICAgaWYoIWxvYWRpbmcgfHwgKG9wdHMuc3VibWl0dGVyICYmICEoZWwgPT09IG9wdHMuc3VibWl0dGVyIHx8IGVsID09PSBvcHRzLmZvcm0pKSl7IGNvbnRpbnVlIH1cblxuICAgICAgbGV0IGxvY2tDb21wbGV0ZVByb21pc2UgPSBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICAgICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihgcGh4OnVuZG8tbG9jazoke25ld1JlZn1gLCAoKSA9PiByZXNvbHZlKGRldGFpbCksIHtvbmNlOiB0cnVlfSlcbiAgICAgIH0pXG5cbiAgICAgIGxldCBsb2FkaW5nQ29tcGxldGVQcm9taXNlID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoYHBoeDp1bmRvLWxvYWRpbmc6JHtuZXdSZWZ9YCwgKCkgPT4gcmVzb2x2ZShkZXRhaWwpLCB7b25jZTogdHJ1ZX0pXG4gICAgICB9KVxuXG4gICAgICBlbC5jbGFzc0xpc3QuYWRkKGBwaHgtJHtldmVudFR5cGV9LWxvYWRpbmdgKVxuICAgICAgbGV0IGRpc2FibGVUZXh0ID0gZWwuZ2V0QXR0cmlidXRlKGRpc2FibGVXaXRoKVxuICAgICAgaWYoZGlzYWJsZVRleHQgIT09IG51bGwpe1xuICAgICAgICBpZighZWwuZ2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFX1dJVEhfUkVTVE9SRSkpe1xuICAgICAgICAgIGVsLnNldEF0dHJpYnV0ZShQSFhfRElTQUJMRV9XSVRIX1JFU1RPUkUsIGVsLmlubmVyVGV4dClcbiAgICAgICAgfVxuICAgICAgICBpZihkaXNhYmxlVGV4dCAhPT0gXCJcIil7IGVsLmlubmVyVGV4dCA9IGRpc2FibGVUZXh0IH1cbiAgICAgICAgLy8gUEhYX0RJU0FCTEVEIGNvdWxkIGhhdmUgYWxyZWFkeSBiZWVuIHNldCBpbiBkaXNhYmxlRm9ybVxuICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoUEhYX0RJU0FCTEVELCBlbC5nZXRBdHRyaWJ1dGUoUEhYX0RJU0FCTEVEKSB8fCBlbC5kaXNhYmxlZClcbiAgICAgICAgZWwuc2V0QXR0cmlidXRlKFwiZGlzYWJsZWRcIiwgXCJcIilcbiAgICAgIH1cblxuICAgICAgbGV0IGRldGFpbCA9IHtcbiAgICAgICAgZXZlbnQ6IHBoeEV2ZW50LFxuICAgICAgICBldmVudFR5cGU6IGV2ZW50VHlwZSxcbiAgICAgICAgcmVmOiBuZXdSZWYsXG4gICAgICAgIGlzTG9hZGluZzogbG9hZGluZyxcbiAgICAgICAgaXNMb2NrZWQ6IGxvY2ssXG4gICAgICAgIGxvY2tFbGVtZW50czogZWxlbWVudHMuZmlsdGVyKCh7bG9ja30pID0+IGxvY2spLm1hcCgoe2VsfSkgPT4gZWwpLFxuICAgICAgICBsb2FkaW5nRWxlbWVudHM6IGVsZW1lbnRzLmZpbHRlcigoe2xvYWRpbmd9KSA9PiBsb2FkaW5nKS5tYXAoKHtlbH0pID0+IGVsKSxcbiAgICAgICAgdW5sb2NrOiAoZWxzKSA9PiB7XG4gICAgICAgICAgZWxzID0gQXJyYXkuaXNBcnJheShlbHMpID8gZWxzIDogW2Vsc11cbiAgICAgICAgICB0aGlzLnVuZG9SZWZzKG5ld1JlZiwgcGh4RXZlbnQsIGVscylcbiAgICAgICAgfSxcbiAgICAgICAgbG9ja0NvbXBsZXRlOiBsb2NrQ29tcGxldGVQcm9taXNlLFxuICAgICAgICBsb2FkaW5nQ29tcGxldGU6IGxvYWRpbmdDb21wbGV0ZVByb21pc2UsXG4gICAgICAgIGxvY2s6IChsb2NrRWwpID0+IHtcbiAgICAgICAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICAgICAgICBpZih0aGlzLmlzQWNrZWQobmV3UmVmKSl7IHJldHVybiByZXNvbHZlKGRldGFpbCkgfVxuICAgICAgICAgICAgbG9ja0VsLnNldEF0dHJpYnV0ZShQSFhfUkVGX0xPQ0ssIG5ld1JlZilcbiAgICAgICAgICAgIGxvY2tFbC5zZXRBdHRyaWJ1dGUoUEhYX1JFRl9TUkMsIHRoaXMucmVmU3JjKCkpXG4gICAgICAgICAgICBsb2NrRWwuYWRkRXZlbnRMaXN0ZW5lcihgcGh4OmxvY2stc3RvcDoke25ld1JlZn1gLCAoKSA9PiByZXNvbHZlKGRldGFpbCksIHtvbmNlOiB0cnVlfSlcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbC5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChcInBoeDpwdXNoXCIsIHtcbiAgICAgICAgZGV0YWlsOiBkZXRhaWwsXG4gICAgICAgIGJ1YmJsZXM6IHRydWUsXG4gICAgICAgIGNhbmNlbGFibGU6IGZhbHNlXG4gICAgICB9KSlcbiAgICAgIGlmKHBoeEV2ZW50KXtcbiAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoYHBoeDpwdXNoOiR7cGh4RXZlbnR9YCwge1xuICAgICAgICAgIGRldGFpbDogZGV0YWlsLFxuICAgICAgICAgIGJ1YmJsZXM6IHRydWUsXG4gICAgICAgICAgY2FuY2VsYWJsZTogZmFsc2VcbiAgICAgICAgfSkpXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBbbmV3UmVmLCBlbGVtZW50cy5tYXAoKHtlbH0pID0+IGVsKSwgb3B0c11cbiAgfVxuXG4gIGlzQWNrZWQocmVmKXsgcmV0dXJuIHRoaXMubGFzdEFja1JlZiAhPT0gbnVsbCAmJiB0aGlzLmxhc3RBY2tSZWYgPj0gcmVmIH1cblxuICBjb21wb25lbnRJRChlbCl7XG4gICAgbGV0IGNpZCA9IGVsLmdldEF0dHJpYnV0ZSAmJiBlbC5nZXRBdHRyaWJ1dGUoUEhYX0NPTVBPTkVOVClcbiAgICByZXR1cm4gY2lkID8gcGFyc2VJbnQoY2lkKSA6IG51bGxcbiAgfVxuXG4gIHRhcmdldENvbXBvbmVudElEKHRhcmdldCwgdGFyZ2V0Q3R4LCBvcHRzID0ge30pe1xuICAgIGlmKGlzQ2lkKHRhcmdldEN0eCkpeyByZXR1cm4gdGFyZ2V0Q3R4IH1cblxuICAgIGxldCBjaWRPclNlbGVjdG9yID0gb3B0cy50YXJnZXQgfHwgdGFyZ2V0LmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoXCJ0YXJnZXRcIikpXG4gICAgaWYoaXNDaWQoY2lkT3JTZWxlY3Rvcikpe1xuICAgICAgcmV0dXJuIHBhcnNlSW50KGNpZE9yU2VsZWN0b3IpXG4gICAgfSBlbHNlIGlmKHRhcmdldEN0eCAmJiAoY2lkT3JTZWxlY3RvciAhPT0gbnVsbCB8fCBvcHRzLnRhcmdldCkpe1xuICAgICAgcmV0dXJuIHRoaXMuY2xvc2VzdENvbXBvbmVudElEKHRhcmdldEN0eClcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG4gIH1cblxuICBjbG9zZXN0Q29tcG9uZW50SUQodGFyZ2V0Q3R4KXtcbiAgICBpZihpc0NpZCh0YXJnZXRDdHgpKXtcbiAgICAgIHJldHVybiB0YXJnZXRDdHhcbiAgICB9IGVsc2UgaWYodGFyZ2V0Q3R4KXtcbiAgICAgIHJldHVybiBtYXliZSh0YXJnZXRDdHguY2xvc2VzdChgWyR7UEhYX0NPTVBPTkVOVH1dYCksIGVsID0+IHRoaXMub3duc0VsZW1lbnQoZWwpICYmIHRoaXMuY29tcG9uZW50SUQoZWwpKVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgfVxuXG4gIHB1c2hIb29rRXZlbnQoZWwsIHRhcmdldEN0eCwgZXZlbnQsIHBheWxvYWQsIG9uUmVwbHkpe1xuICAgIGlmKCF0aGlzLmlzQ29ubmVjdGVkKCkpe1xuICAgICAgdGhpcy5sb2coXCJob29rXCIsICgpID0+IFtcInVuYWJsZSB0byBwdXNoIGhvb2sgZXZlbnQuIExpdmVWaWV3IG5vdCBjb25uZWN0ZWRcIiwgZXZlbnQsIHBheWxvYWRdKVxuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICAgIGxldCBbcmVmLCBlbHMsIG9wdHNdID0gdGhpcy5wdXRSZWYoW3tlbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZX1dLCBldmVudCwgXCJob29rXCIpXG4gICAgdGhpcy5wdXNoV2l0aFJlcGx5KCgpID0+IFtyZWYsIGVscywgb3B0c10sIFwiZXZlbnRcIiwge1xuICAgICAgdHlwZTogXCJob29rXCIsXG4gICAgICBldmVudDogZXZlbnQsXG4gICAgICB2YWx1ZTogcGF5bG9hZCxcbiAgICAgIGNpZDogdGhpcy5jbG9zZXN0Q29tcG9uZW50SUQodGFyZ2V0Q3R4KVxuICAgIH0pLnRoZW4oKHtyZXNwOiBfcmVzcCwgcmVwbHk6IGhvb2tSZXBseX0pID0+IG9uUmVwbHkoaG9va1JlcGx5LCByZWYpKVxuXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgZXh0cmFjdE1ldGEoZWwsIG1ldGEsIHZhbHVlKXtcbiAgICBsZXQgcHJlZml4ID0gdGhpcy5iaW5kaW5nKFwidmFsdWUtXCIpXG4gICAgZm9yKGxldCBpID0gMDsgaSA8IGVsLmF0dHJpYnV0ZXMubGVuZ3RoOyBpKyspe1xuICAgICAgaWYoIW1ldGEpeyBtZXRhID0ge30gfVxuICAgICAgbGV0IG5hbWUgPSBlbC5hdHRyaWJ1dGVzW2ldLm5hbWVcbiAgICAgIGlmKG5hbWUuc3RhcnRzV2l0aChwcmVmaXgpKXsgbWV0YVtuYW1lLnJlcGxhY2UocHJlZml4LCBcIlwiKV0gPSBlbC5nZXRBdHRyaWJ1dGUobmFtZSkgfVxuICAgIH1cbiAgICBpZihlbC52YWx1ZSAhPT0gdW5kZWZpbmVkICYmICEoZWwgaW5zdGFuY2VvZiBIVE1MRm9ybUVsZW1lbnQpKXtcbiAgICAgIGlmKCFtZXRhKXsgbWV0YSA9IHt9IH1cbiAgICAgIG1ldGEudmFsdWUgPSBlbC52YWx1ZVxuXG4gICAgICBpZihlbC50YWdOYW1lID09PSBcIklOUFVUXCIgJiYgQ0hFQ0tBQkxFX0lOUFVUUy5pbmRleE9mKGVsLnR5cGUpID49IDAgJiYgIWVsLmNoZWNrZWQpe1xuICAgICAgICBkZWxldGUgbWV0YS52YWx1ZVxuICAgICAgfVxuICAgIH1cbiAgICBpZih2YWx1ZSl7XG4gICAgICBpZighbWV0YSl7IG1ldGEgPSB7fSB9XG4gICAgICBmb3IobGV0IGtleSBpbiB2YWx1ZSl7IG1ldGFba2V5XSA9IHZhbHVlW2tleV0gfVxuICAgIH1cbiAgICByZXR1cm4gbWV0YVxuICB9XG5cbiAgcHVzaEV2ZW50KHR5cGUsIGVsLCB0YXJnZXRDdHgsIHBoeEV2ZW50LCBtZXRhLCBvcHRzID0ge30sIG9uUmVwbHkpe1xuICAgIHRoaXMucHVzaFdpdGhSZXBseSgoKSA9PiB0aGlzLnB1dFJlZihbe2VsLCBsb2FkaW5nOiB0cnVlLCBsb2NrOiB0cnVlfV0sIHBoeEV2ZW50LCB0eXBlLCBvcHRzKSwgXCJldmVudFwiLCB7XG4gICAgICB0eXBlOiB0eXBlLFxuICAgICAgZXZlbnQ6IHBoeEV2ZW50LFxuICAgICAgdmFsdWU6IHRoaXMuZXh0cmFjdE1ldGEoZWwsIG1ldGEsIG9wdHMudmFsdWUpLFxuICAgICAgY2lkOiB0aGlzLnRhcmdldENvbXBvbmVudElEKGVsLCB0YXJnZXRDdHgsIG9wdHMpXG4gICAgfSlcbiAgICAgIC50aGVuKCh7cmVwbHl9KSA9PiBvblJlcGx5ICYmIG9uUmVwbHkocmVwbHkpKVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBldmVudFwiLCBlcnJvcikpXG4gIH1cblxuICBwdXNoRmlsZVByb2dyZXNzKGZpbGVFbCwgZW50cnlSZWYsIHByb2dyZXNzLCBvblJlcGx5ID0gZnVuY3Rpb24gKCl7IH0pe1xuICAgIHRoaXMubGl2ZVNvY2tldC53aXRoaW5Pd25lcnMoZmlsZUVsLmZvcm0sICh2aWV3LCB0YXJnZXRDdHgpID0+IHtcbiAgICAgIHZpZXcucHVzaFdpdGhSZXBseShudWxsLCBcInByb2dyZXNzXCIsIHtcbiAgICAgICAgZXZlbnQ6IGZpbGVFbC5nZXRBdHRyaWJ1dGUodmlldy5iaW5kaW5nKFBIWF9QUk9HUkVTUykpLFxuICAgICAgICByZWY6IGZpbGVFbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpLFxuICAgICAgICBlbnRyeV9yZWY6IGVudHJ5UmVmLFxuICAgICAgICBwcm9ncmVzczogcHJvZ3Jlc3MsXG4gICAgICAgIGNpZDogdmlldy50YXJnZXRDb21wb25lbnRJRChmaWxlRWwuZm9ybSwgdGFyZ2V0Q3R4KVxuICAgICAgfSlcbiAgICAgICAgLnRoZW4oKHtyZXNwfSkgPT4gb25SZXBseShyZXNwKSlcbiAgICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBmaWxlIHByb2dyZXNzXCIsIGVycm9yKSlcbiAgICB9KVxuICB9XG5cbiAgcHVzaElucHV0KGlucHV0RWwsIHRhcmdldEN0eCwgZm9yY2VDaWQsIHBoeEV2ZW50LCBvcHRzLCBjYWxsYmFjayl7XG4gICAgaWYoIWlucHV0RWwuZm9ybSl7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJmb3JtIGV2ZW50cyByZXF1aXJlIHRoZSBpbnB1dCB0byBiZSBpbnNpZGUgYSBmb3JtXCIpXG4gICAgfVxuXG4gICAgbGV0IHVwbG9hZHNcbiAgICBsZXQgY2lkID0gaXNDaWQoZm9yY2VDaWQpID8gZm9yY2VDaWQgOiB0aGlzLnRhcmdldENvbXBvbmVudElEKGlucHV0RWwuZm9ybSwgdGFyZ2V0Q3R4LCBvcHRzKVxuICAgIGxldCByZWZHZW5lcmF0b3IgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5wdXRSZWYoW1xuICAgICAgICB7ZWw6IGlucHV0RWwsIGxvYWRpbmc6IHRydWUsIGxvY2s6IHRydWV9LFxuICAgICAgICB7ZWw6IGlucHV0RWwuZm9ybSwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZX1cbiAgICAgIF0sIHBoeEV2ZW50LCBcImNoYW5nZVwiLCBvcHRzKVxuICAgIH1cbiAgICBsZXQgZm9ybURhdGFcbiAgICBsZXQgbWV0YSA9IHRoaXMuZXh0cmFjdE1ldGEoaW5wdXRFbC5mb3JtLCB7fSwgb3B0cy52YWx1ZSlcbiAgICBsZXQgc2VyaWFsaXplT3B0cyA9IHt9XG4gICAgaWYoaW5wdXRFbCBpbnN0YW5jZW9mIEhUTUxCdXR0b25FbGVtZW50KXsgc2VyaWFsaXplT3B0cy5zdWJtaXR0ZXIgPSBpbnB1dEVsIH1cbiAgICBpZihpbnB1dEVsLmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIikpKXtcbiAgICAgIGZvcm1EYXRhID0gc2VyaWFsaXplRm9ybShpbnB1dEVsLmZvcm0sIHNlcmlhbGl6ZU9wdHMsIFtpbnB1dEVsLm5hbWVdKVxuICAgIH0gZWxzZSB7XG4gICAgICBmb3JtRGF0YSA9IHNlcmlhbGl6ZUZvcm0oaW5wdXRFbC5mb3JtLCBzZXJpYWxpemVPcHRzKVxuICAgIH1cbiAgICBpZihET00uaXNVcGxvYWRJbnB1dChpbnB1dEVsKSAmJiBpbnB1dEVsLmZpbGVzICYmIGlucHV0RWwuZmlsZXMubGVuZ3RoID4gMCl7XG4gICAgICBMaXZlVXBsb2FkZXIudHJhY2tGaWxlcyhpbnB1dEVsLCBBcnJheS5mcm9tKGlucHV0RWwuZmlsZXMpKVxuICAgIH1cbiAgICB1cGxvYWRzID0gTGl2ZVVwbG9hZGVyLnNlcmlhbGl6ZVVwbG9hZHMoaW5wdXRFbClcblxuICAgIGxldCBldmVudCA9IHtcbiAgICAgIHR5cGU6IFwiZm9ybVwiLFxuICAgICAgZXZlbnQ6IHBoeEV2ZW50LFxuICAgICAgdmFsdWU6IGZvcm1EYXRhLFxuICAgICAgbWV0YToge1xuICAgICAgICAvLyBubyB0YXJnZXQgd2FzIGltcGxpY2l0bHkgc2VudCBhcyBcInVuZGVmaW5lZFwiIGluIExWIDw9IDEuMC41LCB0aGVyZWZvcmVcbiAgICAgICAgLy8gd2UgaGF2ZSB0byBrZWVwIGl0LiBJbiAxLjAuNiB3ZSBzd2l0Y2hlZCBmcm9tIHBhc3NpbmcgbWV0YSBhcyBVUkwgZW5jb2RlZCBkYXRhXG4gICAgICAgIC8vIHRvIHBhc3NpbmcgaXQgZGlyZWN0bHkgaW4gdGhlIGV2ZW50LCBidXQgdGhlIEpTT04gZW5jb2RlIHdvdWxkIGRyb3Aga2V5cyB3aXRoXG4gICAgICAgIC8vIHVuZGVmaW5lZCB2YWx1ZXMuXG4gICAgICAgIF90YXJnZXQ6IG9wdHMuX3RhcmdldCB8fCBcInVuZGVmaW5lZFwiLFxuICAgICAgICAuLi5tZXRhXG4gICAgICB9LFxuICAgICAgdXBsb2FkczogdXBsb2FkcyxcbiAgICAgIGNpZDogY2lkXG4gICAgfVxuICAgIHRoaXMucHVzaFdpdGhSZXBseShyZWZHZW5lcmF0b3IsIFwiZXZlbnRcIiwgZXZlbnQpLnRoZW4oKHtyZXNwfSkgPT4ge1xuICAgICAgaWYoRE9NLmlzVXBsb2FkSW5wdXQoaW5wdXRFbCkgJiYgRE9NLmlzQXV0b1VwbG9hZChpbnB1dEVsKSl7XG4gICAgICAgIC8vIHRoZSBlbGVtZW50IGNvdWxkIGJlIGluc2lkZSBhIGxvY2tlZCBwYXJlbnQgZm9yIG90aGVyIHVucmVsYXRlZCBjaGFuZ2VzO1xuICAgICAgICAvLyB3ZSBjYW4gb25seSBzdGFydCB1cGxvYWRzIHdoZW4gdGhlIHRyZWUgaXMgdW5sb2NrZWQgYW5kIHRoZVxuICAgICAgICAvLyBuZWNlc3NhcnkgZGF0YSBhdHRyaWJ1dGVzIGFyZSBzZXQgaW4gdGhlIHJlYWwgRE9NXG4gICAgICAgIEVsZW1lbnRSZWYub25VbmxvY2soaW5wdXRFbCwgKCkgPT4ge1xuICAgICAgICAgIGlmKExpdmVVcGxvYWRlci5maWxlc0F3YWl0aW5nUHJlZmxpZ2h0KGlucHV0RWwpLmxlbmd0aCA+IDApe1xuICAgICAgICAgICAgbGV0IFtyZWYsIF9lbHNdID0gcmVmR2VuZXJhdG9yKClcbiAgICAgICAgICAgIHRoaXMudW5kb1JlZnMocmVmLCBwaHhFdmVudCwgW2lucHV0RWwuZm9ybV0pXG4gICAgICAgICAgICB0aGlzLnVwbG9hZEZpbGVzKGlucHV0RWwuZm9ybSwgcGh4RXZlbnQsIHRhcmdldEN0eCwgcmVmLCBjaWQsIChfdXBsb2FkcykgPT4ge1xuICAgICAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhyZXNwKVxuICAgICAgICAgICAgICB0aGlzLnRyaWdnZXJBd2FpdGluZ1N1Ym1pdChpbnB1dEVsLmZvcm0sIHBoeEV2ZW50KVxuICAgICAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGh4RXZlbnQpXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKHJlc3ApXG4gICAgICB9XG4gICAgfSkuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIGlucHV0IGV2ZW50XCIsIGVycm9yKSlcbiAgfVxuXG4gIHRyaWdnZXJBd2FpdGluZ1N1Ym1pdChmb3JtRWwsIHBoeEV2ZW50KXtcbiAgICBsZXQgYXdhaXRpbmdTdWJtaXQgPSB0aGlzLmdldFNjaGVkdWxlZFN1Ym1pdChmb3JtRWwpXG4gICAgaWYoYXdhaXRpbmdTdWJtaXQpe1xuICAgICAgbGV0IFtfZWwsIF9yZWYsIF9vcHRzLCBjYWxsYmFja10gPSBhd2FpdGluZ1N1Ym1pdFxuICAgICAgdGhpcy5jYW5jZWxTdWJtaXQoZm9ybUVsLCBwaHhFdmVudClcbiAgICAgIGNhbGxiYWNrKClcbiAgICB9XG4gIH1cblxuICBnZXRTY2hlZHVsZWRTdWJtaXQoZm9ybUVsKXtcbiAgICByZXR1cm4gdGhpcy5mb3JtU3VibWl0cy5maW5kKChbZWwsIF9yZWYsIF9vcHRzLCBfY2FsbGJhY2tdKSA9PiBlbC5pc1NhbWVOb2RlKGZvcm1FbCkpXG4gIH1cblxuICBzY2hlZHVsZVN1Ym1pdChmb3JtRWwsIHJlZiwgb3B0cywgY2FsbGJhY2spe1xuICAgIGlmKHRoaXMuZ2V0U2NoZWR1bGVkU3VibWl0KGZvcm1FbCkpeyByZXR1cm4gdHJ1ZSB9XG4gICAgdGhpcy5mb3JtU3VibWl0cy5wdXNoKFtmb3JtRWwsIHJlZiwgb3B0cywgY2FsbGJhY2tdKVxuICB9XG5cbiAgY2FuY2VsU3VibWl0KGZvcm1FbCwgcGh4RXZlbnQpe1xuICAgIHRoaXMuZm9ybVN1Ym1pdHMgPSB0aGlzLmZvcm1TdWJtaXRzLmZpbHRlcigoW2VsLCByZWYsIF9vcHRzLCBfY2FsbGJhY2tdKSA9PiB7XG4gICAgICBpZihlbC5pc1NhbWVOb2RlKGZvcm1FbCkpe1xuICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGh4RXZlbnQpXG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgZGlzYWJsZUZvcm0oZm9ybUVsLCBwaHhFdmVudCwgb3B0cyA9IHt9KXtcbiAgICBsZXQgZmlsdGVySWdub3JlZCA9IGVsID0+IHtcbiAgICAgIGxldCB1c2VySWdub3JlZCA9IGNsb3Nlc3RQaHhCaW5kaW5nKGVsLCBgJHt0aGlzLmJpbmRpbmcoUEhYX1VQREFURSl9PWlnbm9yZWAsIGVsLmZvcm0pXG4gICAgICByZXR1cm4gISh1c2VySWdub3JlZCB8fCBjbG9zZXN0UGh4QmluZGluZyhlbCwgXCJkYXRhLXBoeC11cGRhdGU9aWdub3JlXCIsIGVsLmZvcm0pKVxuICAgIH1cbiAgICBsZXQgZmlsdGVyRGlzYWJsZXMgPSBlbCA9PiB7XG4gICAgICByZXR1cm4gZWwuaGFzQXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfRElTQUJMRV9XSVRIKSlcbiAgICB9XG4gICAgbGV0IGZpbHRlckJ1dHRvbiA9IGVsID0+IGVsLnRhZ05hbWUgPT0gXCJCVVRUT05cIlxuXG4gICAgbGV0IGZpbHRlcklucHV0ID0gZWwgPT4gW1wiSU5QVVRcIiwgXCJURVhUQVJFQVwiLCBcIlNFTEVDVFwiXS5pbmNsdWRlcyhlbC50YWdOYW1lKVxuXG4gICAgbGV0IGZvcm1FbGVtZW50cyA9IEFycmF5LmZyb20oZm9ybUVsLmVsZW1lbnRzKVxuICAgIGxldCBkaXNhYmxlcyA9IGZvcm1FbGVtZW50cy5maWx0ZXIoZmlsdGVyRGlzYWJsZXMpXG4gICAgbGV0IGJ1dHRvbnMgPSBmb3JtRWxlbWVudHMuZmlsdGVyKGZpbHRlckJ1dHRvbikuZmlsdGVyKGZpbHRlcklnbm9yZWQpXG4gICAgbGV0IGlucHV0cyA9IGZvcm1FbGVtZW50cy5maWx0ZXIoZmlsdGVySW5wdXQpLmZpbHRlcihmaWx0ZXJJZ25vcmVkKVxuXG4gICAgYnV0dG9ucy5mb3JFYWNoKGJ1dHRvbiA9PiB7XG4gICAgICBidXR0b24uc2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRCwgYnV0dG9uLmRpc2FibGVkKVxuICAgICAgYnV0dG9uLmRpc2FibGVkID0gdHJ1ZVxuICAgIH0pXG4gICAgaW5wdXRzLmZvckVhY2goaW5wdXQgPT4ge1xuICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKFBIWF9SRUFET05MWSwgaW5wdXQucmVhZE9ubHkpXG4gICAgICBpbnB1dC5yZWFkT25seSA9IHRydWVcbiAgICAgIGlmKGlucHV0LmZpbGVzKXtcbiAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRCwgaW5wdXQuZGlzYWJsZWQpXG4gICAgICAgIGlucHV0LmRpc2FibGVkID0gdHJ1ZVxuICAgICAgfVxuICAgIH0pXG4gICAgbGV0IGZvcm1FbHMgPSBkaXNhYmxlcy5jb25jYXQoYnV0dG9ucykuY29uY2F0KGlucHV0cykubWFwKGVsID0+IHtcbiAgICAgIHJldHVybiB7ZWwsIGxvYWRpbmc6IHRydWUsIGxvY2s6IHRydWV9XG4gICAgfSlcblxuICAgIC8vIHdlIHJldmVyc2UgdGhlIG9yZGVyIHNvIGZvcm0gY2hpbGRyZW4gYXJlIGFscmVhZHkgbG9ja2VkIGJ5IHRoZSB0aW1lXG4gICAgLy8gdGhlIGZvcm0gaXMgbG9ja2VkXG4gICAgbGV0IGVscyA9IFt7ZWw6IGZvcm1FbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogZmFsc2V9XS5jb25jYXQoZm9ybUVscykucmV2ZXJzZSgpXG4gICAgcmV0dXJuIHRoaXMucHV0UmVmKGVscywgcGh4RXZlbnQsIFwic3VibWl0XCIsIG9wdHMpXG4gIH1cblxuICBwdXNoRm9ybVN1Ym1pdChmb3JtRWwsIHRhcmdldEN0eCwgcGh4RXZlbnQsIHN1Ym1pdHRlciwgb3B0cywgb25SZXBseSl7XG4gICAgbGV0IHJlZkdlbmVyYXRvciA9ICgpID0+IHRoaXMuZGlzYWJsZUZvcm0oZm9ybUVsLCBwaHhFdmVudCwge1xuICAgICAgLi4ub3B0cyxcbiAgICAgIGZvcm06IGZvcm1FbCxcbiAgICAgIHN1Ym1pdHRlcjogc3VibWl0dGVyXG4gICAgfSlcbiAgICAvLyBzdG9yZSB0aGUgc3VibWl0dGVyIGluIHRoZSBmb3JtIGVsZW1lbnQgaW4gb3JkZXIgdG8gdHJpZ2dlciBpdFxuICAgIC8vIGZvciBwaHgtdHJpZ2dlci1hY3Rpb25cbiAgICBET00ucHV0UHJpdmF0ZShmb3JtRWwsIFwic3VibWl0dGVyXCIsIHN1Ym1pdHRlcilcbiAgICBsZXQgY2lkID0gdGhpcy50YXJnZXRDb21wb25lbnRJRChmb3JtRWwsIHRhcmdldEN0eClcbiAgICBpZihMaXZlVXBsb2FkZXIuaGFzVXBsb2Fkc0luUHJvZ3Jlc3MoZm9ybUVsKSl7XG4gICAgICBsZXQgW3JlZiwgX2Vsc10gPSByZWZHZW5lcmF0b3IoKVxuICAgICAgbGV0IHB1c2ggPSAoKSA9PiB0aGlzLnB1c2hGb3JtU3VibWl0KGZvcm1FbCwgdGFyZ2V0Q3R4LCBwaHhFdmVudCwgc3VibWl0dGVyLCBvcHRzLCBvblJlcGx5KVxuICAgICAgcmV0dXJuIHRoaXMuc2NoZWR1bGVTdWJtaXQoZm9ybUVsLCByZWYsIG9wdHMsIHB1c2gpXG4gICAgfSBlbHNlIGlmKExpdmVVcGxvYWRlci5pbnB1dHNBd2FpdGluZ1ByZWZsaWdodChmb3JtRWwpLmxlbmd0aCA+IDApe1xuICAgICAgbGV0IFtyZWYsIGVsc10gPSByZWZHZW5lcmF0b3IoKVxuICAgICAgbGV0IHByb3h5UmVmR2VuID0gKCkgPT4gW3JlZiwgZWxzLCBvcHRzXVxuICAgICAgdGhpcy51cGxvYWRGaWxlcyhmb3JtRWwsIHBoeEV2ZW50LCB0YXJnZXRDdHgsIHJlZiwgY2lkLCAoX3VwbG9hZHMpID0+IHtcbiAgICAgICAgLy8gaWYgd2Ugc3RpbGwgaGF2aW5nIHBlbmRpbmcgcHJlZmxpZ2h0cyBpdCBtZWFucyB3ZSBoYXZlIGludmFsaWQgZW50cmllc1xuICAgICAgICAvLyBhbmQgdGhlIHBoeC1zdWJtaXQgY2Fubm90IGJlIGNvbXBsZXRlZFxuICAgICAgICBpZihMaXZlVXBsb2FkZXIuaW5wdXRzQXdhaXRpbmdQcmVmbGlnaHQoZm9ybUVsKS5sZW5ndGggPiAwKXtcbiAgICAgICAgICByZXR1cm4gdGhpcy51bmRvUmVmcyhyZWYsIHBoeEV2ZW50KVxuICAgICAgICB9XG4gICAgICAgIGxldCBtZXRhID0gdGhpcy5leHRyYWN0TWV0YShmb3JtRWwsIHt9LCBvcHRzLnZhbHVlKVxuICAgICAgICBsZXQgZm9ybURhdGEgPSBzZXJpYWxpemVGb3JtKGZvcm1FbCwge3N1Ym1pdHRlcn0pXG4gICAgICAgIHRoaXMucHVzaFdpdGhSZXBseShwcm94eVJlZkdlbiwgXCJldmVudFwiLCB7XG4gICAgICAgICAgdHlwZTogXCJmb3JtXCIsXG4gICAgICAgICAgZXZlbnQ6IHBoeEV2ZW50LFxuICAgICAgICAgIHZhbHVlOiBmb3JtRGF0YSxcbiAgICAgICAgICBtZXRhOiBtZXRhLFxuICAgICAgICAgIGNpZDogY2lkXG4gICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4oKHtyZXNwfSkgPT4gb25SZXBseShyZXNwKSlcbiAgICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIGZvcm0gc3VibWl0XCIsIGVycm9yKSlcbiAgICAgIH0pXG4gICAgfSBlbHNlIGlmKCEoZm9ybUVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX1NSQykgJiYgZm9ybUVsLmNsYXNzTGlzdC5jb250YWlucyhcInBoeC1zdWJtaXQtbG9hZGluZ1wiKSkpe1xuICAgICAgbGV0IG1ldGEgPSB0aGlzLmV4dHJhY3RNZXRhKGZvcm1FbCwge30sIG9wdHMudmFsdWUpXG4gICAgICBsZXQgZm9ybURhdGEgPSBzZXJpYWxpemVGb3JtKGZvcm1FbCwge3N1Ym1pdHRlcn0pXG4gICAgICB0aGlzLnB1c2hXaXRoUmVwbHkocmVmR2VuZXJhdG9yLCBcImV2ZW50XCIsIHtcbiAgICAgICAgdHlwZTogXCJmb3JtXCIsXG4gICAgICAgIGV2ZW50OiBwaHhFdmVudCxcbiAgICAgICAgdmFsdWU6IGZvcm1EYXRhLFxuICAgICAgICBtZXRhOiBtZXRhLFxuICAgICAgICBjaWQ6IGNpZFxuICAgICAgfSlcbiAgICAgICAgLnRoZW4oKHtyZXNwfSkgPT4gb25SZXBseShyZXNwKSlcbiAgICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBmb3JtIHN1Ym1pdFwiLCBlcnJvcikpXG4gICAgfVxuICB9XG5cbiAgdXBsb2FkRmlsZXMoZm9ybUVsLCBwaHhFdmVudCwgdGFyZ2V0Q3R4LCByZWYsIGNpZCwgb25Db21wbGV0ZSl7XG4gICAgbGV0IGpvaW5Db3VudEF0VXBsb2FkID0gdGhpcy5qb2luQ291bnRcbiAgICBsZXQgaW5wdXRFbHMgPSBMaXZlVXBsb2FkZXIuYWN0aXZlRmlsZUlucHV0cyhmb3JtRWwpXG4gICAgbGV0IG51bUZpbGVJbnB1dHNJblByb2dyZXNzID0gaW5wdXRFbHMubGVuZ3RoXG5cbiAgICAvLyBnZXQgZWFjaCBmaWxlIGlucHV0XG4gICAgaW5wdXRFbHMuZm9yRWFjaChpbnB1dEVsID0+IHtcbiAgICAgIGxldCB1cGxvYWRlciA9IG5ldyBMaXZlVXBsb2FkZXIoaW5wdXRFbCwgdGhpcywgKCkgPT4ge1xuICAgICAgICBudW1GaWxlSW5wdXRzSW5Qcm9ncmVzcy0tXG4gICAgICAgIGlmKG51bUZpbGVJbnB1dHNJblByb2dyZXNzID09PSAwKXsgb25Db21wbGV0ZSgpIH1cbiAgICAgIH0pXG5cbiAgICAgIGxldCBlbnRyaWVzID0gdXBsb2FkZXIuZW50cmllcygpLm1hcChlbnRyeSA9PiBlbnRyeS50b1ByZWZsaWdodFBheWxvYWQoKSlcblxuICAgICAgaWYoZW50cmllcy5sZW5ndGggPT09IDApe1xuICAgICAgICBudW1GaWxlSW5wdXRzSW5Qcm9ncmVzcy0tXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBsZXQgcGF5bG9hZCA9IHtcbiAgICAgICAgcmVmOiBpbnB1dEVsLmdldEF0dHJpYnV0ZShQSFhfVVBMT0FEX1JFRiksXG4gICAgICAgIGVudHJpZXM6IGVudHJpZXMsXG4gICAgICAgIGNpZDogdGhpcy50YXJnZXRDb21wb25lbnRJRChpbnB1dEVsLmZvcm0sIHRhcmdldEN0eClcbiAgICAgIH1cblxuICAgICAgdGhpcy5sb2coXCJ1cGxvYWRcIiwgKCkgPT4gW1wic2VuZGluZyBwcmVmbGlnaHQgcmVxdWVzdFwiLCBwYXlsb2FkXSlcblxuICAgICAgdGhpcy5wdXNoV2l0aFJlcGx5KG51bGwsIFwiYWxsb3dfdXBsb2FkXCIsIHBheWxvYWQpLnRoZW4oKHtyZXNwfSkgPT4ge1xuICAgICAgICB0aGlzLmxvZyhcInVwbG9hZFwiLCAoKSA9PiBbXCJnb3QgcHJlZmxpZ2h0IHJlc3BvbnNlXCIsIHJlc3BdKVxuICAgICAgICAvLyB0aGUgcHJlZmxpZ2h0IHdpbGwgcmVqZWN0IGVudHJpZXMgYmV5b25kIHRoZSBtYXggZW50cmllc1xuICAgICAgICAvLyBzbyB3ZSBlcnJvciBhbmQgY2FuY2VsIGVudHJpZXMgb24gdGhlIGNsaWVudCB0aGF0IGFyZSBtaXNzaW5nIGZyb20gdGhlIHJlc3BvbnNlXG4gICAgICAgIHVwbG9hZGVyLmVudHJpZXMoKS5mb3JFYWNoKGVudHJ5ID0+IHtcbiAgICAgICAgICBpZihyZXNwLmVudHJpZXMgJiYgIXJlc3AuZW50cmllc1tlbnRyeS5yZWZdKXtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlRmFpbGVkRW50cnlQcmVmbGlnaHQoZW50cnkucmVmLCBcImZhaWxlZCBwcmVmbGlnaHRcIiwgdXBsb2FkZXIpXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAvLyBmb3IgYXV0byB1cGxvYWRzLCB3ZSBtYXkgaGF2ZSBhbiBlbXB0eSBlbnRyaWVzIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZlclxuICAgICAgICAvLyBmb3IgZm9ybSBzdWJtaXRzIHRoYXQgY29udGFpbiBpbnZhbGlkIGVudHJpZXNcbiAgICAgICAgaWYocmVzcC5lcnJvciB8fCBPYmplY3Qua2V5cyhyZXNwLmVudHJpZXMpLmxlbmd0aCA9PT0gMCl7XG4gICAgICAgICAgdGhpcy51bmRvUmVmcyhyZWYsIHBoeEV2ZW50KVxuICAgICAgICAgIGxldCBlcnJvcnMgPSByZXNwLmVycm9yIHx8IFtdXG4gICAgICAgICAgZXJyb3JzLm1hcCgoW2VudHJ5X3JlZiwgcmVhc29uXSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVGYWlsZWRFbnRyeVByZWZsaWdodChlbnRyeV9yZWYsIHJlYXNvbiwgdXBsb2FkZXIpXG4gICAgICAgICAgfSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgb25FcnJvciA9IChjYWxsYmFjaykgPT4ge1xuICAgICAgICAgICAgdGhpcy5jaGFubmVsLm9uRXJyb3IoKCkgPT4ge1xuICAgICAgICAgICAgICBpZih0aGlzLmpvaW5Db3VudCA9PT0gam9pbkNvdW50QXRVcGxvYWQpeyBjYWxsYmFjaygpIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfVxuICAgICAgICAgIHVwbG9hZGVyLmluaXRBZGFwdGVyVXBsb2FkKHJlc3AsIG9uRXJyb3IsIHRoaXMubGl2ZVNvY2tldClcbiAgICAgICAgfVxuICAgICAgfSkuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIHVwbG9hZFwiLCBlcnJvcikpXG4gICAgfSlcbiAgfVxuXG4gIGhhbmRsZUZhaWxlZEVudHJ5UHJlZmxpZ2h0KHVwbG9hZFJlZiwgcmVhc29uLCB1cGxvYWRlcil7XG4gICAgaWYodXBsb2FkZXIuaXNBdXRvVXBsb2FkKCkpe1xuICAgICAgLy8gdXBsb2FkUmVmIG1heSBiZSB0b3AgbGV2ZWwgdXBsb2FkIGNvbmZpZyByZWYgb3IgZW50cnkgcmVmXG4gICAgICBsZXQgZW50cnkgPSB1cGxvYWRlci5lbnRyaWVzKCkuZmluZChlbnRyeSA9PiBlbnRyeS5yZWYgPT09IHVwbG9hZFJlZi50b1N0cmluZygpKVxuICAgICAgaWYoZW50cnkpeyBlbnRyeS5jYW5jZWwoKSB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHVwbG9hZGVyLmVudHJpZXMoKS5tYXAoZW50cnkgPT4gZW50cnkuY2FuY2VsKCkpXG4gICAgfVxuICAgIHRoaXMubG9nKFwidXBsb2FkXCIsICgpID0+IFtgZXJyb3IgZm9yIGVudHJ5ICR7dXBsb2FkUmVmfWAsIHJlYXNvbl0pXG4gIH1cblxuICBkaXNwYXRjaFVwbG9hZHModGFyZ2V0Q3R4LCBuYW1lLCBmaWxlc09yQmxvYnMpe1xuICAgIGxldCB0YXJnZXRFbGVtZW50ID0gdGhpcy50YXJnZXRDdHhFbGVtZW50KHRhcmdldEN0eCkgfHwgdGhpcy5lbFxuICAgIGxldCBpbnB1dHMgPSBET00uZmluZFVwbG9hZElucHV0cyh0YXJnZXRFbGVtZW50KS5maWx0ZXIoZWwgPT4gZWwubmFtZSA9PT0gbmFtZSlcbiAgICBpZihpbnB1dHMubGVuZ3RoID09PSAwKXsgbG9nRXJyb3IoYG5vIGxpdmUgZmlsZSBpbnB1dHMgZm91bmQgbWF0Y2hpbmcgdGhlIG5hbWUgXCIke25hbWV9XCJgKSB9XG4gICAgZWxzZSBpZihpbnB1dHMubGVuZ3RoID4gMSl7IGxvZ0Vycm9yKGBkdXBsaWNhdGUgbGl2ZSBmaWxlIGlucHV0cyBmb3VuZCBtYXRjaGluZyB0aGUgbmFtZSBcIiR7bmFtZX1cImApIH1cbiAgICBlbHNlIHsgRE9NLmRpc3BhdGNoRXZlbnQoaW5wdXRzWzBdLCBQSFhfVFJBQ0tfVVBMT0FEUywge2RldGFpbDoge2ZpbGVzOiBmaWxlc09yQmxvYnN9fSkgfVxuICB9XG5cbiAgdGFyZ2V0Q3R4RWxlbWVudCh0YXJnZXRDdHgpe1xuICAgIGlmKGlzQ2lkKHRhcmdldEN0eCkpe1xuICAgICAgbGV0IFt0YXJnZXRdID0gRE9NLmZpbmRDb21wb25lbnROb2RlTGlzdCh0aGlzLmVsLCB0YXJnZXRDdHgpXG4gICAgICByZXR1cm4gdGFyZ2V0XG4gICAgfSBlbHNlIGlmKHRhcmdldEN0eCl7XG4gICAgICByZXR1cm4gdGFyZ2V0Q3R4XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgcHVzaEZvcm1SZWNvdmVyeShvbGRGb3JtLCBuZXdGb3JtLCB0ZW1wbGF0ZURvbSwgY2FsbGJhY2spe1xuICAgIC8vIHdlIGFyZSBvbmx5IHJlY292ZXJpbmcgZm9ybXMgaW5zaWRlIHRoZSBjdXJyZW50IHZpZXcsIHRoZXJlZm9yZSBpdCBpcyBzYWZlIHRvXG4gICAgLy8gc2tpcCB3aXRoaW5Pd25lcnMgaGVyZSBhbmQgYWx3YXlzIHVzZSB0aGlzIHdoZW4gcmVmZXJyaW5nIHRvIHRoZSB2aWV3XG4gICAgY29uc3QgcGh4Q2hhbmdlID0gdGhpcy5iaW5kaW5nKFwiY2hhbmdlXCIpXG4gICAgY29uc3QgcGh4VGFyZ2V0ID0gbmV3Rm9ybS5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwidGFyZ2V0XCIpKSB8fCBuZXdGb3JtXG4gICAgY29uc3QgcGh4RXZlbnQgPSBuZXdGb3JtLmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoUEhYX0FVVE9fUkVDT1ZFUikpIHx8IG5ld0Zvcm0uZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcImNoYW5nZVwiKSlcbiAgICBjb25zdCBpbnB1dHMgPSBBcnJheS5mcm9tKG9sZEZvcm0uZWxlbWVudHMpLmZpbHRlcihlbCA9PiBET00uaXNGb3JtSW5wdXQoZWwpICYmIGVsLm5hbWUgJiYgIWVsLmhhc0F0dHJpYnV0ZShwaHhDaGFuZ2UpKVxuICAgIGlmKGlucHV0cy5sZW5ndGggPT09IDApe1xuICAgICAgY2FsbGJhY2soKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gd2UgbXVzdCBjbGVhciB0cmFja2VkIHVwbG9hZHMgYmVmb3JlIHJlY292ZXJ5IGFzIHRoZXkgbm8gbG9uZ2VyIGhhdmUgdmFsaWQgcmVmc1xuICAgIGlucHV0cy5mb3JFYWNoKGlucHV0ID0+IGlucHV0Lmhhc0F0dHJpYnV0ZShQSFhfVVBMT0FEX1JFRikgJiYgTGl2ZVVwbG9hZGVyLmNsZWFyRmlsZXMoaW5wdXQpKVxuICAgIC8vIHB1c2hJbnB1dCBhc3N1bWVzIHRoYXQgdGhlcmUgaXMgYSBzb3VyY2UgZWxlbWVudCB0aGF0IGluaXRpYXRlZCB0aGUgY2hhbmdlO1xuICAgIC8vIGJlY2F1c2UgdGhpcyBpcyBub3QgdGhlIGNhc2Ugd2hlbiB3ZSByZWNvdmVyIGZvcm1zLCB3ZSBwcm92aWRlIHRoZSBmaXJzdCBpbnB1dCB3ZSBmaW5kXG4gICAgbGV0IGlucHV0ID0gaW5wdXRzLmZpbmQoZWwgPT4gZWwudHlwZSAhPT0gXCJoaWRkZW5cIikgfHwgaW5wdXRzWzBdXG5cbiAgICAvLyBpbiB0aGUgY2FzZSB0aGF0IHRoZXJlIGFyZSBtdWx0aXBsZSB0YXJnZXRzLCB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIHBlbmRpbmcgcmVjb3ZlcnkgZXZlbnRzXG4gICAgLy8gYW5kIG9ubHkgY2FsbCB0aGUgY2FsbGJhY2sgb25jZSBhbGwgZXZlbnRzIGhhdmUgYmVlbiBwcm9jZXNzZWRcbiAgICBsZXQgcGVuZGluZyA9IDBcbiAgICAvLyB3aXRoaW5UYXJnZXRzKHBoeFRhcmdldCwgY2FsbGJhY2ssIGRvbSwgdmlld0VsKVxuICAgIHRoaXMud2l0aGluVGFyZ2V0cyhwaHhUYXJnZXQsICh0YXJnZXRWaWV3LCB0YXJnZXRDdHgpID0+IHtcbiAgICAgIGNvbnN0IGNpZCA9IHRoaXMudGFyZ2V0Q29tcG9uZW50SUQobmV3Rm9ybSwgdGFyZ2V0Q3R4KVxuICAgICAgcGVuZGluZysrXG4gICAgICBsZXQgZSA9IG5ldyBDdXN0b21FdmVudChcInBoeDpmb3JtLXJlY292ZXJ5XCIsIHtkZXRhaWw6IHtzb3VyY2VFbGVtZW50OiBvbGRGb3JtfX0pXG4gICAgICBKUy5leGVjKGUsIFwiY2hhbmdlXCIsIHBoeEV2ZW50LCB0aGlzLCBpbnB1dCwgW1wicHVzaFwiLCB7XG4gICAgICAgIF90YXJnZXQ6IGlucHV0Lm5hbWUsXG4gICAgICAgIHRhcmdldFZpZXcsXG4gICAgICAgIHRhcmdldEN0eCxcbiAgICAgICAgbmV3Q2lkOiBjaWQsXG4gICAgICAgIGNhbGxiYWNrOiAoKSA9PiB7XG4gICAgICAgICAgcGVuZGluZy0tXG4gICAgICAgICAgaWYocGVuZGluZyA9PT0gMCl7IGNhbGxiYWNrKCkgfVxuICAgICAgICB9XG4gICAgICB9XSlcbiAgICB9LCB0ZW1wbGF0ZURvbSwgdGVtcGxhdGVEb20pXG4gIH1cblxuICBwdXNoTGlua1BhdGNoKGUsIGhyZWYsIHRhcmdldEVsLCBjYWxsYmFjayl7XG4gICAgbGV0IGxpbmtSZWYgPSB0aGlzLmxpdmVTb2NrZXQuc2V0UGVuZGluZ0xpbmsoaHJlZilcbiAgICAvLyBvbmx5IGFkZCBsb2FkaW5nIHN0YXRlcyBpZiBldmVudCBpcyB0cnVzdGVkIChpdCB3YXMgdHJpZ2dlcmVkIGJ5IHVzZXIsIHN1Y2ggYXMgY2xpY2spIGFuZFxuICAgIC8vIGl0J3Mgbm90IGEgZm9yd2FyZC9iYWNrIG5hdmlnYXRpb24gZnJvbSBwb3BzdGF0ZVxuICAgIGxldCBsb2FkaW5nID0gZS5pc1RydXN0ZWQgJiYgZS50eXBlICE9PSBcInBvcHN0YXRlXCJcbiAgICBsZXQgcmVmR2VuID0gdGFyZ2V0RWwgPyAoKSA9PiB0aGlzLnB1dFJlZihbe2VsOiB0YXJnZXRFbCwgbG9hZGluZzogbG9hZGluZywgbG9jazogdHJ1ZX1dLCBudWxsLCBcImNsaWNrXCIpIDogbnVsbFxuICAgIGxldCBmYWxsYmFjayA9ICgpID0+IHRoaXMubGl2ZVNvY2tldC5yZWRpcmVjdCh3aW5kb3cubG9jYXRpb24uaHJlZilcbiAgICBsZXQgdXJsID0gaHJlZi5zdGFydHNXaXRoKFwiL1wiKSA/IGAke2xvY2F0aW9uLnByb3RvY29sfS8vJHtsb2NhdGlvbi5ob3N0fSR7aHJlZn1gIDogaHJlZlxuXG4gICAgdGhpcy5wdXNoV2l0aFJlcGx5KHJlZkdlbiwgXCJsaXZlX3BhdGNoXCIsIHt1cmx9KS50aGVuKFxuICAgICAgKHtyZXNwfSkgPT4ge1xuICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgaWYocmVzcC5saW5rX3JlZGlyZWN0KXtcbiAgICAgICAgICAgIHRoaXMubGl2ZVNvY2tldC5yZXBsYWNlTWFpbihocmVmLCBudWxsLCBjYWxsYmFjaywgbGlua1JlZilcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYodGhpcy5saXZlU29ja2V0LmNvbW1pdFBlbmRpbmdMaW5rKGxpbmtSZWYpKXtcbiAgICAgICAgICAgICAgdGhpcy5ocmVmID0gaHJlZlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5hcHBseVBlbmRpbmdVcGRhdGVzKClcbiAgICAgICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKGxpbmtSZWYpXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgfSxcbiAgICAgICh7ZXJyb3I6IF9lcnJvciwgdGltZW91dDogX3RpbWVvdXR9KSA9PiBmYWxsYmFjaygpXG4gICAgKVxuICB9XG5cbiAgZ2V0Rm9ybXNGb3JSZWNvdmVyeSgpe1xuICAgIGlmKHRoaXMuam9pbkNvdW50ID09PSAwKXsgcmV0dXJuIHt9IH1cblxuICAgIGxldCBwaHhDaGFuZ2UgPSB0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIilcblxuICAgIHJldHVybiBET00uYWxsKHRoaXMuZWwsIGBmb3JtWyR7cGh4Q2hhbmdlfV1gKVxuICAgICAgLmZpbHRlcihmb3JtID0+IGZvcm0uaWQpXG4gICAgICAuZmlsdGVyKGZvcm0gPT4gZm9ybS5lbGVtZW50cy5sZW5ndGggPiAwKVxuICAgICAgLmZpbHRlcihmb3JtID0+IGZvcm0uZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfQVVUT19SRUNPVkVSKSkgIT09IFwiaWdub3JlXCIpXG4gICAgICAubWFwKGZvcm0gPT4ge1xuICAgICAgICAvLyB3ZSBwZXJmb3JtIGEgc2hhbGxvdyBjbG9uZSBhbmQgbWFudWFsbHkgY29weSBhbGwgZWxlbWVudHNcbiAgICAgICAgY29uc3QgY2xvbmVkRm9ybSA9IGZvcm0uY2xvbmVOb2RlKGZhbHNlKVxuICAgICAgICAvLyB3ZSBuZWVkIHRvIGNvcHkgdGhlIHByaXZhdGUgZGF0YSBhcyBpdCBjb250YWluc1xuICAgICAgICAvLyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgdG91Y2hlZCBmaWVsZHNcbiAgICAgICAgRE9NLmNvcHlQcml2YXRlcyhjbG9uZWRGb3JtLCBmb3JtKVxuICAgICAgICBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpLmZvckVhY2goKGVsKSA9PiB7XG4gICAgICAgICAgLy8gd2UgbmVlZCB0byBjbG9uZSBhbGwgY2hpbGQgbm9kZXMgYXMgd2VsbCxcbiAgICAgICAgICAvLyBiZWNhdXNlIHRob3NlIGNvdWxkIGFsc28gYmUgc2VsZWN0c1xuICAgICAgICAgIGNvbnN0IGNsb25lZEVsID0gZWwuY2xvbmVOb2RlKHRydWUpXG4gICAgICAgICAgLy8gd2UgY2FsbCBtb3JwaGRvbSB0byBjb3B5IGFueSBzcGVjaWFsIHN0YXRlXG4gICAgICAgICAgLy8gbGlrZSB0aGUgc2VsZWN0ZWQgb3B0aW9uIG9mIGEgPHNlbGVjdD4gZWxlbWVudDtcbiAgICAgICAgICAvLyB0aGlzIHNob3VsZCBiZSBwbGVudHkgZmFzdCBhcyB3ZSBjYWxsIGl0IG9uIGEgc21hbGwgc3Vic2V0IG9mIHRoZSBET00sXG4gICAgICAgICAgLy8gc2luZ2xlIGlucHV0cyBvciBhIHNlbGVjdCB3aXRoIGNoaWxkcmVuXG4gICAgICAgICAgbW9ycGhkb20oY2xvbmVkRWwsIGVsKVxuICAgICAgICAgIERPTS5jb3B5UHJpdmF0ZXMoY2xvbmVkRWwsIGVsKVxuICAgICAgICAgIGNsb25lZEZvcm0uYXBwZW5kQ2hpbGQoY2xvbmVkRWwpXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVybiBjbG9uZWRGb3JtXG4gICAgICB9KVxuICAgICAgLnJlZHVjZSgoYWNjLCBmb3JtKSA9PiB7XG4gICAgICAgIGFjY1tmb3JtLmlkXSA9IGZvcm1cbiAgICAgICAgcmV0dXJuIGFjY1xuICAgICAgfSwge30pXG4gIH1cblxuICBtYXliZVB1c2hDb21wb25lbnRzRGVzdHJveWVkKGRlc3Ryb3llZENJRHMpe1xuICAgIGxldCB3aWxsRGVzdHJveUNJRHMgPSBkZXN0cm95ZWRDSURzLmZpbHRlcihjaWQgPT4ge1xuICAgICAgcmV0dXJuIERPTS5maW5kQ29tcG9uZW50Tm9kZUxpc3QodGhpcy5lbCwgY2lkKS5sZW5ndGggPT09IDBcbiAgICB9KVxuXG4gICAgaWYod2lsbERlc3Ryb3lDSURzLmxlbmd0aCA+IDApe1xuICAgICAgLy8gd2UgbXVzdCByZXNldCB0aGUgcmVuZGVyIGNoYW5nZSB0cmFja2luZyBmb3IgY2lkcyB0aGF0XG4gICAgICAvLyBjb3VsZCBiZSBhZGRlZCBiYWNrIGZyb20gdGhlIHNlcnZlciBzbyB3ZSBkb24ndCBza2lwIHRoZW1cbiAgICAgIHdpbGxEZXN0cm95Q0lEcy5mb3JFYWNoKGNpZCA9PiB0aGlzLnJlbmRlcmVkLnJlc2V0UmVuZGVyKGNpZCkpXG5cbiAgICAgIHRoaXMucHVzaFdpdGhSZXBseShudWxsLCBcImNpZHNfd2lsbF9kZXN0cm95XCIsIHtjaWRzOiB3aWxsRGVzdHJveUNJRHN9KS50aGVuKCgpID0+IHtcbiAgICAgICAgLy8gd2UgbXVzdCB3YWl0IGZvciBwZW5kaW5nIHRyYW5zaXRpb25zIHRvIGNvbXBsZXRlIGJlZm9yZSBkZXRlcm1pbmluZ1xuICAgICAgICAvLyBpZiB0aGUgY2lkcyB3ZXJlIGFkZGVkIGJhY2sgdG8gdGhlIERPTSBpbiB0aGUgbWVhbnRpbWUgKCMzMTM5KVxuICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgLy8gU2VlIGlmIGFueSBvZiB0aGUgY2lkcyB3ZSB3YW50ZWQgdG8gZGVzdHJveSB3ZXJlIGFkZGVkIGJhY2ssXG4gICAgICAgICAgLy8gaWYgdGhleSB3ZXJlIGFkZGVkIGJhY2ssIHdlIGRvbid0IGFjdHVhbGx5IGRlc3Ryb3kgdGhlbS5cbiAgICAgICAgICBsZXQgY29tcGxldGVseURlc3Ryb3lDSURzID0gd2lsbERlc3Ryb3lDSURzLmZpbHRlcihjaWQgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIERPTS5maW5kQ29tcG9uZW50Tm9kZUxpc3QodGhpcy5lbCwgY2lkKS5sZW5ndGggPT09IDBcbiAgICAgICAgICB9KVxuXG4gICAgICAgICAgaWYoY29tcGxldGVseURlc3Ryb3lDSURzLmxlbmd0aCA+IDApe1xuICAgICAgICAgICAgdGhpcy5wdXNoV2l0aFJlcGx5KG51bGwsIFwiY2lkc19kZXN0cm95ZWRcIiwge2NpZHM6IGNvbXBsZXRlbHlEZXN0cm95Q0lEc30pLnRoZW4oKHtyZXNwfSkgPT4ge1xuICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVkLnBydW5lQ0lEcyhyZXNwLmNpZHMpXG4gICAgICAgICAgICB9KS5jYXRjaCgoZXJyb3IpID0+IGxvZ0Vycm9yKFwiRmFpbGVkIHRvIHB1c2ggY29tcG9uZW50cyBkZXN0cm95ZWRcIiwgZXJyb3IpKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0pLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBjb21wb25lbnRzIGRlc3Ryb3llZFwiLCBlcnJvcikpXG4gICAgfVxuICB9XG5cbiAgb3duc0VsZW1lbnQoZWwpe1xuICAgIGxldCBwYXJlbnRWaWV3RWwgPSBlbC5jbG9zZXN0KFBIWF9WSUVXX1NFTEVDVE9SKVxuICAgIHJldHVybiBlbC5nZXRBdHRyaWJ1dGUoUEhYX1BBUkVOVF9JRCkgPT09IHRoaXMuaWQgfHxcbiAgICAgIChwYXJlbnRWaWV3RWwgJiYgcGFyZW50Vmlld0VsLmlkID09PSB0aGlzLmlkKSB8fFxuICAgICAgKCFwYXJlbnRWaWV3RWwgJiYgdGhpcy5pc0RlYWQpXG4gIH1cblxuICBzdWJtaXRGb3JtKGZvcm0sIHRhcmdldEN0eCwgcGh4RXZlbnQsIHN1Ym1pdHRlciwgb3B0cyA9IHt9KXtcbiAgICBET00ucHV0UHJpdmF0ZShmb3JtLCBQSFhfSEFTX1NVQk1JVFRFRCwgdHJ1ZSlcbiAgICBjb25zdCBpbnB1dHMgPSBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpXG4gICAgaW5wdXRzLmZvckVhY2goaW5wdXQgPT4gRE9NLnB1dFByaXZhdGUoaW5wdXQsIFBIWF9IQVNfU1VCTUlUVEVELCB0cnVlKSlcbiAgICB0aGlzLmxpdmVTb2NrZXQuYmx1ckFjdGl2ZUVsZW1lbnQodGhpcylcbiAgICB0aGlzLnB1c2hGb3JtU3VibWl0KGZvcm0sIHRhcmdldEN0eCwgcGh4RXZlbnQsIHN1Ym1pdHRlciwgb3B0cywgKCkgPT4ge1xuICAgICAgdGhpcy5saXZlU29ja2V0LnJlc3RvcmVQcmV2aW91c2x5QWN0aXZlRm9jdXMoKVxuICAgIH0pXG4gIH1cblxuICBiaW5kaW5nKGtpbmQpeyByZXR1cm4gdGhpcy5saXZlU29ja2V0LmJpbmRpbmcoa2luZCkgfVxufVxuIiwgIi8qKiBJbml0aWFsaXplcyB0aGUgTGl2ZVNvY2tldFxuICpcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5kUG9pbnQgLSBUaGUgc3RyaW5nIFdlYlNvY2tldCBlbmRwb2ludCwgaWUsIGBcIndzczovL2V4YW1wbGUuY29tL2xpdmVcImAsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFwiL2xpdmVcImAgKGluaGVyaXRlZCBob3N0ICYgcHJvdG9jb2wpXG4gKiBAcGFyYW0ge1Bob2VuaXguU29ja2V0fSBzb2NrZXQgLSB0aGUgcmVxdWlyZWQgUGhvZW5peCBTb2NrZXQgY2xhc3MgaW1wb3J0ZWQgZnJvbSBcInBob2VuaXhcIi4gRm9yIGV4YW1wbGU6XG4gKlxuICogICAgIGltcG9ydCB7U29ja2V0fSBmcm9tIFwicGhvZW5peFwiXG4gKiAgICAgaW1wb3J0IHtMaXZlU29ja2V0fSBmcm9tIFwicGhvZW5peF9saXZlX3ZpZXdcIlxuICogICAgIGxldCBsaXZlU29ja2V0ID0gbmV3IExpdmVTb2NrZXQoXCIvbGl2ZVwiLCBTb2NrZXQsIHsuLi59KVxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0c10gLSBPcHRpb25hbCBjb25maWd1cmF0aW9uLiBPdXRzaWRlIG9mIGtleXMgbGlzdGVkIGJlbG93LCBhbGxcbiAqIGNvbmZpZ3VyYXRpb24gaXMgcGFzc2VkIGRpcmVjdGx5IHRvIHRoZSBQaG9lbml4IFNvY2tldCBjb25zdHJ1Y3Rvci5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5kZWZhdWx0c10gLSBUaGUgb3B0aW9uYWwgZGVmYXVsdHMgdG8gdXNlIGZvciB2YXJpb3VzIGJpbmRpbmdzLFxuICogc3VjaCBhcyBgcGh4LWRlYm91bmNlYC4gU3VwcG9ydHMgdGhlIGZvbGxvd2luZyBrZXlzOlxuICpcbiAqICAgLSBkZWJvdW5jZSAtIHRoZSBtaWxsaXNlY29uZCBwaHgtZGVib3VuY2UgdGltZS4gRGVmYXVsdHMgMzAwXG4gKiAgIC0gdGhyb3R0bGUgLSB0aGUgbWlsbGlzZWNvbmQgcGh4LXRocm90dGxlIHRpbWUuIERlZmF1bHRzIDMwMFxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRzLnBhcmFtc10gLSBUaGUgb3B0aW9uYWwgZnVuY3Rpb24gZm9yIHBhc3NpbmcgY29ubmVjdCBwYXJhbXMuXG4gKiBUaGUgZnVuY3Rpb24gcmVjZWl2ZXMgdGhlIGVsZW1lbnQgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gTGl2ZVZpZXcuIEZvciBleGFtcGxlOlxuICpcbiAqICAgICAoZWwpID0+IHt2aWV3OiBlbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLW15LXZpZXctbmFtZVwiLCB0b2tlbjogd2luZG93Lm15VG9rZW59XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmJpbmRpbmdQcmVmaXhdIC0gVGhlIG9wdGlvbmFsIHByZWZpeCB0byB1c2UgZm9yIGFsbCBwaHggRE9NIGFubm90YXRpb25zLlxuICogRGVmYXVsdHMgdG8gXCJwaHgtXCIuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdHMuaG9va3NdIC0gVGhlIG9wdGlvbmFsIG9iamVjdCBmb3IgcmVmZXJlbmNpbmcgTGl2ZVZpZXcgaG9vayBjYWxsYmFja3MuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdHMudXBsb2FkZXJzXSAtIFRoZSBvcHRpb25hbCBvYmplY3QgZm9yIHJlZmVyZW5jaW5nIExpdmVWaWV3IHVwbG9hZGVyIGNhbGxiYWNrcy5cbiAqIEBwYXJhbSB7aW50ZWdlcn0gW29wdHMubG9hZGVyVGltZW91dF0gLSBUaGUgb3B0aW9uYWwgZGVsYXkgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgYmVmb3JlIGFwcGx5XG4gKiBsb2FkaW5nIHN0YXRlcy5cbiAqIEBwYXJhbSB7aW50ZWdlcn0gW29wdHMuZGlzY29ubmVjdGVkVGltZW91dF0gLSBUaGUgZGVsYXkgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgYmVmb3JlXG4gKiBleGVjdXRpbmcgcGh4LWRpc2Nvbm5lY3RlZCBjb21tYW5kcy4gRGVmYXVsdHMgdG8gNTAwLlxuICogQHBhcmFtIHtpbnRlZ2VyfSBbb3B0cy5tYXhSZWxvYWRzXSAtIFRoZSBtYXhpbXVtIHJlbG9hZHMgYmVmb3JlIGVudGVyaW5nIGZhaWxzYWZlIG1vZGUuXG4gKiBAcGFyYW0ge2ludGVnZXJ9IFtvcHRzLnJlbG9hZEppdHRlck1pbl0gLSBUaGUgbWluaW11bSB0aW1lIGJldHdlZW4gbm9ybWFsIHJlbG9hZCBhdHRlbXB0cy5cbiAqIEBwYXJhbSB7aW50ZWdlcn0gW29wdHMucmVsb2FkSml0dGVyTWF4XSAtIFRoZSBtYXhpbXVtIHRpbWUgYmV0d2VlbiBub3JtYWwgcmVsb2FkIGF0dGVtcHRzLlxuICogQHBhcmFtIHtpbnRlZ2VyfSBbb3B0cy5mYWlsc2FmZUppdHRlcl0gLSBUaGUgdGltZSBiZXR3ZWVuIHJlbG9hZCBhdHRlbXB0cyBpbiBmYWlsc2FmZSBtb2RlLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMudmlld0xvZ2dlcl0gLSBUaGUgb3B0aW9uYWwgZnVuY3Rpb24gdG8gbG9nIGRlYnVnIGluZm9ybWF0aW9uLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiAgICAgKHZpZXcsIGtpbmQsIG1zZywgb2JqKSA9PiBjb25zb2xlLmxvZyhgJHt2aWV3LmlkfSAke2tpbmR9OiAke21zZ30gLSBgLCBvYmopXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRzLm1ldGFkYXRhXSAtIFRoZSBvcHRpb25hbCBvYmplY3QgbWFwcGluZyBldmVudCBuYW1lcyB0byBmdW5jdGlvbnMgZm9yXG4gKiBwb3B1bGF0aW5nIGV2ZW50IG1ldGFkYXRhLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiAgICAgbWV0YWRhdGE6IHtcbiAqICAgICAgIGNsaWNrOiAoZSwgZWwpID0+IHtcbiAqICAgICAgICAgcmV0dXJuIHtcbiAqICAgICAgICAgICBjdHJsS2V5OiBlLmN0cmxLZXksXG4gKiAgICAgICAgICAgbWV0YUtleTogZS5tZXRhS2V5LFxuICogICAgICAgICAgIGRldGFpbDogZS5kZXRhaWwgfHwgMSxcbiAqICAgICAgICAgfVxuICogICAgICAgfSxcbiAqICAgICAgIGtleWRvd246IChlLCBlbCkgPT4ge1xuICogICAgICAgICByZXR1cm4ge1xuICogICAgICAgICAgIGtleTogZS5rZXksXG4gKiAgICAgICAgICAgY3RybEtleTogZS5jdHJsS2V5LFxuICogICAgICAgICAgIG1ldGFLZXk6IGUubWV0YUtleSxcbiAqICAgICAgICAgICBzaGlmdEtleTogZS5zaGlmdEtleVxuICogICAgICAgICB9XG4gKiAgICAgICB9XG4gKiAgICAgfVxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRzLnNlc3Npb25TdG9yYWdlXSAtIEFuIG9wdGlvbmFsIFN0b3JhZ2UgY29tcGF0aWJsZSBvYmplY3RcbiAqIFVzZWZ1bCB3aGVuIExpdmVWaWV3IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBzZXNzaW9uU3RvcmFnZWAuICBGb3IgZXhhbXBsZSwgVGhpcyBjb3VsZFxuICogaGFwcGVuIGlmIGEgc2l0ZSBsb2FkcyBhIGNyb3NzLWRvbWFpbiBMaXZlVmlldyBpbiBhbiBpZnJhbWUuICBFeGFtcGxlIHVzYWdlOlxuICpcbiAqICAgICBjbGFzcyBJbk1lbW9yeVN0b3JhZ2Uge1xuICogICAgICAgY29uc3RydWN0b3IoKSB7IHRoaXMuc3RvcmFnZSA9IHt9IH1cbiAqICAgICAgIGdldEl0ZW0oa2V5TmFtZSkgeyByZXR1cm4gdGhpcy5zdG9yYWdlW2tleU5hbWVdIHx8IG51bGwgfVxuICogICAgICAgcmVtb3ZlSXRlbShrZXlOYW1lKSB7IGRlbGV0ZSB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gfVxuICogICAgICAgc2V0SXRlbShrZXlOYW1lLCBrZXlWYWx1ZSkgeyB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gPSBrZXlWYWx1ZSB9XG4gKiAgICAgfVxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5sb2NhbFN0b3JhZ2VdIC0gQW4gb3B0aW9uYWwgU3RvcmFnZSBjb21wYXRpYmxlIG9iamVjdFxuICogVXNlZnVsIGZvciB3aGVuIExpdmVWaWV3IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBsb2NhbFN0b3JhZ2VgLlxuICogU2VlIGBvcHRzLnNlc3Npb25TdG9yYWdlYCBmb3IgZXhhbXBsZXMuXG4qL1xuXG5pbXBvcnQge1xuICBCSU5ESU5HX1BSRUZJWCxcbiAgQ09OU0VDVVRJVkVfUkVMT0FEUyxcbiAgREVGQVVMVFMsXG4gIEZBSUxTQUZFX0pJVFRFUixcbiAgTE9BREVSX1RJTUVPVVQsXG4gIERJU0NPTk5FQ1RFRF9USU1FT1VULFxuICBNQVhfUkVMT0FEUyxcbiAgUEhYX0RFQk9VTkNFLFxuICBQSFhfRFJPUF9UQVJHRVQsXG4gIFBIWF9IQVNfRk9DVVNFRCxcbiAgUEhYX0tFWSxcbiAgUEhYX0xJTktfU1RBVEUsXG4gIFBIWF9MSVZFX0xJTkssXG4gIFBIWF9MVl9ERUJVRyxcbiAgUEhYX0xWX0xBVEVOQ1lfU0lNLFxuICBQSFhfTFZfUFJPRklMRSxcbiAgUEhYX0xWX0hJU1RPUllfUE9TSVRJT04sXG4gIFBIWF9NQUlOLFxuICBQSFhfUEFSRU5UX0lELFxuICBQSFhfVklFV19TRUxFQ1RPUixcbiAgUEhYX1JPT1RfSUQsXG4gIFBIWF9USFJPVFRMRSxcbiAgUEhYX1RSQUNLX1VQTE9BRFMsXG4gIFBIWF9TRVNTSU9OLFxuICBSRUxPQURfSklUVEVSX01JTixcbiAgUkVMT0FEX0pJVFRFUl9NQVgsXG4gIFBIWF9SRUZfU1JDLFxuICBQSFhfUkVMT0FEX1NUQVRVU1xufSBmcm9tIFwiLi9jb25zdGFudHNcIlxuXG5pbXBvcnQge1xuICBjbG9uZSxcbiAgY2xvc2VzdFBoeEJpbmRpbmcsXG4gIGNsb3N1cmUsXG4gIGRlYnVnLFxuICBtYXliZVxufSBmcm9tIFwiLi91dGlsc1wiXG5cbmltcG9ydCBCcm93c2VyIGZyb20gXCIuL2Jyb3dzZXJcIlxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIlxuaW1wb3J0IEhvb2tzIGZyb20gXCIuL2hvb2tzXCJcbmltcG9ydCBMaXZlVXBsb2FkZXIgZnJvbSBcIi4vbGl2ZV91cGxvYWRlclwiXG5pbXBvcnQgVmlldyBmcm9tIFwiLi92aWV3XCJcbmltcG9ydCBKUyBmcm9tIFwiLi9qc1wiXG5cbmV4cG9ydCBsZXQgaXNVc2VkSW5wdXQgPSAoZWwpID0+IERPTS5pc1VzZWRJbnB1dChlbClcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTGl2ZVNvY2tldCB7XG4gIGNvbnN0cnVjdG9yKHVybCwgcGh4U29ja2V0LCBvcHRzID0ge30pe1xuICAgIHRoaXMudW5sb2FkZWQgPSBmYWxzZVxuICAgIGlmKCFwaHhTb2NrZXQgfHwgcGh4U29ja2V0LmNvbnN0cnVjdG9yLm5hbWUgPT09IFwiT2JqZWN0XCIpe1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBcbiAgICAgIGEgcGhvZW5peCBTb2NrZXQgbXVzdCBiZSBwcm92aWRlZCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHRvIHRoZSBMaXZlU29ja2V0IGNvbnN0cnVjdG9yLiBGb3IgZXhhbXBsZTpcblxuICAgICAgICAgIGltcG9ydCB7U29ja2V0fSBmcm9tIFwicGhvZW5peFwiXG4gICAgICAgICAgaW1wb3J0IHtMaXZlU29ja2V0fSBmcm9tIFwicGhvZW5peF9saXZlX3ZpZXdcIlxuICAgICAgICAgIGxldCBsaXZlU29ja2V0ID0gbmV3IExpdmVTb2NrZXQoXCIvbGl2ZVwiLCBTb2NrZXQsIHsuLi59KVxuICAgICAgYClcbiAgICB9XG4gICAgdGhpcy5zb2NrZXQgPSBuZXcgcGh4U29ja2V0KHVybCwgb3B0cylcbiAgICB0aGlzLmJpbmRpbmdQcmVmaXggPSBvcHRzLmJpbmRpbmdQcmVmaXggfHwgQklORElOR19QUkVGSVhcbiAgICB0aGlzLm9wdHMgPSBvcHRzXG4gICAgdGhpcy5wYXJhbXMgPSBjbG9zdXJlKG9wdHMucGFyYW1zIHx8IHt9KVxuICAgIHRoaXMudmlld0xvZ2dlciA9IG9wdHMudmlld0xvZ2dlclxuICAgIHRoaXMubWV0YWRhdGFDYWxsYmFja3MgPSBvcHRzLm1ldGFkYXRhIHx8IHt9XG4gICAgdGhpcy5kZWZhdWx0cyA9IE9iamVjdC5hc3NpZ24oY2xvbmUoREVGQVVMVFMpLCBvcHRzLmRlZmF1bHRzIHx8IHt9KVxuICAgIHRoaXMuYWN0aXZlRWxlbWVudCA9IG51bGxcbiAgICB0aGlzLnByZXZBY3RpdmUgPSBudWxsXG4gICAgdGhpcy5zaWxlbmNlZCA9IGZhbHNlXG4gICAgdGhpcy5tYWluID0gbnVsbFxuICAgIHRoaXMub3V0Z29pbmdNYWluRWwgPSBudWxsXG4gICAgdGhpcy5jbGlja1N0YXJ0ZWRBdFRhcmdldCA9IG51bGxcbiAgICB0aGlzLmxpbmtSZWYgPSAxXG4gICAgdGhpcy5yb290cyA9IHt9XG4gICAgdGhpcy5ocmVmID0gd2luZG93LmxvY2F0aW9uLmhyZWZcbiAgICB0aGlzLnBlbmRpbmdMaW5rID0gbnVsbFxuICAgIHRoaXMuY3VycmVudExvY2F0aW9uID0gY2xvbmUod2luZG93LmxvY2F0aW9uKVxuICAgIHRoaXMuaG9va3MgPSBvcHRzLmhvb2tzIHx8IHt9XG4gICAgdGhpcy51cGxvYWRlcnMgPSBvcHRzLnVwbG9hZGVycyB8fCB7fVxuICAgIHRoaXMubG9hZGVyVGltZW91dCA9IG9wdHMubG9hZGVyVGltZW91dCB8fCBMT0FERVJfVElNRU9VVFxuICAgIHRoaXMuZGlzY29ubmVjdGVkVGltZW91dCA9IG9wdHMuZGlzY29ubmVjdGVkVGltZW91dCB8fCBESVNDT05ORUNURURfVElNRU9VVFxuICAgIHRoaXMucmVsb2FkV2l0aEppdHRlclRpbWVyID0gbnVsbFxuICAgIHRoaXMubWF4UmVsb2FkcyA9IG9wdHMubWF4UmVsb2FkcyB8fCBNQVhfUkVMT0FEU1xuICAgIHRoaXMucmVsb2FkSml0dGVyTWluID0gb3B0cy5yZWxvYWRKaXR0ZXJNaW4gfHwgUkVMT0FEX0pJVFRFUl9NSU5cbiAgICB0aGlzLnJlbG9hZEppdHRlck1heCA9IG9wdHMucmVsb2FkSml0dGVyTWF4IHx8IFJFTE9BRF9KSVRURVJfTUFYXG4gICAgdGhpcy5mYWlsc2FmZUppdHRlciA9IG9wdHMuZmFpbHNhZmVKaXR0ZXIgfHwgRkFJTFNBRkVfSklUVEVSXG4gICAgdGhpcy5sb2NhbFN0b3JhZ2UgPSBvcHRzLmxvY2FsU3RvcmFnZSB8fCB3aW5kb3cubG9jYWxTdG9yYWdlXG4gICAgdGhpcy5zZXNzaW9uU3RvcmFnZSA9IG9wdHMuc2Vzc2lvblN0b3JhZ2UgfHwgd2luZG93LnNlc3Npb25TdG9yYWdlXG4gICAgdGhpcy5ib3VuZFRvcExldmVsRXZlbnRzID0gZmFsc2VcbiAgICB0aGlzLmJvdW5kRXZlbnROYW1lcyA9IG5ldyBTZXQoKVxuICAgIHRoaXMuc2VydmVyQ2xvc2VSZWYgPSBudWxsXG4gICAgdGhpcy5kb21DYWxsYmFja3MgPSBPYmplY3QuYXNzaWduKHtcbiAgICAgIGpzUXVlcnlTZWxlY3RvckFsbDogbnVsbCxcbiAgICAgIG9uUGF0Y2hTdGFydDogY2xvc3VyZSgpLFxuICAgICAgb25QYXRjaEVuZDogY2xvc3VyZSgpLFxuICAgICAgb25Ob2RlQWRkZWQ6IGNsb3N1cmUoKSxcbiAgICAgIG9uQmVmb3JlRWxVcGRhdGVkOiBjbG9zdXJlKCl9LFxuICAgIG9wdHMuZG9tIHx8IHt9KVxuICAgIHRoaXMudHJhbnNpdGlvbnMgPSBuZXcgVHJhbnNpdGlvblNldCgpXG4gICAgdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uID0gcGFyc2VJbnQodGhpcy5zZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFBIWF9MVl9ISVNUT1JZX1BPU0lUSU9OKSkgfHwgMFxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGFnZWhpZGVcIiwgX2UgPT4ge1xuICAgICAgdGhpcy51bmxvYWRlZCA9IHRydWVcbiAgICB9KVxuICAgIHRoaXMuc29ja2V0Lm9uT3BlbigoKSA9PiB7XG4gICAgICBpZih0aGlzLmlzVW5sb2FkZWQoKSl7XG4gICAgICAgIC8vIHJlbG9hZCBwYWdlIGlmIGJlaW5nIHJlc3RvcmVkIGZyb20gYmFjay9mb3J3YXJkIGNhY2hlIGFuZCBicm93c2VyIGRvZXMgbm90IGVtaXQgXCJwYWdlc2hvd1wiXG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvLyBwdWJsaWNcblxuICB2ZXJzaW9uKCl7IHJldHVybiBMVl9WU04gfVxuXG4gIGlzUHJvZmlsZUVuYWJsZWQoKXsgcmV0dXJuIHRoaXMuc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShQSFhfTFZfUFJPRklMRSkgPT09IFwidHJ1ZVwiIH1cblxuICBpc0RlYnVnRW5hYmxlZCgpeyByZXR1cm4gdGhpcy5zZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFBIWF9MVl9ERUJVRykgPT09IFwidHJ1ZVwiIH1cblxuICBpc0RlYnVnRGlzYWJsZWQoKXsgcmV0dXJuIHRoaXMuc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShQSFhfTFZfREVCVUcpID09PSBcImZhbHNlXCIgfVxuXG4gIGVuYWJsZURlYnVnKCl7IHRoaXMuc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShQSFhfTFZfREVCVUcsIFwidHJ1ZVwiKSB9XG5cbiAgZW5hYmxlUHJvZmlsaW5nKCl7IHRoaXMuc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShQSFhfTFZfUFJPRklMRSwgXCJ0cnVlXCIpIH1cblxuICBkaXNhYmxlRGVidWcoKXsgdGhpcy5zZXNzaW9uU3RvcmFnZS5zZXRJdGVtKFBIWF9MVl9ERUJVRywgXCJmYWxzZVwiKSB9XG5cbiAgZGlzYWJsZVByb2ZpbGluZygpeyB0aGlzLnNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oUEhYX0xWX1BST0ZJTEUpIH1cblxuICBlbmFibGVMYXRlbmN5U2ltKHVwcGVyQm91bmRNcyl7XG4gICAgdGhpcy5lbmFibGVEZWJ1ZygpXG4gICAgY29uc29sZS5sb2coXCJsYXRlbmN5IHNpbXVsYXRvciBlbmFibGVkIGZvciB0aGUgZHVyYXRpb24gb2YgdGhpcyBicm93c2VyIHNlc3Npb24uIENhbGwgZGlzYWJsZUxhdGVuY3lTaW0oKSB0byBkaXNhYmxlXCIpXG4gICAgdGhpcy5zZXNzaW9uU3RvcmFnZS5zZXRJdGVtKFBIWF9MVl9MQVRFTkNZX1NJTSwgdXBwZXJCb3VuZE1zKVxuICB9XG5cbiAgZGlzYWJsZUxhdGVuY3lTaW0oKXsgdGhpcy5zZXNzaW9uU3RvcmFnZS5yZW1vdmVJdGVtKFBIWF9MVl9MQVRFTkNZX1NJTSkgfVxuXG4gIGdldExhdGVuY3lTaW0oKXtcbiAgICBsZXQgc3RyID0gdGhpcy5zZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFBIWF9MVl9MQVRFTkNZX1NJTSlcbiAgICByZXR1cm4gc3RyID8gcGFyc2VJbnQoc3RyKSA6IG51bGxcbiAgfVxuXG4gIGdldFNvY2tldCgpeyByZXR1cm4gdGhpcy5zb2NrZXQgfVxuXG4gIGNvbm5lY3QoKXtcbiAgICAvLyBlbmFibGUgZGVidWcgYnkgZGVmYXVsdCBpZiBvbiBsb2NhbGhvc3QgYW5kIG5vdCBleHBsaWNpdGx5IGRpc2FibGVkXG4gICAgaWYod2luZG93LmxvY2F0aW9uLmhvc3RuYW1lID09PSBcImxvY2FsaG9zdFwiICYmICF0aGlzLmlzRGVidWdEaXNhYmxlZCgpKXsgdGhpcy5lbmFibGVEZWJ1ZygpIH1cbiAgICBsZXQgZG9Db25uZWN0ID0gKCkgPT4ge1xuICAgICAgdGhpcy5yZXNldFJlbG9hZFN0YXR1cygpXG4gICAgICBpZih0aGlzLmpvaW5Sb290Vmlld3MoKSl7XG4gICAgICAgIHRoaXMuYmluZFRvcExldmVsRXZlbnRzKClcbiAgICAgICAgdGhpcy5zb2NrZXQuY29ubmVjdCgpXG4gICAgICB9IGVsc2UgaWYodGhpcy5tYWluKXtcbiAgICAgICAgdGhpcy5zb2NrZXQuY29ubmVjdCgpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJpbmRUb3BMZXZlbEV2ZW50cyh7ZGVhZDogdHJ1ZX0pXG4gICAgICB9XG4gICAgICB0aGlzLmpvaW5EZWFkVmlldygpXG4gICAgfVxuICAgIGlmKFtcImNvbXBsZXRlXCIsIFwibG9hZGVkXCIsIFwiaW50ZXJhY3RpdmVcIl0uaW5kZXhPZihkb2N1bWVudC5yZWFkeVN0YXRlKSA+PSAwKXtcbiAgICAgIGRvQ29ubmVjdCgpXG4gICAgfSBlbHNlIHtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJET01Db250ZW50TG9hZGVkXCIsICgpID0+IGRvQ29ubmVjdCgpKVxuICAgIH1cbiAgfVxuXG4gIGRpc2Nvbm5lY3QoY2FsbGJhY2spe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlbG9hZFdpdGhKaXR0ZXJUaW1lcilcbiAgICAvLyByZW1vdmUgdGhlIHNvY2tldCBjbG9zZSBsaXN0ZW5lciB0byBhdm9pZCB0cnlpbmcgdG8gaGFuZGxlXG4gICAgLy8gYSBzZXJ2ZXIgY2xvc2UgZXZlbnQgd2hlbiBpdCBpcyBhY3R1YWxseSBjYXVzZWQgYnkgdXMgZGlzY29ubmVjdGluZ1xuICAgIGlmKHRoaXMuc2VydmVyQ2xvc2VSZWYpe1xuICAgICAgdGhpcy5zb2NrZXQub2ZmKHRoaXMuc2VydmVyQ2xvc2VSZWYpXG4gICAgICB0aGlzLnNlcnZlckNsb3NlUmVmID0gbnVsbFxuICAgIH1cbiAgICB0aGlzLnNvY2tldC5kaXNjb25uZWN0KGNhbGxiYWNrKVxuICB9XG5cbiAgcmVwbGFjZVRyYW5zcG9ydCh0cmFuc3BvcnQpe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlbG9hZFdpdGhKaXR0ZXJUaW1lcilcbiAgICB0aGlzLnNvY2tldC5yZXBsYWNlVHJhbnNwb3J0KHRyYW5zcG9ydClcbiAgICB0aGlzLmNvbm5lY3QoKVxuICB9XG5cbiAgZXhlY0pTKGVsLCBlbmNvZGVkSlMsIGV2ZW50VHlwZSA9IG51bGwpe1xuICAgIGxldCBlID0gbmV3IEN1c3RvbUV2ZW50KFwicGh4OmV4ZWNcIiwge2RldGFpbDoge3NvdXJjZUVsZW1lbnQ6IGVsfX0pXG4gICAgdGhpcy5vd25lcihlbCwgdmlldyA9PiBKUy5leGVjKGUsIGV2ZW50VHlwZSwgZW5jb2RlZEpTLCB2aWV3LCBlbCkpXG4gIH1cblxuICAvLyBwcml2YXRlXG5cbiAgZXhlY0pTSG9va1B1c2goZWwsIHBoeEV2ZW50LCBkYXRhLCBjYWxsYmFjayl7XG4gICAgdGhpcy53aXRoaW5Pd25lcnMoZWwsIHZpZXcgPT4ge1xuICAgICAgbGV0IGUgPSBuZXcgQ3VzdG9tRXZlbnQoXCJwaHg6ZXhlY1wiLCB7ZGV0YWlsOiB7c291cmNlRWxlbWVudDogZWx9fSlcbiAgICAgIEpTLmV4ZWMoZSwgXCJob29rXCIsIHBoeEV2ZW50LCB2aWV3LCBlbCwgW1wicHVzaFwiLCB7ZGF0YSwgY2FsbGJhY2t9XSlcbiAgICB9KVxuICB9XG5cbiAgdW5sb2FkKCl7XG4gICAgaWYodGhpcy51bmxvYWRlZCl7IHJldHVybiB9XG4gICAgaWYodGhpcy5tYWluICYmIHRoaXMuaXNDb25uZWN0ZWQoKSl7IHRoaXMubG9nKHRoaXMubWFpbiwgXCJzb2NrZXRcIiwgKCkgPT4gW1wiZGlzY29ubmVjdCBmb3IgcGFnZSBuYXZcIl0pIH1cbiAgICB0aGlzLnVubG9hZGVkID0gdHJ1ZVxuICAgIHRoaXMuZGVzdHJveUFsbFZpZXdzKClcbiAgICB0aGlzLmRpc2Nvbm5lY3QoKVxuICB9XG5cbiAgdHJpZ2dlckRPTShraW5kLCBhcmdzKXsgdGhpcy5kb21DYWxsYmFja3Nba2luZF0oLi4uYXJncykgfVxuXG4gIHRpbWUobmFtZSwgZnVuYyl7XG4gICAgaWYoIXRoaXMuaXNQcm9maWxlRW5hYmxlZCgpIHx8ICFjb25zb2xlLnRpbWUpeyByZXR1cm4gZnVuYygpIH1cbiAgICBjb25zb2xlLnRpbWUobmFtZSlcbiAgICBsZXQgcmVzdWx0ID0gZnVuYygpXG4gICAgY29uc29sZS50aW1lRW5kKG5hbWUpXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgbG9nKHZpZXcsIGtpbmQsIG1zZ0NhbGxiYWNrKXtcbiAgICBpZih0aGlzLnZpZXdMb2dnZXIpe1xuICAgICAgbGV0IFttc2csIG9ial0gPSBtc2dDYWxsYmFjaygpXG4gICAgICB0aGlzLnZpZXdMb2dnZXIodmlldywga2luZCwgbXNnLCBvYmopXG4gICAgfSBlbHNlIGlmKHRoaXMuaXNEZWJ1Z0VuYWJsZWQoKSl7XG4gICAgICBsZXQgW21zZywgb2JqXSA9IG1zZ0NhbGxiYWNrKClcbiAgICAgIGRlYnVnKHZpZXcsIGtpbmQsIG1zZywgb2JqKVxuICAgIH1cbiAgfVxuXG4gIHJlcXVlc3RET01VcGRhdGUoY2FsbGJhY2spe1xuICAgIHRoaXMudHJhbnNpdGlvbnMuYWZ0ZXIoY2FsbGJhY2spXG4gIH1cblxuICB0cmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRG9uZSA9IGZ1bmN0aW9uKCl7fSl7XG4gICAgdGhpcy50cmFuc2l0aW9ucy5hZGRUcmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRG9uZSlcbiAgfVxuXG4gIG9uQ2hhbm5lbChjaGFubmVsLCBldmVudCwgY2Ipe1xuICAgIGNoYW5uZWwub24oZXZlbnQsIGRhdGEgPT4ge1xuICAgICAgbGV0IGxhdGVuY3kgPSB0aGlzLmdldExhdGVuY3lTaW0oKVxuICAgICAgaWYoIWxhdGVuY3kpe1xuICAgICAgICBjYihkYXRhKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiBjYihkYXRhKSwgbGF0ZW5jeSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgcmVsb2FkV2l0aEppdHRlcih2aWV3LCBsb2cpe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlbG9hZFdpdGhKaXR0ZXJUaW1lcilcbiAgICB0aGlzLmRpc2Nvbm5lY3QoKVxuICAgIGxldCBtaW5NcyA9IHRoaXMucmVsb2FkSml0dGVyTWluXG4gICAgbGV0IG1heE1zID0gdGhpcy5yZWxvYWRKaXR0ZXJNYXhcbiAgICBsZXQgYWZ0ZXJNcyA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChtYXhNcyAtIG1pbk1zICsgMSkpICsgbWluTXNcbiAgICBsZXQgdHJpZXMgPSBCcm93c2VyLnVwZGF0ZUxvY2FsKHRoaXMubG9jYWxTdG9yYWdlLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUsIENPTlNFQ1VUSVZFX1JFTE9BRFMsIDAsIGNvdW50ID0+IGNvdW50ICsgMSlcbiAgICBpZih0cmllcyA+PSB0aGlzLm1heFJlbG9hZHMpe1xuICAgICAgYWZ0ZXJNcyA9IHRoaXMuZmFpbHNhZmVKaXR0ZXJcbiAgICB9XG4gICAgdGhpcy5yZWxvYWRXaXRoSml0dGVyVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIC8vIGlmIHZpZXcgaGFzIHJlY292ZXJlZCwgc3VjaCBhcyB0cmFuc3BvcnQgcmVwbGFjZWQsIHRoZW4gY2FuY2VsXG4gICAgICBpZih2aWV3LmlzRGVzdHJveWVkKCkgfHwgdmlldy5pc0Nvbm5lY3RlZCgpKXsgcmV0dXJuIH1cbiAgICAgIHZpZXcuZGVzdHJveSgpXG4gICAgICBsb2cgPyBsb2coKSA6IHRoaXMubG9nKHZpZXcsIFwiam9pblwiLCAoKSA9PiBbYGVuY291bnRlcmVkICR7dHJpZXN9IGNvbnNlY3V0aXZlIHJlbG9hZHNgXSlcbiAgICAgIGlmKHRyaWVzID49IHRoaXMubWF4UmVsb2Fkcyl7XG4gICAgICAgIHRoaXMubG9nKHZpZXcsIFwiam9pblwiLCAoKSA9PiBbYGV4Y2VlZGVkICR7dGhpcy5tYXhSZWxvYWRzfSBjb25zZWN1dGl2ZSByZWxvYWRzLiBFbnRlcmluZyBmYWlsc2FmZSBtb2RlYF0pXG4gICAgICB9XG4gICAgICBpZih0aGlzLmhhc1BlbmRpbmdMaW5rKCkpe1xuICAgICAgICB3aW5kb3cubG9jYXRpb24gPSB0aGlzLnBlbmRpbmdMaW5rXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKClcbiAgICAgIH1cbiAgICB9LCBhZnRlck1zKVxuICB9XG5cbiAgZ2V0SG9va0NhbGxiYWNrcyhuYW1lKXtcbiAgICByZXR1cm4gbmFtZSAmJiBuYW1lLnN0YXJ0c1dpdGgoXCJQaG9lbml4LlwiKSA/IEhvb2tzW25hbWUuc3BsaXQoXCIuXCIpWzFdXSA6IHRoaXMuaG9va3NbbmFtZV1cbiAgfVxuXG4gIGlzVW5sb2FkZWQoKXsgcmV0dXJuIHRoaXMudW5sb2FkZWQgfVxuXG4gIGlzQ29ubmVjdGVkKCl7IHJldHVybiB0aGlzLnNvY2tldC5pc0Nvbm5lY3RlZCgpIH1cblxuICBnZXRCaW5kaW5nUHJlZml4KCl7IHJldHVybiB0aGlzLmJpbmRpbmdQcmVmaXggfVxuXG4gIGJpbmRpbmcoa2luZCl7IHJldHVybiBgJHt0aGlzLmdldEJpbmRpbmdQcmVmaXgoKX0ke2tpbmR9YCB9XG5cbiAgY2hhbm5lbCh0b3BpYywgcGFyYW1zKXsgcmV0dXJuIHRoaXMuc29ja2V0LmNoYW5uZWwodG9waWMsIHBhcmFtcykgfVxuXG4gIGpvaW5EZWFkVmlldygpe1xuICAgIGxldCBib2R5ID0gZG9jdW1lbnQuYm9keVxuICAgIGlmKGJvZHkgJiYgIXRoaXMuaXNQaHhWaWV3KGJvZHkpICYmICF0aGlzLmlzUGh4Vmlldyhkb2N1bWVudC5maXJzdEVsZW1lbnRDaGlsZCkpe1xuICAgICAgbGV0IHZpZXcgPSB0aGlzLm5ld1Jvb3RWaWV3KGJvZHkpXG4gICAgICB2aWV3LnNldEhyZWYodGhpcy5nZXRIcmVmKCkpXG4gICAgICB2aWV3LmpvaW5EZWFkKClcbiAgICAgIGlmKCF0aGlzLm1haW4peyB0aGlzLm1haW4gPSB2aWV3IH1cbiAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICB2aWV3LmV4ZWNOZXdNb3VudGVkKClcbiAgICAgICAgLy8gcmVzdG9yZSBzY3JvbGwgcG9zaXRpb24gd2hlbiBuYXZpZ2F0aW5nIGZyb20gYW4gZXh0ZXJuYWwgLyBub24tbGl2ZSBwYWdlXG4gICAgICAgIHRoaXMubWF5YmVTY3JvbGwoaGlzdG9yeS5zdGF0ZT8uc2Nyb2xsKVxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBqb2luUm9vdFZpZXdzKCl7XG4gICAgbGV0IHJvb3RzRm91bmQgPSBmYWxzZVxuICAgIERPTS5hbGwoZG9jdW1lbnQsIGAke1BIWF9WSUVXX1NFTEVDVE9SfTpub3QoWyR7UEhYX1BBUkVOVF9JRH1dKWAsIHJvb3RFbCA9PiB7XG4gICAgICBpZighdGhpcy5nZXRSb290QnlJZChyb290RWwuaWQpKXtcbiAgICAgICAgbGV0IHZpZXcgPSB0aGlzLm5ld1Jvb3RWaWV3KHJvb3RFbClcbiAgICAgICAgLy8gc3RpY2tpZXMgY2Fubm90IGJlIG1vdW50ZWQgYXQgdGhlIHJvdXRlciBhbmQgdGhlcmVmb3JlIHNob3VsZCBub3RcbiAgICAgICAgLy8gZ2V0IGEgaHJlZiBzZXQgb24gdGhlbVxuICAgICAgICBpZighRE9NLmlzUGh4U3RpY2t5KHJvb3RFbCkpeyB2aWV3LnNldEhyZWYodGhpcy5nZXRIcmVmKCkpIH1cbiAgICAgICAgdmlldy5qb2luKClcbiAgICAgICAgaWYocm9vdEVsLmhhc0F0dHJpYnV0ZShQSFhfTUFJTikpeyB0aGlzLm1haW4gPSB2aWV3IH1cbiAgICAgIH1cbiAgICAgIHJvb3RzRm91bmQgPSB0cnVlXG4gICAgfSlcbiAgICByZXR1cm4gcm9vdHNGb3VuZFxuICB9XG5cbiAgcmVkaXJlY3QodG8sIGZsYXNoLCByZWxvYWRUb2tlbil7XG4gICAgaWYocmVsb2FkVG9rZW4peyBCcm93c2VyLnNldENvb2tpZShQSFhfUkVMT0FEX1NUQVRVUywgcmVsb2FkVG9rZW4sIDYwKSB9XG4gICAgdGhpcy51bmxvYWQoKVxuICAgIEJyb3dzZXIucmVkaXJlY3QodG8sIGZsYXNoKVxuICB9XG5cbiAgcmVwbGFjZU1haW4oaHJlZiwgZmxhc2gsIGNhbGxiYWNrID0gbnVsbCwgbGlua1JlZiA9IHRoaXMuc2V0UGVuZGluZ0xpbmsoaHJlZikpe1xuICAgIGNvbnN0IGxpdmVSZWZlcmVyID0gdGhpcy5jdXJyZW50TG9jYXRpb24uaHJlZlxuICAgIHRoaXMub3V0Z29pbmdNYWluRWwgPSB0aGlzLm91dGdvaW5nTWFpbkVsIHx8IHRoaXMubWFpbi5lbFxuXG4gICAgY29uc3Qgc3RpY2tpZXMgPSBET00uZmluZFBoeFN0aWNreShkb2N1bWVudCkgfHwgW11cbiAgICBjb25zdCByZW1vdmVFbHMgPSBET00uYWxsKHRoaXMub3V0Z29pbmdNYWluRWwsIGBbJHt0aGlzLmJpbmRpbmcoXCJyZW1vdmVcIil9XWApXG4gICAgICAuZmlsdGVyKGVsID0+ICFET00uaXNDaGlsZE9mQW55KGVsLCBzdGlja2llcykpXG5cbiAgICBjb25zdCBuZXdNYWluRWwgPSBET00uY2xvbmVOb2RlKHRoaXMub3V0Z29pbmdNYWluRWwsIFwiXCIpXG4gICAgdGhpcy5tYWluLnNob3dMb2FkZXIodGhpcy5sb2FkZXJUaW1lb3V0KVxuICAgIHRoaXMubWFpbi5kZXN0cm95KClcblxuICAgIHRoaXMubWFpbiA9IHRoaXMubmV3Um9vdFZpZXcobmV3TWFpbkVsLCBmbGFzaCwgbGl2ZVJlZmVyZXIpXG4gICAgdGhpcy5tYWluLnNldFJlZGlyZWN0KGhyZWYpXG4gICAgdGhpcy50cmFuc2l0aW9uUmVtb3ZlcyhyZW1vdmVFbHMpXG4gICAgdGhpcy5tYWluLmpvaW4oKGpvaW5Db3VudCwgb25Eb25lKSA9PiB7XG4gICAgICBpZihqb2luQ291bnQgPT09IDEgJiYgdGhpcy5jb21taXRQZW5kaW5nTGluayhsaW5rUmVmKSl7XG4gICAgICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgLy8gcmVtb3ZlIHBoeC1yZW1vdmUgZWxzIHJpZ2h0IGJlZm9yZSB3ZSByZXBsYWNlIHRoZSBtYWluIGVsZW1lbnRcbiAgICAgICAgICByZW1vdmVFbHMuZm9yRWFjaChlbCA9PiBlbC5yZW1vdmUoKSlcbiAgICAgICAgICBzdGlja2llcy5mb3JFYWNoKGVsID0+IG5ld01haW5FbC5hcHBlbmRDaGlsZChlbCkpXG4gICAgICAgICAgdGhpcy5vdXRnb2luZ01haW5FbC5yZXBsYWNlV2l0aChuZXdNYWluRWwpXG4gICAgICAgICAgdGhpcy5vdXRnb2luZ01haW5FbCA9IG51bGxcbiAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhsaW5rUmVmKVxuICAgICAgICAgIG9uRG9uZSgpXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIHRyYW5zaXRpb25SZW1vdmVzKGVsZW1lbnRzLCBjYWxsYmFjayl7XG4gICAgbGV0IHJlbW92ZUF0dHIgPSB0aGlzLmJpbmRpbmcoXCJyZW1vdmVcIilcbiAgICBsZXQgc2lsZW5jZUV2ZW50cyA9IChlKSA9PiB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KClcbiAgICAgIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKClcbiAgICB9XG4gICAgZWxlbWVudHMuZm9yRWFjaChlbCA9PiB7XG4gICAgICAvLyBwcmV2ZW50IGFsbCBsaXN0ZW5lcnMgd2UgY2FyZSBhYm91dCBmcm9tIGJ1YmJsaW5nIHRvIHdpbmRvd1xuICAgICAgLy8gc2luY2Ugd2UgYXJlIHJlbW92aW5nIHRoZSBlbGVtZW50XG4gICAgICBmb3IobGV0IGV2ZW50IG9mIHRoaXMuYm91bmRFdmVudE5hbWVzKXtcbiAgICAgICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgc2lsZW5jZUV2ZW50cywgdHJ1ZSlcbiAgICAgIH1cbiAgICAgIHRoaXMuZXhlY0pTKGVsLCBlbC5nZXRBdHRyaWJ1dGUocmVtb3ZlQXR0ciksIFwicmVtb3ZlXCIpXG4gICAgfSlcbiAgICAvLyByZW1vdmUgdGhlIHNpbGVuY2VkIGxpc3RlbmVycyB3aGVuIHRyYW5zaXRpb25zIGFyZSBkb25lIGluY2FzZSB0aGUgZWxlbWVudCBpcyByZS11c2VkXG4gICAgLy8gYW5kIGNhbGwgY2FsbGVyJ3MgY2FsbGJhY2sgYXMgc29vbiBhcyB3ZSBhcmUgZG9uZSB3aXRoIHRyYW5zaXRpb25zXG4gICAgdGhpcy5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHtcbiAgICAgIGVsZW1lbnRzLmZvckVhY2goZWwgPT4ge1xuICAgICAgICBmb3IobGV0IGV2ZW50IG9mIHRoaXMuYm91bmRFdmVudE5hbWVzKXtcbiAgICAgICAgICBlbC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCBzaWxlbmNlRXZlbnRzLCB0cnVlKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soKVxuICAgIH0pXG4gIH1cblxuICBpc1BoeFZpZXcoZWwpeyByZXR1cm4gZWwuZ2V0QXR0cmlidXRlICYmIGVsLmdldEF0dHJpYnV0ZShQSFhfU0VTU0lPTikgIT09IG51bGwgfVxuXG4gIG5ld1Jvb3RWaWV3KGVsLCBmbGFzaCwgbGl2ZVJlZmVyZXIpe1xuICAgIGxldCB2aWV3ID0gbmV3IFZpZXcoZWwsIHRoaXMsIG51bGwsIGZsYXNoLCBsaXZlUmVmZXJlcilcbiAgICB0aGlzLnJvb3RzW3ZpZXcuaWRdID0gdmlld1xuICAgIHJldHVybiB2aWV3XG4gIH1cblxuICBvd25lcihjaGlsZEVsLCBjYWxsYmFjayl7XG4gICAgbGV0IHZpZXdcbiAgICBjb25zdCBjbG9zZXN0Vmlld0VsID0gY2hpbGRFbC5jbG9zZXN0KFBIWF9WSUVXX1NFTEVDVE9SKVxuICAgIGlmKGNsb3Nlc3RWaWV3RWwpe1xuICAgICAgLy8gaXQgY2FuIGhhcHBlbiB0aGF0IHdlIGZpbmQgYSB2aWV3IHRoYXQgaXMgYWxyZWFkeSBkZXN0cm95ZWQ7XG4gICAgICAvLyBpbiB0aGF0IGNhc2Ugd2UgRE8gTk9UIHdhbnQgdG8gZmFsbGJhY2sgdG8gdGhlIG1haW4gZWxlbWVudFxuICAgICAgdmlldyA9IHRoaXMuZ2V0Vmlld0J5RWwoY2xvc2VzdFZpZXdFbClcbiAgICB9IGVsc2Uge1xuICAgICAgdmlldyA9IHRoaXMubWFpblxuICAgIH1cbiAgICByZXR1cm4gdmlldyAmJiBjYWxsYmFjayA/IGNhbGxiYWNrKHZpZXcpIDogdmlld1xuICB9XG5cbiAgd2l0aGluT3duZXJzKGNoaWxkRWwsIGNhbGxiYWNrKXtcbiAgICB0aGlzLm93bmVyKGNoaWxkRWwsIHZpZXcgPT4gY2FsbGJhY2sodmlldywgY2hpbGRFbCkpXG4gIH1cblxuICBnZXRWaWV3QnlFbChlbCl7XG4gICAgbGV0IHJvb3RJZCA9IGVsLmdldEF0dHJpYnV0ZShQSFhfUk9PVF9JRClcbiAgICByZXR1cm4gbWF5YmUodGhpcy5nZXRSb290QnlJZChyb290SWQpLCByb290ID0+IHJvb3QuZ2V0RGVzY2VuZGVudEJ5RWwoZWwpKVxuICB9XG5cbiAgZ2V0Um9vdEJ5SWQoaWQpeyByZXR1cm4gdGhpcy5yb290c1tpZF0gfVxuXG4gIGRlc3Ryb3lBbGxWaWV3cygpe1xuICAgIGZvcihsZXQgaWQgaW4gdGhpcy5yb290cyl7XG4gICAgICB0aGlzLnJvb3RzW2lkXS5kZXN0cm95KClcbiAgICAgIGRlbGV0ZSB0aGlzLnJvb3RzW2lkXVxuICAgIH1cbiAgICB0aGlzLm1haW4gPSBudWxsXG4gIH1cblxuICBkZXN0cm95Vmlld0J5RWwoZWwpe1xuICAgIGxldCByb290ID0gdGhpcy5nZXRSb290QnlJZChlbC5nZXRBdHRyaWJ1dGUoUEhYX1JPT1RfSUQpKVxuICAgIGlmKHJvb3QgJiYgcm9vdC5pZCA9PT0gZWwuaWQpe1xuICAgICAgcm9vdC5kZXN0cm95KClcbiAgICAgIGRlbGV0ZSB0aGlzLnJvb3RzW3Jvb3QuaWRdXG4gICAgfSBlbHNlIGlmKHJvb3Qpe1xuICAgICAgcm9vdC5kZXN0cm95RGVzY2VuZGVudChlbC5pZClcbiAgICB9XG4gIH1cblxuICBnZXRBY3RpdmVFbGVtZW50KCl7XG4gICAgcmV0dXJuIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnRcbiAgfVxuXG4gIGRyb3BBY3RpdmVFbGVtZW50KHZpZXcpe1xuICAgIGlmKHRoaXMucHJldkFjdGl2ZSAmJiB2aWV3Lm93bnNFbGVtZW50KHRoaXMucHJldkFjdGl2ZSkpe1xuICAgICAgdGhpcy5wcmV2QWN0aXZlID0gbnVsbFxuICAgIH1cbiAgfVxuXG4gIHJlc3RvcmVQcmV2aW91c2x5QWN0aXZlRm9jdXMoKXtcbiAgICBpZih0aGlzLnByZXZBY3RpdmUgJiYgdGhpcy5wcmV2QWN0aXZlICE9PSBkb2N1bWVudC5ib2R5KXtcbiAgICAgIHRoaXMucHJldkFjdGl2ZS5mb2N1cygpXG4gICAgfVxuICB9XG5cbiAgYmx1ckFjdGl2ZUVsZW1lbnQoKXtcbiAgICB0aGlzLnByZXZBY3RpdmUgPSB0aGlzLmdldEFjdGl2ZUVsZW1lbnQoKVxuICAgIGlmKHRoaXMucHJldkFjdGl2ZSAhPT0gZG9jdW1lbnQuYm9keSl7IHRoaXMucHJldkFjdGl2ZS5ibHVyKCkgfVxuICB9XG5cbiAgYmluZFRvcExldmVsRXZlbnRzKHtkZWFkfSA9IHt9KXtcbiAgICBpZih0aGlzLmJvdW5kVG9wTGV2ZWxFdmVudHMpeyByZXR1cm4gfVxuXG4gICAgdGhpcy5ib3VuZFRvcExldmVsRXZlbnRzID0gdHJ1ZVxuICAgIC8vIGVudGVyIGZhaWxzYWZlIHJlbG9hZCBpZiBzZXJ2ZXIgaGFzIGdvbmUgYXdheSBpbnRlbnRpb25hbGx5LCBzdWNoIGFzIFwiZGlzY29ubmVjdFwiIGJyb2FkY2FzdFxuICAgIHRoaXMuc2VydmVyQ2xvc2VSZWYgPSB0aGlzLnNvY2tldC5vbkNsb3NlKGV2ZW50ID0+IHtcbiAgICAgIC8vIGZhaWxzYWZlIHJlbG9hZCBpZiBub3JtYWwgY2xvc3VyZSBhbmQgd2Ugc3RpbGwgaGF2ZSBhIG1haW4gTFZcbiAgICAgIGlmKGV2ZW50ICYmIGV2ZW50LmNvZGUgPT09IDEwMDAgJiYgdGhpcy5tYWluKXsgcmV0dXJuIHRoaXMucmVsb2FkV2l0aEppdHRlcih0aGlzLm1haW4pIH1cbiAgICB9KVxuICAgIGRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGZ1bmN0aW9uICgpeyB9KSAvLyBlbnN1cmUgYWxsIGNsaWNrIGV2ZW50cyBidWJibGUgZm9yIG1vYmlsZSBTYWZhcmlcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBhZ2VzaG93XCIsIGUgPT4ge1xuICAgICAgaWYoZS5wZXJzaXN0ZWQpeyAvLyByZWxvYWQgcGFnZSBpZiBiZWluZyByZXN0b3JlZCBmcm9tIGJhY2svZm9yd2FyZCBjYWNoZVxuICAgICAgICB0aGlzLmdldFNvY2tldCgpLmRpc2Nvbm5lY3QoKVxuICAgICAgICB0aGlzLndpdGhQYWdlTG9hZGluZyh7dG86IHdpbmRvdy5sb2NhdGlvbi5ocmVmLCBraW5kOiBcInJlZGlyZWN0XCJ9KVxuICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKClcbiAgICAgIH1cbiAgICB9LCB0cnVlKVxuICAgIGlmKCFkZWFkKXsgdGhpcy5iaW5kTmF2KCkgfVxuICAgIHRoaXMuYmluZENsaWNrcygpXG4gICAgaWYoIWRlYWQpeyB0aGlzLmJpbmRGb3JtcygpIH1cbiAgICB0aGlzLmJpbmQoe2tleXVwOiBcImtleXVwXCIsIGtleWRvd246IFwia2V5ZG93blwifSwgKGUsIHR5cGUsIHZpZXcsIHRhcmdldEVsLCBwaHhFdmVudCwgX3BoeFRhcmdldCkgPT4ge1xuICAgICAgbGV0IG1hdGNoS2V5ID0gdGFyZ2V0RWwuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfS0VZKSlcbiAgICAgIGxldCBwcmVzc2VkS2V5ID0gZS5rZXkgJiYgZS5rZXkudG9Mb3dlckNhc2UoKSAvLyBjaHJvbWUgY2xpY2tlZCBhdXRvY29tcGxldGVzIHNlbmQgYSBrZXlkb3duIHdpdGhvdXQga2V5XG4gICAgICBpZihtYXRjaEtleSAmJiBtYXRjaEtleS50b0xvd2VyQ2FzZSgpICE9PSBwcmVzc2VkS2V5KXsgcmV0dXJuIH1cblxuICAgICAgbGV0IGRhdGEgPSB7a2V5OiBlLmtleSwgLi4udGhpcy5ldmVudE1ldGEodHlwZSwgZSwgdGFyZ2V0RWwpfVxuICAgICAgSlMuZXhlYyhlLCB0eXBlLCBwaHhFdmVudCwgdmlldywgdGFyZ2V0RWwsIFtcInB1c2hcIiwge2RhdGF9XSlcbiAgICB9KVxuICAgIHRoaXMuYmluZCh7Ymx1cjogXCJmb2N1c291dFwiLCBmb2N1czogXCJmb2N1c2luXCJ9LCAoZSwgdHlwZSwgdmlldywgdGFyZ2V0RWwsIHBoeEV2ZW50LCBwaHhUYXJnZXQpID0+IHtcbiAgICAgIGlmKCFwaHhUYXJnZXQpe1xuICAgICAgICBsZXQgZGF0YSA9IHtrZXk6IGUua2V5LCAuLi50aGlzLmV2ZW50TWV0YSh0eXBlLCBlLCB0YXJnZXRFbCl9XG4gICAgICAgIEpTLmV4ZWMoZSwgdHlwZSwgcGh4RXZlbnQsIHZpZXcsIHRhcmdldEVsLCBbXCJwdXNoXCIsIHtkYXRhfV0pXG4gICAgICB9XG4gICAgfSlcbiAgICB0aGlzLmJpbmQoe2JsdXI6IFwiYmx1clwiLCBmb2N1czogXCJmb2N1c1wifSwgKGUsIHR5cGUsIHZpZXcsIHRhcmdldEVsLCBwaHhFdmVudCwgcGh4VGFyZ2V0KSA9PiB7XG4gICAgICAvLyBibHVyIGFuZCBmb2N1cyBhcmUgdHJpZ2dlcmVkIG9uIGRvY3VtZW50IGFuZCB3aW5kb3cuIERpc2NhcmQgb25lIHRvIGF2b2lkIGR1cHNcbiAgICAgIGlmKHBoeFRhcmdldCA9PT0gXCJ3aW5kb3dcIil7XG4gICAgICAgIGxldCBkYXRhID0gdGhpcy5ldmVudE1ldGEodHlwZSwgZSwgdGFyZ2V0RWwpXG4gICAgICAgIEpTLmV4ZWMoZSwgdHlwZSwgcGh4RXZlbnQsIHZpZXcsIHRhcmdldEVsLCBbXCJwdXNoXCIsIHtkYXRhfV0pXG4gICAgICB9XG4gICAgfSlcbiAgICB0aGlzLm9uKFwiZHJhZ292ZXJcIiwgZSA9PiBlLnByZXZlbnREZWZhdWx0KCkpXG4gICAgdGhpcy5vbihcImRyb3BcIiwgZSA9PiB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KClcbiAgICAgIGxldCBkcm9wVGFyZ2V0SWQgPSBtYXliZShjbG9zZXN0UGh4QmluZGluZyhlLnRhcmdldCwgdGhpcy5iaW5kaW5nKFBIWF9EUk9QX1RBUkdFVCkpLCB0cnVlVGFyZ2V0ID0+IHtcbiAgICAgICAgcmV0dXJuIHRydWVUYXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfRFJPUF9UQVJHRVQpKVxuICAgICAgfSlcbiAgICAgIGxldCBkcm9wVGFyZ2V0ID0gZHJvcFRhcmdldElkICYmIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRyb3BUYXJnZXRJZClcbiAgICAgIGxldCBmaWxlcyA9IEFycmF5LmZyb20oZS5kYXRhVHJhbnNmZXIuZmlsZXMgfHwgW10pXG4gICAgICBpZighZHJvcFRhcmdldCB8fCBkcm9wVGFyZ2V0LmRpc2FibGVkIHx8IGZpbGVzLmxlbmd0aCA9PT0gMCB8fCAhKGRyb3BUYXJnZXQuZmlsZXMgaW5zdGFuY2VvZiBGaWxlTGlzdCkpeyByZXR1cm4gfVxuXG4gICAgICBMaXZlVXBsb2FkZXIudHJhY2tGaWxlcyhkcm9wVGFyZ2V0LCBmaWxlcywgZS5kYXRhVHJhbnNmZXIpXG4gICAgICBkcm9wVGFyZ2V0LmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwiaW5wdXRcIiwge2J1YmJsZXM6IHRydWV9KSlcbiAgICB9KVxuICAgIHRoaXMub24oUEhYX1RSQUNLX1VQTE9BRFMsIGUgPT4ge1xuICAgICAgbGV0IHVwbG9hZFRhcmdldCA9IGUudGFyZ2V0XG4gICAgICBpZighRE9NLmlzVXBsb2FkSW5wdXQodXBsb2FkVGFyZ2V0KSl7IHJldHVybiB9XG4gICAgICBsZXQgZmlsZXMgPSBBcnJheS5mcm9tKGUuZGV0YWlsLmZpbGVzIHx8IFtdKS5maWx0ZXIoZiA9PiBmIGluc3RhbmNlb2YgRmlsZSB8fCBmIGluc3RhbmNlb2YgQmxvYilcbiAgICAgIExpdmVVcGxvYWRlci50cmFja0ZpbGVzKHVwbG9hZFRhcmdldCwgZmlsZXMpXG4gICAgICB1cGxvYWRUYXJnZXQuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJpbnB1dFwiLCB7YnViYmxlczogdHJ1ZX0pKVxuICAgIH0pXG4gIH1cblxuICBldmVudE1ldGEoZXZlbnROYW1lLCBlLCB0YXJnZXRFbCl7XG4gICAgbGV0IGNhbGxiYWNrID0gdGhpcy5tZXRhZGF0YUNhbGxiYWNrc1tldmVudE5hbWVdXG4gICAgcmV0dXJuIGNhbGxiYWNrID8gY2FsbGJhY2soZSwgdGFyZ2V0RWwpIDoge31cbiAgfVxuXG4gIHNldFBlbmRpbmdMaW5rKGhyZWYpe1xuICAgIHRoaXMubGlua1JlZisrXG4gICAgdGhpcy5wZW5kaW5nTGluayA9IGhyZWZcbiAgICB0aGlzLnJlc2V0UmVsb2FkU3RhdHVzKClcbiAgICByZXR1cm4gdGhpcy5saW5rUmVmXG4gIH1cblxuICAvLyBhbnl0aW1lIHdlIGFyZSBuYXZpZ2F0aW5nIG9yIGNvbm5lY3RpbmcsIGRyb3AgcmVsb2FkIGNvb2tpZSBpbiBjYXNlXG4gIC8vIHdlIGlzc3VlIHRoZSBjb29raWUgYnV0IHRoZSBuZXh0IHJlcXVlc3Qgd2FzIGludGVycnVwdGVkIGFuZCB0aGUgc2VydmVyIG5ldmVyIGRyb3BwZWQgaXRcbiAgcmVzZXRSZWxvYWRTdGF0dXMoKXsgQnJvd3Nlci5kZWxldGVDb29raWUoUEhYX1JFTE9BRF9TVEFUVVMpIH1cblxuICBjb21taXRQZW5kaW5nTGluayhsaW5rUmVmKXtcbiAgICBpZih0aGlzLmxpbmtSZWYgIT09IGxpbmtSZWYpe1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaHJlZiA9IHRoaXMucGVuZGluZ0xpbmtcbiAgICAgIHRoaXMucGVuZGluZ0xpbmsgPSBudWxsXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIGdldEhyZWYoKXsgcmV0dXJuIHRoaXMuaHJlZiB9XG5cbiAgaGFzUGVuZGluZ0xpbmsoKXsgcmV0dXJuICEhdGhpcy5wZW5kaW5nTGluayB9XG5cbiAgYmluZChldmVudHMsIGNhbGxiYWNrKXtcbiAgICBmb3IobGV0IGV2ZW50IGluIGV2ZW50cyl7XG4gICAgICBsZXQgYnJvd3NlckV2ZW50TmFtZSA9IGV2ZW50c1tldmVudF1cblxuICAgICAgdGhpcy5vbihicm93c2VyRXZlbnROYW1lLCBlID0+IHtcbiAgICAgICAgbGV0IGJpbmRpbmcgPSB0aGlzLmJpbmRpbmcoZXZlbnQpXG4gICAgICAgIGxldCB3aW5kb3dCaW5kaW5nID0gdGhpcy5iaW5kaW5nKGB3aW5kb3ctJHtldmVudH1gKVxuICAgICAgICBsZXQgdGFyZ2V0UGh4RXZlbnQgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUgJiYgZS50YXJnZXQuZ2V0QXR0cmlidXRlKGJpbmRpbmcpXG4gICAgICAgIGlmKHRhcmdldFBoeEV2ZW50KXtcbiAgICAgICAgICB0aGlzLmRlYm91bmNlKGUudGFyZ2V0LCBlLCBicm93c2VyRXZlbnROYW1lLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLndpdGhpbk93bmVycyhlLnRhcmdldCwgdmlldyA9PiB7XG4gICAgICAgICAgICAgIGNhbGxiYWNrKGUsIGV2ZW50LCB2aWV3LCBlLnRhcmdldCwgdGFyZ2V0UGh4RXZlbnQsIG51bGwpXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH0pXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgRE9NLmFsbChkb2N1bWVudCwgYFske3dpbmRvd0JpbmRpbmd9XWAsIGVsID0+IHtcbiAgICAgICAgICAgIGxldCBwaHhFdmVudCA9IGVsLmdldEF0dHJpYnV0ZSh3aW5kb3dCaW5kaW5nKVxuICAgICAgICAgICAgdGhpcy5kZWJvdW5jZShlbCwgZSwgYnJvd3NlckV2ZW50TmFtZSwgKCkgPT4ge1xuICAgICAgICAgICAgICB0aGlzLndpdGhpbk93bmVycyhlbCwgdmlldyA9PiB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZSwgZXZlbnQsIHZpZXcsIGVsLCBwaHhFdmVudCwgXCJ3aW5kb3dcIilcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBiaW5kQ2xpY2tzKCl7XG4gICAgdGhpcy5vbihcIm1vdXNlZG93blwiLCBlID0+IHRoaXMuY2xpY2tTdGFydGVkQXRUYXJnZXQgPSBlLnRhcmdldClcbiAgICB0aGlzLmJpbmRDbGljayhcImNsaWNrXCIsIFwiY2xpY2tcIilcbiAgfVxuXG4gIGJpbmRDbGljayhldmVudE5hbWUsIGJpbmRpbmdOYW1lKXtcbiAgICBsZXQgY2xpY2sgPSB0aGlzLmJpbmRpbmcoYmluZGluZ05hbWUpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBlID0+IHtcbiAgICAgIGxldCB0YXJnZXQgPSBudWxsXG4gICAgICAvLyBhIHN5bnRoZXRpYyBjbGljayBldmVudCAoZGV0YWlsIDApIHdpbGwgbm90IGhhdmUgY2F1c2VkIGEgbW91c2Vkb3duIGV2ZW50LFxuICAgICAgLy8gdGhlcmVmb3JlIHRoZSBjbGlja1N0YXJ0ZWRBdFRhcmdldCBpcyBzdGFsZVxuICAgICAgaWYoZS5kZXRhaWwgPT09IDApIHRoaXMuY2xpY2tTdGFydGVkQXRUYXJnZXQgPSBlLnRhcmdldFxuICAgICAgbGV0IGNsaWNrU3RhcnRlZEF0VGFyZ2V0ID0gdGhpcy5jbGlja1N0YXJ0ZWRBdFRhcmdldCB8fCBlLnRhcmdldFxuICAgICAgLy8gd2hlbiBzZWFyY2hpbmcgdGhlIHRhcmdldCBmb3IgdGhlIGNsaWNrIGV2ZW50LCB3ZSBhbHdheXMgd2FudCB0b1xuICAgICAgLy8gdXNlIHRoZSBhY3R1YWwgZXZlbnQgdGFyZ2V0LCBzZWUgIzMzNzJcbiAgICAgIHRhcmdldCA9IGNsb3Nlc3RQaHhCaW5kaW5nKGUudGFyZ2V0LCBjbGljaylcbiAgICAgIHRoaXMuZGlzcGF0Y2hDbGlja0F3YXkoZSwgY2xpY2tTdGFydGVkQXRUYXJnZXQpXG4gICAgICB0aGlzLmNsaWNrU3RhcnRlZEF0VGFyZ2V0ID0gbnVsbFxuICAgICAgbGV0IHBoeEV2ZW50ID0gdGFyZ2V0ICYmIHRhcmdldC5nZXRBdHRyaWJ1dGUoY2xpY2spXG4gICAgICBpZighcGh4RXZlbnQpe1xuICAgICAgICBpZihET00uaXNOZXdQYWdlQ2xpY2soZSwgd2luZG93LmxvY2F0aW9uKSl7IHRoaXMudW5sb2FkKCkgfVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgaWYodGFyZ2V0LmdldEF0dHJpYnV0ZShcImhyZWZcIikgPT09IFwiI1wiKXsgZS5wcmV2ZW50RGVmYXVsdCgpIH1cblxuICAgICAgLy8gbm9vcCBpZiB3ZSBhcmUgaW4gdGhlIG1pZGRsZSBvZiBhd2FpdGluZyBhbiBhY2sgZm9yIHRoaXMgZWwgYWxyZWFkeVxuICAgICAgaWYodGFyZ2V0Lmhhc0F0dHJpYnV0ZShQSFhfUkVGX1NSQykpeyByZXR1cm4gfVxuXG4gICAgICB0aGlzLmRlYm91bmNlKHRhcmdldCwgZSwgXCJjbGlja1wiLCAoKSA9PiB7XG4gICAgICAgIHRoaXMud2l0aGluT3duZXJzKHRhcmdldCwgdmlldyA9PiB7XG4gICAgICAgICAgSlMuZXhlYyhlLCBcImNsaWNrXCIsIHBoeEV2ZW50LCB2aWV3LCB0YXJnZXQsIFtcInB1c2hcIiwge2RhdGE6IHRoaXMuZXZlbnRNZXRhKFwiY2xpY2tcIiwgZSwgdGFyZ2V0KX1dKVxuICAgICAgICB9KVxuICAgICAgfSlcbiAgICB9LCBmYWxzZSlcbiAgfVxuXG4gIGRpc3BhdGNoQ2xpY2tBd2F5KGUsIGNsaWNrU3RhcnRlZEF0KXtcbiAgICBsZXQgcGh4Q2xpY2tBd2F5ID0gdGhpcy5iaW5kaW5nKFwiY2xpY2stYXdheVwiKVxuICAgIERPTS5hbGwoZG9jdW1lbnQsIGBbJHtwaHhDbGlja0F3YXl9XWAsIGVsID0+IHtcbiAgICAgIGlmKCEoZWwuaXNTYW1lTm9kZShjbGlja1N0YXJ0ZWRBdCkgfHwgZWwuY29udGFpbnMoY2xpY2tTdGFydGVkQXQpKSl7XG4gICAgICAgIHRoaXMud2l0aGluT3duZXJzKGVsLCB2aWV3ID0+IHtcbiAgICAgICAgICBsZXQgcGh4RXZlbnQgPSBlbC5nZXRBdHRyaWJ1dGUocGh4Q2xpY2tBd2F5KVxuICAgICAgICAgIGlmKEpTLmlzVmlzaWJsZShlbCkgJiYgSlMuaXNJblZpZXdwb3J0KGVsKSl7XG4gICAgICAgICAgICBKUy5leGVjKGUsIFwiY2xpY2tcIiwgcGh4RXZlbnQsIHZpZXcsIGVsLCBbXCJwdXNoXCIsIHtkYXRhOiB0aGlzLmV2ZW50TWV0YShcImNsaWNrXCIsIGUsIGUudGFyZ2V0KX1dKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgYmluZE5hdigpe1xuICAgIGlmKCFCcm93c2VyLmNhblB1c2hTdGF0ZSgpKXsgcmV0dXJuIH1cbiAgICBpZihoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uKXsgaGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbiA9IFwibWFudWFsXCIgfVxuICAgIGxldCBzY3JvbGxUaW1lciA9IG51bGxcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCBfZSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQoc2Nyb2xsVGltZXIpXG4gICAgICBzY3JvbGxUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBCcm93c2VyLnVwZGF0ZUN1cnJlbnRTdGF0ZShzdGF0ZSA9PiBPYmplY3QuYXNzaWduKHN0YXRlLCB7c2Nyb2xsOiB3aW5kb3cuc2Nyb2xsWX0pKVxuICAgICAgfSwgMTAwKVxuICAgIH0pXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJwb3BzdGF0ZVwiLCBldmVudCA9PiB7XG4gICAgICBpZighdGhpcy5yZWdpc3Rlck5ld0xvY2F0aW9uKHdpbmRvdy5sb2NhdGlvbikpeyByZXR1cm4gfVxuICAgICAgbGV0IHt0eXBlLCBiYWNrVHlwZSwgaWQsIHNjcm9sbCwgcG9zaXRpb259ID0gZXZlbnQuc3RhdGUgfHwge31cbiAgICAgIGxldCBocmVmID0gd2luZG93LmxvY2F0aW9uLmhyZWZcblxuICAgICAgLy8gQ29tcGFyZSBwb3NpdGlvbnMgdG8gZGV0ZXJtaW5lIGRpcmVjdGlvblxuICAgICAgbGV0IGlzRm9yd2FyZCA9IHBvc2l0aW9uID4gdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uXG5cbiAgICAgIHR5cGUgPSBpc0ZvcndhcmQgPyB0eXBlIDogKGJhY2tUeXBlIHx8IHR5cGUpXG5cbiAgICAgIC8vIFVwZGF0ZSBjdXJyZW50IHBvc2l0aW9uXG4gICAgICB0aGlzLmN1cnJlbnRIaXN0b3J5UG9zaXRpb24gPSBwb3NpdGlvbiB8fCAwXG4gICAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oUEhYX0xWX0hJU1RPUllfUE9TSVRJT04sIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbi50b1N0cmluZygpKVxuXG4gICAgICBET00uZGlzcGF0Y2hFdmVudCh3aW5kb3csIFwicGh4Om5hdmlnYXRlXCIsIHtkZXRhaWw6IHtocmVmLCBwYXRjaDogdHlwZSA9PT0gXCJwYXRjaFwiLCBwb3A6IHRydWUsIGRpcmVjdGlvbjogaXNGb3J3YXJkID8gXCJmb3J3YXJkXCIgOiBcImJhY2t3YXJkXCJ9fSlcbiAgICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gKCkgPT4geyB0aGlzLm1heWJlU2Nyb2xsKHNjcm9sbCkgfVxuICAgICAgICBpZih0aGlzLm1haW4uaXNDb25uZWN0ZWQoKSAmJiAodHlwZSA9PT0gXCJwYXRjaFwiICYmIGlkID09PSB0aGlzLm1haW4uaWQpKXtcbiAgICAgICAgICB0aGlzLm1haW4ucHVzaExpbmtQYXRjaChldmVudCwgaHJlZiwgbnVsbCwgY2FsbGJhY2spXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5yZXBsYWNlTWFpbihocmVmLCBudWxsLCBjYWxsYmFjaylcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9LCBmYWxzZSlcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGUgPT4ge1xuICAgICAgbGV0IHRhcmdldCA9IGNsb3Nlc3RQaHhCaW5kaW5nKGUudGFyZ2V0LCBQSFhfTElWRV9MSU5LKVxuICAgICAgbGV0IHR5cGUgPSB0YXJnZXQgJiYgdGFyZ2V0LmdldEF0dHJpYnV0ZShQSFhfTElWRV9MSU5LKVxuICAgICAgaWYoIXR5cGUgfHwgIXRoaXMuaXNDb25uZWN0ZWQoKSB8fCAhdGhpcy5tYWluIHx8IERPTS53YW50c05ld1RhYihlKSl7IHJldHVybiB9XG5cbiAgICAgIC8vIFdoZW4gd3JhcHBpbmcgYW4gU1ZHIGVsZW1lbnQgaW4gYW4gYW5jaG9yIHRhZywgdGhlIGhyZWYgY2FuIGJlIGFuIFNWR0FuaW1hdGVkU3RyaW5nXG4gICAgICBsZXQgaHJlZiA9IHRhcmdldC5ocmVmIGluc3RhbmNlb2YgU1ZHQW5pbWF0ZWRTdHJpbmcgPyB0YXJnZXQuaHJlZi5iYXNlVmFsIDogdGFyZ2V0LmhyZWZcblxuICAgICAgbGV0IGxpbmtTdGF0ZSA9IHRhcmdldC5nZXRBdHRyaWJ1dGUoUEhYX0xJTktfU1RBVEUpXG4gICAgICBlLnByZXZlbnREZWZhdWx0KClcbiAgICAgIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkgLy8gZG8gbm90IGJ1YmJsZSBjbGljayB0byByZWd1bGFyIHBoeC1jbGljayBiaW5kaW5nc1xuICAgICAgaWYodGhpcy5wZW5kaW5nTGluayA9PT0gaHJlZil7IHJldHVybiB9XG5cbiAgICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgIGlmKHR5cGUgPT09IFwicGF0Y2hcIil7XG4gICAgICAgICAgdGhpcy5wdXNoSGlzdG9yeVBhdGNoKGUsIGhyZWYsIGxpbmtTdGF0ZSwgdGFyZ2V0KVxuICAgICAgICB9IGVsc2UgaWYodHlwZSA9PT0gXCJyZWRpcmVjdFwiKXtcbiAgICAgICAgICB0aGlzLmhpc3RvcnlSZWRpcmVjdChlLCBocmVmLCBsaW5rU3RhdGUsIG51bGwsIHRhcmdldClcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGV4cGVjdGVkICR7UEhYX0xJVkVfTElOS30gdG8gYmUgXCJwYXRjaFwiIG9yIFwicmVkaXJlY3RcIiwgZ290OiAke3R5cGV9YClcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGh4Q2xpY2sgPSB0YXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcImNsaWNrXCIpKVxuICAgICAgICBpZihwaHhDbGljayl7XG4gICAgICAgICAgdGhpcy5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHRoaXMuZXhlY0pTKHRhcmdldCwgcGh4Q2xpY2ssIFwiY2xpY2tcIikpXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSwgZmFsc2UpXG4gIH1cblxuICBtYXliZVNjcm9sbChzY3JvbGwpe1xuICAgIGlmKHR5cGVvZihzY3JvbGwpID09PSBcIm51bWJlclwiKXtcbiAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGxUbygwLCBzY3JvbGwpXG4gICAgICB9KSAvLyB0aGUgYm9keSBuZWVkcyB0byByZW5kZXIgYmVmb3JlIHdlIHNjcm9sbC5cbiAgICB9XG4gIH1cblxuICBkaXNwYXRjaEV2ZW50KGV2ZW50LCBwYXlsb2FkID0ge30pe1xuICAgIERPTS5kaXNwYXRjaEV2ZW50KHdpbmRvdywgYHBoeDoke2V2ZW50fWAsIHtkZXRhaWw6IHBheWxvYWR9KVxuICB9XG5cbiAgZGlzcGF0Y2hFdmVudHMoZXZlbnRzKXtcbiAgICBldmVudHMuZm9yRWFjaCgoW2V2ZW50LCBwYXlsb2FkXSkgPT4gdGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50LCBwYXlsb2FkKSlcbiAgfVxuXG4gIHdpdGhQYWdlTG9hZGluZyhpbmZvLCBjYWxsYmFjayl7XG4gICAgRE9NLmRpc3BhdGNoRXZlbnQod2luZG93LCBcInBoeDpwYWdlLWxvYWRpbmctc3RhcnRcIiwge2RldGFpbDogaW5mb30pXG4gICAgbGV0IGRvbmUgPSAoKSA9PiBET00uZGlzcGF0Y2hFdmVudCh3aW5kb3csIFwicGh4OnBhZ2UtbG9hZGluZy1zdG9wXCIsIHtkZXRhaWw6IGluZm99KVxuICAgIHJldHVybiBjYWxsYmFjayA/IGNhbGxiYWNrKGRvbmUpIDogZG9uZVxuICB9XG5cbiAgcHVzaEhpc3RvcnlQYXRjaChlLCBocmVmLCBsaW5rU3RhdGUsIHRhcmdldEVsKXtcbiAgICBpZighdGhpcy5pc0Nvbm5lY3RlZCgpIHx8ICF0aGlzLm1haW4uaXNNYWluKCkpeyByZXR1cm4gQnJvd3Nlci5yZWRpcmVjdChocmVmKSB9XG5cbiAgICB0aGlzLndpdGhQYWdlTG9hZGluZyh7dG86IGhyZWYsIGtpbmQ6IFwicGF0Y2hcIn0sIGRvbmUgPT4ge1xuICAgICAgdGhpcy5tYWluLnB1c2hMaW5rUGF0Y2goZSwgaHJlZiwgdGFyZ2V0RWwsIGxpbmtSZWYgPT4ge1xuICAgICAgICB0aGlzLmhpc3RvcnlQYXRjaChocmVmLCBsaW5rU3RhdGUsIGxpbmtSZWYpXG4gICAgICAgIGRvbmUoKVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgaGlzdG9yeVBhdGNoKGhyZWYsIGxpbmtTdGF0ZSwgbGlua1JlZiA9IHRoaXMuc2V0UGVuZGluZ0xpbmsoaHJlZikpe1xuICAgIGlmKCF0aGlzLmNvbW1pdFBlbmRpbmdMaW5rKGxpbmtSZWYpKXsgcmV0dXJuIH1cblxuICAgIC8vIEluY3JlbWVudCBwb3NpdGlvbiBmb3IgbmV3IHN0YXRlXG4gICAgdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uKytcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oUEhYX0xWX0hJU1RPUllfUE9TSVRJT04sIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbi50b1N0cmluZygpKVxuXG4gICAgLy8gc3RvcmUgdGhlIHR5cGUgZm9yIGJhY2sgbmF2aWdhdGlvblxuICAgIEJyb3dzZXIudXBkYXRlQ3VycmVudFN0YXRlKChzdGF0ZSkgPT4gKHsuLi5zdGF0ZSwgYmFja1R5cGU6IFwicGF0Y2hcIn0pKVxuXG4gICAgQnJvd3Nlci5wdXNoU3RhdGUobGlua1N0YXRlLCB7XG4gICAgICB0eXBlOiBcInBhdGNoXCIsXG4gICAgICBpZDogdGhpcy5tYWluLmlkLFxuICAgICAgcG9zaXRpb246IHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvblxuICAgIH0sIGhyZWYpXG5cbiAgICBET00uZGlzcGF0Y2hFdmVudCh3aW5kb3csIFwicGh4Om5hdmlnYXRlXCIsIHtkZXRhaWw6IHtwYXRjaDogdHJ1ZSwgaHJlZiwgcG9wOiBmYWxzZSwgZGlyZWN0aW9uOiBcImZvcndhcmRcIn19KVxuICAgIHRoaXMucmVnaXN0ZXJOZXdMb2NhdGlvbih3aW5kb3cubG9jYXRpb24pXG4gIH1cblxuICBoaXN0b3J5UmVkaXJlY3QoZSwgaHJlZiwgbGlua1N0YXRlLCBmbGFzaCwgdGFyZ2V0RWwpe1xuICAgIGNvbnN0IGNsaWNrTG9hZGluZyA9IHRhcmdldEVsICYmIGUuaXNUcnVzdGVkICYmIGUudHlwZSAhPT0gXCJwb3BzdGF0ZVwiXG4gICAgaWYoY2xpY2tMb2FkaW5nKXsgdGFyZ2V0RWwuY2xhc3NMaXN0LmFkZChcInBoeC1jbGljay1sb2FkaW5nXCIpIH1cbiAgICBpZighdGhpcy5pc0Nvbm5lY3RlZCgpIHx8ICF0aGlzLm1haW4uaXNNYWluKCkpeyByZXR1cm4gQnJvd3Nlci5yZWRpcmVjdChocmVmLCBmbGFzaCkgfVxuXG4gICAgLy8gY29udmVydCB0byBmdWxsIGhyZWYgaWYgb25seSBwYXRoIHByZWZpeFxuICAgIGlmKC9eXFwvJHxeXFwvW15cXC9dKy4qJC8udGVzdChocmVmKSl7XG4gICAgICBsZXQge3Byb3RvY29sLCBob3N0fSA9IHdpbmRvdy5sb2NhdGlvblxuICAgICAgaHJlZiA9IGAke3Byb3RvY29sfS8vJHtob3N0fSR7aHJlZn1gXG4gICAgfVxuICAgIGxldCBzY3JvbGwgPSB3aW5kb3cuc2Nyb2xsWVxuICAgIHRoaXMud2l0aFBhZ2VMb2FkaW5nKHt0bzogaHJlZiwga2luZDogXCJyZWRpcmVjdFwifSwgZG9uZSA9PiB7XG4gICAgICB0aGlzLnJlcGxhY2VNYWluKGhyZWYsIGZsYXNoLCAobGlua1JlZikgPT4ge1xuICAgICAgICBpZihsaW5rUmVmID09PSB0aGlzLmxpbmtSZWYpe1xuICAgICAgICAgIC8vIEluY3JlbWVudCBwb3NpdGlvbiBmb3IgbmV3IHN0YXRlXG4gICAgICAgICAgdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uKytcbiAgICAgICAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oUEhYX0xWX0hJU1RPUllfUE9TSVRJT04sIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbi50b1N0cmluZygpKVxuXG4gICAgICAgICAgLy8gc3RvcmUgdGhlIHR5cGUgZm9yIGJhY2sgbmF2aWdhdGlvblxuICAgICAgICAgIEJyb3dzZXIudXBkYXRlQ3VycmVudFN0YXRlKChzdGF0ZSkgPT4gKHsuLi5zdGF0ZSwgYmFja1R5cGU6IFwicmVkaXJlY3RcIn0pKVxuXG4gICAgICAgICAgQnJvd3Nlci5wdXNoU3RhdGUobGlua1N0YXRlLCB7XG4gICAgICAgICAgICB0eXBlOiBcInJlZGlyZWN0XCIsXG4gICAgICAgICAgICBpZDogdGhpcy5tYWluLmlkLFxuICAgICAgICAgICAgc2Nyb2xsOiBzY3JvbGwsXG4gICAgICAgICAgICBwb3NpdGlvbjogdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uXG4gICAgICAgICAgfSwgaHJlZilcblxuICAgICAgICAgIERPTS5kaXNwYXRjaEV2ZW50KHdpbmRvdywgXCJwaHg6bmF2aWdhdGVcIiwge2RldGFpbDoge2hyZWYsIHBhdGNoOiBmYWxzZSwgcG9wOiBmYWxzZSwgZGlyZWN0aW9uOiBcImZvcndhcmRcIn19KVxuICAgICAgICAgIHRoaXMucmVnaXN0ZXJOZXdMb2NhdGlvbih3aW5kb3cubG9jYXRpb24pXG4gICAgICAgIH1cbiAgICAgICAgLy8gZXhwbGljaXRseSB1bmRvIGNsaWNrLWxvYWRpbmcgY2xhc3NcbiAgICAgICAgLy8gKGluIGNhc2UgaXQgb3JpZ2luYXRlZCBpbiBhIHN0aWNreSBsaXZlIHZpZXcsIG90aGVyd2lzZSBpdCB3b3VsZCBiZSByZW1vdmVkIGFueXdheSlcbiAgICAgICAgaWYoY2xpY2tMb2FkaW5nKXsgdGFyZ2V0RWwuY2xhc3NMaXN0LnJlbW92ZShcInBoeC1jbGljay1sb2FkaW5nXCIpIH1cbiAgICAgICAgZG9uZSgpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICByZWdpc3Rlck5ld0xvY2F0aW9uKG5ld0xvY2F0aW9uKXtcbiAgICBsZXQge3BhdGhuYW1lLCBzZWFyY2h9ID0gdGhpcy5jdXJyZW50TG9jYXRpb25cbiAgICBpZihwYXRobmFtZSArIHNlYXJjaCA9PT0gbmV3TG9jYXRpb24ucGF0aG5hbWUgKyBuZXdMb2NhdGlvbi5zZWFyY2gpe1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3VycmVudExvY2F0aW9uID0gY2xvbmUobmV3TG9jYXRpb24pXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIGJpbmRGb3Jtcygpe1xuICAgIGxldCBpdGVyYXRpb25zID0gMFxuICAgIGxldCBleHRlcm5hbEZvcm1TdWJtaXR0ZWQgPSBmYWxzZVxuXG4gICAgLy8gZGlzYWJsZSBmb3JtcyBvbiBzdWJtaXQgdGhhdCB0cmFjayBwaHgtY2hhbmdlIGJ1dCBwZXJmb3JtIGV4dGVybmFsIHN1Ym1pdFxuICAgIHRoaXMub24oXCJzdWJtaXRcIiwgZSA9PiB7XG4gICAgICBsZXQgcGh4U3VibWl0ID0gZS50YXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcInN1Ym1pdFwiKSlcbiAgICAgIGxldCBwaHhDaGFuZ2UgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwiY2hhbmdlXCIpKVxuICAgICAgaWYoIWV4dGVybmFsRm9ybVN1Ym1pdHRlZCAmJiBwaHhDaGFuZ2UgJiYgIXBoeFN1Ym1pdCl7XG4gICAgICAgIGV4dGVybmFsRm9ybVN1Ym1pdHRlZCA9IHRydWVcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpXG4gICAgICAgIHRoaXMud2l0aGluT3duZXJzKGUudGFyZ2V0LCB2aWV3ID0+IHtcbiAgICAgICAgICB2aWV3LmRpc2FibGVGb3JtKGUudGFyZ2V0KVxuICAgICAgICAgIC8vIHNhZmFyaSBuZWVkcyBuZXh0IHRpY2tcbiAgICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICAgIGlmKERPTS5pc1VubG9hZGFibGVGb3JtU3VibWl0KGUpKXsgdGhpcy51bmxvYWQoKSB9XG4gICAgICAgICAgICBlLnRhcmdldC5zdWJtaXQoKVxuICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSlcblxuICAgIHRoaXMub24oXCJzdWJtaXRcIiwgZSA9PiB7XG4gICAgICBsZXQgcGh4RXZlbnQgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwic3VibWl0XCIpKVxuICAgICAgaWYoIXBoeEV2ZW50KXtcbiAgICAgICAgaWYoRE9NLmlzVW5sb2FkYWJsZUZvcm1TdWJtaXQoZSkpeyB0aGlzLnVubG9hZCgpIH1cbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG4gICAgICBlLnByZXZlbnREZWZhdWx0KClcbiAgICAgIGUudGFyZ2V0LmRpc2FibGVkID0gdHJ1ZVxuICAgICAgdGhpcy53aXRoaW5Pd25lcnMoZS50YXJnZXQsIHZpZXcgPT4ge1xuICAgICAgICBKUy5leGVjKGUsIFwic3VibWl0XCIsIHBoeEV2ZW50LCB2aWV3LCBlLnRhcmdldCwgW1wicHVzaFwiLCB7c3VibWl0dGVyOiBlLnN1Ym1pdHRlcn1dKVxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgZm9yKGxldCB0eXBlIG9mIFtcImNoYW5nZVwiLCBcImlucHV0XCJdKXtcbiAgICAgIHRoaXMub24odHlwZSwgZSA9PiB7XG4gICAgICAgIGlmKGUgaW5zdGFuY2VvZiBDdXN0b21FdmVudCAmJiBlLnRhcmdldC5mb3JtID09PSB1bmRlZmluZWQpe1xuICAgICAgICAgIC8vIHRocm93IG9uIGludmFsaWQgSlMuZGlzcGF0Y2ggdGFyZ2V0IGFuZCBub29wIGlmIEN1c3RvbUV2ZW50IHRyaWdnZXJlZCBvdXRzaWRlIEpTLmRpc3BhdGNoXG4gICAgICAgICAgaWYoZS5kZXRhaWwgJiYgZS5kZXRhaWwuZGlzcGF0Y2hlcil7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGRpc3BhdGNoaW5nIGEgY3VzdG9tICR7dHlwZX0gZXZlbnQgaXMgb25seSBzdXBwb3J0ZWQgb24gaW5wdXQgZWxlbWVudHMgaW5zaWRlIGEgZm9ybWApXG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIGxldCBwaHhDaGFuZ2UgPSB0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIilcbiAgICAgICAgbGV0IGlucHV0ID0gZS50YXJnZXRcbiAgICAgICAgLy8gZG8gbm90IGZpcmUgcGh4LWNoYW5nZSBpZiB3ZSBhcmUgaW4gdGhlIG1pZGRsZSBvZiBhIGNvbXBvc2l0aW9uIHNlc3Npb25cbiAgICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0tleWJvYXJkRXZlbnQvaXNDb21wb3NpbmdcbiAgICAgICAgLy8gU2FmYXJpIGhhcyBpc3N1ZXMgaWYgdGhlIGlucHV0IGlzIHVwZGF0ZWQgd2hpbGUgY29tcG9zaW5nXG4gICAgICAgIC8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMzMyMlxuICAgICAgICBpZihlLmlzQ29tcG9zaW5nKXtcbiAgICAgICAgICBjb25zdCBrZXkgPSBgY29tcG9zaXRpb24tbGlzdGVuZXItJHt0eXBlfWBcbiAgICAgICAgICBpZighRE9NLnByaXZhdGUoaW5wdXQsIGtleSkpe1xuICAgICAgICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXQsIGtleSwgdHJ1ZSlcbiAgICAgICAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoXCJjb21wb3NpdGlvbmVuZFwiLCAoKSA9PiB7XG4gICAgICAgICAgICAgIC8vIHRyaWdnZXIgYSBuZXcgaW5wdXQvY2hhbmdlIGV2ZW50XG4gICAgICAgICAgICAgIGlucHV0LmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KHR5cGUsIHtidWJibGVzOiB0cnVlfSkpXG4gICAgICAgICAgICAgIERPTS5kZWxldGVQcml2YXRlKGlucHV0LCBrZXkpXG4gICAgICAgICAgICB9LCB7b25jZTogdHJ1ZX0pXG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIGxldCBpbnB1dEV2ZW50ID0gaW5wdXQuZ2V0QXR0cmlidXRlKHBoeENoYW5nZSlcbiAgICAgICAgbGV0IGZvcm1FdmVudCA9IGlucHV0LmZvcm0gJiYgaW5wdXQuZm9ybS5nZXRBdHRyaWJ1dGUocGh4Q2hhbmdlKVxuICAgICAgICBsZXQgcGh4RXZlbnQgPSBpbnB1dEV2ZW50IHx8IGZvcm1FdmVudFxuICAgICAgICBpZighcGh4RXZlbnQpeyByZXR1cm4gfVxuICAgICAgICBpZihpbnB1dC50eXBlID09PSBcIm51bWJlclwiICYmIGlucHV0LnZhbGlkaXR5ICYmIGlucHV0LnZhbGlkaXR5LmJhZElucHV0KXsgcmV0dXJuIH1cblxuICAgICAgICBsZXQgZGlzcGF0Y2hlciA9IGlucHV0RXZlbnQgPyBpbnB1dCA6IGlucHV0LmZvcm1cbiAgICAgICAgbGV0IGN1cnJlbnRJdGVyYXRpb25zID0gaXRlcmF0aW9uc1xuICAgICAgICBpdGVyYXRpb25zKytcbiAgICAgICAgbGV0IHthdDogYXQsIHR5cGU6IGxhc3RUeXBlfSA9IERPTS5wcml2YXRlKGlucHV0LCBcInByZXYtaXRlcmF0aW9uXCIpIHx8IHt9XG4gICAgICAgIC8vIEJyb3dzZXJzIHNob3VsZCBhbHdheXMgZmlyZSBhdCBsZWFzdCBvbmUgXCJpbnB1dFwiIGV2ZW50IGJlZm9yZSBldmVyeSBcImNoYW5nZVwiXG4gICAgICAgIC8vIElnbm9yZSBcImNoYW5nZVwiIGV2ZW50cywgdW5sZXNzIHRoZXJlIHdhcyBubyBwcmlvciBcImlucHV0XCIgZXZlbnQuXG4gICAgICAgIC8vIFRoaXMgY291bGQgaGFwcGVuIGlmIHVzZXIgY29kZSB0cmlnZ2VycyBhIFwiY2hhbmdlXCIgZXZlbnQsIG9yIGlmIHRoZSBicm93c2VyIGlzIG5vbi1jb25mb3JtaW5nLlxuICAgICAgICBpZihhdCA9PT0gY3VycmVudEl0ZXJhdGlvbnMgLSAxICYmIHR5cGUgPT09IFwiY2hhbmdlXCIgJiYgbGFzdFR5cGUgPT09IFwiaW5wdXRcIil7IHJldHVybiB9XG5cbiAgICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXQsIFwicHJldi1pdGVyYXRpb25cIiwge2F0OiBjdXJyZW50SXRlcmF0aW9ucywgdHlwZTogdHlwZX0pXG5cbiAgICAgICAgdGhpcy5kZWJvdW5jZShpbnB1dCwgZSwgdHlwZSwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMud2l0aGluT3duZXJzKGRpc3BhdGNoZXIsIHZpZXcgPT4ge1xuICAgICAgICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXQsIFBIWF9IQVNfRk9DVVNFRCwgdHJ1ZSlcbiAgICAgICAgICAgIEpTLmV4ZWMoZSwgXCJjaGFuZ2VcIiwgcGh4RXZlbnQsIHZpZXcsIGlucHV0LCBbXCJwdXNoXCIsIHtfdGFyZ2V0OiBlLnRhcmdldC5uYW1lLCBkaXNwYXRjaGVyOiBkaXNwYXRjaGVyfV0pXG4gICAgICAgICAgfSlcbiAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfVxuICAgIHRoaXMub24oXCJyZXNldFwiLCAoZSkgPT4ge1xuICAgICAgbGV0IGZvcm0gPSBlLnRhcmdldFxuICAgICAgRE9NLnJlc2V0Rm9ybShmb3JtKVxuICAgICAgbGV0IGlucHV0ID0gQXJyYXkuZnJvbShmb3JtLmVsZW1lbnRzKS5maW5kKGVsID0+IGVsLnR5cGUgPT09IFwicmVzZXRcIilcbiAgICAgIGlmKGlucHV0KXtcbiAgICAgICAgLy8gd2FpdCB1bnRpbCBuZXh0IHRpY2sgdG8gZ2V0IHVwZGF0ZWQgaW5wdXQgdmFsdWVcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgaW5wdXQuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJpbnB1dFwiLCB7YnViYmxlczogdHJ1ZSwgY2FuY2VsYWJsZTogZmFsc2V9KSlcbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgZGVib3VuY2UoZWwsIGV2ZW50LCBldmVudFR5cGUsIGNhbGxiYWNrKXtcbiAgICBpZihldmVudFR5cGUgPT09IFwiYmx1clwiIHx8IGV2ZW50VHlwZSA9PT0gXCJmb2N1c291dFwiKXsgcmV0dXJuIGNhbGxiYWNrKCkgfVxuXG4gICAgbGV0IHBoeERlYm91bmNlID0gdGhpcy5iaW5kaW5nKFBIWF9ERUJPVU5DRSlcbiAgICBsZXQgcGh4VGhyb3R0bGUgPSB0aGlzLmJpbmRpbmcoUEhYX1RIUk9UVExFKVxuICAgIGxldCBkZWZhdWx0RGVib3VuY2UgPSB0aGlzLmRlZmF1bHRzLmRlYm91bmNlLnRvU3RyaW5nKClcbiAgICBsZXQgZGVmYXVsdFRocm90dGxlID0gdGhpcy5kZWZhdWx0cy50aHJvdHRsZS50b1N0cmluZygpXG5cbiAgICB0aGlzLndpdGhpbk93bmVycyhlbCwgdmlldyA9PiB7XG4gICAgICBsZXQgYXN5bmNGaWx0ZXIgPSAoKSA9PiAhdmlldy5pc0Rlc3Ryb3llZCgpICYmIGRvY3VtZW50LmJvZHkuY29udGFpbnMoZWwpXG4gICAgICBET00uZGVib3VuY2UoZWwsIGV2ZW50LCBwaHhEZWJvdW5jZSwgZGVmYXVsdERlYm91bmNlLCBwaHhUaHJvdHRsZSwgZGVmYXVsdFRocm90dGxlLCBhc3luY0ZpbHRlciwgKCkgPT4ge1xuICAgICAgICBjYWxsYmFjaygpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICBzaWxlbmNlRXZlbnRzKGNhbGxiYWNrKXtcbiAgICB0aGlzLnNpbGVuY2VkID0gdHJ1ZVxuICAgIGNhbGxiYWNrKClcbiAgICB0aGlzLnNpbGVuY2VkID0gZmFsc2VcbiAgfVxuXG4gIG9uKGV2ZW50LCBjYWxsYmFjayl7XG4gICAgdGhpcy5ib3VuZEV2ZW50TmFtZXMuYWRkKGV2ZW50KVxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBlID0+IHtcbiAgICAgIGlmKCF0aGlzLnNpbGVuY2VkKXsgY2FsbGJhY2soZSkgfVxuICAgIH0pXG4gIH1cblxuICBqc1F1ZXJ5U2VsZWN0b3JBbGwoc291cmNlRWwsIHF1ZXJ5LCBkZWZhdWx0UXVlcnkpe1xuICAgIGxldCBhbGwgPSB0aGlzLmRvbUNhbGxiYWNrcy5qc1F1ZXJ5U2VsZWN0b3JBbGxcbiAgICByZXR1cm4gYWxsID8gYWxsKHNvdXJjZUVsLCBxdWVyeSwgZGVmYXVsdFF1ZXJ5KSA6IGRlZmF1bHRRdWVyeSgpXG4gIH1cbn1cblxuY2xhc3MgVHJhbnNpdGlvblNldCB7XG4gIGNvbnN0cnVjdG9yKCl7XG4gICAgdGhpcy50cmFuc2l0aW9ucyA9IG5ldyBTZXQoKVxuICAgIHRoaXMucGVuZGluZ09wcyA9IFtdXG4gIH1cblxuICByZXNldCgpe1xuICAgIHRoaXMudHJhbnNpdGlvbnMuZm9yRWFjaCh0aW1lciA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXIpXG4gICAgICB0aGlzLnRyYW5zaXRpb25zLmRlbGV0ZSh0aW1lcilcbiAgICB9KVxuICAgIHRoaXMuZmx1c2hQZW5kaW5nT3BzKClcbiAgfVxuXG4gIGFmdGVyKGNhbGxiYWNrKXtcbiAgICBpZih0aGlzLnNpemUoKSA9PT0gMCl7XG4gICAgICBjYWxsYmFjaygpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucHVzaFBlbmRpbmdPcChjYWxsYmFjaylcbiAgICB9XG4gIH1cblxuICBhZGRUcmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRG9uZSl7XG4gICAgb25TdGFydCgpXG4gICAgbGV0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnRyYW5zaXRpb25zLmRlbGV0ZSh0aW1lcilcbiAgICAgIG9uRG9uZSgpXG4gICAgICB0aGlzLmZsdXNoUGVuZGluZ09wcygpXG4gICAgfSwgdGltZSlcbiAgICB0aGlzLnRyYW5zaXRpb25zLmFkZCh0aW1lcilcbiAgfVxuXG4gIHB1c2hQZW5kaW5nT3Aob3ApeyB0aGlzLnBlbmRpbmdPcHMucHVzaChvcCkgfVxuXG4gIHNpemUoKXsgcmV0dXJuIHRoaXMudHJhbnNpdGlvbnMuc2l6ZSB9XG5cbiAgZmx1c2hQZW5kaW5nT3BzKCl7XG4gICAgaWYodGhpcy5zaXplKCkgPiAwKXsgcmV0dXJuIH1cbiAgICBsZXQgb3AgPSB0aGlzLnBlbmRpbmdPcHMuc2hpZnQoKVxuICAgIGlmKG9wKXtcbiAgICAgIG9wKClcbiAgICAgIHRoaXMuZmx1c2hQZW5kaW5nT3BzKClcbiAgICB9XG4gIH1cbn1cbiIsICIvKlxuPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblBob2VuaXggTGl2ZVZpZXcgSmF2YVNjcmlwdCBDbGllbnRcbj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblNlZSB0aGUgaGV4ZG9jcyBhdCBgaHR0cHM6Ly9oZXhkb2NzLnBtL3Bob2VuaXhfbGl2ZV92aWV3YCBmb3IgZG9jdW1lbnRhdGlvbi5cblxuKi9cblxuaW1wb3J0IExpdmVTb2NrZXQsIHtpc1VzZWRJbnB1dH0gZnJvbSBcIi4vbGl2ZV9zb2NrZXRcIlxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIlxuaW1wb3J0IFZpZXdIb29rIGZyb20gXCIuL3ZpZXdfaG9va1wiXG5pbXBvcnQgVmlldyBmcm9tIFwiLi92aWV3XCJcblxuLyoqIENyZWF0ZXMgYSBWaWV3SG9vayBpbnN0YW5jZSBmb3IgdGhlIGdpdmVuIGVsZW1lbnQgYW5kIGNhbGxiYWNrcy5cbiAqXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIFRoZSBlbGVtZW50IHRvIGFzc29jaWF0ZSB3aXRoIHRoZSBob29rLlxuICogQHBhcmFtIHtPYmplY3R9IFtjYWxsYmFja3NdIC0gVGhlIGxpc3Qgb2YgaG9vayBjYWxsYmFja3MsIHN1Y2ggYXMgbW91bnRlZCxcbiAqICAgdXBkYXRlZCwgZGVzdHJveWVkLCBldGMuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBjbGFzcyBNeUNvbXBvbmVudCBleHRlbmRzIEhUTUxFbGVtZW50IHtcbiAqICAgY29ubmVjdGVkQ2FsbGJhY2soKXtcbiAqICAgICBsZXQgb25MaXZlVmlld01vdW50ZWQgPSAoKSA9PiB0aGlzLmhvb2sucHVzaEV2ZW50KC4uLikpXG4gKiAgICAgdGhpcy5ob29rID0gY3JlYXRlSG9vayh0aGlzLCB7bW91bnRlZDogb25MaXZlVmlld01vdW50ZWR9KVxuICogICB9XG4gKiB9XG4gKlxuICogKk5vdGUqOiBgY3JlYXRlSG9va2AgbXVzdCBiZSBjYWxsZWQgZnJvbSB0aGUgYGNvbm5lY3RlZENhbGxiYWNrYCBsaWZlY3ljbGVcbiAqIHdoaWNoIGlzIHRyaWdnZXJlZCBhZnRlciB0aGUgZWxlbWVudCBoYXMgYmVlbiBhZGRlZCB0byB0aGUgRE9NLiBJZiB5b3UgdHJ5XG4gKiB0byBjYWxsIGBjcmVhdGVIb29rYCBmcm9tIHRoZSBjb25zdHJ1Y3RvciwgYW4gZXJyb3Igd2lsbCBiZSBsb2dnZWQuXG4gKlxuICogQHJldHVybnMge1ZpZXdIb29rfSBSZXR1cm5zIHRoZSBWaWV3SG9vayBpbnN0YW5jZSBmb3IgdGhlIGN1c3RvbSBlbGVtZW50LlxuICovXG5sZXQgY3JlYXRlSG9vayA9IChlbCwgY2FsbGJhY2tzID0ge30pID0+IHtcbiAgbGV0IGV4aXN0aW5nSG9vayA9IERPTS5nZXRDdXN0b21FbEhvb2soZWwpXG4gIGlmKGV4aXN0aW5nSG9vayl7IHJldHVybiBleGlzdGluZ0hvb2sgfVxuXG4gIGxldCBob29rID0gbmV3IFZpZXdIb29rKFZpZXcuY2xvc2VzdFZpZXcoZWwpLCBlbCwgY2FsbGJhY2tzKVxuICBET00ucHV0Q3VzdG9tRWxIb29rKGVsLCBob29rKVxuICByZXR1cm4gaG9va1xufVxuXG5leHBvcnQge1xuICBMaXZlU29ja2V0LFxuICBpc1VzZWRJbnB1dCxcbiAgY3JlYXRlSG9va1xufVxuIiwgIi8vIElmIHlvdSB3YW50IHRvIHVzZSBQaG9lbml4IGNoYW5uZWxzLCBydW4gYG1peCBoZWxwIHBoeC5nZW4uY2hhbm5lbGBcbi8vIHRvIGdldCBzdGFydGVkIGFuZCB0aGVuIHVuY29tbWVudCB0aGUgbGluZSBiZWxvdy5cbi8vIGltcG9ydCBcIi4vdXNlcl9zb2NrZXQuanNcIlxuXG4vLyBZb3UgY2FuIGluY2x1ZGUgZGVwZW5kZW5jaWVzIGluIHR3byB3YXlzLlxuLy9cbi8vIFRoZSBzaW1wbGVzdCBvcHRpb24gaXMgdG8gcHV0IHRoZW0gaW4gYXNzZXRzL3ZlbmRvciBhbmRcbi8vIGltcG9ydCB0aGVtIHVzaW5nIHJlbGF0aXZlIHBhdGhzOlxuLy9cbi8vICAgICBpbXBvcnQgXCIuLi92ZW5kb3Ivc29tZS1wYWNrYWdlLmpzXCJcbi8vXG4vLyBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIGBucG0gaW5zdGFsbCBzb21lLXBhY2thZ2UgLS1wcmVmaXggYXNzZXRzYCBhbmQgaW1wb3J0XG4vLyB0aGVtIHVzaW5nIGEgcGF0aCBzdGFydGluZyB3aXRoIHRoZSBwYWNrYWdlIG5hbWU6XG4vL1xuLy8gICAgIGltcG9ydCBcInNvbWUtcGFja2FnZVwiXG4vL1xuXG4vLyBJbmNsdWRlIHBob2VuaXhfaHRtbCB0byBoYW5kbGUgbWV0aG9kPVBVVC9ERUxFVEUgaW4gZm9ybXMgYW5kIGJ1dHRvbnMuXG5pbXBvcnQgXCJwaG9lbml4X2h0bWxcIlxuLy8gRXN0YWJsaXNoIFBob2VuaXggU29ja2V0IGFuZCBMaXZlVmlldyBjb25maWd1cmF0aW9uLlxuaW1wb3J0IHtTb2NrZXR9IGZyb20gXCJwaG9lbml4XCJcbmltcG9ydCB7TGl2ZVNvY2tldH0gZnJvbSBcInBob2VuaXhfbGl2ZV92aWV3XCJcbmltcG9ydCB0b3BiYXIgZnJvbSBcIi4uL3ZlbmRvci90b3BiYXJcIlxuXG5sZXQgY3NyZlRva2VuID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIm1ldGFbbmFtZT0nY3NyZi10b2tlbiddXCIpLmdldEF0dHJpYnV0ZShcImNvbnRlbnRcIilcbmxldCBsaXZlU29ja2V0ID0gbmV3IExpdmVTb2NrZXQoXCIvbGl2ZVwiLCBTb2NrZXQsIHtcbiAgbG9uZ1BvbGxGYWxsYmFja01zOiAyNTAwLFxuICBwYXJhbXM6IHtfY3NyZl90b2tlbjogY3NyZlRva2VufVxufSlcblxuLy8gU2hvdyBwcm9ncmVzcyBiYXIgb24gbGl2ZSBuYXZpZ2F0aW9uIGFuZCBmb3JtIHN1Ym1pdHNcbnRvcGJhci5jb25maWcoe2JhckNvbG9yczogezA6IFwiIzI5ZFwifSwgc2hhZG93Q29sb3I6IFwicmdiYSgwLCAwLCAwLCAuMylcIn0pXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBoeDpwYWdlLWxvYWRpbmctc3RhcnRcIiwgX2luZm8gPT4gdG9wYmFyLnNob3coMzAwKSlcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGh4OnBhZ2UtbG9hZGluZy1zdG9wXCIsIF9pbmZvID0+IHRvcGJhci5oaWRlKCkpXG5cbi8vIGNvbm5lY3QgaWYgdGhlcmUgYXJlIGFueSBMaXZlVmlld3Mgb24gdGhlIHBhZ2VcbmxpdmVTb2NrZXQuY29ubmVjdCgpXG5cbi8vIGV4cG9zZSBsaXZlU29ja2V0IG9uIHdpbmRvdyBmb3Igd2ViIGNvbnNvbGUgZGVidWcgbG9ncyBhbmQgbGF0ZW5jeSBzaW11bGF0aW9uOlxuLy8gPj4gbGl2ZVNvY2tldC5lbmFibGVEZWJ1ZygpXG4vLyA+PiBsaXZlU29ja2V0LmVuYWJsZUxhdGVuY3lTaW0oMTAwMCkgIC8vIGVuYWJsZWQgZm9yIGR1cmF0aW9uIG9mIGJyb3dzZXIgc2Vzc2lvblxuLy8gPj4gbGl2ZVNvY2tldC5kaXNhYmxlTGF0ZW5jeVNpbSgpXG53aW5kb3cubGl2ZVNvY2tldCA9IGxpdmVTb2NrZXRcblxuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQU1BLE9BQUMsU0FBVUEsU0FBUUMsV0FBVTtBQUMzQjtBQUdBLFNBQUMsV0FBWTtBQUNYLGNBQUksV0FBVztBQUNmLGNBQUksVUFBVSxDQUFDLE1BQU0sT0FBTyxVQUFVLEdBQUc7QUFDekMsbUJBQVMsSUFBSSxHQUFHLElBQUksUUFBUSxVQUFVLENBQUNELFFBQU8sdUJBQXVCLEVBQUUsR0FBRztBQUN4RSxZQUFBQSxRQUFPLHdCQUNMQSxRQUFPLFFBQVEsQ0FBQyxJQUFJLHVCQUF1QjtBQUM3QyxZQUFBQSxRQUFPLHVCQUNMQSxRQUFPLFFBQVEsQ0FBQyxJQUFJLHNCQUFzQixLQUMxQ0EsUUFBTyxRQUFRLENBQUMsSUFBSSw2QkFBNkI7QUFBQSxVQUNyRDtBQUNBLGNBQUksQ0FBQ0EsUUFBTztBQUNWLFlBQUFBLFFBQU8sd0JBQXdCLFNBQVUsVUFBVSxTQUFTO0FBQzFELGtCQUFJLFlBQVcsb0JBQUksS0FBSyxHQUFFLFFBQVE7QUFDbEMsa0JBQUksYUFBYSxLQUFLLElBQUksR0FBRyxNQUFNLFdBQVcsU0FBUztBQUN2RCxrQkFBSSxLQUFLQSxRQUFPLFdBQVcs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QUFNLFNBQVMsUUFBTztBQUNsQyxjQUFRO0FBQ1IsVUFBSSxRQUFRLFdBQVcsTUFBTTtBQUMzQixhQUFLLFlBQVksT0FBTyxLQUFLO0FBQzdCLGVBQU87QUFDUCxhQUFLLGdCQUFnQjtNQUN2QixHQUFHLElBQUk7QUFDUCxXQUFLLFlBQVksSUFBSSxLQUFLO0lBQzVCO0lBRUEsY0FBYyxJQUFHO0FBQUUsV0FBSyxXQUFXLEtBQUssRUFBRTtJQUFFO0lBRTVDLE9BQU07QUFBRSxhQUFPLEtBQUssWUFBWTtJQUFLO0lBRXJDLGtCQUFpQjtBQUNmLFVBQUcsS0FBSyxLQUFLLElBQUksR0FBRTtBQUFFO01BQU87QUFDNUIsVUFBSSxLQUFLLEtBQUssV0FBVyxNQUFNO0FBQy9CLFVBQUcsSUFBRztBQUNKLFdBQUc7QUFDSCxhQUFLLGdCQUFnQjtNQUN2QjtJQUNGO0VBQ0Y7OztBRTMvQkEsc0JBQW1CO0FBRW5CLE1BQUksWUFBWSxTQUFTLGNBQWMseUJBQXlCLEVBQUUsYUFBYSxTQUFTO0FBQ3hGLE1BQUksYUFBYSxJQUFJLFdBQVcsU0FBUyxRQUFRO0FBQUEsSUFDL0Msb0JBQW9CO0FBQUEsSUFDcEIsUUFBUSxFQUFDLGFBQWEsVUFBUztBQUFBLEVBQ2pDLENBQUM7QUFHRCxnQkFBQUMsUUFBTyxPQUFPLEVBQUMsV0FBVyxFQUFDLEdBQUcsT0FBTSxHQUFHLGFBQWEsb0JBQW1CLENBQUM7QUFDeEUsU0FBTyxpQkFBaUIsMEJBQTBCLFdBQVMsY0FBQUEsUUFBTyxLQUFLLEdBQUcsQ0FBQztBQUMzRSxTQUFPLGlCQUFpQix5QkFBeUIsV0FBUyxjQUFBQSxRQUFPLEtBQUssQ0FBQztBQUd2RSxhQUFXLFFBQVE7QUFNbkIsU0FBTyxhQUFhOyIsCiAgIm5hbWVzIjogWyJ3aW5kb3ciLCAiZG9jdW1lbnQiLCAidG9wYmFyIiwgIkN1c3RvbUV2ZW50IiwgImNsb3N1cmUiLCAibGl2ZVNvY2tldCIsICJjbG9zdXJlIiwgImUiLCAiaXNFbXB0eSIsICJmaWxlIiwgIm1vcnBoQXR0cnMiLCAibW9ycGhkb20iLCAiY2hpbGRyZW5Pbmx5IiwgInRhcmdldENvbnRhaW5lciIsICJjbG9uZSIsICJlbCIsICJpbnB1dHNVbnVzZWQiLCAib25seUhpZGRlbklucHV0cyIsICJsb2NrIiwgImxvYWRpbmciLCAiZW50cnkiLCAiaW5wdXQiLCAiY2xvc3VyZSIsICJ0b3BiYXIiXQp9Cg==