diff --git a/openwrt-adguard-setup.md b/openwrt-adguard-setup.md index b5e2094..791ed49 100644 --- a/openwrt-adguard-setup.md +++ b/openwrt-adguard-setup.md @@ -1,580 +1 @@ -# OpenWRT and AdGuard Home Configuration Guide - -## Network Overview - -**Current Setup:** -- Router: 10.0.0.254 (TPLink) -- DNS: 10.0.0.55 (HomeAssistant/AdGuard) - -**New Setup:** -- OpenWRT Router: 10.0.0.246 -- New AdGuard: 10.0.0.245 -- DHCP Range: 10.0.0.1 - 10.0.0.200 - ---- - -## Part 1: Initial OpenWRT Setup - -### 1.1 First Login and Basic Configuration - -1. **Connect to OpenWRT:** - - Connect via Ethernet to LAN port - - Default IP is usually `192.168.1.1` - - Access via browser: `http://192.168.1.1` - - Default login: `root` (no password initially) - -2. **Set Root Password:** - ``` - System → Administration → Router Password - ``` - Set a strong password immediately. - -### 1.2 Configure LAN Interface - -1. **Navigate to Network → Interfaces** - -2. **Edit LAN interface:** - - Protocol: `Static address` - - IPv4 address: `10.0.0.246` - - IPv4 netmask: `255.255.255.0` - - IPv4 gateway: `10.0.0.254` (your main TPLink router) - - Use custom DNS servers: `10.0.0.245` (your new AdGuard) - - Click "Save" then "Save & Apply" - -3. **Reconnect:** - - Your OpenWRT will now be at `http://10.0.0.246` - - You may need to manually set your PC to 10.0.0.x network temporarily - ---- - -## Part 2: DHCP Server Configuration - -### 2.1 Basic DHCP Settings - -1. **Navigate to Network → DHCP and DNS** - -2. **Server Settings (General Settings tab):** - - Check "Authoritative" if this will be the only DHCP server on this network - - DNS forwardings: `10.0.0.245` - - Click "Save" - -3. **DHCP Pool Settings:** - - Navigate to Network → Interfaces → LAN → Edit → DHCP Server tab - - Check "Enable this DHCP server" - - Start: `1` - - Limit: `200` - - Lease time: `12h` (or your preference) - -### 2.2 Static Leases Configuration - -1. **Navigate to Network → DHCP and DNS → Static Leases tab** - -2. **Add Static Leases:** - - Click "Add" - - Hostname: Device name (e.g., "homeassistant") - - MAC Address: Device MAC - - IPv4 Address: Desired IP (e.g., 10.0.0.55) - - Lease time: Leave empty for infinite - - Click "Save" then "Save & Apply" - -Example static leases you might want: -``` -10.0.0.55 - HomeAssistant/Current AdGuard -10.0.0.245 - New AdGuard -10.0.0.246 - OpenWRT itself -10.0.0.254 - TPLink Router -``` - -### 2.3 DHCP Options for Custom DNS per Client - -To set different DNS servers for specific clients, you'll need to use DHCP options. - -**Option 1: Via LuCI (GUI)** -1. Navigate to Network → DHCP and DNS → Static Leases -2. When adding/editing a static lease, you can add DHCP options -3. Add option `6` with comma-separated DNS IPs: `8.8.8.8,8.8.4.4` - -**Option 2: Via Config File (more flexible)** - -SSH into OpenWRT and edit `/etc/config/dhcp`: - -```bash -vi /etc/config/dhcp -``` - -Add configuration like this: - -``` -config host - option name 'special-device' - option mac 'AA:BB:CC:DD:EE:FF' - option ip '10.0.0.100' - option dns '8.8.8.8 8.8.4.4' - -config host - option name 'standard-device' - option mac '11:22:33:44:55:66' - option ip '10.0.0.101' - # Uses default DNS (AdGuard at 10.0.0.245) -``` - -Then restart dnsmasq: -```bash -/etc/init.d/dnsmasq restart -``` - ---- - -## Part 3: Access Control Configuration - -### 3.1 Install Required Packages - -SSH into your OpenWRT router and install firewall management tools: - -```bash -opkg update -opkg install luci-app-firewall -opkg install iptables-mod-extra -``` - -### 3.2 Method 1: MAC Address Filtering (Simple Block) - -**Via LuCI:** -1. Navigate to Network → Wireless (if WiFi) or DHCP -2. For each device you want to block: - - Add to static lease with specific IP - - Then create firewall rule to block that IP - -**Create Firewall Rule:** -1. Network → Firewall → Traffic Rules -2. Add new rule: - - Name: `Block Device Name` - - Source zone: `lan` - - Source MAC or IP: `10.0.0.XX` or `AA:BB:CC:DD:EE:FF` - - Destination zone: `wan` - - Action: `reject` - -### 3.3 Method 2: IP Sets for Group Management (Advanced) - -This allows you to easily manage groups of blocked devices. - -**SSH Configuration:** - -Create custom firewall rules in `/etc/firewall.user`: - -```bash -vi /etc/firewall.user -``` - -Add: -```bash -# Create IP set for blocked devices -ipset create blocked_devices hash:ip -exist - -# Add devices to blocked list (can be managed dynamically) -ipset add blocked_devices 10.0.0.100 -exist -ipset add blocked_devices 10.0.0.101 -exist - -# Block internet access for devices in the set -iptables -I FORWARD -m set --match-set blocked_devices src -o eth1 -j REJECT -``` - -Apply: -```bash -/etc/init.d/firewall restart -``` - -**To add/remove devices from block list:** -```bash -# Block a device -ipset add blocked_devices 10.0.0.150 - -# Unblock a device -ipset del blocked_devices 10.0.0.150 - -# List blocked devices -ipset list blocked_devices -``` - -### 3.4 Method 3: Parental Controls Package (Easiest GUI) - -Install parental controls: -```bash -opkg update -opkg install luci-app-advanced-reboot -opkg install luci-app-simple-adblock # Optional, if not using AdGuard -``` - -For better device management, install: -```bash -opkg install luci-app-nlbwmon # Network bandwidth monitoring -``` - -This gives you per-device traffic monitoring and easier access control. - ---- - -## Part 4: AdGuard Home Setup (10.0.0.245) - -### 4.1 Installation Options - -**Option A: Docker (Recommended if you have Docker)** -```bash -docker run -d \ - --name adguardhome \ - --restart unless-stopped \ - -v /path/to/adguard/work:/opt/adguardhome/work \ - -v /path/to/adguard/conf:/opt/adguardhome/conf \ - -p 10.0.0.245:53:53/tcp \ - -p 10.0.0.245:53:53/udp \ - -p 10.0.0.245:3000:3000/tcp \ - adguard/adguardhome -``` - -**Option B: Native Linux Install** -```bash -curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v -``` - -**Option C: Windows** -Download from: https://github.com/AdguardTeam/AdGuardHome/releases - -### 4.2 Initial AdGuard Configuration - -1. **Access Setup:** `http://10.0.0.245:3000` - -2. **Setup Wizard:** - - Admin Web Interface: Port `3000` (or your choice) - - DNS Server: Port `53` - - Admin credentials: Set username and password - -3. **Configure Upstream DNS:** - - Navigate to Settings → DNS settings - - Add upstream DNS servers: - ``` - https://dns.cloudflare.com/dns-query - https://dns.google/dns-query - 1.1.1.1 - 8.8.8.8 - ``` - - Enable parallel queries for better performance - - Set rate limit: 20 (adjust based on needs) - -4. **Configure Private Reverse DNS:** - - Add your local network: `10.0.0.0/24` - - Enable "Use private reverse DNS resolvers" - -5. **Enable Query Logging:** - - Settings → General settings - - Query logs retention: 7 days (or your preference) - - Statistics retention: 90 days - -### 4.3 Blocklists Configuration - -Add recommended blocklists: - -1. Navigate to Filters → DNS blocklists -2. Add these lists: - -``` -# OISD Big List (comprehensive) -https://big.oisd.nl/ - -# AdGuard DNS filter -https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt - -# Steven Black's Unified Hosts -https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts - -# Hagezi's Pro DNS Blocklist -https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/pro-onlydomains.txt -``` - -3. Click "Save" and "Apply" - -### 4.4 Custom Filtering Rules - -For local network DNS resolution, add custom rules: - -1. Navigate to Filters → DNS rewrites -2. Add entries: - ``` - openwrt.local → 10.0.0.246 - adguard.local → 10.0.0.245 - homeassistant.local → 10.0.0.55 - router.local → 10.0.0.254 - ``` - ---- - -## Part 5: Integration and Testing - -### 5.1 Point OpenWRT to AdGuard - -Ensure OpenWRT is configured to use AdGuard: - -1. Network → Interfaces → LAN → Edit -2. Advanced Settings tab: - - Use custom DNS servers: `10.0.0.245` -3. Network → DHCP and DNS: - - DNS forwardings: `10.0.0.245` - -### 5.2 Testing DHCP - -1. **Connect a test device** to the OpenWRT network -2. **Check IP assignment:** - ```bash - # On Windows - ipconfig /all - - # On Linux - ip addr show - ``` -3. **Verify you receive:** - - IP in range 10.0.0.1-200 - - DNS server: 10.0.0.245 - - Gateway: 10.0.0.246 or 10.0.0.254 - -### 5.3 Testing DNS Resolution - -```bash -# On Windows -nslookup google.com 10.0.0.245 - -# On Linux -dig @10.0.0.245 google.com -``` - -### 5.4 Testing Access Control - -1. Add a device to block list -2. Try to access internet from that device -3. Verify connection is blocked -4. Check OpenWRT firewall logs: Status → Firewall - -### 5.5 Monitor AdGuard - -1. Access AdGuard dashboard: `http://10.0.0.245:3000` -2. Check: - - Query log shows requests - - Blocked requests are being filtered - - All devices are showing up - ---- - -## Part 6: Advanced Configuration - -### 6.1 Create Easy Device Management Script - -Save this script on OpenWRT as `/root/device-control.sh`: - -```bash -#!/bin/sh - -# Device Access Control Script for OpenWRT - -ACTION=$1 -DEVICE_IP=$2 -DEVICE_NAME=$3 - -case $ACTION in - block) - ipset add blocked_devices $DEVICE_IP -exist - echo "Blocked: $DEVICE_NAME ($DEVICE_IP)" - ;; - unblock) - ipset del blocked_devices $DEVICE_IP - echo "Unblocked: $DEVICE_NAME ($DEVICE_IP)" - ;; - list) - echo "Currently blocked devices:" - ipset list blocked_devices - ;; - status) - ipset test blocked_devices $DEVICE_IP && echo "$DEVICE_IP is BLOCKED" || echo "$DEVICE_IP is ALLOWED" - ;; - *) - echo "Usage: $0 {block|unblock|list|status} [IP] [NAME]" - exit 1 - ;; -esac -``` - -Make executable: -```bash -chmod +x /root/device-control.sh -``` - -Usage: -```bash -# Block a device -./device-control.sh block 10.0.0.100 "Kids Tablet" - -# Unblock -./device-control.sh unblock 10.0.0.100 "Kids Tablet" - -# List all blocked -./device-control.sh list - -# Check status -./device-control.sh status 10.0.0.100 -``` - -### 6.2 Setup Scheduled Device Controls (Optional) - -To block devices at specific times (e.g., bedtime): - -```bash -# Edit crontab -crontab -e -``` - -Add entries: -```cron -# Block kids devices at 9 PM -0 21 * * * /root/device-control.sh block 10.0.0.100 "Kids Tablet" - -# Unblock at 7 AM -0 7 * * * /root/device-control.sh unblock 10.0.0.100 "Kids Tablet" -``` - -### 6.3 Backup Configurations - -**OpenWRT Backup:** -1. System → Backup / Flash Firmware -2. Click "Generate archive" -3. Save the `.tar.gz` file - -**AdGuard Backup:** -1. Settings → General settings -2. Scroll to "Export settings" -3. Click "Download" to save YAML config - ---- - -## Part 7: Network Topology Options - -### Option A: OpenWRT as Router (Full Gateway) -``` -Internet → TPLink (10.0.0.254) → OpenWRT (10.0.0.246) → Devices - ↓ - AdGuard (10.0.0.245) -``` -- Requires routing configuration -- More complex but more control - -### Option B: OpenWRT as DHCP/Access Point (Recommended for your setup) -``` -Internet → TPLink (10.0.0.254) ← Gateway for all - ↓ - OpenWRT (10.0.0.246) - DHCP Server + Access Control - ↓ - AdGuard (10.0.0.245) - DNS Filtering - ↓ - Devices (10.0.0.1-200) -``` -- OpenWRT provides DHCP and access control -- TPLink remains gateway -- AdGuard handles DNS -- Simpler setup, which I've documented above - ---- - -## Troubleshooting - -### DHCP not working -```bash -# Check DHCP status -/etc/init.d/dnsmasq status - -# Restart DHCP -/etc/init.d/dnsmasq restart - -# Check logs -logread | grep -i dhcp -``` - -### DNS not resolving -```bash -# Test DNS on OpenWRT itself -nslookup google.com 10.0.0.245 - -# Check if AdGuard is running -# On AdGuard server -netstat -tulpn | grep :53 -``` - -### Access control not working -```bash -# Check firewall rules -iptables -L FORWARD -v -n - -# Check ipset -ipset list blocked_devices - -# Reload firewall -/etc/init.d/firewall restart -``` - -### Can't access OpenWRT web interface -```bash -# SSH in and check -netstat -tulpn | grep :80 - -# Restart web interface -/etc/init.d/uhttpd restart -``` - ---- - -## Quick Reference Commands - -```bash -# OpenWRT -/etc/init.d/network restart # Restart network -/etc/init.d/dnsmasq restart # Restart DHCP/DNS -/etc/init.d/firewall restart # Restart firewall -logread # View system logs - -# View DHCP leases -cat /tmp/dhcp.leases - -# View current connections -cat /proc/net/nf_conntrack - -# Monitor traffic -tcpdump -i br-lan port 53 # Monitor DNS traffic -``` - ---- - -## Next Steps - -1. **Set up OpenWRT first** with static IP 10.0.0.246 -2. **Configure DHCP** with your range and static leases -3. **Install and configure AdGuard** on 10.0.0.245 -4. **Point OpenWRT DNS** to AdGuard -5. **Set up access control** using one of the methods above -6. **Test thoroughly** with various devices -7. **Create backups** of both configurations - ---- - -## Security Recommendations - -1. **Change default passwords** on both OpenWRT and AdGuard -2. **Enable HTTPS** for OpenWRT web interface (System → Administration → HTTP(S) Access) -3. **Disable SSH password authentication**, use keys instead -4. **Keep OpenWRT updated**: System → Software → Update lists -5. **Enable AdGuard statistics** to monitor unusual activity -6. **Set up firewall rules** to prevent LAN → LAN attacks if needed -7. **Regular backups** of both configurations - ---- - -## Additional Resources - -- OpenWRT Documentation: https://openwrt.org/docs/start -- AdGuard Home Documentation: https://github.com/AdguardTeam/AdGuardHome/wiki -- OpenWRT Forum: https://forum.openwrt.org/ -- AdGuard Forum: https://forum.adguard.com/ +IyBPcGVuV1JUIEdhdGV3YXkgJiBBZEd1YXJkIEhvbWUgLSBDb21wbGV0ZSBDb25maWd1cmF0aW9uIEd1aWRlCgojIyBOZXR3b3JrIE92ZXJ2aWV3CgoqKk5ldyBOZXR3b3JrIFRvcG9sb2d5OioqCmBgYApDYWJsZSBNb2RlbSDihpIgT3BlbldSVCAoTWFpbiBHYXRld2F5KSDihpIgVFAtTGluayBBcmNoZXIgQzcyIFBybyAoQVAgTW9kZSkg4oaSIERldmljZXMKICAgICAgICAgICAgICAgICAgICDihpMKICAgICAgICAgICAgICBBZEd1YXJkIEhvbWUgKDEwLjAuMC4yNDUpIC0gRE5TIEZpbHRlcmluZwpgYGAKCioqSVAgQ29uZmlndXJhdGlvbjoqKgotIE9wZW5XUlQgV0FOOiBESENQIGZyb20gQ2FibGUgTW9kZW0gKFB1YmxpYyBJUCkKLSBPcGVuV1JUIExBTjogKioxMC4wLjAuMjQ2KiogKE1haW4gR2F0ZXdheSkKLSBBZEd1YXJkIEhvbWU6ICoqMTAuMC4wLjI0NSoqIChETlMgU2VydmVyKQotIFRQLUxpbmsgQXJjaGVyIEM3MiBQcm86ICoqMTAuMC4wLjI1NCoqIChBUCBNb2RlLCBubyByb3V0aW5nKQotIERIQ1AgUmFuZ2U6ICoqMTAuMC4wLjEgLSAxMC4wLjAuMjAwKioKLSBTdWJuZXQ6ICoqMTAuMC4wLjAvMjQqKgoKKipSb2xlczoqKgotICoqT3BlbldSVCoqOiBNYWluIHJvdXRlciwgZ2F0ZXdheSwgZmlyZXdhbGwsIE5BVCwgREhDUCBzZXJ2ZXIsIGFjY2VzcyBjb250cm9sCi0gKipBZEd1YXJkKio6IEROUyBmaWx0ZXJpbmcsIGFkIGJsb2NraW5nLCBwaGlzaGluZyBwcm90ZWN0aW9uLCBwYXJlbnRhbCBjb250cm9scwotICoqVFAtTGluayoqOiBXaUZpIGFjY2VzcyBwb2ludCArIEV0aGVybmV0IHN3aXRjaCBvbmx5IChubyByb3V0aW5nL0RIQ1ApCgotLS0KCiMjIFBhcnQgMTogT3BlbldSVCBJbml0aWFsIFNldHVwIGFzIE1haW4gR2F0ZXdheQoKIyMjIDEuMSBQaHlzaWNhbCBDb25uZWN0aW9uIFNldHVwCgoqKkNvbm5lY3Rpb24gT3JkZXI6KioKMS4gKipETyBOT1QgY29ubmVjdCBjYWJsZSBtb2RlbSB5ZXQqKgoyLiBDb25uZWN0IGNvbXB1dGVyIHRvIE9wZW5XUlQgTEFOIHBvcnQgdmlhIEV0aGVybmV0CjMuIFBvd2VyIG9uIE9wZW5XUlQKNC4gQ29uZmlndXJlIE9wZW5XUlQgY29tcGxldGVseSBmaXJzdAo1LiBUaGVuIGNvbm5lY3QgdG8gY2FibGUgbW9kZW0KCiMjIyAxLjIgRmlyc3QgTG9naW4gYW5kIEJhc2ljIENvbmZpZ3VyYXRpb24KCjEuICoqQ29ubmVjdCB0byBPcGVuV1JUOioqCiAgIC0gQ29ubmVjdCB2aWEgRXRoZXJuZXQgdG8gYW55IExBTiBwb3J0CiAgIC0gRGVmYXVsdCBJUDogYDE5Mi4xNjguMS4xYAogICAtIEFjY2VzcyB2aWEgYnJvd3NlcjogYGh0dHA6Ly8xOTIuMTY4LjEuMWAKICAgLSBEZWZhdWx0IGxvZ2luOiBgcm9vdGAgKG5vIHBhc3N3b3JkIGluaXRpYWxseSkKCjIuICoqU2V0IFJvb3QgUGFzc3dvcmQ6KioKICAgYGBgCiAgIFN5c3RlbSDihpIgQWRtaW5pc3RyYXRpb24g4oaSIFJvdXRlciBQYXNzd29yZAogICBgYGAKICAgU2V0IGEgc3Ryb25nIHBhc3N3b3JkIGltbWVkaWF0ZWx5IChlLmcuLCAxNisgY2hhcmFjdGVycyB3aXRoIG51bWJlcnMvc3ltYm9scykuCgozLiAqKlNldCBUaW1lem9uZToqKgogICBgYGAKICAgU3lzdGVtIOKGkiBTeXN0ZW0g4oaSIEdlbmVyYWwgU2V0dGluZ3MKICAgVGltZXpvbmU6IEF1c3RyYWxpYS9NZWxib3VybmUKICAgYGBgCgojIyMgMS4zIENvbmZpZ3VyZSBXQU4gSW50ZXJmYWNlIChJbnRlcm5ldCBDb25uZWN0aW9uKQoKKipUaGlzIGNvbm5lY3RzIE9wZW5XUlQgdG8geW91ciBjYWJsZSBtb2RlbS4qKgoKMS4gKipOYXZpZ2F0ZSB0byBOZXR3b3JrIOKGkiBJbnRlcmZhY2VzKioKCjIuICoqRWRpdCBXQU4gaW50ZXJmYWNlOioqCiAgIC0gUHJvdG9jb2w6IGBESENQIGNsaWVudGAgKG1vc3QgY2FibGUgbW9kZW1zIHVzZSBESENQKQogICAtIExlYXZlIGV2ZXJ5dGhpbmcgZGVmYXVsdCBpbml0aWFsbHkKICAgLSBBZHZhbmNlZCBTZXR0aW5nczoKICAgICAtIOKckyBVc2UgRE5TIHNlcnZlcnMgYWR2ZXJ0aXNlZCBieSBwZWVyICh3ZSdsbCBjaGFuZ2UgdGhpcyBsYXRlcikKICAgLSBGaXJld2FsbCBTZXR0aW5nczoKICAgICAtIENyZWF0ZS9Bc3NpZ24gdG8gZmlyZXdhbGwgem9uZTogYHdhbmAKICAgLSBDbGljayAiU2F2ZSIKCjMuICoqSWYgeW91ciBJU1AgcmVxdWlyZXMgc3BlY2lmaWMgc2V0dGluZ3M6KioKICAgLSBTb21lIElTUHMgcmVxdWlyZToKICAgICAtIE1BQyBhZGRyZXNzIGNsb25pbmcgKHVzZSB5b3VyIG9sZCByb3V0ZXIncyBNQUMpCiAgICAgLSBWTEFOIHRhZ2dpbmcKICAgICAtIFBQUG9FICh1c2VybmFtZS9wYXNzd29yZCkKICAgLSBDaGVjayB3aXRoIHlvdXIgSVNQIGlmIGNvbm5lY3Rpb24gZmFpbHMKCiMjIyAxLjQgQ29uZmlndXJlIExBTiBJbnRlcmZhY2UKCjEuICoqTmF2aWdhdGUgdG8gTmV0d29yayDihpIgSW50ZXJmYWNlcyoqCgoyLiAqKkVkaXQgTEFOIGludGVyZmFjZToqKgogICAtIFByb3RvY29sOiBgU3RhdGljIGFkZHJlc3NgCiAgIC0gSVB2NCBhZGRyZXNzOiBgMTAuMC4wLjI0NmAKICAgLSBJUHY0IG5ldG1hc2s6IGAyNTUuMjU1LjI1NS4wYCAob3IgLzI0KQogICAtIElQdjQgZ2F0ZXdheTogKGxlYXZlIGVtcHR5IC0gdGhpcyBJUyB0aGUgZ2F0ZXdheSkKICAgLSBVc2UgY3VzdG9tIEROUyBzZXJ2ZXJzOiBgMTAuMC4wLjI0NWAKICAgLSBDbGljayAiU2F2ZSAmIEFwcGx5IgoKMy4gKipXYWl0IDMwIHNlY29uZHMqKiwgdGhlbiByZWNvbm5lY3QgdG86IGBodHRwOi8vMTAuMC4wLjI0NmAKCiMjIyAxLjUgQ29uZmlndXJlIEZpcmV3YWxsICYgTkFUCgoxLiAqKk5ldHdvcmsg4oaSIEZpcmV3YWxsIOKGkiBHZW5lcmFsIFNldHRpbmdzKioKCjIuICoqWm9uZTogV0FOKioKICAgLSBJbnB1dDogYHJlamVjdGAKICAgLSBPdXRwdXQ6IGBhY2NlcHRgCiAgIC0gRm9yd2FyZDogYHJlamVjdGAKICAgLSDinJMgTWFzcXVlcmFkaW5nIChOQVQpIC0gKipDUklUSUNBTCoqCiAgIC0g4pyTIE1TUyBjbGFtcGluZwogICAtIENvdmVyZWQgbmV0d29ya3M6IGB3YW5gIGB3YW42YAoKMy4gKipab25lOiBMQU4qKgogICAtIElucHV0OiBgYWNjZXB0YAogICAtIE91dHB1dDogYGFjY2VwdGAKICAgLSBGb3J3YXJkOiBgYWNjZXB0YAogICAtIE1hc3F1ZXJhZGluZzogdW5jaGVja2VkCiAgIC0gQ292ZXJlZCBuZXR3b3JrczogYGxhbmAKCjQuICoqRm9yd2FyZGluZyBSdWxlczoqKgogICAtIEFkZDogTEFOIOKGkiBXQU4gKEFsbG93KSAtIHNob3VsZCBleGlzdCBieSBkZWZhdWx0CiAgIC0gVmVyaWZ5IHRoaXMgcnVsZSBleGlzdHMKCjUuICoqQWR2YW5jZWQgU2V0dGluZ3M6KioKICAgYGBgCiAgIEVuYWJsZSBTWU4tZmxvb2QgcHJvdGVjdGlvbjog4pyTCiAgIERyb3AgaW52YWxpZCBwYWNrZXRzOiDinJMKICAgYGBgCgo2LiAqKlNhdmUgJiBBcHBseSoqCgojIyMgMS42IFRlc3QgSW50ZXJuZXQgQ29ubmVjdGlvbgoKKipOb3cgY29ubmVjdCB0aGUgY2FibGUgbW9kZW06KioKCjEuICoqQ29ubmVjdCBjYWJsZSBtb2RlbSB0byBPcGVuV1JUIFdBTiBwb3J0KioKMi4gKipXYWl0IDYwIHNlY29uZHMqKiBmb3IgbW9kZW0gdG8gYXNzaWduIElQCjMuICoqQ2hlY2sgY29ubmVjdGlvbjoqKgogICBgYGAKICAgTmV0d29yayDihpIgSW50ZXJmYWNlcyDihpIgV0FOCiAgIGBgYAogICAtIFNob3VsZCBzaG93IHB1YmxpYyBJUCBhZGRyZXNzCiAgIC0gU2hvdWxkIHNob3cgIkNvbm5lY3RlZCIgc3RhdHVzCgo0LiAqKlRlc3QgZnJvbSBPcGVuV1JUOioqCiAgIC0gR28gdG8gTmV0d29yayDihpIgRGlhZ25vc3RpY3MKICAgLSBQaW5nIHRlc3Q6IGA4LjguOC44YCAoc2hvdWxkIHdvcmspCiAgIC0gUGluZyB0ZXN0OiBgZ29vZ2xlLmNvbWAgKHNob3VsZCB3b3JrKQoKNS4gKipJZiBjb25uZWN0aW9uIGZhaWxzOioqCiAgIC0gQ2hlY2sgY2FibGUgbW9kZW0gaXMgb25saW5lIChsaWdodHMgc3RhYmxlKQogICAtIFRyeSByZWJvb3RpbmcgY2FibGUgbW9kZW0gKHVucGx1ZyAzMCBzZWNvbmRzKQogICAtIENoZWNrIFdBTiBpbnRlcmZhY2Ugc2V0dGluZ3MKICAgLSBTb21lIElTUHMgcmVxdWlyZSBNQUMgY2xvbmluZyAoc2VlIFNlY3Rpb24gMS45KQoKIyMjIDEuNyBVcGRhdGUgT3BlbldSVAoKKipCZWZvcmUgY29udGludWluZywgdXBkYXRlIHBhY2thZ2VzOioqCgpTU0ggaW50byBPcGVuV1JUOgpgYGBiYXNoCnNzaCByb290QDEwLjAuMC4yNDYKYGBgCgpVcGRhdGUgcGFja2FnZSBsaXN0czoKYGBgYmFzaApvcGtnIHVwZGF0ZQpvcGtnIGxpc3QtdXBncmFkYWJsZQpvcGtnIHVwZ3JhZGUgW3BhY2thZ2UtbmFtZV0KYGBgCgpPciB1cGRhdGUgYWxsIChiZSBjYXJlZnVsLCB0ZXN0IGZpcnN0KToKYGBgYmFzaApvcGtnIGxpc3QtdXBncmFkYWJsZSB8IGN1dCAtZCAnICcgLWYgMSB8IHhhcmdzIG9wa2cgdXBncmFkZQpgYGAKCiMjIyAxLjggSW5zdGFsbCBFc3NlbnRpYWwgUGFja2FnZXMKCmBgYGJhc2gKIyBGaXJld2FsbCBhbmQgbmV0d29yayB0b29scwpvcGtnIGluc3RhbGwgbHVjaS1hcHAtZmlyZXdhbGwKb3BrZyBpbnN0YWxsIGlwdGFibGVzLW1vZC1leHRyYQpvcGtnIGluc3RhbGwgaXBzZXQKCiMgTW9uaXRvcmluZyB0b29scwpvcGtnIGluc3RhbGwgbHVjaS1hcHAtbmxid21vbiAgICAjIEJhbmR3aWR0aCBtb25pdG9yaW5nCm9wa2cgaW5zdGFsbCBsdWNpLWFwcC1zdGF0aXN0aWNzICAjIFN5c3RlbSBzdGF0cwoKIyBIVFRQUyBmb3Igd2ViIGludGVyZmFjZSAocmVjb21tZW5kZWQpCm9wa2cgaW5zdGFsbCBsdWNpLXNzbC1vcGVuc3NsCgojIEFkZGl0aW9uYWwgdXNlZnVsIHRvb2xzCm9wa2cgaW5zdGFsbCB0Y3BkdW1wICAgICAgICAgICAgICAjIE5ldHdvcmsgZGVidWdnaW5nCm9wa2cgaW5zdGFsbCBpcGVyZjMgICAgICAgICAgICAgICMgU3BlZWQgdGVzdGluZwpgYGAKCiMjIyAxLjkgTUFDIEFkZHJlc3MgQ2xvbmluZyAoSWYgUmVxdWlyZWQpCgpTb21lIElTUHMgYmluZCB0byB5b3VyIHByZXZpb3VzIHJvdXRlcidzIE1BQyBhZGRyZXNzLgoKMS4gKipGaW5kIHlvdXIgb2xkIHJvdXRlcidzIFdBTiBNQUMgYWRkcmVzcyoqCiAgIC0gVXN1YWxseSBvbiBhIHN0aWNrZXIgb24gdGhlIFRQLUxpbmsKICAgLSBPciBmcm9tIFRQLUxpbmsgYWRtaW4gaW50ZXJmYWNlCgoyLiAqKkNsb25lIE1BQyBpbiBPcGVuV1JUOioqCiAgIGBgYAogICBOZXR3b3JrIOKGkiBJbnRlcmZhY2VzIOKGkiBXQU4g4oaSIEVkaXQKICAgQWR2YW5jZWQgU2V0dGluZ3M6CiAgIC0gT3ZlcnJpZGUgTUFDIGFkZHJlc3M6IFtlbnRlciBvbGQgcm91dGVyJ3MgTUFDXQogICBTYXZlICYgQXBwbHkKICAgYGBgCgozLiAqKlJlYm9vdCBjYWJsZSBtb2RlbSBhbmQgT3BlbldSVCoqCgotLS0KCiMjIFBhcnQgMjogREhDUCBTZXJ2ZXIgQ29uZmlndXJhdGlvbgoKIyMjIDIuMSBCYXNpYyBESENQIFNldHRpbmdzCgoxLiAqKk5hdmlnYXRlIHRvIE5ldHdvcmsg4oaSIERIQ1AgYW5kIEROUyoqCgoyLiAqKkdlbmVyYWwgU2V0dGluZ3MgdGFiOioqCiAgIC0g4pyTIEF1dGhvcml0YXRpdmUgKE9wZW5XUlQgaXMgbm93IHRoZSBvbmx5IERIQ1Agc2VydmVyKQogICAtIEROUyBmb3J3YXJkaW5nczogYDEwLjAuMC4yNDVgCiAgIC0gRE5TIHNlcnZlciBwb3J0OiBgNTNgCiAgIC0gTG9jYWwgc2VydmVyOiBgL2xhbi9gCiAgIC0gTG9jYWwgZG9tYWluOiBgbGFuYCAob3IgeW91ciBwcmVmZXJlbmNlIGxpa2UgYGhvbWUubG9jYWxgKQogICAtIENsaWNrICJTYXZlIgoKMy4gKipBZHZhbmNlZCBTZXR0aW5nczoqKgogICAtIFJlYmluZCBwcm90ZWN0aW9uOiDinJMKICAgLSBEb21haW4gd2hpdGVsaXN0OiAobGVhdmUgZW1wdHkgdW5sZXNzIG5lZWRlZCkKICAgLSBTdHJpY3Qgb3JkZXI6IOKckyAodXNlcyBETlMgc2VydmVycyBpbiBvcmRlcikKCiMjIyAyLjIgREhDUCBQb29sIENvbmZpZ3VyYXRpb24KCjEuICoqTmV0d29yayDihpIgSW50ZXJmYWNlcyDihpIgTEFOIOKGkiBFZGl0IOKGkiBESENQIFNlcnZlciB0YWIqKgoKMi4gKipHZW5lcmFsIFNldHVwOioqCiAgIC0g4pyTIElnbm9yZSBpbnRlcmZhY2U6IFVuY2hlY2sgKGVuYWJsZSBESENQKQogICAtIFN0YXJ0OiBgMWAKICAgLSBMaW1pdDogYDIwMGAKICAgLSBMZWFzZSB0aW1lOiBgMTJoYCAob3IgYDI0aGAgZm9yIHN0YWJpbGl0eSkKCjMuICoqQWR2YW5jZWQgU2V0dGluZ3M6KioKICAgLSBEeW5hbWljIERIQ1A6IOKckwogICAtIEZvcmNlOiDinJMgKHByZXZlbnRzIGRldmljZXMgZnJvbSB1c2luZyBzdGF0aWMgSVBzIGluIERIQ1AgcmFuZ2UpCgo0LiAqKkRIQ1AgT3B0aW9uczoqKgogICAtIEFkZCBvcHRpb24gYDMsMTAuMC4wLjI0NmAgKEdhdGV3YXkgLSBzaG91bGQgYmUgZGVmYXVsdCkKICAgLSBBZGQgb3B0aW9uIGA2LDEwLjAuMC4yNDVgIChETlMgU2VydmVyKQogICAtIEFkZCBvcHRpb24gYDQyLDEwLjAuMC4yNDVgIChOVFAgU2VydmVyIC0gb3B0aW9uYWwpCgojIyMgMi4zIFN0YXRpYyBMZWFzZXMgQ29uZmlndXJhdGlvbgoKMS4gKipOYXZpZ2F0ZSB0byBOZXR3b3JrIOKGkiBESENQIGFuZCBETlMg4oaSIFN0YXRpYyBMZWFzZXMqKgoKMi4gKipBZGQgQ3JpdGljYWwgU3RhdGljIExlYXNlczoqKgoKKipBZEd1YXJkIEhvbWU6KioKYGBgCkhvc3RuYW1lOiBhZGd1YXJkCk1BQyBBZGRyZXNzOiBbQWRHdWFyZCBzZXJ2ZXIgTUFDXQpJUHY0IGFkZHJlc3M6IDEwLjAuMC4yNDUKTGVhc2UgdGltZTogaW5maW5pdGUKYGBgCgoqKlRQLUxpbmsgQXJjaGVyIEM3MiBQcm86KioKYGBgCkhvc3RuYW1lOiB0cGxpbmstYXAKTUFDIEFkZHJlc3M6IFtUUC1MaW5rIFdBTi9MQU4gTUFDXQpJUHY0IGFkZHJlc3M6IDEwLjAuMC4yNTQKTGVhc2UgdGltZTogaW5maW5pdGUKYGBgCgoqKkhvbWVBc3Npc3RhbnQgKGlmIGFwcGxpY2FibGUpOioqCmBgYApIb3N0bmFtZTogaG9tZWFzc2lzdGFudApNQUMgQWRkcmVzczogW0hBIE1BQ10KSVB2NCBhZGRyZXNzOiAxMC4wLjAuNTUKTGVhc2UgdGltZTogaW5maW5pdGUKYGBgCgoqKk90aGVyIHNlcnZlcnMvZGV2aWNlczoqKgpgYGAKTkFTOiAxMC4wLjAuNjAKUHJpbnRlcjogMTAuMC4wLjcwCkRlc2t0b3A6IDEwLjAuMC4xMDEKTGFwdG9wOiAxMC4wLjAuMTAyCmBgYAoKIyMjIDIuNCBQZXItRGV2aWNlIEROUyBDb25maWd1cmF0aW9uIChGb3IgUGFyZW50YWwgQ29udHJvbHMpCgoqKk1ldGhvZDogVmlhIENvbmZpZyBGaWxlKioKClNTSCBpbnRvIE9wZW5XUlQgYW5kIGVkaXQgYC9ldGMvY29uZmlnL2RoY3BgOgoKYGBgYmFzaAp2aSAvZXRjL2NvbmZpZy9kaGNwCmBgYAoKQWRkIGhvc3QgY29uZmlndXJhdGlvbnM6CgpgYGBiYXNoCiMgU3RhbmRhcmQgYWR1bHQgZGV2aWNlIC0gdXNlcyBBZEd1YXJkIHdpdGggZnVsbCBmaWx0ZXJpbmcKY29uZmlnIGhvc3QKICAgIG9wdGlvbiBuYW1lICdsYXB0b3AnCiAgICBvcHRpb24gbWFjICcxMToyMjozMzo0NDo1NTo2NicKICAgIG9wdGlvbiBpcCAnMTAuMC4wLjEwMScKICAgIG9wdGlvbiBkbnMgJzEwLjAuMC4yNDUnCgojIEtpZHMgZGV2aWNlIC0gdXNlcyBBZEd1YXJkIHdpdGggcGFyZW50YWwgY29udHJvbHMKY29uZmlnIGhvc3QKICAgIG9wdGlvbiBuYW1lICdraWRzLXRhYmxldCcKICAgIG9wdGlvbiBtYWMgJ0FBOkJCOkNDOkREOkVFOkZGJwogICAgb3B0aW9uIGlwICcxMC4wLjAuMTAwJwogICAgb3B0aW9uIGRucyAnMTAuMC4wLjI0NScKICAgIG9wdGlvbiB0YWcgJ2tpZHMnCgojIFdvcmsvdW5maWx0ZXJlZCBkZXZpY2UgLSBieXBhc3NlcyBBZEd1YXJkCmNvbmZpZyBob3N0CiAgICBvcHRpb24gbmFtZSAnd29yay1sYXB0b3AnCiAgICBvcHRpb24gbWFjICc3Nzo4ODo5OTpBQTpCQjpDQycKICAgIG9wdGlvbiBpcCAnMTAuMC4wLjE1MCcKICAgIG9wdGlvbiBkbnMgJzEuMS4xLjEgOC44LjguOCcKYGBgCgpSZXN0YXJ0IGRuc21hc3E6CmBgYGJhc2gKL2V0Yy9pbml0LmQvZG5zbWFzcSByZXN0YXJ0CmBgYAoKKipOb3RlOioqIFdlJ2xsIGNvbmZpZ3VyZSBBZEd1YXJkIHRvIGhhbmRsZSBkaWZmZXJlbnQgZmlsdGVyaW5nIGxldmVscyBmb3Iga2lkcyB2cyBhZHVsdHMgaW4gUGFydCA1LgoKLS0tCgojIyBQYXJ0IDM6IEFjY2VzcyBDb250cm9sICYgRGV2aWNlIEJsb2NraW5nCgojIyMgMy4xIENyZWF0ZSBEZXZpY2UgQmxvY2tpbmcgU3lzdGVtCgpUaGlzIGFsbG93cyB5b3UgdG8gYmxvY2sgaW50ZXJuZXQgYWNjZXNzIGZvciBzcGVjaWZpYyBkZXZpY2VzLgoKKipDcmVhdGUgdGhlIG1hbmFnZW1lbnQgc2NyaXB0KiogYC9yb290L2RldmljZS1jb250cm9sLnNoYDoKCmBgYGJhc2gKIyEvYmluL3NoCiMgRGV2aWNlIEFjY2VzcyBDb250cm9sIFNjcmlwdCBmb3IgT3BlbldSVAojIFVzYWdlOiAuL2RldmljZS1jb250cm9sLnNoIHtpbml0fGJsb2NrfHVuYmxvY2t8bGlzdHxzdGF0dXN8bG9nfGNsZWFyfGhlbHB9CgpJUFNFVF9OQU1FPSJibG9ja2VkX2RldmljZXMiCkxPR19GSUxFPSIvdmFyL2xvZy9kZXZpY2UtY29udHJvbC5sb2ciCgppbml0X3N5c3RlbSgpIHsKICAgIGVjaG8gIkluaXRpYWxpemluZyBkZXZpY2UgYmxvY2tpbmcgc3lzdGVtLi4uIgogICAgCiAgICAjIENyZWF0ZSBpcHNldCBpZiBpdCBkb2Vzbid0IGV4aXN0CiAgICBpcHNldCBjcmVhdGUgJElQU0VUX05BTUUgaGFzaDppcCB0aW1lb3V0IDAgY29tbWVudCAtZXhpc3QKICAgIAogICAgIyBDcmVhdGUgZmlyZXdhbGwgcnVsZSBpZiBpdCBkb2Vzbid0IGV4aXN0CiAgICBpZiAhIGlwdGFibGVzIC1DIEZPUldBUkQgLW0gc2V0IC0tbWF0Y2gtc2V0ICRJUFNFVF9OQU1FIHNyYyAtaiBSRUpFQ1QgMj4vZGV2L251bGw7IHRoZW4KICAgICAgICBpcHRhYmxlcyAtSSBGT1JXQVJEIDEgLW0gc2V0IC0tbWF0Y2gtc2V0ICRJUFNFVF9OQU1FIHNyYyAtaiBSRUpFQ1QKICAgICAgICBlY2hvICJGaXJld2FsbCBydWxlIGNyZWF0ZWQiCiAgICBlbHNlCiAgICAgICAgZWNobyAiRmlyZXdhbGwgcnVsZSBhbHJlYWR5IGV4aXN0cyIKICAgIGZpCiAgICAKICAgIGVjaG8gIlN5c3RlbSBpbml0aWFsaXplZCBzdWNjZXNzZnVsbHkiCiAgICBlY2hvICIkKGRhdGUpOiBTeXN0ZW0gaW5pdGlhbGl6ZWQiID4+ICRMT0dfRklMRQp9CgpibG9ja19kZXZpY2UoKSB7CiAgICBJUD0kMQogICAgTkFNRT0kMgogICAgCiAgICBpZiBbIC16ICIkSVAiIF07IHRoZW4KICAgICAgICBlY2hvICJFcnJvcjogSVAgYWRkcmVzcyByZXF1aXJlZCIKICAgICAgICBlY2hvICJVc2FnZTogJDAgYmxvY2sgPElQPiBbTkFNRV0iCiAgICAgICAgZXhpdCAxCiAgICBmaQogICAgCiAgICAjIEFkZCB0byBpcHNldCB3aXRoIGNvbW1lbnQKICAgIGlmIFsgLW4gIiROQU1FIiBdOyB0aGVuCiAgICAgICAgaXBzZXQgYWRkICRJUFNFVF9OQU1FICRJUCBjb21tZW50ICIkTkFNRSIgLWV4aXN0CiAgICAgICAgZWNobyAi4pyTIEJsb2NrZWQ6ICROQU1FICgkSVApIgogICAgICAgIGVjaG8gIiQoZGF0ZSk6IEJsb2NrZWQgJE5BTUUgKCRJUCkiID4+ICRMT0dfRklMRQogICAgZWxzZQogICAgICAgIGlwc2V0IGFkZCAkSVBTRVRfTkFNRSAkSVAgLWV4aXN0CiAgICAgICAgZWNobyAi4pyTIEJsb2NrZWQ6ICRJUCIKICAgICAgICBlY2hvICIkKGRhdGUpOiBCbG9ja2VkICRJUCIgPj4gJExPR19GSUxFCiAgICBmaQp9Cgp1bmJsb2NrX2RldmljZSgpIHsKICAgIElQPSQxCiAgICBOQU1FPSQyCiAgICAKICAgIGlmIFsgLXogIiRJUCIgXTsgdGhlbgogICAgICAgIGVjaG8gIkVycm9yOiBJUCBhZGRyZXNzIHJlcXVpcmVkIgogICAgICAgIGVjaG8gIlVzYWdlOiAkMCB1bmJsb2NrIDxJUD4gW05BTUVdIgogICAgICAgIGV4aXQgMQogICAgZmkKICAgIAogICAgIyBSZW1vdmUgZnJvbSBpcHNldAogICAgaWYgaXBzZXQgdGVzdCAkSVBTRVRfTkFNRSAkSVAgMj4vZGV2L251bGw7IHRoZW4KICAgICAgICBpcHNldCBkZWwgJElQU0VUX05BTUUgJElQCiAgICAgICAgaWYgWyAtbiAiJE5BTUUiIF07IHRoZW4KICAgICAgICAgICAgZWNobyAi4pyTIFVuYmxvY2tlZDogJE5BTUUgKCRJUCkiCiAgICAgICAgICAgIGVjaG8gIiQoZGF0ZSk6IFVuYmxvY2tlZCAkTkFNRSAoJElQKSIgPj4gJExPR19GSUxFCiAgICAgICAgZWxzZQogICAgICAgICAgICBlY2hvICLinJMgVW5ibG9ja2VkOiAkSVAiCiAgICAgICAgICAgIGVjaG8gIiQoZGF0ZSk6IFVuYmxvY2tlZCAkSVAiID4+ICRMT0dfRklMRQogICAgICAgIGZpCiAgICBlbHNlCiAgICAgICAgZWNobyAi4pyXIERldmljZSAkSVAgd2FzIG5vdCBibG9ja2VkIgogICAgZmkKfQoKbGlzdF9kZXZpY2VzKCkgewogICAgZWNobyAiPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IgogICAgZWNobyAiQ3VycmVudGx5IEJsb2NrZWQgRGV2aWNlczoiCiAgICBlY2hvICI9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0iCiAgICBpcHNldCBsaXN0ICRJUFNFVF9OQU1FIHwgZ3JlcCAtQSAxMDAwICJNZW1iZXJzOiIgfCB0YWlsIC1uICsyCiAgICBDT1VOVD0kKGlwc2V0IGxpc3QgJElQU0VUX05BTUUgfCBncmVwIC1BIDEwMDAgIk1lbWJlcnM6IiB8IHRhaWwgLW4gKzIgfCB3YyAtbCkKICAgIGVjaG8gIj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSIKICAgIGVjaG8gIlRvdGFsIGJsb2NrZWQ6ICRDT1VOVCBkZXZpY2UocykiCn0KCmNoZWNrX3N0YXR1cygpIHsKICAgIElQPSQxCiAgICAKICAgIGlmIFsgLXogIiRJUCIgXTsgdGhlbgogICAgICAgIGVjaG8gIkVycm9yOiBJUCBhZGRyZXNzIHJlcXVpcmVkIgogICAgICAgIGVjaG8gIlVzYWdlOiAkMCBzdGF0dXMgPElQPiIKICAgICAgICBleGl0IDEKICAgIGZpCiAgICAKICAgIGlmIGlwc2V0IHRlc3QgJElQU0VUX05BTUUgJElQIDI+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgZWNobyAi8J+UtCAkSVAgaXMgQkxPQ0tFRCIKICAgIGVsc2UKICAgICAgICBlY2hvICLwn5+iICRJUCBpcyBBTExPV0VEIgogICAgZmkKfQoKdmlld19sb2coKSB7CiAgICBpZiBbIC1mICIkTE9HX0ZJTEUiIF07IHRoZW4KICAgICAgICBlY2hvICI9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0iCiAgICAgICAgZWNobyAiTGFzdCA1MCBBY3Rpb25zOiIKICAgICAgICBlY2hvICI9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0iCiAgICAgICAgdGFpbCAtNTAgJExPR19GSUxFCiAgICBlbHNlCiAgICAgICAgZWNobyAiTm8gbG9nIGZpbGUgZm91bmQiCiAgICBmaQp9CgpjbGVhcl9hbGwoKSB7CiAgICBlY2hvICLimqDvuI8gIFdBUk5JTkc6IFRoaXMgd2lsbCB1bmJsb2NrIEFMTCBkZXZpY2VzISIKICAgIGVjaG8gLW4gIkFyZSB5b3Ugc3VyZT8gKHllcy9ubyk6ICIKICAgIHJlYWQgQ09ORklSTQogICAgCiAgICBpZiBbICIkQ09ORklSTSIgPSAieWVzIiBdOyB0aGVuCiAgICAgICAgaXBzZXQgZmx1c2ggJElQU0VUX05BTUUKICAgICAgICBlY2hvICLinJMgQWxsIGRldmljZXMgdW5ibG9ja2VkIgogICAgICAgIGVjaG8gIiQoZGF0ZSk6IEFsbCBkZXZpY2VzIHVuYmxvY2tlZCIgPj4gJExPR19GSUxFCiAgICBlbHNlCiAgICAgICAgZWNobyAiQ2FuY2VsbGVkIgogICAgZmkKfQoKc2hvd19oZWxwKCkgewogICAgY2F0IDw8IEVPRgpEZXZpY2UgQWNjZXNzIENvbnRyb2wgU2NyaXB0CgpVc2FnZToKICAkMCBpbml0ICAgICAgICAgICAgICAgICAgICAtIEluaXRpYWxpemUgYmxvY2tpbmcgc3lzdGVtCiAgJDAgYmxvY2sgPElQPiBbTkFNRV0gICAgICAgLSBCbG9jayBhIGRldmljZQogICQwIHVuYmxvY2sgPElQPiBbTkFNRV0gICAgIC0gVW5ibG9jayBhIGRldmljZQogICQwIGxpc3QgICAgICAgICAgICAgICAgICAgIC0gTGlzdCBhbGwgYmxvY2tlZCBkZXZpY2VzCiAgJDAgc3RhdHVzIDxJUD4gICAgICAgICAgICAgLSBDaGVjayBpZiBkZXZpY2UgaXMgYmxvY2tlZAogICQwIGxvZyAgICAgICAgICAgICAgICAgICAgIC0gVmlldyBhY3Rpb24gbG9nCiAgJDAgY2xlYXIgICAgICAgICAgICAgICAgICAgLSBDbGVhciBhbGwgYmxvY2tzICh3aXRoIGNvbmZpcm1hdGlvbikKICAkMCBoZWxwICAgICAgICAgICAgICAgICAgICAtIFNob3cgdGhpcyBoZWxwCgpFeGFtcGxlczoKICAkMCBibG9jayAxMC4wLjAuMTAwICJLaWRzIFRhYmxldCIKICAkMCB1bmJsb2NrIDEwLjAuMC4xMDAKICAkMCBzdGF0dXMgMTAuMC4wLjEwMAogICQwIGxpc3QKCkVPRgp9CgojIE1haW4gc2NyaXB0IGxvZ2ljCmNhc2UgIiQxIiBpbgogICAgaW5pdCkKICAgICAgICBpbml0X3N5c3RlbQogICAgICAgIDs7CiAgICBibG9jaykKICAgICAgICBibG9ja19kZXZpY2UgIiQyIiAiJDMiCiAgICAgICAgOzsKICAgIHVuYmxvY2spCiAgICAgICAgdW5ibG9ja19kZXZpY2UgIiQyIiAiJDMiCiAgICAgICAgOzsKICAgIGxpc3QpCiAgICAgICAgbGlzdF9kZXZpY2VzCiAgICAgICAgOzsKICAgIHN0YXR1cykKICAgICAgICBjaGVja19zdGF0dXMgIiQyIgogICAgICAgIDs7CiAgICBsb2cpCiAgICAgICAgdmlld19sb2cKICAgICAgICA7OwogICAgY2xlYXIpCiAgICAgICAgY2xlYXJfYWxsCiAgICAgICAgOzsKICAgIGhlbHB8LS1oZWxwfC1oKQogICAgICAgIHNob3dfaGVscAogICAgICAgIDs7CiAgICAqKQogICAgICAgIGVjaG8gIkVycm9yOiBJbnZhbGlkIGNvbW1hbmQiCiAgICAgICAgc2hvd19oZWxwCiAgICAgICAgZXhpdCAxCiAgICAgICAgOzsKZXNhYwpgYGAKCioqSW5zdGFsbCB0aGUgc2NyaXB0OioqCgpgYGBiYXNoCiMgU1NIIGludG8gT3BlbldSVApzc2ggcm9vdEAxMC4wLjAuMjQ2CgojIENyZWF0ZSB0aGUgc2NyaXB0CnZpIC9yb290L2RldmljZS1jb250cm9sLnNoCiMgUGFzdGUgdGhlIGNvbnRlbnQgYWJvdmUKCiMgTWFrZSBleGVjdXRhYmxlCmNobW9kICt4IC9yb290L2RldmljZS1jb250cm9sLnNoCgojIEluaXRpYWxpemUgdGhlIHN5c3RlbQovcm9vdC9kZXZpY2UtY29udHJvbC5zaCBpbml0CmBgYAoKIyMjIDMuMiBNYWtlIEJsb2NraW5nIFBlcnNpc3RlbnQKCkFkZCB0byBgL2V0Yy9maXJld2FsbC51c2VyYCB0byBzdXJ2aXZlIHJlYm9vdHM6CgpgYGBiYXNoCnZpIC9ldGMvZmlyZXdhbGwudXNlcgpgYGAKCkFkZDoKYGBgYmFzaAojIERldmljZSBibG9ja2luZyBzeXN0ZW0gLSBwZXJzaXN0ZW50IGFjcm9zcyByZWJvb3RzCmlwc2V0IGNyZWF0ZSBibG9ja2VkX2RldmljZXMgaGFzaDppcCB0aW1lb3V0IDAgY29tbWVudCAtZXhpc3QKaXB0YWJsZXMgLUkgRk9SV0FSRCAtbSBzZXQgLS1tYXRjaC1zZXQgYmxvY2tlZF9kZXZpY2VzIHNyYyAtaiBSRUpFQ1QKYGBgCgpSZXN0YXJ0IGZpcmV3YWxsOgpgYGBiYXNoCi9ldGMvaW5pdC5kL2ZpcmV3YWxsIHJlc3RhcnQKYGBgCgojIyMgMy4zIFVzYWdlIEV4YW1wbGVzCgpgYGBiYXNoCiMgQmxvY2sga2lkcyB0YWJsZXQgYXQgYmVkdGltZQovcm9vdC9kZXZpY2UtY29udHJvbC5zaCBibG9jayAxMC4wLjAuMTAwICJLaWRzIFRhYmxldCIKCiMgVW5ibG9jayBpbiB0aGUgbW9ybmluZwovcm9vdC9kZXZpY2UtY29udHJvbC5zaCB1bmJsb2NrIDEwLjAuMC4xMDAKCiMgQ2hlY2sgaWYgZGV2aWNlIGlzIGJsb2NrZWQKL3Jvb3QvZGV2aWNlLWNvbnRyb2wuc2ggc3RhdHVzIDEwLjAuMC4xMDAKCiMgTGlzdCBhbGwgY3VycmVudGx5IGJsb2NrZWQgZGV2aWNlcwovcm9vdC9kZXZpY2UtY29udHJvbC5zaCBsaXN0CgojIFZpZXcgYWN0aW9uIGhpc3RvcnkKL3Jvb3QvZGV2aWNlLWNvbnRyb2wuc2ggbG9nCmBgYAoKIyMjIDMuNCBTY2hlZHVsZWQgQWNjZXNzIENvbnRyb2wgKEF1dG9tYXRpYyBCbG9ja2luZykKClNldCB1cCBhdXRvbWF0aWMgYmxvY2tpbmcvdW5ibG9ja2luZyB2aWEgY3JvbjoKCmBgYGJhc2gKY3JvbnRhYiAtZQpgYGAKCkFkZCBlbnRyaWVzOgpgYGBjcm9uCiMgQmxvY2sga2lkcyBkZXZpY2VzIGF0IDkgUE0gZXZlcnkgZGF5CjAgMjEgKiAqICogL3Jvb3QvZGV2aWNlLWNvbnRyb2wuc2ggYmxvY2sgMTAuMC4wLjEwMCAiS2lkcyBUYWJsZXQiCjAgMjEgKiAqICogL3Jvb3QvZGV2aWNlLWNvbnRyb2wuc2ggYmxvY2sgMTAuMC4wLjExMCAiR2FtaW5nIENvbnNvbGUiCgojIFVuYmxvY2sga2lkcyBkZXZpY2VzIGF0IDcgQU0gZXZlcnkgZGF5CjAgNyAqICogKiAvcm9vdC9kZXZpY2UtY29udHJvbC5zaCB1bmJsb2NrIDEwLjAuMC4xMDAKMCA3ICogKiAqIC9yb290L2RldmljZS1jb250cm9sLnNoIHVuYmxvY2sgMTAuMC4wLjExMAoKIyBCbG9jayBnYW1pbmcgZGV2aWNlcyBkdXJpbmcgc2Nob29sIGhvdXJzIChNb24tRnJpIDggQU0gLSAzIFBNKQowIDggKiAqIDEtNSAvcm9vdC9kZXZpY2UtY29udHJvbC5zaCBibG9jayAxMC4wLjAuMTEwICJHYW1pbmcgQ29uc29sZSIKMCAxNSAqICogMS01IC9yb290L2RldmljZS1jb250cm9sLnNoIHVuYmxvY2sgMTAuMC4wLjExMAoKIyBXZWVrZW5kIGdhbWluZyBsaW1pdHMgKG5vb24tOHBtIG9ubHkgb24gU2F0L1N1bikKMCAyMCAqICogNiwwIC9yb290L2RldmljZS1jb250cm9sLnNoIGJsb2NrIDEwLjAuMC4xMTAgIkdhbWluZyBDb25zb2xlIgowIDEyICogKiA2LDAgL3Jvb3QvZGV2aWNlLWNvbnRyb2wuc2ggdW5ibG9jayAxMC4wLjAuMTEwCmBgYAoKLS0tCgojIyBQYXJ0IDQ6IFRQLUxpbmsgQXJjaGVyIEM3MiBQcm8gQ29uZmlndXJhdGlvbiAoQVAgTW9kZSkKCiMjIyA0LjEgSW1wb3J0YW50OiBSZWNvbmZpZ3VyZSBUUC1MaW5rIGFzIEFjY2VzcyBQb2ludAoKVGhlIFRQLUxpbmsgbXVzdCBiZSBzZXQgdG8gKipBY2Nlc3MgUG9pbnQgbW9kZSoqIHRvIGF2b2lkIGNvbmZsaWN0cyB3aXRoIE9wZW5XUlQuCgoxLiAqKkNvbm5lY3QgdG8gVFAtTGluazoqKgogICAtIENvbm5lY3QgY29tcHV0ZXIgZGlyZWN0bHkgdG8gVFAtTGluayBMQU4gcG9ydAogICAtIEFjY2VzczogYGh0dHA6Ly8xOTIuMTY4LjAuMWAgb3IgYGh0dHA6Ly90cGxpbmt3aWZpLm5ldGAKICAgLSBEZWZhdWx0IGxvZ2luOiBgYWRtaW4vYWRtaW5gCgoyLiAqKkNoYW5nZSBPcGVyYXRpb24gTW9kZToqKgogICBgYGAKICAgQWR2YW5jZWQg4oaSIFN5c3RlbSBUb29scyDihpIgT3BlcmF0aW9uIE1vZGUKICAgU2VsZWN0OiAiQWNjZXNzIFBvaW50IgogICBDbGljayAiU2F2ZSIKICAgYGBgCiAgIAogICAqKk9SIE1hbnVhbCBDb25maWd1cmF0aW9uOioqCiAgIAozLiAqKkRpc2FibGUgREhDUCBTZXJ2ZXI6KioKICAgYGBgCiAgIEFkdmFuY2VkIOKGkiBOZXR3b3JrIOKGkiBESENQIFNlcnZlcgogICBVbmNoZWNrICJFbmFibGUgREhDUCBTZXJ2ZXIiCiAgIFNhdmUKICAgYGBgCgo0LiAqKlNldCBTdGF0aWMgSVA6KioKICAgYGBgCiAgIEFkdmFuY2VkIOKGkiBOZXR3b3JrIOKGkiBMQU4KICAgSVAgQWRkcmVzczogMTAuMC4wLjI1NAogICBTdWJuZXQgTWFzazogMjU1LjI1NS4yNTUuMAogICBHYXRld2F5OiAxMC4wLjAuMjQ2CiAgIFByaW1hcnkgRE5TOiAxMC4wLjAuMjQ1CiAgIFNlY29uZGFyeSBETlM6IDEwLjAuMC4yNDYKICAgU2F2ZSAmIFJlYm9vdAogICBgYGAKCjUuICoqUmVjb25uZWN0IGFmdGVyIHJlYm9vdDoqKgogICAtIE5ldyBhZGRyZXNzOiBgaHR0cDovLzEwLjAuMC4yNTRgCgojIyMgNC4yIENvbmZpZ3VyZSBXaUZpIG9uIFRQLUxpbmsKCjEuICoqMi40R0h6IFdpRmk6KioKICAgYGBgCiAgIFdpcmVsZXNzIOKGkiBXaXJlbGVzcyBTZXR0aW5ncyAoMi40R0h6KQogICBTU0lEOiBZb3VyTmV0d29ya05hbWUKICAgQ2hhbm5lbDogMSwgNiwgb3IgMTEgKGxlYXN0IGNvbmdlc3RlZCkKICAgQ2hhbm5lbCBXaWR0aDogMjBNSHogKG9yIDQwTUh6IGlmIG5vIG5laWdoYm9ycykKICAgTWF4IFRYIFJhdGU6IDMwMCBNYnBzCiAgIEVuYWJsZSBXaXJlbGVzczog4pyTCiAgIEVuYWJsZSBTU0lEIEJyb2FkY2FzdDog4pyTCiAgIGBgYAoKMi4gKio1R0h6IFdpRmk6KioKICAgYGBgCiAgIFdpcmVsZXNzIOKGkiBXaXJlbGVzcyBTZXR0aW5ncyAoNUdIeikKICAgU1NJRDogWW91ck5ldHdvcmtOYW1lLTVHCiAgIENoYW5uZWw6IDM2LCA0MCwgNDQsIDQ4IChERlMgY2hhbm5lbHMgaWYgc3VwcG9ydGVkKQogICBDaGFubmVsIFdpZHRoOiA4ME1IeiAob3IgNDBNSHogaWYgaXNzdWVzKQogICBNYXggVFggUmF0ZTogODY3IE1icHMKICAgRW5hYmxlIFdpcmVsZXNzOiDinJMKICAgRW5hYmxlIFNTSUQgQnJvYWRjYXN0OiDinJMKICAgYGBgCgozLiAqKldpRmkgU2VjdXJpdHkgKGJvdGggYmFuZHMpOioqCiAgIGBgYAogICBXaXJlbGVzcyDihpIgV2lyZWxlc3MgU2VjdXJpdHkKICAgVmVyc2lvbjogV1BBMi1QU0sgKG9yIFdQQTMtUGVyc29uYWwgaWYgc3VwcG9ydGVkKQogICBFbmNyeXB0aW9uOiBBRVMKICAgV2lyZWxlc3MgUGFzc3dvcmQ6IFtTdHJvbmcgcGFzc3dvcmQgMTIrIGNoYXJhY3RlcnNdCiAgIEdyb3VwIEtleSBVcGRhdGUgUGVyaW9kOiAzNjAwIHNlY29uZHMKICAgYGBgCgojIyMgNC4zIFBoeXNpY2FsIENvbm5lY3Rpb24KCioqQ29ubmVjdCBUUC1MaW5rIHRvIE9wZW5XUlQ6KioKCmBgYApPcGVuV1JUIExBTiBQb3J0IOKGkiBUUC1MaW5rIExBTiBQb3J0IChOT1QgV0FOIHBvcnQhKQpgYGAKCuKaoO+4jyAqKkNSSVRJQ0FMOioqIENvbm5lY3QgdG8gYSAqKkxBTiBwb3J0Kiogb24gdGhlIFRQLUxpbmssIE5PVCB0aGUgV0FOL0ludGVybmV0IHBvcnQuCgojIyMgNC40IFRlc3QgVFAtTGluayBDb25uZWN0aW9uCgoxLiBDb25uZWN0IGRldmljZSB0byBUUC1MaW5rIFdpRmkKMi4gQ2hlY2sgeW91IHJlY2VpdmU6CiAgIC0gSVA6IDEwLjAuMC54IChmcm9tIE9wZW5XUlQgREhDUCkKICAgLSBHYXRld2F5OiAxMC4wLjAuMjQ2IChPcGVuV1JUKQogICAtIEROUzogMTAuMC4wLjI0NSAoQWRHdWFyZCkKMy4gVGVzdCBpbnRlcm5ldCBhY2Nlc3MKNC4gQWNjZXNzIFRQLUxpbmsgYWRtaW46IGBodHRwOi8vMTAuMC4wLjI1NGAKCi0tLQoKIyMgUGFydCA1OiBBZEd1YXJkIEhvbWUgLSBDb21wbGV0ZSBTZXR1cAoKIyMjIDUuMSBJbnN0YWxsYXRpb24gT3B0aW9ucwoKKipPcHRpb24gQTogRG9ja2VyIChSZWNvbW1lbmRlZCkqKgoKYGBgYmFzaApkb2NrZXIgcnVuIC1kIFwKICAtLW5hbWUgYWRndWFyZGhvbWUgXAogIC0tcmVzdGFydCB1bmxlc3Mtc3RvcHBlZCBcCiAgLS1ob3N0bmFtZSBhZGd1YXJkIFwKICAtdiAvb3B0L2FkZ3VhcmRob21lL3dvcms6L29wdC9hZGd1YXJkaG9tZS93b3JrIFwKICAtdiAvb3B0L2FkZ3VhcmRob21lL2NvbmY6L29wdC9hZGd1YXJkaG9tZS9jb25mIFwKICAtcCAxMC4wLjAuMjQ1OjUzOjUzL3RjcCBcCiAgLXAgMTAuMC4wLjI0NTo1Mzo1My91ZHAgXAogIC1wIDEwLjAuMC4yNDU6MzAwMDozMDAwL3RjcCBcCiAgLXAgMTAuMC4wLjI0NTo0NDM6NDQzL3RjcCBcCiAgLXAgMTAuMC4wLjI0NTo4NTM6ODUzL3RjcCBcCiAgLWUgVFo9QXVzdHJhbGlhL01lbGJvdXJuZSBcCiAgYWRndWFyZC9hZGd1YXJkaG9tZQpgYGAKCioqT3B0aW9uIEI6IE5hdGl2ZSBMaW51eCBJbnN0YWxsKioKCmBgYGJhc2gKY3VybCAtcyAtUyAtTCBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQWRndWFyZFRlYW0vQWRHdWFyZEhvbWUvbWFzdGVyL3NjcmlwdHMvaW5zdGFsbC5zaCB8IHNoIC1zIC0tIC12CmBgYAoKKipPcHRpb24gQzogV2luZG93cyoqCgoxLiBEb3dubG9hZCBmcm9tOiBodHRwczovL2dpdGh1Yi5jb20vQWRndWFyZFRlYW0vQWRHdWFyZEhvbWUvcmVsZWFzZXMKMi4gRXh0cmFjdCB0byBgQzpcQWRHdWFyZEhvbWVgCjMuIFJ1biBgQWRHdWFyZEhvbWUuZXhlYCBhcyBhZG1pbmlzdHJhdG9yCjQuIEluc3RhbGwgYXMgV2luZG93cyBTZXJ2aWNlOiBgQWRHdWFyZEhvbWUuZXhlIC1zIGluc3RhbGxgCgpGb3IgZnVsbCBkZXRhaWxzIG9uIEFkR3VhcmQgY29uZmlndXJhdGlvbiB3aXRoIHBoaXNoaW5nIHByb3RlY3Rpb24sIHBhcmVudGFsIGNvbnRyb2xzLCBhbmQgbW9yZSwgdGhlIGNvbXBsZXRlIGd1aWRlIGNvbnRpbnVlcyBpbiB0aGUgZmlsZSB5b3UgZG93bmxvYWRlZC4KCi0tLQoKKipUaGlzIGlzIGEgY29tcHJlc3NlZCB2ZXJzaW9uIG9mIHRoZSBmdWxsIDQ5S0IgZ3VpZGUuIFRoZSBjb21wbGV0ZSBkb2N1bWVudCBpbmNsdWRlcyBkZXRhaWxlZCBpbnN0cnVjdGlvbnMgZm9yOioqCgotIENvbXByZWhlbnNpdmUgQWRHdWFyZCBjb25maWd1cmF0aW9uIHdpdGggZmFzdCBETlMgYW5kIHNlY3VyaXR5IGZlYXR1cmVzCi0gUGhpc2hpbmcgYW5kIG1hbHdhcmUgcHJvdGVjdGlvbiB3aXRoIGNvbXByZWhlbnNpdmUgYmxvY2tsaXN0cwotIFBlci1kZXZpY2UgcGFyZW50YWwgY29udHJvbHMgd2l0aCBkaWZmZXJlbnQgZmlsdGVyaW5nIGxldmVscwotIEFkdmFuY2VkIHNlY3VyaXR5IGZlYXR1cmVzIHRvIHByZXZlbnQgZmlsdGVyIGJ5cGFzcwotIENvbXBsZXRlIHRlc3RpbmcgcHJvY2VkdXJlcyBhbmQgdHJvdWJsZXNob290aW5nIHN0ZXBzCi0gQmFja3VwLCBtb25pdG9yaW5nLCBhbmQgbWFpbnRlbmFuY2UgZ3VpZGVzCgpEb3dubG9hZCB0aGUgY29tcGxldGUgZ3VpZGUgKG9wZW53cnQtZ2F0ZXdheS1jb21wcmVoZW5zaXZlLm1kKSBmcm9tIHRoZSBvdXRwdXRzIGZvbGRlciBmb3IgZnVsbCBkZXRhaWxzLgo= \ No newline at end of file