Repository: StackExchange/dnscontrol
Pull request #979 (2020-11-28 22:01:17)

Fix REV and PTR
Fixes https://github.com/StackExchange/dnscontrol/issues/965


Patch:
diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html
index a9761533..effcb44b 100644
--- a/docs/_includes/matrix.html
+++ b/docs/_includes/matrix.html
@@ -884,7 +884,9 @@
 		<td class="success">
 			<i class="fa fa-check text-success" aria-hidden="true"></i>
 		</td>
-		<td><i class="fa fa-minus dim"></i></td>
+		<td class="success">
+			<i class="fa fa-check text-success" aria-hidden="true"></i>
+		</td>
 		<td><i class="fa fa-minus dim"></i></td>
 		<td><i class="fa fa-minus dim"></i></td>
 		<td><i class="fa fa-minus dim"></i></td>
diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js
index 942faf45..e532cc8f 100644
--- a/pkg/js/helpers.js
+++ b/pkg/js/helpers.js
@@ -682,12 +682,17 @@ function recordBuilder(type, opts) {
             opts.transform(record, parsedArgs, modifiers);
 
             // Handle D_EXTEND() with subdomains.
-            if (d.subdomain && record.type != 'CF_REDIRECT' &&
-                    record.type != 'CF_TEMP_REDIRECT') {
+            if (d.subdomain &&
+                record.type != 'CF_REDIRECT' &&
+                record.type != 'CF_TEMP_REDIRECT') {
+                fqdn = [d.subdomain, d.name].join(".")
+
                 record.subdomain = d.subdomain;
                 if (record.name == '@') {
+                    record.subdomain = d.subdomain;
                     record.name = d.subdomain;
-                } else {
+                } else if (fqdn != record.name && record.type != 'PTR') {
+                    record.subdomain = d.subdomain;
                     record.name += '.' + d.subdomain;
                 }
             }
diff --git a/pkg/js/static.go b/pkg/js/static.go
index 97fa25f8..787617c0 100644
--- a/pkg/js/static.go
+++ b/pkg/js/static.go
@@ -212,134 +212,135 @@ var _escData = map[string]*_escFile{
 	"/helpers.js": {
 		name:    "helpers.js",
 		local:   "pkg/js/helpers.js",
-		size:    28419,
+		size:    28640,
 		modtime: 0,
 		compressed: `
-H4sIAAAAAAAC/+x9aXcbN7Lod/2Kis67adJuU4ujzD3UcN4wWjI6o+2QdK7n6unxQmyQhN0EegC0aCZW
-fvs7WBu9UbJPli/PHxI2UCgUCoVCVaEARbnAICQnMxkd7+zs7cHFHDYsB5wQCXJJBMxJimNdtsqFBJ5T
-+J8FgwWmmCOJ/wckA7x6wIkGVyhUCyAU5BKDYDmfYZixBPdC/IhjWGL0SNINJPghXywIXZgOFWysG+++
-SfDjLsxTtIA1SVPVnmOUFIRBQjieyXQDhAqpqtgccmFwYWC5zHIJbK5alqjuwb9YHqUpCEnSFChW9LOG
-0T3gOeNYtVdkz9hqpRmDYbZEdIFFb2fnEXGYMTqHAfyyAwDA8YIIyREXfbi7j3VZQsU04+yRJLhUzFaI
-0FrBlKIVtqVPx6aLBM9RnsohXwgYwN398c7OPKczSRgFQokkKCU/407XElGiqI2qLZQ1Uvd0bIiskfKk
-J3eEZc6pAEQBcY42ajYsDlgvyWwJa8yxpQRznIBgMFdjy7maM55TSVaa2zdrCn54c6Y4vMqQJA8kJXKj
-xEAwKoBxIHMQbIUhQRsQGZ4RlELG2QwLLQdrlqcJPKhe/50TjpNewbYFlieMzski5zg5NYR6BnI9GM3H
-XjgrerAexTVejxxjO6o+BrnJcAwrLJFDRebQUaXdYDrUNwwGEF0Nr98NLyPD2Sf9XzXdHC/U9IHC2YcC
-cz/A39f/dbOiKS1muZflYtnheNE9DsejMNWGcErFrRWBZwfB5qbXgSKePXzAMxnBt99CRLLpjNFHzAVh
-VERKBYTt1T/13SvDwUBN7wrJqZSdhvpulTGJyL6GMSUxN7xJRPYcbyheG7mwbPHsrUhJMcSALF8m8gcj
-QX2Iori+IvvFz7jEqz788hTCzxhP6sv3tli9IbhdpZPJZR/24xKBAvPH2monC8o4TkLdU62SiC+wLCuE
-kF123Z0ivhCdVWwXv+OV2hsYB4xmS1ixhMwJ5rGSKyKBCEC9Xs/DWYx9mKE0VQBrIpcWnwPSOqbvOlXs
-ybkgjzjdOAgjnkoa+ALrbqhkmrMJksiL9bRHxLntsbPqliS2Y8dgxRBwKrBvNFQUVFqoIXaUoH7QKyCs
-Uv/KLLr7cO+5dOzhnpr6utFjqXQ27eFPEtPEUtlTQ4thVaY2UDpLztYQ/ddwdH1x/WPf9uwnwyilnIo8
-yxiXOOlDBK9L5DsNUCmO4NQJeKXGEmaWlhmc2SxOzZIqVlQfTjhGEgOC0+uxRdiDdwLrDTdDHK2wxFwA
-Em4tAKKJIl8EWv20ba1q7WFGPNiysg2ZfhoJDGD/GAj8Ndz3eimmC7k8BvL6dTghpekN4O9IdaKf6t0c
-mm4QX+QrTGVrJwp+BYMC8I7cHzeTsGrsVclUbWPrEZrgTzdzzZAufDMYwJuDbk16VC28hkgt2QTPUqT2
-8RXjapYQBUZnuLSZBf04vRsSVCdDw2ganF1xOj17Pzm7NhPb7cO7LKnKCaBUmYYbQEmCE6MtTjvdWFkI
-Xv0qOeKYzQNZKWFukpPpAkvThV2AljLHRgc4AJqn6RZ2rZEAymTBsw2WWnw1UcrKhBmiCuIBQ65HmBjp
-P+10rR3aK3HWLi328KFXDHGge1QFQvLOfmw+jSC9CVoExfAGDn53qVedtkv+we8o+bWeQ4m8szAkuYdB
-0OBYbR8plpEA9oj5mhNp1JDZUnpWMpulow8T5aGQVZZiTaVu6ZQtkrMloQvVHKULxolcriAXOIGHTSGQ
-3R6cIJoQLem6DRbabUIU8Cc0k6ZQYWHzAH8krE1kTGMtfmpzVczJcLgYTDOFoNSyB5MlhpQp78Z2ohAY
-Q6dkPjcPvlHZ5ml6XCm+xFTLWKvclRTHFnlQ3uC1GuagPLPk/m5XUbQbSIhxpITyA8b5fE4+wQB2e7vw
-2mMpw85ZTgvIcGW9KaGx9AV7uPF1tadKRGXS1Nxo79ggtrPrzB+nWfTUKSvbD/Dz5zJBg0F5MFVbI6DB
-zyMyU8ttidHZOYdZzjmmSvm4WQ/p8Q6AJcVpjr8Vk1ntvNBQZqYrTY9bgLVtT5I+kFittX51Tp1RX7aV
-AqspNMtNM7+NnJ0P311OxmD9AMUMgaX2Uo3OKvQKSAYoy9KN/pGmMM9lzt0iEz2F70wZsto+laxAviZp
-CrMUIw6IbiDj+JGwXMAjSnMsVIehrWJbea+z7lq3LY9ndWWot/WeGirNbtkYm0wuO4/dPoyxiW5MJpe6
-U7PFGmMrINuAB46hMlDHUjnxnceSgfoIAx1goosJO8050ib2Y0kd27lyyDs8bM97UqYwgMfjJn+jAXOg
-fpzWHMBjT//u7P3fzv9JXnc7d2K1TNZ0c/+/u/9rL9jMfYu23fzRWT5qn0ZqTkkCie3dklPao3NKJAwg
-ElGtl7vD+7ADC1lUlhxfGCgDWOALKn37AzeLarC5XjiiDwcxrPrw/X4Myz68/X5/362Y/C5KIrXL5b0l
-vILD73zx2hYn8Ar+4ktpUPp23xdvwuLvjywF8GoA+Z0aw33JpX70i897oyVBcwvPCVyxkYWrJGz7O0ld
-Ulo6vcJ5bhW+FfqIT4bD8xQtOnpxV2IChUDr5VOSarOgZgjp4ObngdEOYTd7e3AyHE5PRheTi5PhpXKO
-iCQzlKpiHRPVUcEQRktPQdMB/PWv8JeuieuGEZ5dFwdR6ng3hv2ugqDihOVUa8N9WGFEBSSMRlKZJmrD
-clE7rdWCIEIvbKyWhcNukajmKE3D6axFm2zzhlCTQ6yjTTlN8JxQnEQhMz0IvDn4khkOAid3igwl1hZX
-ZSKGhkySxXbmrqzDrPbsrp6HIQxs3Q85SdXIomFkeT8cDl+CYThsQjIcFnguL4Zjg8gEYrYgU6AN2FSx
-R/ff70Zn0wCpDaA9i7to19BDURnFlt/KHO/Dnef9XaS6i2Io1m8Qa7qLFBlRbJQrknj4c87xMCVITDYZ
-LkNqUpsw2f9JjqiYM77qV5djrMmKfeyjYXkaA0zDBfGLAMB070DM13HJhgsCN7YNUqOZIjWcbtVkqoNY
-Ztz7PjZZQEYtvtOMRO8MJkTqkYRmlDWc4p2nbnio0Mz/sqpTY/wmVMO6ssxLswpRKnDD6ryLhlEMRsxj
-iE6uh1dn0b0PRdjOTCzCHzMcvS2LrRVYI75tYutb1YXWV/1WIjs6evu7C6z4oySWH73dLq8e4Oul1aP4
-Mlm1wvDfN9dnnZ8ZxVOSdAsBrlW17c/huKo82Db8cOS2Dz14+/u5oVdGbVv13Y+GYZcNkCZp+42XZ6eQ
-3XK8dxicY5gCvYLLZWY1VwvrcFfvqyWT95Nq0e1kVC0a357XikY/VYuuh+WmLdpF13cD28vttItYw7Vr
-lpOmjVsPszj4mNyc3nRkSlbdPlxIEEt3LIkoYM5NsEb347yLfWV0HRz+Z+/rFBJatFfqfv48JTRDSKJF
-oYQWz6ip0DY2BLrur/PVA+YNVJZWQd3iFlWTu9AnWmZfZmRp0IaZ11Lv7G63SX3EGyVKRcgvhoQssDCb
-lvlp0J7Wd6jd0/Hu125NpmNbbxhWqvcEtYMY6uwetxWmTMYfKFOJMON0QOarAawIuVpIX9AAXAzcQRcl
-reBl0C/YggMpvJ2MXiaDt5NRXQKVvrOItPIzqBhPMI8zjueYYzrDsV4JsXLjyEwfxOFP2bMdaoT1Lq2S
-/UoZ1aS1y1ZBczuMHkx7D3aU7QBm+NsU6p9ruVGUSa755MD0RzNcwTAHXJQ0tzBa0QLrj2Y4y0cHaT+b
-YQ1LHaj5+rrlMB79ZGQ440Qt1k28xmSxlHHGuHxWZMejn+oCqw2FrxRXR0W7NBrytkg041tq/2xZE/zR
-DbGQH/PdBGsG6yDNVyNOxj2U+v2VsjD+x/mtkYZiL9W76DNmmm7YIAiq+KtF4QW755zQBeYZJ3TLlP/J
-JpkQy3n2BVujhg8G5jVHUfRFRp2bXGMr5QItcAwCp3gmGY/9makxlmaYSzInMySxntjJ5bjBAFelXz2t
-moL22XKUtUOEFH/hQged5hqMRaenCkCwa+B3/dnPHxk5SAXSXHFQ+qMRzHGn2CTMdyNwyCjXICz7CiVR
-pMVant5wk6j1qRIBCDzjT134/BmKnK5PxhPUcdJ3k5vx7eXFxByfFslSSyR13jHPZ/aI/0f2JsWPONVJ
-zCCZai6y1OVST95P7CgiYaNWJiNttszpRwFsDodHRz0TZfW96ojIJzlWeIZuRfYhWuWpJPbICZ50woJN
-oDo8OnrzsJHY4t3Z29PL5P3k6t3l5GJ8Ozw5a8UqMjTDDp+uBUZBl8Kd8kt9VgNO7s3Z4fvJy2xVNfz6
-MlWe/tdG3dzyqUz0H6M6FX+kyXvC9rRJgFyTGe6HMABOZIkRkjnhQtoGVcBP0iGywIQm5JEkOUpdF71y
-m+ubyVnfHPNjjnWGSJGMdWAbxf5QRrjQA6PpBtBshoVoJSIGucwFEAkJw4JGOjFAYg5rJfprNWrVFaFu
-iBXa/sHW+BHzGB42GtTl5YccMHTHOjlzpajEAh7Q7OMa8aRCWTkFfL3E5o5BimlHp4J2YTCAA51T1SFU
-YqqmGqXppgsPHKOPFXQPnH3ENOAMRlzfJLCMl3hhz3UlFlL0aiFCqzoCPdQWId0edg0BCwEYwF0Aff+y
-OGpTR3f798/31UhYLdh69b5ihj+35K/e11f81fvf0fD+s03n1acm36vFdn6RvXv9wiO/64aDjetxEQe4
-OhufjX46K8UVgmB5BSCMIFczTeCbATQkhkYFikK7ZFIAo9hbLPqQX+dRRV9wVhseN+tUljD9H566lfPa
-gpBpW2JLQKtNJe418WL6e+Qc/AJUTKVM+/DYk8wi61aj+8WtCC+yU4keUhyk00/0EdpdytY672NJFss+
-HMZA8foHJHAf3t7HYKq/c9VHuvritg/f3987RNoK2T2AX+EQfoW38OsxfAe/whH8CvArfL/r00xSQvFz
-mUkVerfl7pEMBlX4UkqnAtLkwgBI1tM/ywdWuqiqd8sJ+gakKUHNoZ72VigzcHEhhaSpSXhfJF8dJkx2
-SLeezfbU7X1ghHaiOKrUNurvkBiH1pC9Pd0t4JGacc8l9VHjkyp8llMaqIVXtgvPLfX9p/LLEhRwTJP/
-Mp4ppTWAO09V1kvZuhtDUKCWTNevJ7tyAvHUy8HetGJrOwL4FaJu08I30BboGCJ/2nTx4/XNyJw6BCo5
-LC3WfIIzjpXvm8Q6t8ZATZXOCvsKisvJ9LWKaodBVcuBaUU7ly4OldL3S1rZYp8MRz+eTTq1DaipOgY+
-Ce7NvZAOe0vJ7hSZNllpv5Qm0DeIyzuHJvLq9mY0mU5Gw+vx+c3oyijfVGtzo578hQq961bh63twFaJq
-/NxFtS4ipbUjm5Wtf0uZlm2e39Kaif4ePWOauDzaqrGDJbLkF+pbn4AXm5cxbaoj7NY71GmeBlqm9QOR
-d6MfzzqBuJgCLwFJ758YZ+/oR8rWVBFgDrStPXAzrbX3Za0oJM89BuWNn16Px2cnmhjMV0RKnLikXsRx
-X1Xs7gKcMn18q/m+Mb4hllJ5Op0g4VGn3O0yugsAZ1SxJOjDZkIS4S68adj5XGEn4jlgP8QCZnpz7caZ
-9FAu2TShQuAZDDQNapSNrc7P25vN523tXJsZo4Kp/Z8tTB7Brr94FpCvrxE5ldaDC2kOwNeAgLI3LOsB
-3KZY6Xml7UpjAsYr5JrLCy6plOg07hX6iIEyuxJmWgpFz1zRWGGhY1o6aTshAmUZVmYJBeQyvjnWvfeU
-DWSV6KtXO/AK/l6QvQOv9krXir153jGrUEjEZSk3mSWtZpQG9knerfnd+tqbS+wu5XQHulIBhUSP9Goz
-F/0ejIrSY9G36+AXY8A+mfoAtgmGZVL0dNf3d/v3MHQWvtIqIbzjy6Dc5OAebjLjobtMFsa3tfN6Btxd
-zSJJv5S379LV4ZVj1USJQGviHxJBMj0M6aZQmkYwHnCAS3VIcGJvZNm3CCxBvSC3Y5VLZO8MLcgjpiFZ
-raxRg3Gy0zDMgi7JNGaDsyx+5f3HhMwVdic76rc24uwyEZ1fngxEHEiX350aPPLCz1b7UOEGft1mZO0a
-A2kYvkSPOBisv9tnWF9tqXC7iQJE7RUtvaaCS6M2dbgpEtLu1YcWstl5t4Z7mjZQZ02G7V5o4L44ehRY
-uMF8lKSpYU5aZ6PJqfPAbeqodEWPJTAommiPrgZYv3nNkm6bB7Fiicujb/Admm9Kb0G3twfmjQFZSK1e
-VDYi1thI391gSaCIvv02ODIoVbX2bAcTICk9gFDCcdyI4amx1N8ED2wzPcXt/Gom0AZzzkajm1EfnDlU
-uiIeNaBsl0fj3VkBqJrw1YCAvuSS2OtPvzyVAwGFRrAPoIQzU4tS/bXYbtz1vMqQFU7f7JLo1B3fpjZE
-7fQWvq7Eq2fcXQVSC74abtSRW+cXqt6vmQ69H7+utYqc1rSPm4ja9Xun8EM2NCIqdtBOE44ymxoQdHtw
-Q9MNbG28jQD9NIzIjYqPqhFrxdAwML1TWslpqhS+72ZnmyKrcqNRkVnJOFV7BtG7aiAZpQCVgza5m203
-kwMhLXAWlygPmiRJ7Yk5LWwj/dJN3rAF+kzfEva7g/uGfN8Xi1ZNxKItQOWO9++34vOhYDsyHexEJK3N
-+ja9oq97e11xVyVA+aBBhkG7zHiV0iwzDcLykquXYY5q++XLClVboxvFs0B6MgYNUxo8glOrqz8m41vJ
-tF+671YGeaps3HUztcGcOK438ZuaBy9mr9y0at39A9EkxcHFePO4g7/HLuq3lJPgPYRvv/VmlBL0bwYQ
-nZxPR2enF6Ozk0kE337bosJrbSZnV7dFwy2mX/gYQ/B13LhoSyaojsW07yqhsboV8dYNPsTzegBRL4LX
-z6CrLMLyAy89d4BiH5xqMNKsaJu6QPhLEcJnvGqUJMYh7STuqk/5+o9ydYM4KZlDce5Ote0eAxIiX2Eg
-mULHsRA9bwcSe3pdMfcbLP2aaV+y6sMnvGalhdq0QJueizLofMBy5wVL1R0xll56Ki96y+zmR5gSPCMJ
-hgckcALK41SkOvg33hN1zzEJswYLD1T50OqrlJikm940PsGkYEvPMGlYl85/cQ5X7wvMZsr0PLpx7gT2
-uGh8fansujy72a+Mv9K8a295H6p4J4rjWbNft/UBp692SPTgW12RFzgiqzYXZKsDUnc+Qsej8v7UF4K1
-aq1aILFmVPjA4lXrU1ZR3GwE2QetmmujzvgjyTJCF990oxpE9yVPUdT1Y/nROY5nLspMMihevvOGgIA5
-ZytYSpn19/aERLOP7BHzecrWvRlb7aG9/zzYP/rLd/t7B4cH33+/rzA9EuQafECPSMw4yWQPPbBc6jYp
-eeCIb/YeUpJZuest5So4jbntJKwUsUz0+ziyp/PZOlHPOSp7e5BxLCXB/I05gSldINP/Xid3+/ddeAWH
-R9934TWogoP7bqXksFby9r5beY/PHfTlq/BQnuYrfUPcXxBvuOIWRdUXsIKjfIWvoQ3NV7XnB43eh/9Q
-dDYEb98qnfM3rXrevCldU1c0whWSy948ZYxrovf0aAsxUtg7Hr1ig92eG0K7ib+rlrI8maf6caCUIIFF
-32TrYInc4YPQVAbZZD7rQd9kOp/ejm7e/2t6c36uMwNnHuU04+zTpg8Rm89dWuCtKtLh8ocUJ1UU160Y
-aBkBpk3tz99dXrZhmOdpWsLxeoRIushpgcscz7xxjy2FLNBHNJZ2e0LA5nOzHVJJ/Osu5YOafpk8+2JL
-K6emtl3BsYZeab3Ttm6un+2Fuk7eUaJ0B0rH48vmkflO3l1f/HQ2Gg8vx+PLpqHkDpUQaXkk5U7oi/u4
-fq4LMwwtz+/Gk5urGG5HNz9dnJ6NYHx7dnJxfnECo7OTm9EpTP51ezYOtMLU3YQtVsIIm6eBf+P7sLqB
-vz8axVFX6x17N90O3PkIDVcDA8+jPQfOPJocxdvGVb57h4UkVHvSL2r1xx4e2zegX0MUK1VmDpQListH
-vZaFJV+rkY9lb+z/M7ONme9Gl3X+vRtdqu3b1r/dP2gEebt/4KDOR41XXXWxSzEc355Pf3h3calWrEQf
-sSjOYrTmzRCXoq8PaPVP927d+Pbc2fodyeABwwem9nDjY0QQdbVWT9EDTk3z0+ux+fRPBmWcrBDfBLh6
-0Cl05N8jfd7O0boP/6XzpDvmPWqNpWvsbGYe18spSs3j1M4QC+h0W4mmSPtjih5JVliTonwykzmMuX55
-UquZkBTzAqS2UWL7UnnxulHX3xewePEqS5E0uFGSEHtc6h4/Ndya6aT/JBzvVGTz/0jMoOcpkhLTPgwh
-JUKGb3Kb9hbAbp7KtFxilBz0Ybhi+vV02H3I53PMgTO22jUnrDobU3uKPp+bSLzy775nc5gt9StOilGf
-5BX6NCY/YzOuFfpEVvkKBPkZF97o5P3EM+wnk1ehiIHDoyNzusex0Kf6FPTVhywt0u6DsR8eHUXdYHMI
-xLJhMzAK3cjj588QfBbHCIcNua6hsPvgO5KQYiQkHAK2Lz/WjE7boxW88PDDF4eKoNaQo7Xy9YqPbwYD
-iKI6KlU3gGjK0Vpkc4/O7GbmAEWnkC6xl4tArsx+ZyIimTmKcdDKpgrOVdXawdKJgrafinsuBoEhwYVk
-LXttGlzU9YiLlVdeajvFW4ZWVtWy0W9S/jvHQmfCuRf7AQW9B1EKtK4gdWw1JFm8BWdtQRGi3y+9d+ob
-DCrwDTmMe3vmZAQliadFscPS6N6/ppHUj0GsMrmp3g4pCG2ecc3krHJiZgp7tUs+SirCu0PBTR9Fngua
-zfW1M5zUw6uGEinTxhiocXMn7ycFxbGVgBh4FpvHAz2K7osPw59B3H3WGw/kyDnQSor0Hw2YEyVFxosw
-KljJSVVMXLOyLJgbXk4SHExpwZVRaP1axuGLS3h0SQuiQqmWMRXlHlVRVML1W8iG4+mP29dfWWdU2VoR
-pdpMa61YzHWrDNVk51lMRZpuKSQTvsC3zaTZapOcDIdbbBHCEjw3TWeMSvM2LEmLuHSH2eyoAnw6s28A
-9uEHxlKMqD4TxDTRfz0D6wvWVi8SjpM9B99TMq9MDx8OK92iDZ6j4XieC5zUuhcix324tBvFydD9QQ8T
-dEjZ2vwBFQ0XohaVVx2hY8wVcyvEiokzAYyhp3GsSZr0YWgxF/3N1Jh1JwpihnjS1JtPhuxt7y8wE4Kp
-bjUTXr5pVwTcUOw3F/OptDhlFEfdcjHcRcfR/XETCjXmChpd1IzKVDl0Hp+n3g3LU/dNpXEXPn8uoMvA
-lQi6r3I75mAA+1vA7Ei2VYeYTMJEgx0WrtC6HabmHFPJN6rIUM54IWBfaxRVp0atzeobYkGVX7b1B8S0
-ejoZDsvqKdLNohgCJHHpqc9ws2t5XOzlqLv1Pz3RKMDdllOWGNLAEgqlwJy/pJiac5cXUqgQFBSqrzty
-3+0e77QtiS8gLBCsrydOy05cRRsSWd1IzBaK4PSfF1fu4qv/wyd/Ozz6Dh42Epf+isU/L646iPu36fRV
-brurHx4dFQ//jlpvY7nhI84bhgyvBwXSYvQjl67AeyIlM9whsYINQMvHFyM3RJ+tuuYoyzDXxCxS9tDp
-6p/Bn2eBlCG9Zc1Jio0vPRSF++B50CEUfmRdxSNiXylnVHKWAqKbNdrE+mVu1c7m4fsr0C5jVCBK5ObN
-bIlnH62De80k7jvCiLBXFal227nyrnOasFlubrjDEqd6LD7Bd8x0Hrq5Fr9RNLE1BU7Ex16Ygqs10dT2
-4mNTNgPk8B4GsPtB7B7b49gZVupFU0LoLM0TDL0PwrHHP0avPmGgaTc5GB2ap2lcYA7/ikNwAGrwtJyA
-Wlo7Gqgli1zXOVHG0geyLdtVfyeXF4pIogxoEWyrlxdT/8i5Szh23Xtx/Yj1vetqfeUtYLWv333Em3sd
-c931hz27Vb0aAHqc+rum5p52/l8AAAD//0o7eJQDbwAA
+H4sIAAAAAAAC/+x9WXfbONLou39Fxed+oZQw9JJ25jtya+6ovfT4jLcjyf1lxtdXA4uQhIQiOQBoRd1x
+//Z7sBLgIjs+vbzcPHSLQKFQKBQKVYUCHBQMA+OUTHlwuLW1swNnM1hnBeCYcOALwmBGEhzKsmXBONAi
+hX/PM5jjFFPE8b+BZ4CX9ziW4AKFaAEkBb7AwLKCTjFMsxhHLn5EMSwweiDJGmJ8X8znJJ2rDgVsKBtv
+v4vxwzbMEjSHFUkS0Z5iFJeEQUwonvJkDSRlXFRlMyiYwoUhK3hecMhmoqVHdQT/zIogSYBxkiSQYkF/
+1jC6ezzLKBbtBdnTbLmUjMEwXaB0jlm0tfWAKEyzdAZ9+GULAIDiOWGcIsp6cHsXyrI4ZZOcZg8kxl5x
+tkQkrRVMUrTEuvTxUHUR4xkqEj6gcwZ9uL073NqaFemUkywFkhJOUEJ+xp2uJsKjqI2qDZQ1Uvd4qIis
+kfIoJ3eIeUFTBigFRClai9nQOGC1INMFrDDFmhJMcQwsg5kYW0HFnNEi5WQpuX21SsEOb5YJDi9zxMk9
+SQhfCzFgWcogo0BmwLIlhhitgeV4SlACOc2mmEk5WGVFEsO96PU/BaE4jkq2zTE/ytIZmRcUx8eKUMtA
+Kgcj+Ri5syIHa1Fc4tXQMLYj6kPg6xyHsMQcGVRkBh1R2nWmQ3xDvw/BxeDyZnAeKM4+yv+K6aZ4LqYP
+BM4elJh7Dv6e/K+ZFUlpOctRXrBFh+J599Adj8BUG8Jxyq61CDw5iGymeu0L4rP7T3jKA3j9GgKST6ZZ
++oApI1nKAqEC3Pbin/iOfDjoi+ldIj7hvNNQ360yJmb5SxjjibniTczyp3iT4pWSC80Wy96KlJRDdMiy
+Zay4VxLUgyAI6yuyV/4MPV714JdHF36a0bi+fK/L1euC61U6Hp/3YDf0CGSYPtRWO5mnGcWxq3uqVRzR
+Oea+QnDZpdfdMaJz1lmGevEbXom9IaOA0XQByywmM4JpKOSKcCAMUBRFFk5j7MEUJYkAWBG+0PgMkNQx
+PdOpYE9BGXnAydpAKPEU0kDnWHaT8kxyNkYcWbGeRISd6h47y64nsR09Bi2GgBOGbaOBoKDSQgyxIwT1
+k1wBbpX457Po9tOd5dKhhXts6utKjqXS2STCXzhOY01lJIYWwtKn1lE6C5qtIPifwfDy7PLHnu7ZToZS
+SkXKijzPKMdxDwJ465FvNEClOIBjI+CVGk2YWlpqcGqzOFZLqlxRPTiiGHEMCI4vRxphBDcMyw03RxQt
+MceUAWJmLQBKY0E+c7T6cdtaldpDjbi/YWUrMu00EujD7iEQ+N7d96IEp3O+OATy9q07Id70OvC3pDrR
+j/Vu9lU3iM6LJU55aycCfgn9EvCW3B02k7Bs7FXIVG1ji0ga4y9XM8mQLrzq9+HdXrcmPaIW3kIglmyM
+pwkS+/gyo2KWUApZOsXeZub0Y/SuS1CdDAkjaTB2xfHk5OP45FJNbLcHN3lclRNAiTAN14DiGMdKWxx3
+uqGwEKz6FXJEcTZzZMXD3CQnkznmqgu9ADVlho0GsA9pkSQb2LVCDNKMlzxbYy7FVxIlrEyYolRA3GMo
+5AhjJf3Hna62QyOPs3ppZfefonKIfdmjKGCcdnZD9akE6Z3TwimGd7D3u0u96LRd8vd+R8mv9exK5K2G
+IfEd9J0Gh2L7SDAPGGQPmK4o4UoNqS0l0pLZLB09GAsPhSzzBEsqZUujbBGfLkg6F81RMs8o4YslFAzH
+cL8uBbIbwRFKYyIlXbbBTLpNKAX8BU25KhRYspmDP2DaJlKmsRQ/sbkK5uTYXQyqmUDgtYxgvMCQZMK7
+0Z0IBMrQ8czn5sE3KtsiSQ4rxec4lTLWKnee4tggD8IbvBTD7PszS+5utwVF246EKEeKCT9gVMxm5Av0
+YTvahrcWiw87y4q0hHRX1jsPjabP2cOVrys9VcIqkybmRnrHCrGeXWP+GM0ip05Y2XaAX7/6BPX7/mCq
+toZDg51HpKaW6hKlswsK04JSnArlY2bdpcc6AJoUozn+Wk5mtfNSQ6mZrjQ9bAGWtj2Je0BCsdZ61Tk1
+Rr1vKzlWk2uWq2Z2Gzk5Hdycj0eg/QDBDIa59FKVzir1CvAMUJ4na/kjSWBW8IKaRcYige9EGLLSPuVZ
+iXxFkgSmCUYUULqGnOIHkhUMHlBSYCY6dG0V3cp6nXXXum15PKkrXb0t91RXaXZ9Y2w8Pu88dHswwiq6
+MR6fy07VFquMLYdsBe44hsJAHXHhxHcePAP1AfoywJTOx9lxQZE0sR88daznyiDvULc9jThPoA8Ph03+
+RgNmR/0YrdmHh0j+7uz8387/id92O7dsuYhX6fruf3f/146zmdsWbbv5g7F8xD6NxJySGGLduybH26OL
+lHDoQ8CCWi+3+3duBxqyrPQcX+gLA5jhs5Tb9ntmFsVgC7lwWA/2Qlj24MNuCIsevP+wu2tWTHEbxIHY
+5YpoAW9g/ztbvNLFMbyBv9jS1Cl9v2uL127xhwNNAbzpQ3ErxnDnudQPdvFZb9QTNLPwjMCVG5m7Sty2
+v5PUxd7SiUrnuVX4lugzPhoMThM078jFXYkJlAItl48n1WpBTRGSwc2vfaUd3G52duBoMJgcDc/GZ0eD
+c+EcEU6mKBHFMiYqo4IujJSekqY9+P57+EtXxXXdCM+2iYMIdbwdwm5XQKTsKCtSqQ13YYlRyiDO0oAL
+00RsWCZqJ7WaE0SI3MZiWRjsGolojpLEnc5atEk3bwg1GcQy2lSkMZ6RFMeBy0wLAu/2vmWGncDJrSBD
+iLXGVZmIgSKT5KGeuQvtMIs9uyvnYQB9XfdDQRIxsmAQaN4PBoPnYBgMmpAMBiWe87PBSCFSgZgNyARo
+AzZRbNH962Z4MnGQ6gDak7jLdg09lJVBqPktzPEe3Fre3waiuyCEcv06sabbQJARhEq5Io4HPxcUDxKC
+2HidYx9SktqESf+PU5SyWUaXvepyDCVZoY19NCxPZYBJOCd+4QCo7g2I+jr0bDgncKPbIDGaCRLD6VZN
+pjqIZsad7WOdO2TU4jvNSOTOoEKkFolrRmnDKdx67LqHCs3891WdGOMrVw3LSp+XahWihOGG1XkbDIIQ
+lJiHEBxdDi5OgjsbitCdqViEPWY4eO+LrRZYJb5tYmtb1YXWVv1WIjs8eP+7Cyz7oySWHrzfLK8W4OXS
+alF8m6xqYfjX1eVJ5+csxRMSd0sBrlW17c/uuKo82DR8d+S6Dzl4/fupoVdGrVv1zI+GYfsGSJO0/cbL
+s1PKrh/vHTjnGKpArmC/TK3mamEd7uJjtWT8cVwtuh4Pq0Wj69Na0fCnatHlwG/aol1kfdexvcxOOw8l
+XLtmOWrauOUwy4OP8dXxVYcnZNntwRkHtjDHkigFTKkK1sh+jHexK4yuvf3/jl6mkNC8vVL28+cpoSlC
+HM1LJTR/Qk25trEi0HR/WSzvMW2g0lsFdYubVU3uUp9ImX2ekSVBG2ZeSr2xu80m9RmvhSiVIb8QYjLH
+TG1a6qdCe1zfobaPR9sv3ZpUx7peMcyrtwS1gyjq9B63EcYn4w+UqZipcRog9dUAVoZcNaQtaAAuB26g
+y5JWcB/0G7ZgRwqvx8PnyeD1eFiXQKHvNCKp/BSqjMaYhjnFM0xxOsWhXAmhcOPIVB7E4S/5kx1KhPUu
+tZJ9oYxK0tplq6S5HUYOpr0HPcp2ADX8TQr1z7XcUpRzKvlkwORHM1zJMANcljS3UFpRA8uPZjjNRwOp
+P5thFUsNqPp62XIYDX9SMpxTIhbrOlxhMl/wMM8of1JkR8Of6gIrDYUXiquhol0aFXkbJDqjG2r/bFlj
+9MEMsZQf9d0EqwZrINVXI86MWijx+4WyMPr76bWShnIvlbvoE2aabNggCKL4xaLwjN1zRtI5pjkl6YYp
+/5NNMsYWs/wbtkYJ7wzMao6y6JuMOjO5ylYqGJrjEBhO8JRnNLRnpspYmmLKyYxMEcdyYsfnowYDXJS+
+eFolBe2zZShrh3Ap/saFDjLN1RmLTE9lgGBbwW/bs58/MnKQMCS5YqDkRyOY4U65SajvRmCXUaaBW/YC
+JVGmxWqeXlGVqPWlEgFwPOMvXfj6Fcqcri/KE5Rx0pvx1ej6/Gysjk/LZKkF4jLvmBZTfcT/Y/YuwQ84
+kUnMwDPRnOWJyaUefxzrUQRMR61URtp0UaSfGWQz2D84iFSU1fYqIyJf+EjgGZgV2YNgWSSc6CMneJQJ
+CzqBav/g4N39mmONd2tnRy6Tj+OLm/Px2eh6cHTSipXlaIoNPlkLWQqyFG6FX2qzGnB8p84OP46fZ6uK
+4deXqfD0Xxp1M8unMtF/jOoU/OEq7wnr0yYGfEWmuOfCABiRJUpIZoQyrhtUAb9wg0gDkzQmDyQuUGK6
+iPw2l1fjk5465scUywyRMhlrTzcK7aEMM6GHLE3WgKZTzFgrESHwRcGAcIgzzNJAJgZwTGElRH8lRi26
+IqkZYoW2v2cr/IBpCPdrCWry8l0OKLpDmZy5FFRiBvdo+nmFaFyhzE8BXy2wumOQ4LQjU0G70O/Dnsyp
+6pCU41RMNUqSdRfuKUafK+juafYZpw5nMKLyJoFmPMdzfa7LMeMsqoUItepw9FBbhHRz2NUFLAWgD7cO
+9N3z4qhNHd3u3j3dVyNhtWDrxceKGf7Ukr/4WF/xFx9/R8P7zzadl1+afK8W2/lZ9u7lM4/8LhsONi5H
+ZRzg4mR0MvzpxIsrOMHyCoAbQa5mmsCrPjQkhgYlilK75JxBlmJrschDfplHFXzDWa173CxTWdz0f3js
+Vs5rS0ImbYktDq06lThq4sXk98g5+AVSNuE86cFDxDONrFuN7pe3IqzITji6T7CTTj+WR2i3SbaSeR8L
+Ml/0YD+EFK9+QAz34P1dCKr6O1N9IKvPrnvw4e7OIJJWyPYe/Ar78Cu8h18P4Tv4FQ7gV4Bf4cO2TTNJ
+SIqfykyq0Lspd4/k0K/CeymdAkiSC30geSR/+gdWsqiqd/0EfQXSlKBmUE+iJcoVXFhKIWlq4t4XKZb7
+ccY7pFvPZnvsRp8yknaCMKjUNupvlxiDVpG9Od3N4ZGYccsl8VHjkyh8klMSqIVXugvLLfH9p/JLE+Rw
+TJL/PJ4JpdWHW0tVHiXZqhuCUyCWTNeuJ71yHPGUy0HftMpWegTwKwTdpoWvoDXQIQT2tOnsx8uroTp1
+cFSyW1qu+RjnFAvfNw5lbo2Cmgid5fblFPvJ9LWKaodOVcuBaUU7exeHvPR9Tytr7OPB8MeTcae2ATVV
+h0DHzr25Z9KhbynpnSKXJmva89IEegqxv3NIIi+ur4bjyXg4uBydXg0vlPJNpDZX6sleqJC7bhW+vgdX
+IarGz21Q6yIQWjvQWdnyN+eJb/P8ltZM8LfgCdPE5NFWjR3MkSa/VN/yBLzcvJRpUx1ht96hTPNU0Dyp
+H4jcDH886TjiogqsBMTRPzDOb9LPabZKBQHqQFvbA1eTWntb1oqC08JiEN748eVodHIkicF0STjHsUnq
+RRT3RMX2NsBxJo9vJd/XyjfEnAtPp+MkPMqUu+0s3QaAk1SwxOlDZ0ISZi68SdjZTGAn7ClgO8QSZnJ1
+acYZR6jg2SROGcNT6EsaxCgbW52etjebzdramTbTLGWZ2P+zucoj2LYXzxzy5TUio9IiOOPqAHwFCNLs
+XZZHANcJFnpeaDtvTJDRCrnq8oJJKiUyjXuJPmNIM70SplIKWaSuaCwxkzEtmbQdE4byHAuzJAVkMr4p
+lr1HwgbSSvTNmy14A38ryd6CNzvetWJrnnfUKmQcUe7lJmdxqxklgW2Sd2t+t7z2ZhK7vZxuR1cKIJfo
+oVxt6qLfvVJRcizydh38ogzYR1XvwDbBZDlnkez67nb3DgbGwhdaxYU3fOn7Tfbu4CpXHrrJZMnopnZW
+z4C5q1km6Xt5+yZdHd4YVo2FCLQm/iHmJNPDIF2XSlMJxj12cIkOCY71jSz9FoEmKHJyO5YFR/rO0Jw8
+4NQlq5U1YjBGdhqGWdLFM4lZ4fTFz99/VMhcYDeyI35LI04vE9b55VFBhI502d2pwSMv/WyxD5Vu4Ms2
+I23XKEjF8AV6wM5g7d0+xfpqS4HbTBSgVF/RkmvKuTSqU4ebIiHtXr1rIaudd2O4p2kDNdak2+6ZBu6z
+o0eOhevMhydNDXPSOhtNTp0FblNH3hW9LIZ+2UR6dDXA+s3rLO62eRDLLDZ59A2+Q/NN6Q3odnZAvTHA
+S6mVi0pHxBobybsbWewootevnSMDr6q1Zz0YB4n3AIKH47ARw2Njqb0J7thmcorb+dVMoA7mnAyHV8Me
+GHPIuyIeNKBsl0fl3WkBqJrw1YCAvOQS6+tPvzz6gYBSI+gHUNyZqUWpvi+3G3M9rzJkgdM2Oycydce2
+qQ1ROr2lr8vx8gl3V4DUgq+KG3Xk2vmFqverpkPux29rrQKjNfXjJqx2/d4ofJcNjYjKHbTThMNnUwOC
+bgRXabKGjY03ESCfhmGFUvFBNWItGOoGpre8lZwkQuHbbrY2KbIqNxoVmZaMY7FnELmrOpLhBagMtMrd
+bLuZ7AhpibO8RLnXJEliTyzS0jaSL90UDVugzfT1sN/u3TXk+z5btGoiFmwA8jvevduIz4aC9chksBOR
+pDbrm/SKvO5tdcVtlQDhgzoZBu0yY1VKs8w0CMtzrl66Oartly8rVG2MbpTPAsnJ6DdMqfMITq2u/piM
+bcWTnnffzQd5rGzcdTO1wZw4rDexm5oFL2fPb1q17v6O0jjBzsV49biDvcfO6reUY+c9hNevW80qIfiv
++hAcnU6GJ8dnw5OjcfBM+PHJxXXZqGmBzf4TC6Vx69AS6pOMO6Xst6Pt7lZbZ+6DDs7XYePC98xYGc9p
+35m+DXvdSN4I7hhicvyv+l7r169rvJSpqr8TsW/7EEQBvH2C5oqG8V+viczpkH5Nq8EC1etW1Tkr2wt/
+PhEyQHGsvO1ObO4x+XebhB/vBIHJDMqkglQ6JiEgxoolBpILdBQzFlkjl+ij+Yov0+DG1PwWz2Vx3yeb
+elqoSfs0vYWl0Nlo7NYz9JA5P/WesfI1mmZ28wtTMZ6SGMM9YjgG4U4LUg38O+tmm7emmFIwpXsNSOVi
+eFlXsulV4/tSAtZ7Y0rCmrsKZ6dw8bHErKZMzqMZ55bjbLDGp6V8v+xJS2apnLFmk2TD41flI1gUT5ud
+1o2vU73Y25KDb/WznuFlLdv8q43eVd2zcr2qyuNa3wjW6nPVoqQ1i8lGTS9a3+kKwmYLT7/W1VwbdEaf
+SZ6TdP6qG9Qgus95Z6OuH/0X9SiemhA6yaF81s9aOQxmNFvCgvO8t7PDOJp+zh4wnSXZKppmyx208997
+uwd/+W53Z29/78OHXYHpgSDT4BN6QGxKSc4jdJ8VXLZJyD1FdL1zn5Bcy1204EvnqOm6E2deODaWj//w
+SCbrdYLIeGE7O5BTzDnB9J06XvJux8l/b+Pb3bsuvIH9gw9deAuiYO+uWynZr5W8v+tWHhs0p5jF0s04
+SIulvP5ub7833N8LgurzXk6egsDX0CYtlrW3FZXeh/8SdDZEpt8LnfNXqXrevfPu4Asa4QLxRTRLsoxK
+onfkaEsxEtg7Fr1gg96eG+LWsb2Il2RFPEvky0cJQQyznkpFwhyZkxUmqXRS5WxKh7ymdTq5Hl59/Ofk
+6vRUpj1OLcpJTrMv6x4E2Wxmch6vRZE8C7hPcFxFcdmKIfUR4LSp/enN+XkbhlmRJB6Ot0NEknmRlrjU
+2dM785KUywJ5/qRp18cf2WymtsOUE/t0jX8K1fPJ08/RtHJqotuVHGvoNa132tbN5ZO9pKaTm5QI3YGS
+0ei8eWS2k5vLs59OhqPB+Wh03jSUwqBiLPFH4neSPruPy6e6UMOQ8nwzGl9dhHA9vPrp7PhkCKPrk6Oz
+07MjGJ4cXQ2PYfzP65ORoxUm5ppvuRKGWL17/Btf9pUN7OXYIAy6Uu/oi/d64Mbpabj36LhR7Ql+6kXo
+INw0Lv9iIWacpDJM8KxWf+zJuH7g+i0EoVBl6rS8pNg/x9Ys9JzHRj767uX/Z2YbM2+G53X+3QzPxfat
+69/v7jWCvN/dM1Cnw8Z7vLLY5E+Ork8nP9ycnYsVy9FnzMqDJql5c0Q568nTZ/nTPMo3uj41tn6HZ3CP
+Qfj+5oXKAIKu1OoJuseJan58OVKf9j2knJIlomsHVwSdUkf+LZDJBBStevA/Mgm8ox7blli6ys7O1MuB
+RYoS9fK2McQcOs1WIimS/pigh5MllqQIn0ylRWMqn9WUasYlRT1vKW2UUD/DXj7d1LWXITRevMwTxBVu
+FMdEnwWbl10Vt6byRkPsjnfC8tl/xWrQswRxjtMeDCAhjLsPjqv2GkBvnsK0XGAU7/VgsMzk0/CwfV/M
+ZpgCzbLltjo+lqmm0lO0yeqE46V91D6fwXQhn6gSjPrCL9CXEfkZq3Et0ReyLJbAyM+49EbHH8eWYT+p
+pBFBDOwfHKijS4qZTFlIQd7ryJPyToEz9v2Dg6DrbA6OWDZsBkqhK3n8+hWcz/KMZL8hkdcVdnuygDgk
+GDEO+4D1s5Y1o1P3qAXPPdmxxa4iqDWkaCV8vfLjVb8PQVBHJer6EEwoWrF8ZtGp3UydDsn82AW2cuHI
+ldrvVEQkV+dMBlrYVM6hsVg7mBtRkPZTeYlHIVAkmHizZq/O8Qu6FnG58vyltlU+1KhlVSwb+eDmfwrM
+ZJqf+XMEgJzenSgFWlWQGrYqkjTekrO6oDx/2PUec7UN+hX4hgTNnR117IPi2NIi2KFpNI97pwGXL10s
+c76uXn0pCW2eccnkvHIcqAqj2g0mIRXuxSjnGpMgzwTNZvJOHY7rsWNFCedJ49m+cnPHH8clxaGWgBBo
+HqqXES2K7rNP+p9A3H3SG3fkyDjQQorkX0SYESFFyotQKljISVVMTDNfFtT1NSMJBsZbcD4KqV99HLbY
+wyNLWhCVStXHVJZbVGWRh+u3kA3D0x83rz9fZ1TZWhGl2kxLrVjOdasM1WTnSUxlDrIXknGfF9xk0my0
+SY4Ggw22CMliPFNNp1nK1cO3JCnj0p1Mp36V4JOpfuCwBz9kWYJRKg88cRrLPw2C5e1xrRcJxfGOgY+E
+zAvTw4bDvCvCzls7FM8KhuNa94wVuAfneqM4Gpi/VqKCDkm2Un8dRsK5qFnlyUroKHNFXXnRYmJMAGXo
+SRwrksQ9GGjMZX9TMWbZiYCYIho39WYzPaPN/TlmgjPVrWbC8zftioAriu3moj6FFk+zFAddvxhug8Pg
+7rAJhRhzBY0sakalqgw6i89Sb4ZlqXtVadyFr19LaB+4EkG3VWbH7PdhdwOYHsmmaheTygZpsMPcFVq3
+w8Sc45TTtShSlGe0FLCXGkXVqRFrs/pAmlNll239dTSpno4GA189BbJZEIKDJPTeMXU3u5aX056Pulv/
+uxqNAtxtOWUJIXEsIVcK1PlLglN17vJMCgWCkkLxdUvuut3DrbYl8Q2EOYL1cuKk7IRVtC6R1Y1EbaEI
+jv9xdmFu9dq/6vLX/YPv4H7NsfcnOv5xdtFB1D68J++p6119/+CgfNV42HrVzAwfUdowZHjbL5GWox+a
+XAwasYRMcYeEAtYB9Y8vhmaINhV3RVGeYyqJmSfZfacrfzp/ewaSDMkta0YSrHzpASvdB8uDDknhx6wr
+eET0E+xZymmWAErXK7QO5bPjop2+ZGDvd5t0WIZSwtfvpgs8/awd3MuM454hjDB9DzOVbjsV3nWRxtm0
+UNf3YYETORabvTzKZJK9uvO/FjRlqxQoYZ8jN79YaqKJ7sXGpnR6y/4d9GH7E9s+1MexUyzUi6SEpNOk
+iDFEn5hhj31pX3xCX9KuEkw6aZEkYYnZ/RMVzgGowtNyAqpp7UiglhR5WWdEGXMbyNZsF/0dnZ8JIokw
+oJmzrZ6fTewL7iab2nRvxfUzlpfKq/WVh47Fvn77Ga/vZMx12x72bFf1qgNoccrvmpp73Pp/AQAA//93
+bW+i4G8AAA==
 `,
 	},
 }
diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go
index 364a4010..468840bb 100644
--- a/pkg/normalize/validate.go
+++ b/pkg/normalize/validate.go
@@ -98,9 +98,9 @@ func checkLabel(label string, rType string, target, domain string, meta map[stri
 	if label[len(label)-1] == '.' {
 		return fmt.Errorf("label %s.%s ends with a (.)", label, domain)
 	}
-	if strings.HasSuffix(label, domain) {
+	if label == domain || strings.HasSuffix(label, "."+domain) {
 		if m := meta["skip_fqdn_check"]; m != "true" {
-			return fmt.Errorf(`label %s ends with domain name %s. Record names should not be fully qualified. Add {skip_fqdn_check:"true"} to this record if you really want to make %s.%s`, label, domain, label, domain)
+			return fmt.Errorf(`label %q ends with domain name %q. Record names should not be fully qualified. Add {skip_fqdn_check:"true"} to this record if you really want to make %s.%s`, label, domain, label, domain)
 		}
 	}
 
@@ -281,6 +281,13 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
 			if rec.TTL == 0 {
 				rec.TTL = models.DefaultTTL
 			}
+			// in-addr.arpa magic
+			if strings.HasSuffix(domain.Name, ".in-addr.arpa") || strings.HasSuffix(domain.Name, ".ip6.arpa") {
+				label := rec.GetLabel()
+				if label == domain.Name || strings.HasSuffix(label, "."+domain.Name) {
+					rec.SetLabel(label[0:(len(label)-len("."+domain.Name))], domain.Name)
+				}
+			}
 			// Validate the unmodified inputs:
 			if err := validateRecordTypes(rec, domain.Name, pTypes); err != nil {
 				errs = append(errs, err)
@@ -299,7 +306,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
 				// We normalize them to a FQDN so there is less variation to handle.  If a
 				// provider API requires a shortname, the provider must do the shortening.
 				origin := domain.Name + "."
-				if len(rec.SubDomain) > 0 {
+				if rec.SubDomain != "" {
 					origin = rec.SubDomain + "." + origin
 				}
 				rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), origin))
diff --git a/pkg/transform/arpa.go b/pkg/transform/arpa.go
index db700527..12a8370d 100644
--- a/pkg/transform/arpa.go
+++ b/pkg/transform/arpa.go
@@ -8,6 +8,17 @@ import (
 
 // ReverseDomainName turns a CIDR block into a reversed (in-addr) name.
 func ReverseDomainName(cidr string) (string, error) {
+
+	// If it is an IP address, add the /32 or /128
+	ip := net.ParseIP(cidr)
+	if ip != nil {
+		if ip.To4() != nil {
+			cidr = cidr + "/32"
+		} else {
+			cidr = cidr + "/128"
+		}
+	}
+
 	a, c, err := net.ParseCIDR(cidr)
 	if err != nil {
 		return "", err


Test patch:
diff --git a/pkg/js/parse_tests/032-reverseip.js b/pkg/js/parse_tests/032-reverseip.js
new file mode 100644
index 00000000..a80b9240
--- /dev/null
+++ b/pkg/js/parse_tests/032-reverseip.js
@@ -0,0 +1,29 @@
+var REGISTRAR = NewRegistrar('none', 'NONE');    // No registrar.
+var BIND = NewDnsProvider('bind', 'BIND');
+
+D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
+  PTR("1", 'foo.example.com.'),
+  PTR("1.2.3.2", 'bar.example.com.'),
+  PTR(REV("1.2.3.3"), 'baz.example.com.', {skip_fqdn_check:"true"})
+);
+D_EXTEND(REV("1.2.3.4"), PTR("4", "silly.example.com."))
+D_EXTEND(REV("1.2.3.5"), PTR("1.2.3.5", "willy.example.com."))
+D_EXTEND(REV("1.2.3.6"), PTR(REV("1.2.3.6"), "billy.example.com."))
+
+D_EXTEND(REV("1.2.3.0/24"), PTR("7", "my.example.com."))
+D_EXTEND(REV("1.2.3.0/24"), PTR("1.2.3.8", "fair.example.com."))
+D_EXTEND(REV("1.2.3.0/24"), PTR(REV("1.2.3.9/32"), "lady.example.com.", {skip_fqdn_check:"true"}))
+
+// Expected zone: 3.2.1.in-addr.arpa.zone
+// $TTL 300
+//; generated with dnscontrol 2020-11-30T12:56:28-05:00
+//@                IN SOA   DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2020113000 3600 600 604800 1440
+//1                IN PTR   foo.example.com.
+//2                IN PTR   bar.example.com.
+//3                IN PTR   baz.example.com.
+//4                IN PTR   silly.example.com.
+//5                IN PTR   willy.example.com.
+//6                IN PTR   billy.example.com.
+//7                IN PTR   my.example.com.
+//8                IN PTR   fair.example.com.
+//9                IN PTR   lady.example.com.
diff --git a/pkg/js/parse_tests/032-reverseip.json b/pkg/js/parse_tests/032-reverseip.json
new file mode 100644
index 00000000..6c7c12c6
--- /dev/null
+++ b/pkg/js/parse_tests/032-reverseip.json
@@ -0,0 +1,79 @@
+{
+  "dns_providers": [
+    {
+      "name": "bind",
+      "type": "BIND"
+    }
+  ],
+  "domains": [
+    {
+      "dnsProviders": {
+        "bind": -1
+      },
+      "name": "3.2.1.in-addr.arpa",
+      "records": [
+        {
+          "name": "1",
+          "target": "foo.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "1.2.3.2",
+          "target": "bar.example.com.",
+          "type": "PTR"
+        },
+        {
+          "meta": {
+            "skip_fqdn_check": "true"
+          },
+          "name": "3.3.2.1.in-addr.arpa",
+          "target": "baz.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "4",
+          "subdomain": "4",
+          "target": "silly.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "1.2.3.5",
+          "subdomain": "5",
+          "target": "willy.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "6.3.2.1.in-addr.arpa",
+          "subdomain": "6",
+          "target": "billy.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "7",
+          "target": "my.example.com.",
+          "type": "PTR"
+        },
+        {
+          "name": "1.2.3.8",
+          "target": "fair.example.com.",
+          "type": "PTR"
+        },
+        {
+          "meta": {
+            "skip_fqdn_check": "true"
+          },
+          "name": "9.3.2.1.in-addr.arpa",
+          "target": "lady.example.com.",
+          "type": "PTR"
+        }
+      ],
+      "registrar": "none"
+    }
+  ],
+  "registrars": [
+    {
+      "name": "none",
+      "type": "NONE"
+    }
+  ]
+}
diff --git a/pkg/js/parse_tests/033-revextend.js b/pkg/js/parse_tests/033-revextend.js
new file mode 100644
index 00000000..a1b85892
--- /dev/null
+++ b/pkg/js/parse_tests/033-revextend.js
@@ -0,0 +1,15 @@
+var REGISTRAR = NewRegistrar('none', 'NONE');    // No registrar.
+var BIND = NewDnsProvider('bind', 'BIND');
+
+// Delegating reverse zones
+D(REV('1.3.0.0/16'), REGISTRAR, DnsProvider(BIND),
+	NS(REV('1.3.1.0/24'), "ns1.example.com.")
+);
+D_EXTEND(REV("1.3.2.0/24"), NS(REV("1.3.2.0/24"), "ns2.example.org."))
+
+// Expeccted zone: 3.1.in-addr.arpa.zone
+// $TTL 300
+// ; generated with dnscontrol 2020-11-30T12:58:47-05:00
+// @                IN SOA   DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2020113000 3600 600 604800 1440
+// 1                IN NS    ns1.example.com.
+// 2                IN NS    ns2.example.org.
diff --git a/pkg/js/parse_tests/033-revextend.json b/pkg/js/parse_tests/033-revextend.json
new file mode 100644
index 00000000..80855c26
--- /dev/null
+++ b/pkg/js/parse_tests/033-revextend.json
@@ -0,0 +1,36 @@
+{
+  "dns_providers": [
+    {
+      "name": "bind",
+      "type": "BIND"
+    }
+  ],
+  "domains": [
+    {
+      "dnsProviders": {
+        "bind": -1
+      },
+      "name": "3.1.in-addr.arpa",
+      "records": [
+        {
+          "name": "1.3.1.in-addr.arpa",
+          "target": "ns1.example.com.",
+          "type": "NS"
+        },
+        {
+          "name": "2.3.1.in-addr.arpa",
+          "subdomain": "2",
+          "target": "ns2.example.org.",
+          "type": "NS"
+        }
+      ],
+      "registrar": "none"
+    }
+  ],
+  "registrars": [
+    {
+      "name": "none",
+      "type": "NONE"
+    }
+  ]
+}