nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

commit 5696bddfe919eff2303ec8e962c21ca8441f6634
parent d170d90841aaf52d29fb5e02024f67c6dac2912a
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Sun, 19 Jan 2025 18:24:04 +0100

Update magnetic declination; show info about magnetic model

Also add script for updating declination grid

Fixes #17

Diffstat:
Msrc/lib/leaflet.control.azimuth/control.html | 13++++++++++---
Msrc/lib/leaflet.control.azimuth/index.js | 3++-
Asrc/lib/leaflet.control.azimuth/info.svg | 5+++++
Msrc/lib/leaflet.control.azimuth/style.css | 11+++++++++++
Msrc/lib/magnetic-declination/declination.json | 25+++++++++++++++----------
Msrc/lib/magnetic-declination/index.js | 9++++++++-
Asrc/lib/magnetic-declination/scripts/magnetic_declination_for_nakarte.py | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 172 insertions(+), 15 deletions(-)

diff --git a/src/lib/leaflet.control.azimuth/control.html b/src/lib/leaflet.control.azimuth/control.html @@ -5,7 +5,15 @@ <td data-bind="text: trueAzimuth() !== null ? Math.round(trueAzimuth()) + '&deg;' : '--'"></td> </tr> <tr> - <td>Magnetic azimuth</td> + <td> + Magnetic azimuth +<!-- <div class="icon-info" data-bind="attr: {title: magneticModelInfoText}"></div>--> + <div class="icon-info" data-bind="attr: {title: + `Magnetic model: ${magneticModelInfo.modelName}\n` + + `Date: ${magneticModelInfo.dateYMD[2]}.${magneticModelInfo.dateYMD[1]}.${magneticModelInfo.dateYMD[0]}\n` + + `Horizontal resolution: ${magneticModelInfo.horizontalResolution}&deg;\n` + + `Magnetic declination resolution: ${magneticModelInfo.valueResolution}&deg;`}"></div> + </td> <td data-bind="text: magneticAzimuth() !== null ? magneticAzimuth() + '&deg;' : '--'"></td> </tr> <tr> @@ -19,4 +27,4 @@ <div class="button" data-bind="click: onReverseButtonClick">Reverse</div> <div class="button" data-bind="click: onProfileButtonClick">Elevation / Sightline</div> </div> -</div> -\ No newline at end of file +</div> diff --git a/src/lib/leaflet.control.azimuth/index.js b/src/lib/leaflet.control.azimuth/index.js @@ -4,7 +4,7 @@ import {makeButtonWithBar} from '~/lib/leaflet.control.commons'; import layout from './control.html'; import '~/lib/controls-styles/controls-styles.css'; import './style.css'; -import {getDeclination} from '~/lib/magnetic-declination'; +import {getDeclination, magneticModelInfo} from '~/lib/magnetic-declination'; import 'leaflet-rotatedmarker'; // eslint-disable-line import/no-unassigned-import import iconPointer from './pointer.svg'; import iconPointerStart from './pointer-start.svg'; @@ -57,6 +57,7 @@ L.Control.Azimuth = L.Control.extend({ this.trueAzimuth = ko.observable(null); this.magneticAzimuth = ko.observable(null); this.distance = ko.observable(null); + this.magneticModelInfo = magneticModelInfo; this.points = { start: null, end: null diff --git a/src/lib/leaflet.control.azimuth/info.svg b/src/lib/leaflet.control.azimuth/info.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24"> + <circle cx="12" cy="12" r="10" fill="#bbb"/> + <path fill="#ffffff" d="M11,17v-5c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v5c0,0.552-0.448,1-1,1h0C11.448,18,11,17.552,11,17z"/> + <circle fill="#ffffff" cx="12" cy="7.5" r="1.5"/> +</svg> diff --git a/src/lib/leaflet.control.azimuth/style.css b/src/lib/leaflet.control.azimuth/style.css @@ -44,3 +44,14 @@ .azimuth-control-active { cursor: crosshair; } + +.leaflet-control-azimuth .icon-info { + display: inline-block; + vertical-align: bottom; + background-image: url("./info.svg"); + width: 16px; + height: 16px; + margin: 0; + padding: 0; + margin-left: 2px; +} diff --git a/src/lib/magnetic-declination/declination.json b/src/lib/magnetic-declination/declination.json @@ -1,10 +1,16 @@ { - "minLat": -58, - "step": 2, - "rowsCount": 69, - "maxLat": 78, - "valueOffset": 76, - "array": "7u7t7e3s7Ozr6+rq6unp6Ojn5+fm5ubl5eTk5OPj4uHh4N/e3dzb2djW1dPRz83LycbEwb+8ube0sa+sqaekop+dm5mXlZORj42MiomHhoSCgX9+fHp4dnRyb21raGVjYF1aV1RRTktIRUI/PDk2MzEuKyknJCIgHhwaGBYVExIRDw4ODQwMDAwMDA0OEBEUFxsfJSw0PklWZHSDkqGtuMLK0Nbb3uLk5+jq6+zt7e7u7u7u5ubm5ubm5eXl5OTk5OPj4+Li4uHh4eHg4ODg39/f3t7d3dzb2tnY19bU09HPzcvJx8TCv726t7Wyr6ypp6Shn5yamJaTkpCOjIuJiIaFg4KBf358e3l3dXNxb21qaGVjYF1aV1RRTktIRUI/PDo3NDIvLSooJiQiIB4dGxoZFxYWFRQUFBQUFBUWFxkbHiElKS40O0NMVWBrd4OOmaOttbzDyM3R1djb3d/g4uPk5eXm5ubm4ODg4ODg4N/f39/e3t7e3t3d3d3c3Nzc3Nzc29vb29ra2dnY19fW1dPS0c/Ny8nHxcPAvbu4tbKvraqnpKGenJmXlZKQjoyLiYeGhYOCgYB+fXx6eXh2dHNxb2xqaGVjYF1aV1RRT0xJRkNAPTo4NTMwLiwqKCYkIyEgHx4dHBsbGhoaGxscHR8gIyUoLDA0OT9GTVVeZ3B5g4yVnaWss7i+wsfKztHT1dfZ2tzd3d7f39/g2tvb29vb29ra2tra2tnZ2dnZ2NjY2NjY2NjY2NfX19fX1tbV1dTT0tHQz83LycfFw8G+u7m2s7CtqqekoZ6bmZaUkY+Ni4mHhoSDgoB/fn18e3p5d3Z1c3JwbmxqaGVjYF1bWFVST0xJRkNBPjs5NjQyMC4sKignJSQjIiEhICAgICEhIiMlJigrLjE1OT1DSE5VXGNrc3uDipKZn6arsba6vsLFyMvNz9HT1NXX19jZ2dra1tbW1tbW1tbW1tbW1dXV1dXV1NTU1NTU1NTU1NTU1NTU09PT0tLR0M/OzMvJyMbEwb+8ure0sa6rqKShnpuYlpOQjoyJh4aEgoGAfn18e3p6eXh3dnVzcnFvbWxqZ2VjYF5bWFVSUE1KR0RCPz06ODYzMTAuLCsqKCgnJiYlJSUmJicoKistLzI1ODxARUpPVVthaG91fIOJj5aboaarr7O3u77BxMbIyszOz9DR0tPU1NXV0dLS0tLS0tLS0tLS0tHR0dHR0dHR0dHR0dHR0dHR0dHQ0NDQz8/Ozs3MysnHxsTCv726uLWyr6uopaKfm5iVkpCNioiGhIKAf358e3p5eHh3dnV1dHNycXBubWtpZ2VjYF5bWVZTUE5LSEVDQD48OTc1NDIwLy4tLCsrKioqKissLS4vMTM2ODw/Q0dLUFVaYGZrcXd9g4iOk5idoqaqrrG1uLu+wMLExsjJy8zNzs/Q0NHRzs7Ozs7Pz8/Pzs7Ozs7Ozs7Ozs3Nzc3Nzc3Nzc3Nzs7Nzc3NzczMy8rJyMfFxMLAvbu4trOwrKmmop+cmJWSj4yKh4WCgX99fHp5eHd2dnV0dHNycnFwb25tbGtpZ2VjYV5cWVdUUU9MSUdEQkA9Ozk4NjQzMjEwLy8vLy8vMDEyMzU3OTs+QUVITFFVWl9kaW50eX6DiI2RlpqeoqaprbCztri7vb/Bw8TGx8jJysvMzM3NysvLy8vLy8vLy8vLy8vLy8vLy8rKysrKysrKysrKy8vLy8rKysrJycjHxsXDwsC+vLm2tLGtqqejoJyZlZKPjImGhIF/fXt6eHd2dXRzc3JycXFwcG9vbm1sa2ppZ2VjYV9dWlhVU1BNS0hGREJAPjw6OTc2NTQ0MzMzNDQ1Njc4Ojw+QUNGSk1RVVpeY2hscXZ6f4SIjJCUmJyfoqaprK6xs7a4ury+wMHCxMXGx8jIycnKx8jIyMjIyMjIyMjIyMjIyMjIyMjIx8fHx8fHx8jIyMjIyMjIx8fHxsbFxMPBwL68ube0sa6rqKShnZqWk4+MiYaDgX58enh3dXRzcnFxcG9vb25ubm1tbGxra2ppZ2ZkYmBeXFlXVFJPTUtIRkRCQD89PDs6OTg4ODg4OTk6PD0/QUNFSEtOUlZaXmJma29zeHyAhIiMj5OWmZ2goqWoq62vsrS2uLq7vb7AwcLDxMXFxsbHxMXFxcXGxsbGxsbGxsbGxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXExMPCwsC/vby6t7Wyr6yppaKem5eTkIyJhoOAfnt5d3V0cnFwb29ubW1sbGxsbGtra2tqamlpaGZlY2JgXVtZVlRST01LSUdFREJBQD8+PT09PT09Pj9AQkNFSEpNUFNWWl1hZWltcXV5fYGFiIyPkpWYm52goqWnqqyusLK0tre5ury9vr/AwcLDw8TEwsLCw8PDw8PDw8PDw8PDw8PDw8PDwsLCwsLCwsLCwsLCwsLCwsLCwcHAv769u7q4tbOwraqno5+cmJSRjYqGg4B9e3h2dHNxcG9ubWxsa2tqampqampqampqamlpaGdmZWNiYF5bWVdVU1BOTEtJR0ZFRENCQkJCQkJDREVGSEpMTlFUV1pdYWRobHB0d3t/goWJjI6RlJeZm56goqSnqautrrCytLW3uLm7vL2+v7/AwcHCwMDAwMDBwcHBwcHBwcHBwcHBwcDAwMDAwMDAwMDAwMDAwMDAwMC/v76+vby7ube1s7Guq6ikoZ2ZlpKOi4eEgX57eHZ0cnBvbm1sa2pqaWloaGhoaGhpaWlpaWlpaWhoZ2VkYmFfXVpYVlRSUE9NTEpJSEhHR0dHR0hJSktNTlBTVVhaXWFkZ2tucnZ5fYCDhomMjpGTlpianJ6goqSmqKqrra+wsrO1tre5uru8vL2+vr+/vb6+vr6+v7+/v7+/v7+/v7+/v76+vr6+vr6+vr6+vr6+vr69vb29vby8u7q4t7Wzsa6sqaWinpuXk4+MiIWBfnt5dnRycG5tbGtqaWhoZ2dnZ2dnZ2doaGlpampqampqaWhnZmRiYV9dW1lXVVNSUE9OTU1MTExNTU5PUFFTVVdZW15hZGdqbXF0d3t+gYSHioyPkZOVl5mbnZ6goqSlp6mqrK2vsLKztLa3uLm6uru8vL29u7y8vLy8vb29vb29vb29vb29vby8vLy8vLy8vLu7u7u7u7u7u7u7urq5uLe2tbOxr6yqpqOgnJmVkY2KhoJ/fHl3dHJwbm1ramloaGdmZmZmZmZmZmdnaGlpamtsbGxsbGtramhnZWNiYF5cWllXVlVUU1JSUlJSU1RVVldZW11fYmRnam1wc3Z5fH+ChYiKjY+Rk5WWmJqbnZ6goqOlpqipq6yur7Cys7S1tre4uLm6uru7urq6urq6u7u7u7u7u7u7u7u7u7u7urq6urq6urm5ubm5ubm5ubm5uLi3trW0s7GvraqnpKGempaTj4uHhIB9end1cnBubWtqaWhnZ2ZmZWVlZWVlZmZnaGlqa2xtbm9vb29vbm1samlnZWNiYF5dXFtaWVhYWFhYWVpbXF1fYWNlZ2psb3J1eHt+gIOGiIuNj5GTlJaYmZqcnZ6goaOkpqeoqqusrq+wsbKztLW2t7e4uLm5uLi4uLm5ubm5ubm5ubm5ubm5ubm5ubm4uLi4uLi4t7e3t7e3t7e3tra1tLOysa+tq6ilop+cmJSRjYmFgn97eHZzcW9tbGppaGdmZmVlZWVkZWVlZmdoaWprbW5vcXJzc3Nzc3JxcG5ta2poZmVjYmFgX15eXl5eX2BhYmNlZ2hqbW9xdHd5fH+BhIeJi42PkZOUlpeYmpucnZ6goaKkpaanqaqrra6vsLGys7S0tba2t7e4tra3t7e3t7e3t7e4uLi4uLi4uLe3t7e3t7a2tra2tra1tbW1tbW1tLSzsrGwr62rqaajoJ2alpKPi4eEgH16d3RycG5sa2loZ2dmZWVlZWVlZWVmZ2hpamttb3BydHV2d3h4eHd3dnRzcXBubWtpaGdmZWRkZGRkZWVmZ2lqbG5vcXR2eHt9gIKFh4qMjpCRk5SWl5iZmpucnZ6foaKjpKWnqKmqq62ur7CxsbKztLS1tba2tbW1tbW1tra2tra2tra2tra2tra2trW1tbW1tbS0tLS0tLSzs7OzsrKxsbCuraupp6Sin5uYlJGNiYaCf3x5dnNxb21ramloZ2ZmZWVlZWVlZmZnaGlqbG1vcXN1d3h6e3x8fXx8e3p5eHZ0c3Fwbm1sa2pqampqamtsbW5vcXJ0dnh6fH6Bg4WIioyOkJKTlZaXmJmam5ucnZ6foKGipKWmp6ipqqytrq+vsLGysrOztLS1s7S0tLS0tLS0tLS0tbW1tbW1tbW0tLS0tLSzs7Ozs7KysrKysrKxsbCwr66tq6mnpaOgnZqWk4+LiISBfXp3dXJwbmxraWhnZ2ZmZmVlZWZmZ2doaWtsbnBydHZ4enx9f4CBgYGBgIB/fXx6eXd2dHNycXBwb29vcHBxcnN0dXd4enx+gIKEhoiKjI6QkpOVlpeYmZmam5ycnZ6foKGio6Slpqeoqqusra2ur7CxsbKys7OzsrKzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrKysrKxsbGxsbGwsLCwr6+urayrqqimo6Gem5iVkY6KhoOAfHl2dHJvbWxqaWhnZ2ZmZmZmZmdnaGlqbG1vcHJ0d3l7fX+BgoSFhYaGhYWEg4GAfn17enl3dnV1dHR0dHV1dnd4eXp8fX+Bg4WHiYuNjpCSk5WWl5iZmZqam5ycnZ6fn6ChoqOlpqeoqaqrrKytrq+wsLGxsbKysbGxsbGysrKysrKysrKysrKysrKysrKxsbGxsbCwsLCwr6+vr6+urq2trKuqqKakop+dmpaTkIyJhYJ/e3h2c3FvbWxqaWhoZ2dnZ2dnaGhpamtsbnBxc3V3enx+gIKEhoeIiYqKiomIh4aFg4KBf358e3p6eXl5eXl6ent8fX5/gYKEhYeJi42OkJKTlZaXmJiZmpqbm5ycnZ2en6ChoqOkpaanqKmqq6ysra6vr7CwsLGxsLCwsLCwsLCwsbGxsbGxsbGxsbGxsbCwsLCwr6+vr6+urq6urq6traysq6qop6WjoJ6bmJWSjouIhIF+e3h1c3FvbWxqaWloaGhoaGhpaWprbG5vcXJ0dnh6fH+Bg4WHiYqLjI2NjY2MjIuJiIeFhIKBgH9+fn19fX19fn9/gIGCg4WGiImLjY6QkpOUlpeYmJmZmpqbm5ucnJ2en5+goaKjpKWmp6ipqqusrK2urq+vsLCwr6+vr6+vr6+vr6+wsLCwsLCwsLCwr6+vr6+vrq6urq6tra2traysrKuqqainpaShn52al5SRjYqHg4B9end1cnBubWxramlpaWlpaWpqa2xtb3Byc3V3eXt9f4GEhoiJi42Oj5CQkJCQj46NjIuJiIaFhIOCgYGBgYGBgYKCg4SFhoeIiouNjpCRk5SVlpeYmZmampqbm5ucnJ2dnp+goaKjpKWmp6eoqaqrrKytra6ur6+vrq+vr6+urq6urq6ur6+vr6+vr6+vrq6urq6ura2tra2srKysrKurq6qpqKempKKgnpuZlpOPjImGgn98eXd0cnBvbWxramppaWpqa2tsbW5wcXN0dnh6fH6AgoSGiIqMjY+QkZKSk5OTkpGQj46Ni4qJiIeGhYSEhISEhIWFhoaHiImKi42OkJGSlJWWl5iZmZqampqbm5ubnJydnp6foKGio6Slpqeoqamqq6ysra2urq6urq6urq6urq6urq6urq6urq6urq6urq2tra2traysrKysq6urq6uqqqmop6alo6GfnZqYlZKOi4iFgn98eXd0cnBvbWxra2pqamtrbG1ub3FydHV3eXt9foCChIaIioyOj5GSk5SUlZWVlJSTkpGQjo2Mi4qJiIeHh4eHh4eHiIiJiouMjY6PkZKTlJaXmJiZmZqampqam5ubm5ycnZ6foKGhoqOkpaanqKmqqqusrK2tra6ura2tra2tra2tra2tra2tra2tra2tra2srKysrKyrq6urq6uqqqqpqainpqWkoqCenJmWlJGOioeEgX57eXZ0cnBvbm1sbGtrbGxtbm9wcXN0dnh6e31/gYOFh4mKjI6PkZKTlZWWl5eXlpaVlJOSkZCOjYyLi4qKiYmJiYmKioqLjIyNjo+QkpOUlZaXmJmZmZqampqampqbm5ucnZ2en6ChoqOkpaamp6ipqqqrrKysra2tra2traysrKysrKysrKysrKysrKysrKysrKurq6urq6qqqqqqqampqKenpqSjoZ+dm5iWk5CNioeEgX57eXZ0cnFvbm1tbGxtbW5ub3Fyc3V3eHp8foCCg4WHiYqMjo+RkpSVlpeXmJiYmJiXlpWUk5KRkI+OjYyMjIuLi4uLjIyNjY6Pj5CRkpSVlpeXmJmZmZqampqampqam5ubnJ2enp+goaKjpKWmp6ioqaqqq6usrKytrKysrKysrKyrq6urq6urrKysrKysq6urq6urq6qqqqqqqqmpqaiop6empaOioJ6cmpeVko+MiYaDgH17eHZ0cnFwb25ubW1ubm9wcXJ0dnd5e31+gIKEhoeJi4yOj5GSk5WWl5iYmZmZmZmYmJeWlZSTkpGQj46Ojo2NjY2NjY6Oj4+QkJGSk5SVlpeYmJmZmZmampmZmZqampqbnJydnp+goaKio6SlpqeoqamqqqurrKysrKysrKurq6urq6urq6urq6urq6urq6urq6qqqqqqqqmpqampqKinp6alpKOhn52bmZaUkY6LiIWDgH17eHZ0c3Fwb29ubm9vcHFyc3R2eHl7fX+BgoSGiImLjI6PkZKTlZaXmJmZmpqampqamZiXlpWUk5KSkZCQj4+Pj4+Pj4+PkJCRkZKTlJWVlpeYmJmZmZmZmZmZmZmZmZqam5ycnZ6foKGio6SlpaanqKmpqqurq6ysq6urq6urq6urqqqqqqqqq6urq6urq6uqqqqqqqqpqampqamoqKenpqWko6Kgn52amJaTkI2LiIWCgH17eHZ1c3JxcHBvb3BwcXJzdXZ4eXt9f4GDhIaIiYuMjo+RkpOUlZeYmZmam5ubm5ubmpmZmJeWlZSTkpKRkZCQkJCQkJCQkZGSkpOTlJWWlpeYmJmZmZmZmZmZmZmZmZmampucnZ2en6ChoqOkpaanp6ipqqqrq6urq6urq6urqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmpqampqKioqKempqWko6Ggnpyal5WSkI2Kh4WCf317eHd1c3JxcXBwcHFycnN1dnh5e31/gYOEhoiJi4yOj5CSk5SVlpeYmZqbm5ycnJycm5qamZiXlpWUlJOTkpKSkZGRkZGRkpKSk5OUlZWWl5eYmJiZmZmZmJiYmJiYmJmZmpqbnJ2en5+goaKjpKWmp6ioqaqqqqurq6urq6uqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqampqampqKiop6empaSjoqGfnZuZlpSRj4yJh4SCf317eXd1dHNycnFxcnJzdHV2eHl7fX+BgoSGiImLjI6PkJKTlJWWl5iZmpubnJydnZ2cnJubmpmYl5aWlZSUk5OTkpKSkpKSk5OTk5SUlZaWl5eYmJiYmJiYmJiYl5eXmJiYmZmam5ydnp+goaKjpKSlpqeoqamqqqqrqqurqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqampqamoqKinp6ampaSjoaCenJqYlpORjoyJhoSBf317eXd2dHNzcnJyc3N0dXZ4eXt9foCChIaHiYuMjo+QkZOUlZaXmJmZmpucnJ2dnZ2dnJybm5qZmJeXlpWVlJSUk5OTk5OTk5OUlJSVlZaWl5eXmJiYmJiYl5eXl5eXl5eYmJmZmpucnZ6foKGio6SlpqenqKmpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmpqamoqKinp6alpaOioZ+enJqXlZOQjouIhoOBf3x7eXd2dXRzc3NzdHR1dnh5e3x+gIKDhYeJioyNj5CRkpOUlZaXmJmam5ucnZ2dnp6dnZ2cm5qamZiXl5aWlZWVlJSUlJSUlJSUlZWVlpaWl5eXmJiYmJeXl5eWlpaWlpaXl5iZmZqbnJ2en6ChoqOkpaanqKipqaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqampqKinp6alpKOioJ+dm5mXlJKPjYqIhYOBfnx7eXd2dXV0dHR0dXZ3eHl6fH5/gYOFhoiKjI2OkJGSk5SVlpeYmZqam5ycnZ2enp6enZ2cnJuampmYl5eWlpaVlZWVlZWVlZWVlZWWlpaWl5eXl5eXl5eXlpaWlZWVlZaWlpeYmJmam5ydnp+goaKjpKWmp6ioqamqqqqqqqqqqqqqqqqqqqqqqqqqq6urq6urq6qqqqqqqampqKinp6alpKOhoJ6cmpiWlJGPjIqHhYOAfnx7eXh3dnV1dXV1dnd4eXp8fX+BgoSGiImLjY6PkZKTlJWWl5iYmZqbm5ydnZ6enp6enp2dnJybmpmZmJiXl5aWlpaWlZWVlZWVlpaWlpaXl5eXl5eXl5aWlpWVlZWUlZWVlZaXl5iZmpucnZ6foKGio6SlpqeoqKmpqaqqqqqqqqqqqqqqqqqqqqurq6urq6urq6urq6qqqqmpqainp6alpKOhn56cmpiVk5GOjImHhIKAfnx7eXh3dnZ2dnZ2d3h5ent9foCCg4WHiYqMjY+QkpOUlZaXl5iZmpqbnJydnp6en5+enp6dnZybm5qZmZiYl5eXl5aWlpaWlpaWlpaWlpaXl5eXl5eWlpaVlZWUlJSUlJSUlJWWlpeYmZqbnJ2en6Cho6SlpqanqKmpqamqqqqqqqqqqqqqqqqrq6urq6usrKysrKurq6urqqqpqaiop6alpKKhn52bmZeVkpCNi4mGhIKAfnx7eXh3d3Z2dnd3eHl6e3x+f4GDhIaIiYuNjpCRkpOUlZaXmJmZmpubnJ2dnp6fn5+fn56enZ2cm5uamZmZmJiXl5eXl5eXlpaWlpaWl5eXl5eXl5aWlpWVlJSUk5OTk5OTk5SUlZaXmJmam5ydnp+goqOkpaanp6ipqampqqqqqqqqqqqqq6urq6usrKysrKysrKysrKurq6qqqamop6alpKKhn52bmZaUko+NioiGg4F/fnx7eXh4d3d3d3d4eXp7fH1/gIKEhYeJioyNj5CSk5SVlpeYmJmampucnJ2enp6fn5+fn5+enp2cnJubmpqZmZiYmJiYl5eXl5eXl5eXl5eXl5eWlpaWlZWUlJOTkpKSkpKSkpOTlJWWlpeYmpucnZ6foaKjpKWmp6eoqKmpqaqqqqqqqqurq6urrKysrK2tra2tra2trKysq6uqqqmop6alpKKgnp2amJaTkY+MioeFg4F/fXx7eXl4eHd4eHh5ent8fX6AgYOEhoiJi4yOj5GSk5SWlpeYmZqam5ucnZ2enp+fn5+fn5+fnp6dnJybm5qamZmZmZiYmJiYmJeXl5eXl5eXl5eWlpaVlZSUk5OSkpGRkZGRkZKSk5OUlZaXmJmbnJ2eoKGio6SlpqeoqKipqamqqqqqq6urq6ysrKytra2trq6urq6tra2srKyrqqmpqKalpKKgnpyamJWTkI6MiYeFgoB/fXx7enl4eHh4eHl6ent9fn+AgoOFh4iKi42PkJGTlJWWl5iZmZqbm5ycnZ6en5+foKCgoJ+fn56dnZycm5uampqZmZmZmZiYmJiYmJiXl5eXl5aWlpWVlJSTkpKRkZCQkJCQkJCRkZKTlJWWl5iZm5ydnqChoqOkpaanp6ioqamqqqqrq6urrKysra2trq6urq6urq6urq6traysq6qpqKelpKKgnpyal5WSkI2LiIaEgoB+fXt6enl4eHh5eXp6e3x9foCBg4SGh4mKjI2PkJKTlJWWl5iZmpqbnJydnZ6en5+goKCgoKCfn56enZ2cnJybm5qampqamZmZmZmYmJiYmJeXl5aWlpWUlJOSkpGQkI+Pj4+Pj4+QkJGSk5SVlpeYmZucnZ+goaKjpKWmpqeoqKmqqqqrq6ysrK2tra6urq+vr6+vr6+vr66ura2sq6qpqKelpKKgnpyZl5SSj42KiIaDgYB+fHt6eXl5eXl5eXp7fH1+f4CCg4WGiImLjI6PkZKTlZaXmJiZmpubnJydnp6fn5+goKCgoKCgn5+fnp6dnZycnJubm5qampqamZmZmZiYmJiXl5aWlZWUk5OSkZCQj46Ojo6Ojo6Oj5CQkZKTlJWXmJmbnJ2foKGipKWmpqenqKmpqqqrq6ysra2urq6vr7CwsLCwsLCwsK+vrq6trKuqqaempKKgnpuZl5SRj4yKh4WDgX99fHt6eXl5eXl5enp7fH1+gIGChIWHiIqLjY6QkZKUlZaXmJmampucnJ2dnp6fn6CgoKGhoaCgoKCfn56enZ2dnJycnJubm5uampqamZmZmJiXl5aWlZSUk5KRkJCPjo6NjY2MjY2Njo6PkJGSk5SVl5iZm5yen6Cho6SlpaanqKmpqqqrrKytra6ur6+wsLCxsbGxsbGxsLCwr66urayqqaimpKKgnpuZlpSRjoyJh4SCgH99fHt6eXl5eXl5ent8fH5/gIGDhIWHiIqLjY6QkZOUlZaXmJmam5ucnZ2enp+foKCgoaGhoaGhoKCgn5+fnp6enZ2dnJycnJubm5uampmZmZiYl5aWlZSTkpGRkI+OjY2MjIuLi4uMjI2Ojo+QkpOUlZeYmpucnp+goqOkpKWmp6ipqqurrK2trq6vr7CwsbGxsrKysrKysbGwsK+urayrqqimpKKgnpuZlpOQjouIhoSCgH58e3p5eXl5eXl5ent8fX5/gIGDhIaHiYqMjY+QkZOUlZaXmJmam5ycnZ2enp+goKChoaGhoaGhoaGhoKCgn5+fnp6enZ2dnZycnJubm5qamZiYl5aWlZSTkpGQj46NjIyLi4qKioqLi4yMjY6PkJGTlJWXmJqbnZ6foaKjpKWmp6ipqqurrK2urq+wsLGxsrKys7Ozs7OysrKxsbCvrq2rqqinpaKgnpuYlZOQjYqIhYOBf318e3p5eXh4eHl5ent8fX5/gIKDhIaHiYqMjY+QkpOUlZaYmZmam5ycnZ6en5+goKGhoaKioqKioqKhoaGgoKCgn5+fnp6enp2dnZycm5uamZmYl5aVlZOSkZCPjo2Mi4uKiYmJiYmJioqLjI2Oj5CRk5SWl5mam52eoKGio6SlpqipqqurrK2ur6+wsbGysrOzs7S0tLSzs7OysbGwr62sqqmnpaKgnZuYlZKPjYqHhYKAfn17enl4eHh4eHl5ent8fX5/gIKDhIaHiYqMjY+QkZOUlZeYmZqam5ydnZ6fn6CgoaGhoqKioqOjo6KioqKioaGhoKCgoJ+fn56enp2dnJubmpmYl5aVlJOSkZCOjYyLiomJiIiIiIiIiImKiouMjo+QkZOUlpeZmpydn6CioqOlpqeoqausra2ur7CxsbKzs7S0tLW1tbW0tLSzsrGwr66tq6mnpaOgnZuYlZKPjImGhIJ/fnx6eXh4eHd3eHh5eXp7fH5/gIGDhIaHiYqMjY+QkZOUlZeYmZqbm5ydnp6fn6CgoaGioqOjo6Ojo6Ojo6Ojo6KioqKhoaGgoKCfn56dnZybmpqZmJaVlJOSkI+OjYuKiYiIh4eGhoaHh4iIiYqLjI6PkJKTlZaYmZucnp+hoaOkpqeoqausra6vsLGxsrOztLW1tbW2trW1tbS0s7KxsK+tq6qnpaOgnZqXlJGOi4iGg4F/fXt6eXh3d3d3d3h4eXp7fH1+gIGChIWHiIqLjY6QkZOUlZaYmZqbm5ydnp6foKChoaKio6OkpKSkpKSkpKSkpKSjo6OjoqKioaGgoJ+enp2cm5qZmJeVlJORkI6NjIqJiIeHhoaFhYWFhoaHiImKi4yOj5CSlJWXmJqbnZ6goaKkpaeoqaqsra6vsLGys7S0tbW2tra2t7a2trW1tLOysa+urKqopaOgnZqXlJGOioiFgoB+fHp5eHd2dnZ2dnd4eHl6e31+f4GCg4WGiImLjI6PkZKUlZaXmZqbm5ydnp+foKGhoqKjo6SkpaWlpaWmpqalpaWlpaWkpKSjo6KioaCgn56dnJuZmJeVlJKRj46Mi4qIh4aFhYSEhISEhYWGh4iJiouMjo+RkpSWl5mbnJ6foKKjpaaoqaqsra6vsLKzs7S1tra3t7e3t7e3t7a2tbSzsbCurKqopaOgnZqXk5CNioeEgX98e3l4d3Z1dXV1dXZ3eHh6e3x9f4CBg4SGh4mKjI6PkZKTlZaXmJmbm5ydnp+goKGioqOkpKWlpqamp6enp6enp6enp6ampqWlpKSjoqKhoJ+enJuamJeVlJKQj42MiomHhoWEhIODg4ODg4SFhYaHiYqLjY6QkZOVlpiam52foKGjpaaoqaqsra6wsbKztLW2tre4uLi4uLi4uLe3trW0srGvrauopqOgnZmWk4+MiYaDgH17eXh2dXV0dHR0dHV2d3h5ent8fn+BgoSFh4iKi42PkJKTlJaXmJmam5ydnp+goaKio6Skpaamp6enqKioqampqampqaioqKenpqalpKOioaCfnZyamZeVk5KQjoyLiYiGhYSDgoKCgYKCgoODhIWGiImKjI2PkJKUlpeZm5yen6GjpKanqaqsra+wsbK0tba2t7i4ubm5ubm5ubi4t7a0s7GvrauppqOgnJmVko6LiISBf3x6eHZ1dHNzc3Nzc3R1dXZ3eXp7fX6AgYOEhoeJi4yOj5GSlJWXmJmam5ydnp+goaKjpKSlpqenqKipqaqqqqqrq6urq6qqqqmpqKenpqWkoqGgnpybmZeVk5GPjoyKiIeFhIOCgYGAgICBgYKCg4SFh4iJi4yOkJGTlZaYmpydn6GipKanqausrq+wsrO0tba3uLm5urq6urq6urm4uLe1tLKwrquppqOfnJiVkY2KhoOAfXt4dnVzcnJxcXFxcnJzdHV2d3l6e31+gIKDhYeIiouNj5CSk5WWmJmam5ydn6ChoqKjpKWmp6ioqaqqq6usrKytra2tra2srKyrqqqpqKelpKKhn52bmZeVk5GPjYuJh4aEg4KBgIB/f39/gICBgoOEhoeIiouNj5GSlJaYmZudnqCipKanqausrq+xsrO1tre4ubm6u7u7u7u7u7q5ube2tbOxrqyppqOfm5iUkIyIhYF+e3l3dXNycXBwb29wcHFycnR1dnd5enx9f4CChIWHiYuMjpCRk5SWl5iam5yen6ChoqOkpaanqKmqqqusra2urq+vr6+vr6+vrq6trayrqqinpqSioJ6cmpiWk5GPjIqIhoWDgoGAf35+fn5+f3+AgYKDhYaIiYuMjpCSk5WXmZudnqCipKWnqausrrCxsrS1tre4ubq7u7y8vLy8vLu7uri3tbOxr6yppqKfm5eTj4uHg4B8eXd0c3Fwb25ubW1ubm9wcXJzdHZ3eXp8fX+Bg4SGiIqLjY+QkpSVl5iam5yen6Cho6SlpqeoqaqrrK2urq+wsLGxsrKysrKxsbGwr66trKupp6akop+dm5iWk5GOjIqIhoSCgYB/fn19fX19fn5/gIGChIWHiIqMjY+Rk5WXmZqcnqCipKWnqautrrCxs7S2t7i5uru8vL29vb29vby8u7m4trSyr6yppqKempaRjYmFgX16d3RycG9tbGxra2tsbG1ub3BxcnR1d3h6fH5/gYOFh4iKjI6PkZOVlpiZm5yen6Cio6Smp6ipqqytrq+wsLGys7O0tLS1tbW0tLSzsrGwr62rqqilo6GenJmWk5GOjImHhYOBgH59fXx8fHx8fX1+f4CCg4SGiImLjY+RkpSWmJqcnqCipKWnqautrrCys7W2t7m6u7y9vb6+vr6+vr29vLq5t7WysK2ppaGdmZSQi4eDf3t3dHJvbWxramlpaWlpamtrbG5vcHJzdXd4enx+gIGDhYeJi42PkJKUlpeZm5yen6GipKWnqKmrrK2ur7Gys7S0tba2t7e4uLi3t7e2tbSzsbCurKqnpaKgnZqXlJGOi4mGhIKAf318fHt7e3t7fHx9fn+BgoSFh4mKjI6QkpSWmJqcnqCipKWnqautr7CytLW3uLm7vL29vr+/v8C/v7++vbu6uLWzsK2ppaGcl5OOiYSAfHh0cW9samloZ2ZmZmZnZ2hpamttbnBxc3V2eHp8foCChIaIioyOj5GTlZeZmpyeoKGjpKanqausra+wsbO0tba3uLm5urq7u7u7u7q5uLe2tbOxr6yqp6ShnpuXlJGOi4iGg4F/fnx7enp6enp6e3x8fX+AgYOFhoiKjI6QkpSWmJqcnZ+ho6Wnqautr7GytLa3ubq7vL2+v8DAwMHBwMC/vry7uLazsKyopKCblpCLhoF9eHRxbmtpZ2VkY2NjY2NkZGVmZ2lqbG1vcXN0dnh6fH6AgoSGiIuNj5GTlZaYmpyeoKKjpaepqqytr7Gys7W2t7m6u7y8vb6+vr6+vr69vLu6uLa0sq+tqqajoJyZlZGOi4iFg4B+fXt6eXl5eXl5ent8fX5/gYKEhoeJi42PkZOVl5mbnZ+ho6aoqqutr7Gztba4ubu8vb6/wMHBwsLCwcHAv727ubazsKyoo56Zk46Ig315dHBsaWdkY2FgYF9fX2BgYWJjZWZnaWttbnBydHZ4en1/gYOFh4mMjpCSlJaYmpyeoKKkpqiqq62vsbK0tre5uru9vr/AwMHCwsLCwsLBwL++vLq4trOwrammop6alpKPi4iFgoB+fHt5eXh4eHh4eXp7fH1/gIKDhYeJi42PkZOVl5mbnZ+ho6aoqqyur7Gztbe4uru9vr/AwcLCwsPDwsLBv768ubezr6umoZyWkIqEfnl0b2tnZGJgXl1cW1tbW1xdXl9gYmNlZmhqbG5wcnR2eXt9f4KEhoiLjY+RlJaYmpyeoaOlp6mrra+xs7S2uLq7vb7AwcLDxMXFxsbGxsbGxcTCwb+9ure0sK2ppaCcmJSQjIiFgn99e3p5eHd3d3d4eHl6e3x+f4GDhYaIioyOkJKVl5mbnZ+ho6aoqqyusLKztbe5ury9vsDBwsLDw8PDw8LBwL68ubazrqqkn5iSjIV/eXNuaWViX1xaWVhXV1dXV1hZWltdXmBiZGVnaWxucHJ0d3l7foCChYeKjI6Rk5WYmpyfoaOmqKqsrrCytLa4ury+v8HDxMXHyMnJysvLy8vKysnHxsTCv7y5tbGtqKOfmpaRjYmGgoB9e3l4d3d2dnZ3d3h5enx9f4CChIaIioyOkJKUlpmbnZ+ho6WoqqyusLK0tre5u7y+v8DBwsPExMTEw8PCwL68ubWxrKehm5SNhn94cmxnYl5bWFZUU1JSUlJSU1RVVlhZW11fYWNlZ2lrbnBzdXd6fH+BhIaJi46Qk5WYmp2foqSmqautsLK0tri7vb/AwsTGx8nKy83Ozs/Q0NDQz87NzMrHxcK+urayraijnpiUj4uHg4B9e3l4d3Z2dnZ2d3h5ent9foCCg4WHiYuOkJKUlpibnZ+ho6WoqqyusLK0tri5u72+v8HCw8PExMTEw8PBwL26t7OuqaOclY2FfnZwaWNeWldUUU9OTU1MTU1OT1BRU1RWWFpcXmBiZWdpbG5xc3Z4e36Ag4WIi42Qk5WYmp2goqWnqqyvsbS2uLu9v8HDxcfJy8zOz9HS09TU1dXV1dTT0tDOzMnFwb24s66oop2Xko2JhYJ/fHp4d3Z2dnZ2d3d4eXt8fn+Bg4WHiYuNj5GUlpianJ6ho6WnqqyusLK0tri5u72+v8HCw8PExMTDw8LAvru4tK+po5yUjIR7c2xlX1lVUU5LSUhHR0ZHR0hJSkxNT1FSVFdZW11gYmVnamxvcnR3enx/goWHio2QkpWYm52go6aoq66ws7W4ur2/wcTGyMrMztDS1NXW2Nna2tvb29va2djW1NHOysbBu7awqqOdl5KNiISBfnt6eHd2dnZ2d3d4eXp8fX+Bg4SGiIuNj5GTlZianJ6go6WnqauusLK0tbe5u7y+v8DBwsLDw8LCwb+9ureyraehmZGIf3ZtZV5YUk1JRkRCQUBAQEBBQkNERkdJS01PUVRWWFtdYGNlaGttcHN2eXx+gYSHio2Qk5WYm56hpKaprK+ytLe6vL/BxMbJy83Q0tTW2Nrb3d7f4OHi4uLi4eDf3dvY1NDMxsG6tK2moJmUjomFgn98enl4d3d3d3h4eXt8fX+BgoSGiIqMjpGTlZeam56goqSnqautr7Gztbe4uru9vr+/wMDAwL++vLq3s66popqSiX91bGNbU01IQ0A9Ozo5ODg4OTo7PD4/QUNFR0pMTlFTVllbXmFkZmlsb3J1eHt+gYSHio2Qk5aZnJ+ipaeqrbCztrm8vsHExsnMztHT1dja3N7g4uPl5ujp6erq6urp6Obk4d7a1dDKw7y1raafmJKNiYWBf317enl5eXl6ent9fn+Bg4SGiIqMjpCTlZeZ", - "colsCount": 180, - "valueScale": 2.0 -} -\ No newline at end of file + "array": "6Ojo6Obm5ubk5OTk4uLi4uDg4ODg3t7e3tzc3Nza2trY2NbW1NTS0NDOzMrIxsTCwL66uLaysK6qqKakoJ6cmpaUkpCOjIqKiIaEgoKAfnx8enh2dHJwbmxqaGRiYFxaVlRQTkpGREA+Ojg0Mi4sKCYkIB4cGhgWFBIQDgwKCAgGBgQEAgICAgICAgQEBggKDhIWHCQsNkJQYHCAkJ6stsDIztLY2t7g4uTm5ujo6Ojo6Ojo4ODg4ODg4N7e3t7e3Nzc3Nza2tra2trY2NjY2NjW1tbW1NTS0tDQzszMysjGxMLAvry4trSwrqyopqSgnpyYlpSSkI6MioiGhISCgIB+fHx6eHZ2dHJwbmxqaGRiYFxaVlRQTkpIREA+Ojg0MjAsKiYkIiAeHBoYFhQSEBAODgwMCgoKCgoKCgwMDhASFBgcICYsNDxGUFpmcoCKlqCqsri+xMjM0NTW2Nrc3N7e4ODg4ODg2tra2tra2trY2NjY2NjW1tbW1tbW1tTU1NTU1NTU0tLS0tDQ0M7OzMrKyMbEwsC+vLq2tLKurKimpKCempiWlJCOjIqIhoSEgoCAfnx8enp4dnZ0cnBwbmxqZmRiYFxaVlRQTkpIREI+PDg2MjAuKigmJCIgHhwaGBYWFBQSEhISEBASEhIUFBYYGhwgJCgsMjhARk5YYGp0foiQmKCorrS6vsLGyMzO0NLU1NbY2Nja2tra1NTU1NTU1NTU1NTU0tLS0tLS0tLS0NDQ0NDQ0NDQ0NDOzs7OzMzKysjIxsTCwL68uri0srCsqqakoJ6amJaSkI6MioaGhIKAfn58fHp6eHZ2dHRycnBubGpoZmRiYFxaVlRQTkpIREI+PDg2NDAuLCooJCQiIB4cHBoaGBgYFhYWGBgYGhocHiAiJiouMjY8QkhOVl5mbnZ+hIyUmqCmrLC0uLzAwsbIyszOztDQ0tLU1NTU0NDQ0NDQ0NDQ0NDOzs7Ozs7Ozs7OzMzMzMzMzMzMzMzMzMrKysrIyMbGxMLAvry6uLaysK6qqKSinpqYlJKQjIqIhoSCgH58fHp6eHh2dnR0cnJwcG5ubGpoZmRiYFxaVlRSTkxIRkJAPDo2NDIwLCooJiYkIiAgHh4cHBwcHBwcHh4gIiQmKCouMjY6PkRITlRcYmhwdnyEipCWmqCkqq6ytLi8vsDCxMbIysrMzM7Ozs7QzMzMzMzMzMzMzMzMysrKysrKysrKysrKysrKysjIyMjIyMjIyMbGxsTCwsC+vLq4trSwrqyopKKenJiWko6MioaEgoB+fHp6eHh2dnR0cnJycHBwbm5sampoZmRiYFxaWFRSTkxIRkJAPjo4NjIwLiwqKCgmJCQiIiIgICAiIiIkJCYoKiwuMjQ4PEBESk5UWmBmbHJ2fIKIjJKWnKCkqKyusrS4ury+wMLExMbGyMjKysrKyMjIyMjIyMjIyMjIyMjIxsbGxsbGxsbGxsbGxsbGxsbGxsbExMTEwsLAwL68uri2tLKurKimoqCcmJaSjoyIhoSAfnx6eHh2dHRycnJwcHBubm5ubGxqamhmZmRiYFxaWFRSUExKRkRAPjw6NjQyMC4sLCooKCYmJiYmJiYmKCgqLC4wMjQ4Oj5CRkpOVFheYmhucnh8goaKkJSYnKCipqqsrrK0tri6vL7AwMLCxMTGxsbGxMTExMTExMTExMTExMTExMTExMTEwsLCwsLCwsLCwsLCwsLCwsLAwMC+vry6uLa0srCsqqakoJyalpKQjIiGgoB+fHp4dnRycnBwbm5ubmxsbGxsampqaGhmZGRiYF5aWFZSUE5KSERCQD46ODY0MjAwLiwsLCoqKioqKiwsLi4wMjQ2OjxAREZKUFRYXGJmanB0eHyChoqOkpSYnJ6ipKiqrK6ytLa4uLq8vr7AwMLCwsLEwMDCwsLCwsLCwsLCwsLCwMDAwMDAwMDAwMDAwMDAwMDAwMDAwL6+vr68vLq4trSysK6qqKSinpqWlJCMiIaCgHx6eHZ0cnBwbm5sbGxsampqampqaGhoaGZmZGRiYF5cWlZUUk5MSkZEQkA8Ojg2NjQyMjAwMC4uLi4wMDIyNDY4Ojw+QkRITFBUWFxgZGhscnZ6foKEiIyQkpaYnJ6gpKaoqqyusLK0tri4ury8vr6+wMDAvr6+vr6+vr6+vr6+vr6+vr6+vr6+vr6+vr6+vr6+vr6+vry8vLy8vLq6uLi2tLKwrqyopqKenJiUkIyKhoKAfHp4dHJycG5sbGpqamhoaGhoaGhoaGZmZmZkZGRiYF5cWlhWVFBOTEhGREJAPjw6ODg2NjQ0NDQ0NDQ0Njg4Ojw+QERGSkxQVFhaXmJmbG5ydnp+goSIio6QlJaYnJ6goqSmqKqsrrCytLS2uLi6ury8vLy+vLy8vLy8vLy8vLy8vLy8vLy8vLy8urq6urq6urq6urq6urq6urq6uLi4tra0srCurKimoqCcmJaSjoqGhIB8enZ0cnBubGxqamhoZmZmZmZmZmZmZmZmZmRkZGRiYGBeXFpYVlJQTkxKRkRCQEA+PDw6Ojg4ODg4Ojo6PD4+QEJGSEpOUFRYWl5iZmpucHR4fH6ChIiKjJCSlJaYmpygoqSmqKiqrK6wsLK0tLa2uLi6urq6uLi6urq6urq6urq6urq6urq6uri4uLi4uLi4uLi4uLi4uLi4uLi2tra2tLKysK6sqqakoJ6alpKOjIiEgHx6dnRycG5samhoZmZmZGRkZGRkZGRkZGRkZGRkZGRiYmBgXlxaWFZUUk5MSkhGRERCQEA+Pj4+Pj4+PkBAQkRGSEpMTlJUWFpeYmRobHBydnp8gIKEiIqMjpCSlJaYmpyeoKKkpqioqqyurrCysrS0tra2uLi4tra2uLi4uLi4uLi4uLi4uLi4tra2tra2tra2tra2tra2tra2trS0tLSysrCwrqyqqKSinpqYlJCMiISCfnp4dHJwbmxqaGZmZGRkYmJiYmJiYmJiYmJkZGRkZGRkZGJiYF5eXFpYVlJQTk5MSkhGRkRERERCREREREZGSEpMTlBSVlhaXmBkaGpucnR4en6AgoSIioyOkJKUlJaYmpyeoKCipKaoqKqsrK6wsLKytLS0tra2tLS0tra2tra2tra2tra2tra2trS0tLS0tLS0tLS0tLS0tLSysrKysrKwsK6urKqopKKgnJiWko6KhoJ+fHh2cnBubGpoZmRkZGJiYmBgYGBgYGBiYmJiZGRkZmZmZmZkZGJgYF5cWlhWVFJQTk5MTEpKSkhISEpKSkxOTlBSVFZYXF5gZGZqbHBydnh8foCEhoiKjI6OkJKUlJaYmpycnqCioqSmqKiqrKyurrCwsrKytLS0srKytLS0tLS0tLS0tLS0tLS0tLSysrKysrKysrKysrKysLCwsLCwsLCurqyqqqimoqCempaSkIyIhIB8enZycG5samhmZGRiYmJgYGBgYGBgYGBgYmJiZGRmZmhoaGhoaGZmZGJgXl5cWlhWVFRSUlBQUE5OUFBQUFJUVFZYWlxeYmRmaGxucnR4enyAgoSGiIqMjI6QkpKUlpaYmpqcnp6goqSkpqioqqqsrK6usLCwsrKysLCysrKysrKysrKysrKysrKysrKysLCwsLCwsLCwsLCwrq6urq6urq6srKqoqKakoJ6amJSQjoqGgn56eHRybmxqaGZkZGJiYGBgYGBeXl5gYGBgYmJkZGZoaGpqamxsbGpqaGhmZGRiYF5cXFpYWFZWVlZUVlZWWFhaWlxeYGJkZmhsbnB0dnh6foCChIaIioyMjpCQkpKUlpaYmJqcnJ6goKKkpKaoqKqqrKyurq6wsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCurq6urq6urq6urqysrKysrKyqqqimpqSinpyYlpKOjIiEgHx4dnJwbGpoZmRkYmJgYGBgXl5eXl5gYGBiYmRkZmhoamxsbm5wcHBubm5sampoZmRiYmBeXlxcXFxcXFxcXF5gYGJkZmhqbG5wcnR2enx+gIKEhoiKjIyOkJCSkpSUlJaYmJqanJ6eoKKipKSmpqioqqqsrKyurq6urq6urq6urq6urq6urq6urq6urq6urq6urqysrKysrKysrKysqqqqqqqoqKampKKgnJqWlJCMioaCfnp4dHBubGpoZmRiYmBgYGBeXl5eXmBgYGJiZGRmaGpsbG5wcnJ0dHR0dHJycHBubGpqaGZmZGRiYmJiYmJiYmRkZmZoamxucHJ0dnh6fH6ChIaIiIqMjI6QkJCSkpSUlJaWmJianJyenqCioqSkpqaoqKqqqqysrKyurKysrKysrKysrq6urq6urqysrKysrKysrKysqqqqqqqqqqqqqqqoqKimpqSkoqCempiWko6KiISAfHp2cnBsamhmZGRiYmBgYGBgYGBgYGBgYmJkZmZoamxucHJydHZ2eHh4eHh4dnZ0cnJwbmxsampoaGZmZmZoaGhqamxubnBydHZ4enx+gIKEhoiIioyOjpCQkJKSkpSUlJaWmJiampycnqCgoqKkpKamqKiqqqqqrKysqqysrKysrKysrKysrKysrKysrKysqqqqqqqqqqqqqKioqKioqKiopqampKSioJ6cmpaUkIyKhoJ+fHh0cm5samhmZGRiYmBgYGBgYGBgYGJiZGRmaGhqbG5wcnR2eHp6fHx8fHx8fHp6eHZ2dHJycG5ubGxsbGxsbG5ubnBycnR2dnh6fH6AgoSGiIqKjI6OkJCQkpKSkpSUlJaWlpiYmpqcnp6goKKipKSmpqioqKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqioqKioqKioqKampqampqSkoqKgnpyamJSSjoyIhIB+enZ0cG5samhmZGJiYmBgYGBgYGBiYmRkZmZoamxucHJ0dnh6enx+foCAgICAgIB+fnx6enh2dnRycnJwcHBwcnJycnR0dnh4enx+foCChIaIioqMjo6QkJCQkpKSkpSUlJSWlpiYmpqcnJ6eoKCioqSkpqamqKioqqqqqKiqqqqqqqqqqqqqqqqqqqqqqKioqKioqKioqKampqampqampqSkpKSioqCenpqYlpSQjoqGhIB8eHZycG5qaGZmZGJiYmBgYGBiYmJkZGRmaGhqbG5wcnR2eHp8foCAgoSEhISEhISCgoCAfnx8enh4dnZ2dHR0dnZ2dnh4enp8fH6AgoKEhoiIioyMjpCQkJCSkpKSkpKUlJSUlpaYmJqanJyenqCioqKkpKampqioqKioqKioqKioqKioqKioqKioqKioqKioqKiopqampqampqakpKSkpKSkoqKioJ6enJqYlJKQjIiGgn58eHRycGxqaGZmZGRiYmJiYmJiZGRkZmhoamxubnBydHZ4enx+gIKEhIaGiIiIiIiGhoSEgoCAfnx8enp6eHh4eHh6enp8fHx+gICCgoSGiIiKjIyOjpCQkJKSkpKSkpKSlJSUlpaWmJianJyenqCgoqKkpKSmpqamqKioqKioqKioqKimpqampqampqampqampqampqampqSkpKSkpKSkpKKioqKgoJ6cmpiWlJCOioiEgH56eHRybmxqaGZmZGRiYmJiYmRkZGZmaGpqbG5wcnR2eHp8foCAgoSGhoiKioqKioqKiIiGhoSEgoCAfn58fHx8fHx8fH5+foCAgoKEhIaIiIqMjI6OkJCQkpKSkpKSkpKSkpSUlJaWmJiampycnp6goKKipKSkpqampqampqampqampqampqampqampqampqampqampKSkpKSkpKSkoqKioqKioKCgnpycmpiUkpCMioaEgHx6dnRwbmxqaGZmZGRkZGRkZGRmZmhoamxubnBydHZ4enx+gIKChIaIiIqMjIyMjIyMjIqKiIiGhISCgoCAgIB+fn5+gICAgIKChISEhoiIioqMjo6QkJCQkpKSkpKSkpKSkpKUlJSWlpiYmpqcnJ6eoKCioqSkpKampqampqampqampqampqampqampqampKSkpKSkpKSkpKSioqKioqKioqCgoKCenpyamJaUko6MiIaCgHx6dnRwbmxqaGhmZmRkZGRkZmZoaGpqbG5wcnR0dnh6fH6AgoSEhoiKioyMjo6Ojo6Ojo6MjIqIiIaGhISCgoKCgoKCgoKCgoSEhIaGiIiKioyMjo6QkJCSkpKSkpKSkpKSkpKSlJSWlpiYmpqcnJ6eoKCioqKkpKSkpqampqampqakpKSkpKSkpKSkpKSkpKSkpKSkpKSioqKioqKioqKgoKCgoJ6enJqamJaSkI6KiISCfnx4dnRwbmxqaGhmZmZmZmZmZmhoamxsbnBydHZ4enp8foCChIaGiIqKjI6OjpCQkJCQkJCOjoyMioiIhoaGhISEhISEhISEhISGhoaIiIqKjIyOjo6QkJCSkpKSkpKSkpKSkpKSkpSUlpaYmJqanJyenqCgoqKipKSkpKSmpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkoqKioqKioqKioKCgoKCgnp6cnJqYlpSSkIyKhoSAfnx4dnJwbmxqamhoZmZmZmZoaGpqbG5ucHJ0dnh6fH5+gIKEhoaIioqMjo6QkJCSkpKSkpCQkI6OjIqKiIiIhoaGhoaGhoaGhoaGiIiIioqKjIyOjpCQkJCSkpKSkpCQkJCQkJKSkpSUlJaWmJianJyenp6goKKioqSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSioqKioqKioqKioqCgoKCgoJ6enpycmpqYlpSSjoyKhoSAfnp4dnJwbmxqamhoaGhoaGhoampsbnBwcnR2eHp8foCAgoSGhoiKioyOjpCQkJKSkpKSkpKSkJCOjoyMioqKiIiIiIiGhoaIiIiIiIiKioqMjI6OjpCQkJCQkpCQkJCQkJCQkJCSkpKUlJaWmJiampycnp6goKCioqKkpKSkpKSkpKSkpKSioqKioqKioqKioqKioqKioqKioqKgoKCgoKCgnp6enpycmpiWlJKQjoyIhoKAfnp4dnJwbmxsampoaGhoaGpqbGxucHBydHZ4enx+gICChIaGiIqKjIyOkJCQkpKSlJSUlJSSkpCQkI6OjIyKioqKiIiIiIiIiIiIioqKioyMjI6OjpCQkJCQkJCQkJCQkJCQkJCQkJKSlJSWlpiYmpqcnJ6eoKCioqKipKSkpKSkpKSkoqKioqKioqKioqKioqKioqKioqKioqCgoKCgoKCenp6enJyampiWlJKQjIqIhIKAfHp4dHJwbm5sampqaGhqampsbG5wcHJ0dnh6fH6AgIKEhoaIioqMjI6OkJCSkpSUlJSUlJSUkpKSkJCOjoyMjIqKioqKioqKioqKioqKjIyMjo6OjpCQkJCQkJCQkJCQkI6OkJCQkJCSkpSUlpaYmJqcnJ6eoKCgoqKioqSkpKSkpKSioqKioqKioqKioqKioqKioqKioqKioKCgoKCgoKCenp6cnJyamJaWlJKOjIqIhIJ+fHp4dHJwbm5sbGpqampqamxsbnBwcnR2eHp8foCAgoSGhoiKioyMjo6QkJKSkpSUlJSUlJSUlJKSkpCQjo6OjIyMjIyKioqKioqKioyMjIyMjo6OjpCQkJCQkJCQkJCOjo6Ojo6OkJCQkpKUlJaYmJqanJyenqCgoKKioqKkoqSioqKioqKioqKioqKioqKioqKioqKioqKioKCgoKCgoJ6enp6cnJqamJaUkpCOjIqGhIJ+fHp4dHJwcG5sbGxqamxsbG5ucHBydHZ4enx+foCChIaGiIqKjIyOjpCQkpKSlJSUlpaWlpaUlJSSkpKQkI6Ojo6MjIyMjIyMjIyMjIyMjIyOjo6OjpCQkJCQkJCQjo6Ojo6Ojo6OjpCQkJKSlJaWmJiampycnp6goKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCgoKCgoJ6enp6cnJqYmJaUkpCOioiGhIB+fHp2dHJycG5ubGxsbGxsbm5wcHJ0dnh4enx+gIKEhoaIioqMjI6OkJCQkpKUlJSWlpaWlpaWlJSUkpKSkJCQjo6Ojo6MjIyMjIyMjIyMjI6Ojo6OjpCQkJCQkI6Ojo6OjoyMjI6Ojo6QkJKSlJSWlpiYmpqcnp6eoKCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCgoKCgoJ6enpycmpqYlpaUko6MioiGgoB+fHh2dHJycG5ubmxsbG5ubnBwcnR2dnh6fH6AgoKEhoiIioyMjo6OkJCSkpKUlJSWlpaWlpaWlpSUlJKSkpCQkI6Ojo6Ojo6OjoyMjIyOjo6Ojo6Ojo6QkJCOjo6Ojo6MjIyMjIyMjo6OkJCSkpSUlpaYmJqcnJ6eoKCgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoKCgoJ6enpycmpqYlpSSkI6MioiEgoB+enh2dHJycHBubm5ubm5ucHBydHR2eHp8fn6AgoSGiIiKioyMjo6QkJKSkpSUlJaWlpaWlpaWlpaUlJSSkpKQkJCQjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjIyMjIyMjIyMjIyOjpCQkpKUlJaWmJqanJyenqCgoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKCgoKCenpycmpqYlpSSkI6MioaEgoB8enh2dHRycHBubm5ubnBwcHJ0dHZ4enp8foCChISGiIqKjIyOjpCQkJKSkpSUlJaWlpaWmJaWlpaWlJSUkpKSkJCQkJCQjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6MjIyMjIqKioqKjIyMjo6OkJKSlJSWlpiampycnp6goKCioqKioqKioqKioqKioqKioqKipKSkpKSkpKKioqKioqCgoKCenpycmpiYlpSSkI6KiIaEgn58enh2dHRycHBwcG5wcHBwcnJ0dnZ4enx+gICChIaIiIqMjI6OkJCQkpKSlJSUlpaWlpiYmJiYlpaWlpSUlJKSkpKQkJCQkJCQkI6Ojo6Ojo6Ojo6Ojo6Ojo6OjoyMjIyKioqKioqKioqMjIyOjpCSkpSUlpiYmpqcnJ6eoKCgoKKioqKioqKioqKioqKioqSkpKSkpKSkpKSkoqKioqKgoKCenpycmpiYlpSSkIyKiIaEgH58enh2dHRycnBwcHBwcHBycnR2dnh6enx+gIKEhIaIioqMjI6OkJCSkpKUlJSUlpaWmJiYmJiYmJaWlpaUlJSSkpKSkpCQkJCQkJCQkJCOjo6Ojo6Ojo6Ojo6OjIyMjIqKioqIiIiIioqKioyMjo6QkpKUlJaYmJqanJyenqCgoKCgoqKioqKioqKioqKkpKSkpKSkpKSkpKSkpKSioqKioKCgnpycmpiWlpSQjoyKiIaCgH58enh2dHRycnBwcHBwcnJydHR2eHh6fH6AgIKEhoiIioyMjo6QkJCSkpKUlJSWlpaWmJiYmJiYmJiWlpaWlJSUkpKSkpKSkJCQkJCQkJCQkJCOjo6Ojo6Ojo6MjIyKioqKiIiIiIiIiIiIioqMjI6OkJCSlJSWmJiampyenp6goKCgoKKioqKioqKioqSkpKSkpKSkpqampKSkpKSkpKKioqCgnp6cmpiWlJKQjoyKhoSCgH58enh2dHRycnJwcHBycnJ0dHZ2eHp8fH6AgoKEhoiKioyMjo6QkJKSkpSUlJaWlpaYmJiYmJiYmJiYlpaWlpSUlJSSkpKSkpKSkJCQkJCQkJCQkI6Ojo6OjoyMjIqKioiIiIiGhoaGhoiIiIqKjIyOjpCQkpSUlpiYmpycnp6enqCgoKCioqKioqKkpKSkpKSkpqampqampqampqSkpKSioqCgnp6cmpiWlJKQjoyIhoSCgH58enh2dHRycnJycnJycnR0dnZ4eHp8fn6AgoSGhoiKioyOjpCQkpKSlJSUlJaWlpaYmJiYmJiYmJiYmJaWlpaUlJSUlJKSkpKSkpKSkJCQkJCQkJCOjo6OjIyMjIqKiIiIhoaGhoaGhoaGiIiIioqMjo6QkJKUlJaYmJqcnJ6enp6goKCioqKioqKkpKSkpKampqampqampqampqampKSkoqKgnp6cmpiWlJKQjoyIhoSCfnx6eHh2dHRycnJycnJydHR0dnZ4enp8foCAgoSGhoiKjIyOjpCQkpKSlJSUlpaWlpiYmJiYmJiYmJiYmJiWlpaWlpSUlJSUlJKSkpKSkpKQkJCQkJCOjo6OjIyMioqIiIiGhoaEhISEhISGhoaIiIqKjIyOkJCSlJSWmJianJyenp6eoKCgoqKioqSkpKSkpqampqaoqKioqKimpqampqSkoqKgoJ6cmpiWlJKQjoqIhoSAfnx6eHZ2dHRycnJycnJydHR2dnh4enx8foCCgoSGiIiKjIyOkJCQkpKUlJSWlpaWmJiYmJiYmpqamJiYmJiYlpaWlpaWlJSUlJSUlJKSkpKSkpCQkJCOjo6OjIyKioqIiIaGhoSEhISEhISEhIaGiIiKioyMjpCQkpSWlpiYmpycnJ6eoKCgoqKioqSkpKampqamqKioqKioqKioqKimpqakpKKioJ6cmpiWlJKQjIqIhoKAfnx6eHZ2dHRycnJycnJ0dHR2dnh6enx+foCChISGiIiKjIyOkJCSkpKUlJSWlpaWmJiYmJiampqampqamJiYmJiYlpaWlpaWlJSUlJSUkpKSkpKQkJCQjo6MjIyKioiIhoaEhISCgoKCgoKChISEhoaIiIqMjI6QkJKUlpaYmpqcnJyenqCgoKKioqSkpKampqioqKioqKiqqqioqKiopqampKKioJ6cmpiWlJKQjIqIhIKAfnx6eHZ0dHJycnJycnJ0dHR2dnh6enx+foCChISGiIqKjI6OkJCSkpSUlJaWlpaYmJiYmpqampqampqampqYmJiYmJiYlpaWlpaWlJSUlJSSkpKSkJCQjo6MjIqKiIiGhoSEhIKCgoKAgoKCgoKEhIaGiIiKjIyOkJKSlJaWmJqampycnp6goKKipKSkpqamqKioqKqqqqqqqqqqqqioqKampKSioKCenJqWlJKQjIqGhIKAfHp4eHZ0dHJycnJycnJ0dHR2eHh6enx+foCChISGiIqKjI6OkJCSkpSUlJaWlpiYmJiYmpqampqampqampqampqYmJiYmJiYmJaWlpaWlJSUkpKSkJCQjo6MjIqKiIiGhISCgoKAgICAgICAgIKChISGhoiIioyMjpCSkpSWlpiampycnp6goKKipKSkpqaoqKioqqqqqqqqqqqqqqqqqKimpqSioqCenJqWlJKOjIqGhIJ+fHp4dnZ0dHJycnJycnJ0dHR2eHh6enx+gICChISGiIqKjI6OkJCSkpSUlpaWlpiYmJiampqampqcnJycmpqampqampqampiYmJiYmJaWlpaUlJKSkpCQjo6MjIqIiIaGhISCgoCAgH5+fn6AgICAgoKEhIaIiIqMjo6QkpKUlpiYmJqcnJ6goKKipKSmpqaoqKiqqqqqrKysrKysqqqqqqiopqSkoqCenJqWlJKOjIqGhIB+fHp4dnR0cnJycnJycnJydHR2dnh6enx+foCChISGiIqKjI6OkJCSkpSUlpaWmJiYmJqampqanJycnJycnJycnJycnJqampqampqYmJiYlpaWlJSSkpCQjo6MjIqIiIaEhIKCgIB+fn5+fn5+fn6AgIKChISGiIiKjI6OkJKUlJaYmJqanJ6eoKKipKSmpqioqKqqqqysrKysrKysrKyqqqqopqakoqCenJqWlJKOjIiGgoB+fHp4dnRycnJwcHBwcnJydHR2dnh6enx+foCChISGiIqKjI6OkJCSkpSUlpaWmJiYmpqampycnJycnJycnJycnJycnJycnJycnJqampqYmJiWlpSUkpKQjo6MioqIhoaEgoKAgH5+fHx8fHx8fn5+gICCgoSEhoiKioyOkJCSlJaWmJianJyeoKCipKSmpqioqqqqrKysrK6urq6srKysqqqoqKakoqCenJqWlJKOjIiGgoB+enh2dHRycnBwcHBwcHJycnR2dnh4enx8foCCgoSGiIiKjI6OkJCSkpSUlpaYmJiampqanJycnJyenp6enp6enp6enp6enp6cnJycnJqampiYlpaUkpKQjo6MioiIhoSCgoCAfn58fHx8enx8fHx+fn6AgoKEhoaIioqMjpCSkpSWlpianJyeoKCipKSmpqioqqqsrKyurq6urq6urqysrKqqqKampKKenJqWlJKOioiEgn58enh2dHJycHBwcHBwcHBycnR0dnZ4enp8foCAgoSGhoiKjIyOkJCSkpSUlpaYmJiampqcnJycnp6enp6goKCgoKCgoKCgoKCenp6enJycmpqYmJaUlJKQkI6MioiGhoSCgIB+fHx8enp6enp6enx8fH5+gIKChIaGiIqMjo6QkpSUlpiYmpyeoKCipKSmqKiqqqysrK6urq6urq6urq6urKyqqKimpKKgnJqWlJCOioiEgn58eHZ0dHJwcG5ubm5ucHBwcnJ0dHZ4eHp8fn6AgoSEhoiKioyOkJCSkpSUlpaYmJqampycnJ6enp6goKCgoKCioqKioqKioqCgoKCgnp6cnJqamJiWlJKQkI6MioiGhIKCgH58fHp6enh4eHh4enp6fHx+foCCgoSGiIiKjI6QkJKUlpaYmpyenqCipKSmqKiqqqysrq6usLCwsLCwsK6urqysqqimpKKgnJqWlJCOioaEgH56eHZ0cnBwbm5ubm5ubm5wcHJydHZ2eHp6fH6AgoKEhoiIioyOjpCSkpSUlpaYmJqanJycnp6eoKCgoKKioqKipKSkpKSkpKSioqKioKCenpycmpiWlJSSkI6MioiGhIKAfn58enp4eHh4eHh4eHh6enx8fn6AgoSEhoiKjIyOkJKUlJaYmpycnqCipKSmqKiqrKyurq6wsLCwsLCwsLCwrq6sqqimpKKgnJqWlJCMioaCgHx6dnRycHBubmxsbGxsbG5ucHBycnR2dnh6fH5+gIKEhoaIioyMjpCQkpSUlpaYmJqanJyenp6goKKioqKkpKSkpqampqampqakpKSkoqKgoJ6cnJqYlpSSkI6MioiGhIKAfnx6enh4eHZ2dnZ2eHh4enp8fH6AgIKEhoaIioyOkJKSlJaYmpqcnqCipKSmqKiqrKyurrCwsLKysrKysrCwsK6srKqopqKgnpqWlJCMiISCfnx4dnRycG5sbGxqampsbGxubnBwcnJ0dnh4enx+gICChIaIioqMjpCQkpSUlpaYmpqcnJ6eoKCgoqKkpKSmpqamqKioqKioqKioqKampKSioqCenJqYlpSSkI6MioaEgoB+fHx6eHh2dnZ2dnZ2dnZ4eHp6fHx+gIKChIaIioyMjpCSlJaWmJqcnqCipKSmqKqqrKyurrCwsrKysrKysrKwsK6urKqopqSgnpqWkpCMiISAfHp2dHJwbmxqampqampqampsbG5ucHJydHZ4enp8foCChIaGiIqMjo6QkpSUlpiYmpqcnJ6goKKipKSkpqaoqKiqqqqqqqqqqqqqqqqoqKampKKgnpyamJaUkI6MioaEgoB+fHp4eHZ2dHR0dHR0dHZ2eHh6enx+foCChIaGiIqMjpCSkpSWmJqcnqCipKSmqKqqrK6usLCysrKytLS0srKysLCurKqopqSgnpqWko6KhoJ+fHh0cnBubGpqaGhoaGhoaGhqamxubnBycnR2eHp8fH6AgoSGiIqKjI6QkpKUlpiYmpycnp6goqKkpKamqKiqqqqsrKyurq6urq6urKysqqiopqSioJ6cmpaUko6MioaEgn58enp4dnZ0dHRycnR0dHR2dnh4enx8foCCgoSGiIqMjpCQkpSWmJqcnqCioqSmqKqqrK6usLCysrS0tLS0tLSysrCwrqyqpqSgnpqWko6KhoJ+enZycG5samhmZmZmZmZmZmZoaGpsbG5wcnJ0dnh6fH6AgoKEhoiKjI6QkJKUlpiYmpyenqCioqSkpqioqqqsrK6urrCwsLCwsLCwsLCurqyqqKimoqCenJiWkpCMioaEgH58enh2dnR0cnJycnJycnR0dnZ4eHp8fn6AgoSGiIiKjI6QkpSWmJqcnqCgoqSmqKqsrK6wsLKytLS0tLS0tLS0srKwrqyqqKSgnJqUkIyIhIB8eHRwbmxoaGZkZGRiYmJkZGRmZmhqamxucHJydHZ4enx+gIKEhoiKjI6OkJKUlpiampyeoKCipKamqKqqrKyusLCwsrKytLS0tLS0tLKysLCurKqopqKgnpqWlJCMioaEgH58enh2dHJycnBwcHBycnJ0dHZ2eHp6fH6AgoKEhoiKjI6QkpSWmJqcnJ6goqSmqKqsrK6wsLKytLS0tra2tra0tLKwrqyqqKSgnJiUkIqGgnx4dHJuamhmZGJiYGBgYGBgYmJkZGZoaGpsbnBycnR2eHp8foCChIaIioyOkJKUlpianJyeoKKkpqaoqqysrrCwsrK0tLa2tri4uLi4tra2tLSysK6sqKaioJyYlJKOioaEgH56eHZ0cnJwcHBwcHBwcHJydHR2dnh6fHx+gIKEhoiKjI6QkJKUlpianJ6goqSmqKqsrK6wsLK0tLS2tra2tra2tLKysKyqqKSgnJiSjoiEfnp2cm5qaGRiYGBeXl5eXl5eXmBgYmRkZmhqbG5wcnR2eHp8foCChIaIioyOkJKUlpianJ6goqSkpqiqrK6usLK0tLa2uLi6urq8vLy8vLq6uLi2tLKurKqmop6alpKOioiEgH56eHZ0cnBwbm5ubm5ucHBwcnR0dnh4enx+gIKChIaIioyOkJKUlpianJ6goqSmqKqsrK6wsLK0tLa2tra2tra2tLSysKyqpqSempaQjIaAfHZybmpmZGJgXlxcWlpaWlpcXF5eYGBiZGZoamxucHJ0dnh6fH6AgoSIioyOkJKUlpianJ6goqSmqKqsrrCysrS2uLi6vLy+vr7AwMDAwMC+vry6uLa0sK6qpqKempSQjIiEgH56eHRycnBubm5sbG5ubm5wcHJ0dHZ4enp8foCChIaIioyOkJKUlpianJ6goqSmqKqqrK6wsLK0tLa2tra2tra2tLKyrqyqpqKemJSOiIJ+eHJuamZiYF5aWlhYVlZWVlhYWlpcXF5gYmRmaGpsbnBydHZ4en6AgoSGiIyOkJKUlpianqCipKaoqqyusLK0tri6ury+vsDCwsTExMTExMTEwsLAvry4trKuqqainJiUjoqGgn56eHRycG5ubGxsbGxsbG5ucHBydHR2eHp8foCAgoSGiIqOjpCSlJaYmpyeoKKkpqiqrK6wsLKytLS2tra2tra0tLKwrqyopKCalpCKhH54dG5qZGBeWlhWVlRUUlJUVFRWVlhYWlxeYGJkZmhqbG5wcnZ4enx+goSGiIqOkJKUlpqcnqCipqiqrK6wsrS2uLq8vsDCwsTGxsjIyMrKysrKyMjGxMK+vLi0sKymopyWkoyIgn56eHRycG5sbGpqampqbGxsbnBwcnR0dnh6fH6AgoSGiIqMjJCSlJaYmpyeoKKkpqiqrKyusLCytLS0tra2trS0srCurKikoJyWkoyEfnhybGhkXlxYVlRSUFBQTlBQUFBSVFRWWFpcXmBiZGZoamxwcnR2eHx+gISGiIqOkJKUmJqcoKKkpqisrrCytLa6vL7AwsTExsjKyszOzs7Q0NDQzs7MysjGxMC8uLKuqKKclpCKhoB8eHRycG5sampqaGpqampsbG5ucHJ0dnZ4enx+gIKEhoiKjI6QkpSWmJqcnqCipKaoqqysrrCwsrK0tLS0srKysK6sqKSgnJaQioR+eHJsZmBcWFRSUE5MTExKSkxMTE5QUFJUVlhaXF5gYmRmaGxucHR2eHp+gIKGiIqOkJKWmJqeoKKmqKqusLK0uLq8vsDCxMbIyszO0NLS1NTW1tbW1tbU1NLQzMrGwLy2sKqknJaQioR+enZycGxsamhoaGhoaGhqamxubnBydHZ2eHp8foCChIiKioyOkJKUlpianJ6goqSmqKqqrK6urrCwsLCwsK6sqqimop6alI6Ignp0bmhiXFhUUE5MSkhIRkZGRkhISkpMTlBSVFZYWlxeYGJmaGpucHJ2eHp+gIKGiIyOkJSWmpyeoqSoqqywsrS4ury+wsTGyMrMztDS1NbY2trc3N7e3t7e3Nza2NTQzMjCvLaupp6YkIiCfnh0cG5samhmZmZmZmhoaGpsbG5wcnJ0dnh6fH6AgoaIhoiMjpCSlJaYmpyeoKCipKamqKiqqqqsqqqqqKimoqCcmJSOiIJ8dG5oYlxWUk5MSEZEREJCQkJCRERGRkhKTE5QUlRWWFpeYGJkaGpscHJ2eHp+gISGioyOkpSYmp6gpKaorK6ytLi6vMDCxMjKzM7S1NbY2tze4OLi5Obm5ujo6Obm5OLg3NjSzMa+tq6knJSMhH54dHBsamhmZmRkZGRmZmhoamxsbnBydHZ4enx+gIKE", + "minLat": -58, + "maxLat": 78, + "step": 2, + "rowsCount": 69, + "colsCount": 180, + "valueScale": 2, + "valueOffset": 72, + "model": "WMM-2025", + "dateYMD": [ + 2025, + 7, + 1 + ] +} diff --git a/src/lib/magnetic-declination/index.js b/src/lib/magnetic-declination/index.js @@ -57,4 +57,11 @@ function getDeclination(lat, lon) { data = loadData(); -export {getDeclination}; +const magneticModelInfo = { + modelName: declination.model, + dateYMD: declination.dateYMD, + horizontalResolution: declination.step, + valueResolution: 1 / declination.valueScale, +}; + +export {getDeclination, magneticModelInfo}; diff --git a/src/lib/magnetic-declination/scripts/magnetic_declination_for_nakarte.py b/src/lib/magnetic-declination/scripts/magnetic_declination_for_nakarte.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# coding: utf-8 +import argparse +import base64 +import csv +import datetime +import json +import math +import re +from urllib.parse import urlencode +from urllib.request import urlopen + +MIN_LAT = -58 +MAX_LAT = 78 +GRID_STEP = 2 +OUTPUT_VALUE_SCALE = 2 + + +def fetch_magnetic_declination_grid(date: datetime.date) -> bytes: + # API documentation: https://www.ngdc.noaa.gov/geomag/CalcSurveyFin.shtml + timeout = 30 + url = "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateIgrfgrid" + request_params = { + "key": "gFE5W", + "lat1": MIN_LAT, + "lat2": MAX_LAT, + "latStepSize": GRID_STEP, + "lon1": "-180", + "lon2": "180", + "lonStepSize": GRID_STEP, + "magneticComponent": "d", + "model": "WMM", + "startYear": date.year, + "startMonth": date.month, + "startDay": date.day, + "endYear": date.year, + "endMonth": date.month, + "endDay": date.day, + "resultFormat": "csv", + } + resp = urlopen(url + "?" + urlencode(request_params), timeout=timeout) + assert resp.code == 200 + return resp.read() + + +def parse_declination_csv(data: bytes) -> dict[tuple[float, float], float]: + declinations = {} + csv_lines = [ + line for line in data.decode().splitlines() if not line.startswith("#") + ] + for row in csv.reader(csv_lines): + assert len(row) == 7 + lat = float(row[1]) + lon = float(row[2]) + declination = float(row[4]) + declinations[(lat, lon)] = declination + return declinations + + +def get_model_name(data: bytes) -> str: + m = re.search(r"Magnetic Model:\s*([^(+]+)", data.decode()) + return m.group(1).strip() + + +def write_output( + filename: str, + declinations: dict[tuple[float, float] : float], + model_name: str, + model_date: datetime.date, +) -> None: + value_offset = -math.floor(min(declinations.values())) + packed_values = bytes( + int(round(declinations[(lat, lon)] + value_offset) * OUTPUT_VALUE_SCALE) + for lat in range(MIN_LAT, MAX_LAT + 1, GRID_STEP) + for lon in range(-180, 180, GRID_STEP) + ) + + data = { + "array": base64.standard_b64encode(packed_values).decode(), + "minLat": MIN_LAT, + "maxLat": MAX_LAT, + "step": GRID_STEP, + "rowsCount": (MAX_LAT - MIN_LAT) // GRID_STEP + 1, + "colsCount": 360 // GRID_STEP, + "valueScale": OUTPUT_VALUE_SCALE, + "valueOffset": value_offset, + "model": model_name, + "dateYMD": [model_date.year, model_date.month, model_date.day], + } + with open(filename, "w") as f: + json.dump(data, f, indent=2) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("output", help="Output filename") + parser.add_argument( + "--date", + help="Date for calculating magnetic declination. Format is YYYY-MM-DD. Default current date", + ) + conf = parser.parse_args() + if conf.date is not None: + date = datetime.datetime.strptime(conf.date, "%Y-%m-%d") + else: + date = datetime.date.today() + + csv_data = fetch_magnetic_declination_grid(date) + + # store/load file for debugging + # with open('data.csv', 'wb') as f: + # f.write(csv_data) + # with open("data.csv", "rb") as f: + # csv_data = f.read() + + declinations = parse_declination_csv(csv_data) + model_name = get_model_name(csv_data) + write_output(conf.output, declinations, model_name, date) + + +if __name__ == "__main__": + main()