+7
-7
.gitignore
+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
+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
blonk.db
This is a binary file and will not be displayed.
-6
elixir_blonk/.formatter.exs
-6
elixir_blonk/.formatter.exs
-258
elixir_blonk/README.md
-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/css/app.css
assets/css/app.css
elixir_blonk/assets/js/app.js
assets/js/app.js
elixir_blonk/assets/js/app.js
assets/js/app.js
elixir_blonk/assets/tailwind.config.js
assets/tailwind.config.js
elixir_blonk/assets/tailwind.config.js
assets/tailwind.config.js
elixir_blonk/assets/vendor/topbar.js
assets/vendor/topbar.js
elixir_blonk/assets/vendor/topbar.js
assets/vendor/topbar.js
elixir_blonk/config/config.exs
config/config.exs
elixir_blonk/config/config.exs
config/config.exs
elixir_blonk/config/dev.exs
config/dev.exs
elixir_blonk/config/dev.exs
config/dev.exs
elixir_blonk/config/prod.exs
config/prod.exs
elixir_blonk/config/prod.exs
config/prod.exs
elixir_blonk/config/runtime.exs
config/runtime.exs
elixir_blonk/config/runtime.exs
config/runtime.exs
elixir_blonk/config/test.exs
config/test.exs
elixir_blonk/config/test.exs
config/test.exs
elixir_blonk/lib/elixir_blonk.ex
lib/elixir_blonk.ex
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.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.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_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/accounts/user_token.ex
lib/elixir_blonk/accounts/user_token.ex
elixir_blonk/lib/elixir_blonk/application.ex
lib/elixir_blonk/application.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
+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/client.ex
lib/elixir_blonk/atproto/client.ex
elixir_blonk/lib/elixir_blonk/atproto/session_manager.ex
lib/elixir_blonk/atproto/session_manager.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
-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/atproto/sync.ex
lib/elixir_blonk/atproto/sync.ex
+74
-1
elixir_blonk/lib/elixir_blonk/blips.ex
lib/elixir_blonk/blips.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/blip.ex
lib/elixir_blonk/blips/blip.ex
elixir_blonk/lib/elixir_blonk/blips/comment.ex
lib/elixir_blonk/blips/comment.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
+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
elixir_blonk/lib/elixir_blonk/firehose/supervisor.ex
lib/elixir_blonk/firehose/supervisor.ex
-145
elixir_blonk/lib/elixir_blonk/grooves.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
elixir_blonk/lib/elixir_blonk/grooves/groove.ex
lib/elixir_blonk/grooves/groove.ex
-134
elixir_blonk/lib/elixir_blonk/hot_post_sweeper.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
-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
-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/mailer.ex
lib/elixir_blonk/mailer.ex
elixir_blonk/lib/elixir_blonk/repo.ex
lib/elixir_blonk/repo.ex
elixir_blonk/lib/elixir_blonk/repo.ex
lib/elixir_blonk/repo.ex
-221
elixir_blonk/lib/elixir_blonk/vibes.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.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_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/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.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/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.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/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/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/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_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/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_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.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/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_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.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/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_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_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.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_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_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.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/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_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_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.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_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_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.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/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/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/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/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.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/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.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/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.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/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.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/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/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/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/lib/elixir_blonk_web/user_auth.ex
lib/elixir_blonk_web/user_auth.ex
elixir_blonk/mix.exs
mix.exs
elixir_blonk/mix.exs
mix.exs
elixir_blonk/mix.lock
mix.lock
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/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/gettext/errors.pot
priv/gettext/errors.pot
elixir_blonk/priv/repo/migrations/.formatter.exs
priv/repo/migrations/.formatter.exs
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/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/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/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/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/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/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/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/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/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/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/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/seed_bsky_hot_vibe.exs
priv/repo/seed_bsky_hot_vibe.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/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/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_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/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/favicon.ico
priv/static/favicon.ico
elixir_blonk/priv/static/images/logo.svg
priv/static/images/logo.svg
elixir_blonk/priv/static/images/logo.svg
priv/static/images/logo.svg
elixir_blonk/priv/static/robots.txt
priv/static/robots.txt
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/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_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/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/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_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_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_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_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/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/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/conn_case.ex
test/support/conn_case.ex
elixir_blonk/test/support/data_case.ex
test/support/data_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/support/fixtures/accounts_fixtures.ex
test/support/fixtures/accounts_fixtures.ex
elixir_blonk/test/test_helper.exs
test/test_helper.exs
elixir_blonk/test/test_helper.exs
test/test_helper.exs
elixir_blonk/test_firehose.exs
test_firehose.exs
elixir_blonk/test_firehose.exs
test_firehose.exs
+100
lib/elixir_blonk/atproto/simple_session.ex
+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
+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
+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
+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
+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
+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
+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
+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==