From ac272637ba5b4dac08a61ea61885f6f565cb70d5 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Mon, 21 Feb 2022 16:19:32 +0100 Subject: [PATCH 01/28] first fetch --- code/chart.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/code/chart.js b/code/chart.js index 92e85a30..3472342f 100644 --- a/code/chart.js +++ b/code/chart.js @@ -1,4 +1,25 @@ //DOM-selector for the canvas πŸ‘‡ const ctx = document.getElementById('chart').getContext('2d') +const projects = document.getElementById('projects') +const username = 'idanaslund' + +let API_URL = `https://api.github.com/users/${username}/repos` + +const findingAllRepos = () => { + +fetch(API_URL) +.then((res) => res.json()) +.then((repos) => { + console.log(repos) + projects.innerHTML = `${repos[1].name}` + + repos.forEach((repo) => projects.innerHTML += `
${repo.name}
`) + +}) +} + +findingAllRepos() //"Draw" the chart here πŸ‘‡ + + From e6b4574c495e9dd2a9e511dfb25dde629fc8277a Mon Sep 17 00:00:00 2001 From: idanaslund Date: Tue, 22 Feb 2022 20:33:26 +0100 Subject: [PATCH 02/28] added aside and h4 --- code/chart.js | 3 +-- code/index.html | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/chart.js b/code/chart.js index 3472342f..a49ba98f 100644 --- a/code/chart.js +++ b/code/chart.js @@ -11,9 +11,8 @@ fetch(API_URL) .then((res) => res.json()) .then((repos) => { console.log(repos) - projects.innerHTML = `${repos[1].name}` - repos.forEach((repo) => projects.innerHTML += `
${repo.name}
`) + repos.forEach((repo) => projects.innerHTML += `

${repo.name}

`) }) } diff --git a/code/index.html b/code/index.html index 2fb5e0ae..eef4197a 100644 --- a/code/index.html +++ b/code/index.html @@ -9,6 +9,7 @@

GitHub Tracker

+

Projects:

From ebe040acbd58feedc2406850e3da8bb867414874 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Tue, 22 Feb 2022 22:16:28 +0100 Subject: [PATCH 03/28] started on design --- code/chart.js | 2 +- code/index.html | 11 ++++++++--- code/style.css | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/code/chart.js b/code/chart.js index a49ba98f..6e0140de 100644 --- a/code/chart.js +++ b/code/chart.js @@ -12,7 +12,7 @@ fetch(API_URL) .then((repos) => { console.log(repos) - repos.forEach((repo) => projects.innerHTML += `

${repo.name}

`) + repos.forEach((repo) => projects.innerHTML += `

${repo.name}

`) }) } diff --git a/code/index.html b/code/index.html index eef4197a..dee3972b 100644 --- a/code/index.html +++ b/code/index.html @@ -8,10 +8,15 @@ -

GitHub Tracker

- +
+

GitHub Tracker

+
+ +

Projects:

-
+
diff --git a/code/style.css b/code/style.css index 7c8ad447..1e652f06 100644 --- a/code/style.css +++ b/code/style.css @@ -1,3 +1,49 @@ body { - background: #FFECE9; + background: #83c5be; + /*006d77*/ + margin: 0; + padding: 0; +} + +header { + background: #006d77; + margin: 0 0 5vh 0; + display: flex; + justify-content: center; +} + +h1 { + display: inline; + margin-top: 0; + padding-top: 2vh; +} + +.profile { + background: white; + display: inline; + padding: 2vh 5vw; + margin: 5vh 5vw; + box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + +} + +.projects { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-evenly; +} + +.repos { + background: white; + margin: 1vh 1vw; + padding: 1vh 1vw; + border: solid #006d77; + border-radius: 5%; + box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + } \ No newline at end of file From e89d9226fc7c7ed5b9c708ec52a54e30a0e9df3e Mon Sep 17 00:00:00 2001 From: idanaslund Date: Wed, 23 Feb 2022 09:15:13 +0100 Subject: [PATCH 04/28] added username --- code/chart.js | 17 ----------------- code/index.html | 1 - code/script.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/code/chart.js b/code/chart.js index 6e0140de..f01991fa 100644 --- a/code/chart.js +++ b/code/chart.js @@ -1,23 +1,6 @@ //DOM-selector for the canvas πŸ‘‡ const ctx = document.getElementById('chart').getContext('2d') -const projects = document.getElementById('projects') -const username = 'idanaslund' -let API_URL = `https://api.github.com/users/${username}/repos` - -const findingAllRepos = () => { - -fetch(API_URL) -.then((res) => res.json()) -.then((repos) => { - console.log(repos) - - repos.forEach((repo) => projects.innerHTML += `

${repo.name}

`) - -}) -} - -findingAllRepos() //"Draw" the chart here πŸ‘‡ diff --git a/code/index.html b/code/index.html index dee3972b..5f31edad 100644 --- a/code/index.html +++ b/code/index.html @@ -12,7 +12,6 @@

GitHub Tracker

Projects:

diff --git a/code/script.js b/code/script.js index e69de29b..816f97f5 100644 --- a/code/script.js +++ b/code/script.js @@ -0,0 +1,28 @@ +// DOM selectors +const projects = document.getElementById('projects') +const username = 'idanaslund' + +let API_URL = `https://api.github.com/users/${username}/repos` + +const addingProfile = () => { + profile.innerHTML += `Username: ${username}` +} +addingProfile() + +const findingAllRepos = () => { + +fetch(API_URL) +.then((res) => res.json()) +.then((repos) => { + console.log(repos) + + + repos.forEach((repo) => { + projects.innerHTML += `

${repo.name}

`}) + }) + +} + +findingAllRepos() + +// Eventlisteners \ No newline at end of file From 95fb7754f7cff315c98907691bf1ebe50e9be867 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Wed, 23 Feb 2022 10:06:27 +0100 Subject: [PATCH 05/28] tried another fetch --- code/script.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/code/script.js b/code/script.js index 816f97f5..1e7db651 100644 --- a/code/script.js +++ b/code/script.js @@ -18,11 +18,23 @@ fetch(API_URL) repos.forEach((repo) => { - projects.innerHTML += `

${repo.name}

`}) - }) + projects.innerHTML += `

${repo.name}

`}) +}) -} + //How to get the reponame here? + let API_URL_PR = `https://api.github.com/repos/Technigo/${reponame}/pulls` + + fetch(API_URL_PR) + .then((res) => res.json()) + .then((pulls) => { + console.log(pulls) + + + }) +} findingAllRepos() + + // Eventlisteners \ No newline at end of file From 6e52e1f876f4b5ce67d69b368af3b96d00c588f2 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Wed, 23 Feb 2022 12:40:49 +0100 Subject: [PATCH 06/28] added script for token and added chart --- code/.gitignore | 3 + code/chart.js | 28 + code/index.html | 4 +- code/script.js | 12 + node_modules/.package-lock.json | 12 + node_modules/chart.js/LICENSE.md | 9 + node_modules/chart.js/README.md | 38 + node_modules/chart.js/auto/auto.esm.d.ts | 4 + node_modules/chart.js/auto/auto.esm.js | 5 + node_modules/chart.js/auto/auto.js | 1 + node_modules/chart.js/auto/package.json | 8 + node_modules/chart.js/dist/chart.esm.js | 10627 +++++++++++++ node_modules/chart.js/dist/chart.js | 13269 ++++++++++++++++ node_modules/chart.js/dist/chart.min.js | 13 + .../chart.js/dist/chunks/helpers.segment.js | 2503 +++ node_modules/chart.js/dist/helpers.esm.js | 7 + .../chart.js/helpers/helpers.esm.d.ts | 1 + node_modules/chart.js/helpers/helpers.esm.js | 1 + node_modules/chart.js/helpers/helpers.js | 1 + node_modules/chart.js/helpers/package.json | 8 + node_modules/chart.js/package.json | 111 + node_modules/chart.js/types/adapters.d.ts | 63 + node_modules/chart.js/types/animation.d.ts | 33 + node_modules/chart.js/types/basic.d.ts | 3 + node_modules/chart.js/types/color.d.ts | 1 + node_modules/chart.js/types/element.d.ts | 17 + node_modules/chart.js/types/geometric.d.ts | 37 + .../types/helpers/helpers.canvas.d.ts | 101 + .../types/helpers/helpers.collection.d.ts | 20 + .../chart.js/types/helpers/helpers.color.d.ts | 33 + .../chart.js/types/helpers/helpers.core.d.ts | 157 + .../chart.js/types/helpers/helpers.curve.d.ts | 34 + .../chart.js/types/helpers/helpers.dom.d.ts | 20 + .../types/helpers/helpers.easing.d.ts | 5 + .../types/helpers/helpers.extras.d.ts | 23 + .../types/helpers/helpers.interpolation.d.ts | 1 + .../chart.js/types/helpers/helpers.intl.d.ts | 7 + .../chart.js/types/helpers/helpers.math.d.ts | 17 + .../types/helpers/helpers.options.d.ts | 61 + .../chart.js/types/helpers/helpers.rtl.d.ts | 12 + .../types/helpers/helpers.segment.d.ts | 1 + .../chart.js/types/helpers/index.d.ts | 15 + node_modules/chart.js/types/index.esm.d.ts | 3601 +++++ node_modules/chart.js/types/layout.d.ts | 65 + node_modules/chart.js/types/utils.d.ts | 21 + package-lock.json | 24 + package.json | 5 + 47 files changed, 31041 insertions(+), 1 deletion(-) create mode 100644 code/.gitignore create mode 100644 node_modules/.package-lock.json create mode 100644 node_modules/chart.js/LICENSE.md create mode 100644 node_modules/chart.js/README.md create mode 100644 node_modules/chart.js/auto/auto.esm.d.ts create mode 100644 node_modules/chart.js/auto/auto.esm.js create mode 100644 node_modules/chart.js/auto/auto.js create mode 100644 node_modules/chart.js/auto/package.json create mode 100644 node_modules/chart.js/dist/chart.esm.js create mode 100644 node_modules/chart.js/dist/chart.js create mode 100644 node_modules/chart.js/dist/chart.min.js create mode 100644 node_modules/chart.js/dist/chunks/helpers.segment.js create mode 100644 node_modules/chart.js/dist/helpers.esm.js create mode 100644 node_modules/chart.js/helpers/helpers.esm.d.ts create mode 100644 node_modules/chart.js/helpers/helpers.esm.js create mode 100644 node_modules/chart.js/helpers/helpers.js create mode 100644 node_modules/chart.js/helpers/package.json create mode 100644 node_modules/chart.js/package.json create mode 100644 node_modules/chart.js/types/adapters.d.ts create mode 100644 node_modules/chart.js/types/animation.d.ts create mode 100644 node_modules/chart.js/types/basic.d.ts create mode 100644 node_modules/chart.js/types/color.d.ts create mode 100644 node_modules/chart.js/types/element.d.ts create mode 100644 node_modules/chart.js/types/geometric.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.canvas.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.collection.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.color.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.core.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.curve.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.dom.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.easing.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.extras.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.interpolation.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.intl.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.math.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.options.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.rtl.d.ts create mode 100644 node_modules/chart.js/types/helpers/helpers.segment.d.ts create mode 100644 node_modules/chart.js/types/helpers/index.d.ts create mode 100644 node_modules/chart.js/types/index.esm.d.ts create mode 100644 node_modules/chart.js/types/layout.d.ts create mode 100644 node_modules/chart.js/types/utils.d.ts create mode 100644 package-lock.json create mode 100644 package.json diff --git a/code/.gitignore b/code/.gitignore new file mode 100644 index 00000000..6994c809 --- /dev/null +++ b/code/.gitignore @@ -0,0 +1,3 @@ +#All files that should be hidden: + +token.js \ No newline at end of file diff --git a/code/chart.js b/code/chart.js index f01991fa..6d789db8 100644 --- a/code/chart.js +++ b/code/chart.js @@ -4,4 +4,32 @@ const ctx = document.getElementById('chart').getContext('2d') //"Draw" the chart here πŸ‘‡ +const labels = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + ]; + const data = { + labels: labels, + datasets: [{ + label: 'My First dataset', + backgroundColor: 'rgb(255, 99, 132)', + borderColor: 'rgb(255, 99, 132)', + data: [0, 10, 5, 2, 20, 30, 45], + }] + }; + + const config = { + type: 'line', + data: data, + options: {} + }; + + const myChart = new Chart( + document.getElementById('chart'), + config + ); \ No newline at end of file diff --git a/code/index.html b/code/index.html index 5f31edad..1072ba73 100644 --- a/code/index.html +++ b/code/index.html @@ -4,6 +4,7 @@ + Project GitHub Tracker @@ -20,7 +21,8 @@

Projects:

- + + \ No newline at end of file diff --git a/code/script.js b/code/script.js index 1e7db651..300b6e03 100644 --- a/code/script.js +++ b/code/script.js @@ -2,8 +2,20 @@ const projects = document.getElementById('projects') const username = 'idanaslund' + +//const API_TOKEN = TOKEN OR process.env.API_KEY +//console.log(TOKEN) + let API_URL = `https://api.github.com/users/${username}/repos` +//Get the token here!! +//const options = { + // method: 'GET', + // headers: { + //Authorization: `token ${API_TOKEN}` + //} +//} + const addingProfile = () => { profile.innerHTML += `Username: ${username}` } diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 00000000..28bd1f48 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,12 @@ +{ + "name": "project-github-tracker", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/chart.js": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", + "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" + } + } +} diff --git a/node_modules/chart.js/LICENSE.md b/node_modules/chart.js/LICENSE.md new file mode 100644 index 00000000..5060fabc --- /dev/null +++ b/node_modules/chart.js/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2014-2021 Chart.js Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/chart.js/README.md b/node_modules/chart.js/README.md new file mode 100644 index 00000000..f485b4eb --- /dev/null +++ b/node_modules/chart.js/README.md @@ -0,0 +1,38 @@ +

+ + https://www.chartjs.org/
+
+ Simple yet flexible JavaScript charting for designers & developers +

+ +

+ Downloads + GitHub Workflow Status + Coverage + Awesome + Slack +

+ +## Documentation + +All the links point to the new version 3 of the lib. + +* [Introduction](https://www.chartjs.org/docs/latest/) +* [Getting Started](https://www.chartjs.org/docs/latest/getting-started/index) +* [General](https://www.chartjs.org/docs/latest/general/data-structures) +* [Configuration](https://www.chartjs.org/docs/latest/configuration/index) +* [Charts](https://www.chartjs.org/docs/latest/charts/line) +* [Axes](https://www.chartjs.org/docs/latest/axes/index) +* [Developers](https://www.chartjs.org/docs/latest/developers/index) +* [Popular Extensions](https://github.com/chartjs/awesome) +* [Samples](https://www.chartjs.org/samples/) + +In case you are looking for the docs of version 2, you will have to specify the specific version in the url like this: [https://www.chartjs.org/docs/2.9.4/](https://www.chartjs.org/docs/2.9.4/) + +## Contributing + +Instructions on building and testing Chart.js can be found in [the documentation](https://www.chartjs.org/docs/master/developers/contributing.html#building-and-testing). Before submitting an issue or a pull request, please take a moment to look over the [contributing guidelines](https://www.chartjs.org/docs/master/developers/contributing) first. For support, please post questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/chartjs) with the `chartjs` tag. + +## License + +Chart.js is available under the [MIT license](LICENSE.md). diff --git a/node_modules/chart.js/auto/auto.esm.d.ts b/node_modules/chart.js/auto/auto.esm.d.ts new file mode 100644 index 00000000..f0bc3805 --- /dev/null +++ b/node_modules/chart.js/auto/auto.esm.d.ts @@ -0,0 +1,4 @@ +import { Chart } from '../types/index.esm'; + +export * from '../types/index.esm'; +export default Chart; diff --git a/node_modules/chart.js/auto/auto.esm.js b/node_modules/chart.js/auto/auto.esm.js new file mode 100644 index 00000000..42626764 --- /dev/null +++ b/node_modules/chart.js/auto/auto.esm.js @@ -0,0 +1,5 @@ +import {Chart, registerables} from '../dist/chart.esm'; + +Chart.register(...registerables); + +export default Chart; diff --git a/node_modules/chart.js/auto/auto.js b/node_modules/chart.js/auto/auto.js new file mode 100644 index 00000000..235580fe --- /dev/null +++ b/node_modules/chart.js/auto/auto.js @@ -0,0 +1 @@ +module.exports = require('../dist/chart'); diff --git a/node_modules/chart.js/auto/package.json b/node_modules/chart.js/auto/package.json new file mode 100644 index 00000000..c2ad5b2c --- /dev/null +++ b/node_modules/chart.js/auto/package.json @@ -0,0 +1,8 @@ +{ + "name": "chart.js-auto", + "private": true, + "description": "auto registering package", + "main": "auto.js", + "module": "auto.esm.js", + "types": "auto.esm.d.ts" +} diff --git a/node_modules/chart.js/dist/chart.esm.js b/node_modules/chart.js/dist/chart.esm.js new file mode 100644 index 00000000..2306fa88 --- /dev/null +++ b/node_modules/chart.js/dist/chart.esm.js @@ -0,0 +1,10627 @@ +/*! + * Chart.js v3.7.1 + * https://www.chartjs.org + * (c) 2022 Chart.js Contributors + * Released under the MIT License + */ +import { r as requestAnimFrame, a as resolve, e as effects, c as color, d as defaults, i as isObject, b as isArray, v as valueOrDefault, u as unlistenArrayEvents, l as listenArrayEvents, f as resolveObjectKey, g as isNumberFinite, h as createContext, j as defined, s as sign, k as isNullOrUndef, _ as _arrayUnique, t as toRadians, m as toPercentage, n as toDimension, T as TAU, o as formatNumber, p as _angleBetween, H as HALF_PI, P as PI, q as isNumber, w as _limitValue, x as _lookupByKey, y as getRelativePosition$1, z as _isPointInArea, A as _rlookupByKey, B as getAngleFromPoint, C as toPadding, D as each, E as getMaximumSize, F as _getParentNode, G as readUsedSize, I as throttled, J as supportsEventListenerOptions, K as _isDomSupported, L as log10, M as _factorize, N as finiteOrDefault, O as callback, Q as _addGrace, R as toDegrees, S as _measureText, U as _int16Range, V as _alignPixel, W as clipArea, X as renderText, Y as unclipArea, Z as toFont, $ as _toLeftRightCenter, a0 as _alignStartEnd, a1 as overrides, a2 as merge, a3 as _capitalize, a4 as descriptors, a5 as isFunction, a6 as _attachContext, a7 as _createResolver, a8 as _descriptors, a9 as mergeIf, aa as uid, ab as debounce, ac as retinaScale, ad as clearCanvas, ae as setsEqual, af as _elementsEqual, ag as _isClickEvent, ah as _isBetween, ai as _readValueToProps, aj as _updateBezierControlPoints, ak as _computeSegments, al as _boundSegments, am as _steppedInterpolation, an as _bezierInterpolation, ao as _pointInLine, ap as _steppedLineTo, aq as _bezierCurveTo, ar as drawPoint, as as addRoundedRectPath, at as toTRBL, au as toTRBLCorners, av as _boundSegment, aw as _normalizeAngle, ax as getRtlAdapter, ay as overrideTextDirection, az as _textX, aA as restoreTextDirection, aB as noop, aC as distanceBetweenPoints, aD as _setMinAndMaxByKey, aE as niceNum, aF as almostWhole, aG as almostEquals, aH as _decimalPlaces, aI as _longestText, aJ as _filterBetween, aK as _lookup } from './chunks/helpers.segment.js'; +export { d as defaults } from './chunks/helpers.segment.js'; + +class Animator { + constructor() { + this._request = null; + this._charts = new Map(); + this._running = false; + this._lastDate = undefined; + } + _notify(chart, anims, date, type) { + const callbacks = anims.listeners[type]; + const numSteps = anims.duration; + callbacks.forEach(fn => fn({ + chart, + initial: anims.initial, + numSteps, + currentStep: Math.min(date - anims.start, numSteps) + })); + } + _refresh() { + if (this._request) { + return; + } + this._running = true; + this._request = requestAnimFrame.call(window, () => { + this._update(); + this._request = null; + if (this._running) { + this._refresh(); + } + }); + } + _update(date = Date.now()) { + let remaining = 0; + this._charts.forEach((anims, chart) => { + if (!anims.running || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + let draw = false; + let item; + for (; i >= 0; --i) { + item = items[i]; + if (item._active) { + if (item._total > anims.duration) { + anims.duration = item._total; + } + item.tick(date); + draw = true; + } else { + items[i] = items[items.length - 1]; + items.pop(); + } + } + if (draw) { + chart.draw(); + this._notify(chart, anims, date, 'progress'); + } + if (!items.length) { + anims.running = false; + this._notify(chart, anims, date, 'complete'); + anims.initial = false; + } + remaining += items.length; + }); + this._lastDate = date; + if (remaining === 0) { + this._running = false; + } + } + _getAnims(chart) { + const charts = this._charts; + let anims = charts.get(chart); + if (!anims) { + anims = { + running: false, + initial: true, + items: [], + listeners: { + complete: [], + progress: [] + } + }; + charts.set(chart, anims); + } + return anims; + } + listen(chart, event, cb) { + this._getAnims(chart).listeners[event].push(cb); + } + add(chart, items) { + if (!items || !items.length) { + return; + } + this._getAnims(chart).items.push(...items); + } + has(chart) { + return this._getAnims(chart).items.length > 0; + } + start(chart) { + const anims = this._charts.get(chart); + if (!anims) { + return; + } + anims.running = true; + anims.start = Date.now(); + anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); + this._refresh(); + } + running(chart) { + if (!this._running) { + return false; + } + const anims = this._charts.get(chart); + if (!anims || !anims.running || !anims.items.length) { + return false; + } + return true; + } + stop(chart) { + const anims = this._charts.get(chart); + if (!anims || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + for (; i >= 0; --i) { + items[i].cancel(); + } + anims.items = []; + this._notify(chart, anims, Date.now(), 'complete'); + } + remove(chart) { + return this._charts.delete(chart); + } +} +var animator = new Animator(); + +const transparent = 'transparent'; +const interpolators = { + boolean(from, to, factor) { + return factor > 0.5 ? to : from; + }, + color(from, to, factor) { + const c0 = color(from || transparent); + const c1 = c0.valid && color(to || transparent); + return c1 && c1.valid + ? c1.mix(c0, factor).hexString() + : to; + }, + number(from, to, factor) { + return from + (to - from) * factor; + } +}; +class Animation { + constructor(cfg, target, prop, to) { + const currentValue = target[prop]; + to = resolve([cfg.to, to, currentValue, cfg.from]); + const from = resolve([cfg.from, currentValue, to]); + this._active = true; + this._fn = cfg.fn || interpolators[cfg.type || typeof from]; + this._easing = effects[cfg.easing] || effects.linear; + this._start = Math.floor(Date.now() + (cfg.delay || 0)); + this._duration = this._total = Math.floor(cfg.duration); + this._loop = !!cfg.loop; + this._target = target; + this._prop = prop; + this._from = from; + this._to = to; + this._promises = undefined; + } + active() { + return this._active; + } + update(cfg, to, date) { + if (this._active) { + this._notify(false); + const currentValue = this._target[this._prop]; + const elapsed = date - this._start; + const remain = this._duration - elapsed; + this._start = date; + this._duration = Math.floor(Math.max(remain, cfg.duration)); + this._total += elapsed; + this._loop = !!cfg.loop; + this._to = resolve([cfg.to, to, currentValue, cfg.from]); + this._from = resolve([cfg.from, currentValue, to]); + } + } + cancel() { + if (this._active) { + this.tick(Date.now()); + this._active = false; + this._notify(false); + } + } + tick(date) { + const elapsed = date - this._start; + const duration = this._duration; + const prop = this._prop; + const from = this._from; + const loop = this._loop; + const to = this._to; + let factor; + this._active = from !== to && (loop || (elapsed < duration)); + if (!this._active) { + this._target[prop] = to; + this._notify(true); + return; + } + if (elapsed < 0) { + this._target[prop] = from; + return; + } + factor = (elapsed / duration) % 2; + factor = loop && factor > 1 ? 2 - factor : factor; + factor = this._easing(Math.min(1, Math.max(0, factor))); + this._target[prop] = this._fn(from, to, factor); + } + wait() { + const promises = this._promises || (this._promises = []); + return new Promise((res, rej) => { + promises.push({res, rej}); + }); + } + _notify(resolved) { + const method = resolved ? 'res' : 'rej'; + const promises = this._promises || []; + for (let i = 0; i < promises.length; i++) { + promises[i][method](); + } + } +} + +const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; +const colors = ['color', 'borderColor', 'backgroundColor']; +defaults.set('animation', { + delay: undefined, + duration: 1000, + easing: 'easeOutQuart', + fn: undefined, + from: undefined, + loop: undefined, + to: undefined, + type: undefined, +}); +const animationOptions = Object.keys(defaults.animation); +defaults.describe('animation', { + _fallback: false, + _indexable: false, + _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn', +}); +defaults.set('animations', { + colors: { + type: 'color', + properties: colors + }, + numbers: { + type: 'number', + properties: numbers + }, +}); +defaults.describe('animations', { + _fallback: 'animation', +}); +defaults.set('transitions', { + active: { + animation: { + duration: 400 + } + }, + resize: { + animation: { + duration: 0 + } + }, + show: { + animations: { + colors: { + from: 'transparent' + }, + visible: { + type: 'boolean', + duration: 0 + }, + } + }, + hide: { + animations: { + colors: { + to: 'transparent' + }, + visible: { + type: 'boolean', + easing: 'linear', + fn: v => v | 0 + }, + } + } +}); +class Animations { + constructor(chart, config) { + this._chart = chart; + this._properties = new Map(); + this.configure(config); + } + configure(config) { + if (!isObject(config)) { + return; + } + const animatedProps = this._properties; + Object.getOwnPropertyNames(config).forEach(key => { + const cfg = config[key]; + if (!isObject(cfg)) { + return; + } + const resolved = {}; + for (const option of animationOptions) { + resolved[option] = cfg[option]; + } + (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => { + if (prop === key || !animatedProps.has(prop)) { + animatedProps.set(prop, resolved); + } + }); + }); + } + _animateOptions(target, values) { + const newOptions = values.options; + const options = resolveTargetOptions(target, newOptions); + if (!options) { + return []; + } + const animations = this._createAnimations(options, newOptions); + if (newOptions.$shared) { + awaitAll(target.options.$animations, newOptions).then(() => { + target.options = newOptions; + }, () => { + }); + } + return animations; + } + _createAnimations(target, values) { + const animatedProps = this._properties; + const animations = []; + const running = target.$animations || (target.$animations = {}); + const props = Object.keys(values); + const date = Date.now(); + let i; + for (i = props.length - 1; i >= 0; --i) { + const prop = props[i]; + if (prop.charAt(0) === '$') { + continue; + } + if (prop === 'options') { + animations.push(...this._animateOptions(target, values)); + continue; + } + const value = values[prop]; + let animation = running[prop]; + const cfg = animatedProps.get(prop); + if (animation) { + if (cfg && animation.active()) { + animation.update(cfg, value, date); + continue; + } else { + animation.cancel(); + } + } + if (!cfg || !cfg.duration) { + target[prop] = value; + continue; + } + running[prop] = animation = new Animation(cfg, target, prop, value); + animations.push(animation); + } + return animations; + } + update(target, values) { + if (this._properties.size === 0) { + Object.assign(target, values); + return; + } + const animations = this._createAnimations(target, values); + if (animations.length) { + animator.add(this._chart, animations); + return true; + } + } +} +function awaitAll(animations, properties) { + const running = []; + const keys = Object.keys(properties); + for (let i = 0; i < keys.length; i++) { + const anim = animations[keys[i]]; + if (anim && anim.active()) { + running.push(anim.wait()); + } + } + return Promise.all(running); +} +function resolveTargetOptions(target, newOptions) { + if (!newOptions) { + return; + } + let options = target.options; + if (!options) { + target.options = newOptions; + return; + } + if (options.$shared) { + target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); + } + return options; +} + +function scaleClip(scale, allowedOverflow) { + const opts = scale && scale.options || {}; + const reverse = opts.reverse; + const min = opts.min === undefined ? allowedOverflow : 0; + const max = opts.max === undefined ? allowedOverflow : 0; + return { + start: reverse ? max : min, + end: reverse ? min : max + }; +} +function defaultClip(xScale, yScale, allowedOverflow) { + if (allowedOverflow === false) { + return false; + } + const x = scaleClip(xScale, allowedOverflow); + const y = scaleClip(yScale, allowedOverflow); + return { + top: y.end, + right: x.end, + bottom: y.start, + left: x.start + }; +} +function toClip(value) { + let t, r, b, l; + if (isObject(value)) { + t = value.top; + r = value.right; + b = value.bottom; + l = value.left; + } else { + t = r = b = l = value; + } + return { + top: t, + right: r, + bottom: b, + left: l, + disabled: value === false + }; +} +function getSortedDatasetIndices(chart, filterVisible) { + const keys = []; + const metasets = chart._getSortedDatasetMetas(filterVisible); + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + keys.push(metasets[i].index); + } + return keys; +} +function applyStack(stack, value, dsIndex, options = {}) { + const keys = stack.keys; + const singleMode = options.mode === 'single'; + let i, ilen, datasetIndex, otherValue; + if (value === null) { + return; + } + for (i = 0, ilen = keys.length; i < ilen; ++i) { + datasetIndex = +keys[i]; + if (datasetIndex === dsIndex) { + if (options.all) { + continue; + } + break; + } + otherValue = stack.values[datasetIndex]; + if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) { + value += otherValue; + } + } + return value; +} +function convertObjectDataToArray(data) { + const keys = Object.keys(data); + const adata = new Array(keys.length); + let i, ilen, key; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + adata[i] = { + x: key, + y: data[key] + }; + } + return adata; +} +function isStacked(scale, meta) { + const stacked = scale && scale.options.stacked; + return stacked || (stacked === undefined && meta.stack !== undefined); +} +function getStackKey(indexScale, valueScale, meta) { + return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; +} +function getUserBounds(scale) { + const {min, max, minDefined, maxDefined} = scale.getUserBounds(); + return { + min: minDefined ? min : Number.NEGATIVE_INFINITY, + max: maxDefined ? max : Number.POSITIVE_INFINITY + }; +} +function getOrCreateStack(stacks, stackKey, indexValue) { + const subStack = stacks[stackKey] || (stacks[stackKey] = {}); + return subStack[indexValue] || (subStack[indexValue] = {}); +} +function getLastIndexInStack(stack, vScale, positive, type) { + for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) { + const value = stack[meta.index]; + if ((positive && value > 0) || (!positive && value < 0)) { + return meta.index; + } + } + return null; +} +function updateStacks(controller, parsed) { + const {chart, _cachedMeta: meta} = controller; + const stacks = chart._stacks || (chart._stacks = {}); + const {iScale, vScale, index: datasetIndex} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const key = getStackKey(iScale, vScale, meta); + const ilen = parsed.length; + let stack; + for (let i = 0; i < ilen; ++i) { + const item = parsed[i]; + const {[iAxis]: index, [vAxis]: value} = item; + const itemStacks = item._stacks || (item._stacks = {}); + stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); + stack[datasetIndex] = value; + stack._top = getLastIndexInStack(stack, vScale, true, meta.type); + stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); + } +} +function getFirstScaleId(chart, axis) { + const scales = chart.scales; + return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); +} +function createDatasetContext(parent, index) { + return createContext(parent, + { + active: false, + dataset: undefined, + datasetIndex: index, + index, + mode: 'default', + type: 'dataset' + } + ); +} +function createDataContext(parent, index, element) { + return createContext(parent, { + active: false, + dataIndex: index, + parsed: undefined, + raw: undefined, + element, + index, + mode: 'default', + type: 'data' + }); +} +function clearStacks(meta, items) { + const datasetIndex = meta.controller.index; + const axis = meta.vScale && meta.vScale.axis; + if (!axis) { + return; + } + items = items || meta._parsed; + for (const parsed of items) { + const stacks = parsed._stacks; + if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { + return; + } + delete stacks[axis][datasetIndex]; + } +} +const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none'; +const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached); +const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked + && {keys: getSortedDatasetIndices(chart, true), values: null}; +class DatasetController { + constructor(chart, datasetIndex) { + this.chart = chart; + this._ctx = chart.ctx; + this.index = datasetIndex; + this._cachedDataOpts = {}; + this._cachedMeta = this.getMeta(); + this._type = this._cachedMeta.type; + this.options = undefined; + this._parsing = false; + this._data = undefined; + this._objectData = undefined; + this._sharedOptions = undefined; + this._drawStart = undefined; + this._drawCount = undefined; + this.enableOptionSharing = false; + this.$context = undefined; + this._syncList = []; + this.initialize(); + } + initialize() { + const meta = this._cachedMeta; + this.configure(); + this.linkScales(); + meta._stacked = isStacked(meta.vScale, meta); + this.addElements(); + } + updateIndex(datasetIndex) { + if (this.index !== datasetIndex) { + clearStacks(this._cachedMeta); + } + this.index = datasetIndex; + } + linkScales() { + const chart = this.chart; + const meta = this._cachedMeta; + const dataset = this.getDataset(); + const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; + const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); + const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); + const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); + const indexAxis = meta.indexAxis; + const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); + const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); + meta.xScale = this.getScaleForId(xid); + meta.yScale = this.getScaleForId(yid); + meta.rScale = this.getScaleForId(rid); + meta.iScale = this.getScaleForId(iid); + meta.vScale = this.getScaleForId(vid); + } + getDataset() { + return this.chart.data.datasets[this.index]; + } + getMeta() { + return this.chart.getDatasetMeta(this.index); + } + getScaleForId(scaleID) { + return this.chart.scales[scaleID]; + } + _getOtherScale(scale) { + const meta = this._cachedMeta; + return scale === meta.iScale + ? meta.vScale + : meta.iScale; + } + reset() { + this._update('reset'); + } + _destroy() { + const meta = this._cachedMeta; + if (this._data) { + unlistenArrayEvents(this._data, this); + } + if (meta._stacked) { + clearStacks(meta); + } + } + _dataCheck() { + const dataset = this.getDataset(); + const data = dataset.data || (dataset.data = []); + const _data = this._data; + if (isObject(data)) { + this._data = convertObjectDataToArray(data); + } else if (_data !== data) { + if (_data) { + unlistenArrayEvents(_data, this); + const meta = this._cachedMeta; + clearStacks(meta); + meta._parsed = []; + } + if (data && Object.isExtensible(data)) { + listenArrayEvents(data, this); + } + this._syncList = []; + this._data = data; + } + } + addElements() { + const meta = this._cachedMeta; + this._dataCheck(); + if (this.datasetElementType) { + meta.dataset = new this.datasetElementType(); + } + } + buildOrUpdateElements(resetNewElements) { + const meta = this._cachedMeta; + const dataset = this.getDataset(); + let stackChanged = false; + this._dataCheck(); + const oldStacked = meta._stacked; + meta._stacked = isStacked(meta.vScale, meta); + if (meta.stack !== dataset.stack) { + stackChanged = true; + clearStacks(meta); + meta.stack = dataset.stack; + } + this._resyncElements(resetNewElements); + if (stackChanged || oldStacked !== meta._stacked) { + updateStacks(this, meta._parsed); + } + } + configure() { + const config = this.chart.config; + const scopeKeys = config.datasetScopeKeys(this._type); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); + this.options = config.createResolver(scopes, this.getContext()); + this._parsing = this.options.parsing; + this._cachedDataOpts = {}; + } + parse(start, count) { + const {_cachedMeta: meta, _data: data} = this; + const {iScale, _stacked} = meta; + const iAxis = iScale.axis; + let sorted = start === 0 && count === data.length ? true : meta._sorted; + let prev = start > 0 && meta._parsed[start - 1]; + let i, cur, parsed; + if (this._parsing === false) { + meta._parsed = data; + meta._sorted = true; + parsed = data; + } else { + if (isArray(data[start])) { + parsed = this.parseArrayData(meta, data, start, count); + } else if (isObject(data[start])) { + parsed = this.parseObjectData(meta, data, start, count); + } else { + parsed = this.parsePrimitiveData(meta, data, start, count); + } + const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]); + for (i = 0; i < count; ++i) { + meta._parsed[i + start] = cur = parsed[i]; + if (sorted) { + if (isNotInOrderComparedToPrev()) { + sorted = false; + } + prev = cur; + } + } + meta._sorted = sorted; + } + if (_stacked) { + updateStacks(this, parsed); + } + } + parsePrimitiveData(meta, data, start, count) { + const {iScale, vScale} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = new Array(count); + let i, ilen, index; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + parsed[i] = { + [iAxis]: singleScale || iScale.parse(labels[index], index), + [vAxis]: vScale.parse(data[index], index) + }; + } + return parsed; + } + parseArrayData(meta, data, start, count) { + const {xScale, yScale} = meta; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(item[0], index), + y: yScale.parse(item[1], index) + }; + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const {xScale, yScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(resolveObjectKey(item, xAxisKey), index), + y: yScale.parse(resolveObjectKey(item, yAxisKey), index) + }; + } + return parsed; + } + getParsed(index) { + return this._cachedMeta._parsed[index]; + } + getDataElement(index) { + return this._cachedMeta.data[index]; + } + applyStack(scale, parsed, mode) { + const chart = this.chart; + const meta = this._cachedMeta; + const value = parsed[scale.axis]; + const stack = { + keys: getSortedDatasetIndices(chart, true), + values: parsed._stacks[scale.axis] + }; + return applyStack(stack, value, meta.index, {mode}); + } + updateRangeFromParsed(range, scale, parsed, stack) { + const parsedValue = parsed[scale.axis]; + let value = parsedValue === null ? NaN : parsedValue; + const values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + value = applyStack(stack, parsedValue, this._cachedMeta.index); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + } + getMinMax(scale, canStack) { + const meta = this._cachedMeta; + const _parsed = meta._parsed; + const sorted = meta._sorted && scale === meta.iScale; + const ilen = _parsed.length; + const otherScale = this._getOtherScale(scale); + const stack = createStack(canStack, meta, this.chart); + const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; + const {min: otherMin, max: otherMax} = getUserBounds(otherScale); + let i, parsed; + function _skip() { + parsed = _parsed[i]; + const otherValue = parsed[otherScale.axis]; + return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; + } + for (i = 0; i < ilen; ++i) { + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + if (sorted) { + break; + } + } + if (sorted) { + for (i = ilen - 1; i >= 0; --i) { + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + break; + } + } + return range; + } + getAllParsedValues(scale) { + const parsed = this._cachedMeta._parsed; + const values = []; + let i, ilen, value; + for (i = 0, ilen = parsed.length; i < ilen; ++i) { + value = parsed[i][scale.axis]; + if (isNumberFinite(value)) { + values.push(value); + } + } + return values; + } + getMaxOverflow() { + return false; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const iScale = meta.iScale; + const vScale = meta.vScale; + const parsed = this.getParsed(index); + return { + label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', + value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' + }; + } + _update(mode) { + const meta = this._cachedMeta; + this.update(mode || 'default'); + meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); + } + update(mode) {} + draw() { + const ctx = this._ctx; + const chart = this.chart; + const meta = this._cachedMeta; + const elements = meta.data || []; + const area = chart.chartArea; + const active = []; + const start = this._drawStart || 0; + const count = this._drawCount || (elements.length - start); + const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; + let i; + if (meta.dataset) { + meta.dataset.draw(ctx, area, start, count); + } + for (i = start; i < start + count; ++i) { + const element = elements[i]; + if (element.hidden) { + continue; + } + if (element.active && drawActiveElementsOnTop) { + active.push(element); + } else { + element.draw(ctx, area); + } + } + for (i = 0; i < active.length; ++i) { + active[i].draw(ctx, area); + } + } + getStyle(index, active) { + const mode = active ? 'active' : 'default'; + return index === undefined && this._cachedMeta.dataset + ? this.resolveDatasetElementOptions(mode) + : this.resolveDataElementOptions(index || 0, mode); + } + getContext(index, active, mode) { + const dataset = this.getDataset(); + let context; + if (index >= 0 && index < this._cachedMeta.data.length) { + const element = this._cachedMeta.data[index]; + context = element.$context || + (element.$context = createDataContext(this.getContext(), index, element)); + context.parsed = this.getParsed(index); + context.raw = dataset.data[index]; + context.index = context.dataIndex = index; + } else { + context = this.$context || + (this.$context = createDatasetContext(this.chart.getContext(), this.index)); + context.dataset = dataset; + context.index = context.datasetIndex = this.index; + } + context.active = !!active; + context.mode = mode; + return context; + } + resolveDatasetElementOptions(mode) { + return this._resolveElementOptions(this.datasetElementType.id, mode); + } + resolveDataElementOptions(index, mode) { + return this._resolveElementOptions(this.dataElementType.id, mode, index); + } + _resolveElementOptions(elementType, mode = 'default', index) { + const active = mode === 'active'; + const cache = this._cachedDataOpts; + const cacheKey = elementType + '-' + mode; + const cached = cache[cacheKey]; + const sharing = this.enableOptionSharing && defined(index); + if (cached) { + return cloneIfNotShared(cached, sharing); + } + const config = this.chart.config; + const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); + const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, '']; + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + const names = Object.keys(defaults.elements[elementType]); + const context = () => this.getContext(index, active); + const values = config.resolveNamedOptions(scopes, names, context, prefixes); + if (values.$shared) { + values.$shared = sharing; + cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); + } + return values; + } + _resolveAnimations(index, transition, active) { + const chart = this.chart; + const cache = this._cachedDataOpts; + const cacheKey = `animation-${transition}`; + const cached = cache[cacheKey]; + if (cached) { + return cached; + } + let options; + if (chart.options.animation !== false) { + const config = this.chart.config; + const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + options = config.createResolver(scopes, this.getContext(index, active, transition)); + } + const animations = new Animations(chart, options && options.animations); + if (options && options._cacheable) { + cache[cacheKey] = Object.freeze(animations); + } + return animations; + } + getSharedOptions(options) { + if (!options.$shared) { + return; + } + return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); + } + includeOptions(mode, sharedOptions) { + return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; + } + updateElement(element, index, properties, mode) { + if (isDirectUpdateMode(mode)) { + Object.assign(element, properties); + } else { + this._resolveAnimations(index, mode).update(element, properties); + } + } + updateSharedOptions(sharedOptions, mode, newOptions) { + if (sharedOptions && !isDirectUpdateMode(mode)) { + this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); + } + } + _setStyle(element, index, mode, active) { + element.active = active; + const options = this.getStyle(index, active); + this._resolveAnimations(index, mode, active).update(element, { + options: (!active && this.getSharedOptions(options)) || options + }); + } + removeHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', false); + } + setHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', true); + } + _removeDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', false); + } + } + _setDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', true); + } + } + _resyncElements(resetNewElements) { + const data = this._data; + const elements = this._cachedMeta.data; + for (const [method, arg1, arg2] of this._syncList) { + this[method](arg1, arg2); + } + this._syncList = []; + const numMeta = elements.length; + const numData = data.length; + const count = Math.min(numData, numMeta); + if (count) { + this.parse(0, count); + } + if (numData > numMeta) { + this._insertElements(numMeta, numData - numMeta, resetNewElements); + } else if (numData < numMeta) { + this._removeElements(numData, numMeta - numData); + } + } + _insertElements(start, count, resetNewElements = true) { + const meta = this._cachedMeta; + const data = meta.data; + const end = start + count; + let i; + const move = (arr) => { + arr.length += count; + for (i = arr.length - 1; i >= end; i--) { + arr[i] = arr[i - count]; + } + }; + move(data); + for (i = start; i < end; ++i) { + data[i] = new this.dataElementType(); + } + if (this._parsing) { + move(meta._parsed); + } + this.parse(start, count); + if (resetNewElements) { + this.updateElements(data, start, count, 'reset'); + } + } + updateElements(element, start, count, mode) {} + _removeElements(start, count) { + const meta = this._cachedMeta; + if (this._parsing) { + const removed = meta._parsed.splice(start, count); + if (meta._stacked) { + clearStacks(meta, removed); + } + } + meta.data.splice(start, count); + } + _sync(args) { + if (this._parsing) { + this._syncList.push(args); + } else { + const [method, arg1, arg2] = args; + this[method](arg1, arg2); + } + this.chart._dataChanges.push([this.index, ...args]); + } + _onDataPush() { + const count = arguments.length; + this._sync(['_insertElements', this.getDataset().data.length - count, count]); + } + _onDataPop() { + this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]); + } + _onDataShift() { + this._sync(['_removeElements', 0, 1]); + } + _onDataSplice(start, count) { + if (count) { + this._sync(['_removeElements', start, count]); + } + const newCount = arguments.length - 2; + if (newCount) { + this._sync(['_insertElements', start, newCount]); + } + } + _onDataUnshift() { + this._sync(['_insertElements', 0, arguments.length]); + } +} +DatasetController.defaults = {}; +DatasetController.prototype.datasetElementType = null; +DatasetController.prototype.dataElementType = null; + +function getAllScaleValues(scale, type) { + if (!scale._cache.$bar) { + const visibleMetas = scale.getMatchingVisibleMetas(type); + let values = []; + for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) { + values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); + } + scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b)); + } + return scale._cache.$bar; +} +function computeMinSampleSize(meta) { + const scale = meta.iScale; + const values = getAllScaleValues(scale, meta.type); + let min = scale._length; + let i, ilen, curr, prev; + const updateMinAndPrev = () => { + if (curr === 32767 || curr === -32768) { + return; + } + if (defined(prev)) { + min = Math.min(min, Math.abs(curr - prev) || min); + } + prev = curr; + }; + for (i = 0, ilen = values.length; i < ilen; ++i) { + curr = scale.getPixelForValue(values[i]); + updateMinAndPrev(); + } + prev = undefined; + for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { + curr = scale.getPixelForTick(i); + updateMinAndPrev(); + } + return min; +} +function computeFitCategoryTraits(index, ruler, options, stackCount) { + const thickness = options.barThickness; + let size, ratio; + if (isNullOrUndef(thickness)) { + size = ruler.min * options.categoryPercentage; + ratio = options.barPercentage; + } else { + size = thickness * stackCount; + ratio = 1; + } + return { + chunk: size / stackCount, + ratio, + start: ruler.pixels[index] - (size / 2) + }; +} +function computeFlexCategoryTraits(index, ruler, options, stackCount) { + const pixels = ruler.pixels; + const curr = pixels[index]; + let prev = index > 0 ? pixels[index - 1] : null; + let next = index < pixels.length - 1 ? pixels[index + 1] : null; + const percent = options.categoryPercentage; + if (prev === null) { + prev = curr - (next === null ? ruler.end - ruler.start : next - curr); + } + if (next === null) { + next = curr + curr - prev; + } + const start = curr - (curr - Math.min(prev, next)) / 2 * percent; + const size = Math.abs(next - prev) / 2 * percent; + return { + chunk: size / stackCount, + ratio: options.barPercentage, + start + }; +} +function parseFloatBar(entry, item, vScale, i) { + const startValue = vScale.parse(entry[0], i); + const endValue = vScale.parse(entry[1], i); + const min = Math.min(startValue, endValue); + const max = Math.max(startValue, endValue); + let barStart = min; + let barEnd = max; + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + item[vScale.axis] = barEnd; + item._custom = { + barStart, + barEnd, + start: startValue, + end: endValue, + min, + max + }; +} +function parseValue(entry, item, vScale, i) { + if (isArray(entry)) { + parseFloatBar(entry, item, vScale, i); + } else { + item[vScale.axis] = vScale.parse(entry, i); + } + return item; +} +function parseArrayOrPrimitive(meta, data, start, count) { + const iScale = meta.iScale; + const vScale = meta.vScale; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = []; + let i, ilen, item, entry; + for (i = start, ilen = start + count; i < ilen; ++i) { + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; +} +function isFloatBar(custom) { + return custom && custom.barStart !== undefined && custom.barEnd !== undefined; +} +function barSign(size, vScale, actualBase) { + if (size !== 0) { + return sign(size); + } + return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); +} +function borderProps(properties) { + let reverse, start, end, top, bottom; + if (properties.horizontal) { + reverse = properties.base > properties.x; + start = 'left'; + end = 'right'; + } else { + reverse = properties.base < properties.y; + start = 'bottom'; + end = 'top'; + } + if (reverse) { + top = 'end'; + bottom = 'start'; + } else { + top = 'start'; + bottom = 'end'; + } + return {start, end, reverse, top, bottom}; +} +function setBorderSkipped(properties, options, stack, index) { + let edge = options.borderSkipped; + const res = {}; + if (!edge) { + properties.borderSkipped = res; + return; + } + const {start, end, reverse, top, bottom} = borderProps(properties); + if (edge === 'middle' && stack) { + properties.enableBorderRadius = true; + if ((stack._top || 0) === index) { + edge = top; + } else if ((stack._bottom || 0) === index) { + edge = bottom; + } else { + res[parseEdge(bottom, start, end, reverse)] = true; + edge = top; + } + } + res[parseEdge(edge, start, end, reverse)] = true; + properties.borderSkipped = res; +} +function parseEdge(edge, a, b, reverse) { + if (reverse) { + edge = swap(edge, a, b); + edge = startEnd(edge, b, a); + } else { + edge = startEnd(edge, a, b); + } + return edge; +} +function swap(orig, v1, v2) { + return orig === v1 ? v2 : orig === v2 ? v1 : orig; +} +function startEnd(v, start, end) { + return v === 'start' ? start : v === 'end' ? end : v; +} +function setInflateAmount(properties, {inflateAmount}, ratio) { + properties.inflateAmount = inflateAmount === 'auto' + ? ratio === 1 ? 0.33 : 0 + : inflateAmount; +} +class BarController extends DatasetController { + parsePrimitiveData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseArrayData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseObjectData(meta, data, start, count) { + const {iScale, vScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; + const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; + const parsed = []; + let i, ilen, item, obj; + for (i = start, ilen = start + count; i < ilen; ++i) { + obj = data[i]; + item = {}; + item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); + parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); + } + return parsed; + } + updateRangeFromParsed(range, scale, parsed, stack) { + super.updateRangeFromParsed(range, scale, parsed, stack); + const custom = parsed._custom; + if (custom && scale === this._cachedMeta.vScale) { + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + getMaxOverflow() { + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const {iScale, vScale} = meta; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const value = isFloatBar(custom) + ? '[' + custom.start + ', ' + custom.end + ']' + : '' + vScale.getLabelForValue(parsed[vScale.axis]); + return { + label: '' + iScale.getLabelForValue(parsed[iScale.axis]), + value + }; + } + initialize() { + this.enableOptionSharing = true; + super.initialize(); + const meta = this._cachedMeta; + meta.stack = this.getDataset().stack; + } + update(mode) { + const meta = this._cachedMeta; + this.updateElements(meta.data, 0, meta.data.length, mode); + } + updateElements(bars, start, count, mode) { + const reset = mode === 'reset'; + const {index, _cachedMeta: {vScale}} = this; + const base = vScale.getBasePixel(); + const horizontal = vScale.isHorizontal(); + const ruler = this._getRuler(); + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + this.updateSharedOptions(sharedOptions, mode, firstOpts); + for (let i = start; i < start + count; i++) { + const parsed = this.getParsed(i); + const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i); + const ipixels = this._calculateBarIndexPixels(i, ruler); + const stack = (parsed._stacks || {})[vScale.axis]; + const properties = { + horizontal, + base: vpixels.base, + enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom), + x: horizontal ? vpixels.head : ipixels.center, + y: horizontal ? ipixels.center : vpixels.head, + height: horizontal ? ipixels.size : Math.abs(vpixels.size), + width: horizontal ? Math.abs(vpixels.size) : ipixels.size + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); + } + const options = properties.options || bars[i].options; + setBorderSkipped(properties, options, stack, index); + setInflateAmount(properties, options, ruler.ratio); + this.updateElement(bars[i], i, properties, mode); + } + } + _getStacks(last, dataIndex) { + const meta = this._cachedMeta; + const iScale = meta.iScale; + const metasets = iScale.getMatchingVisibleMetas(this._type); + const stacked = iScale.options.stacked; + const ilen = metasets.length; + const stacks = []; + let i, item; + for (i = 0; i < ilen; ++i) { + item = metasets[i]; + if (!item.controller.options.grouped) { + continue; + } + if (typeof dataIndex !== 'undefined') { + const val = item.controller.getParsed(dataIndex)[ + item.controller._cachedMeta.vScale.axis + ]; + if (isNullOrUndef(val) || isNaN(val)) { + continue; + } + } + if (stacked === false || stacks.indexOf(item.stack) === -1 || + (stacked === undefined && item.stack === undefined)) { + stacks.push(item.stack); + } + if (item.index === last) { + break; + } + } + if (!stacks.length) { + stacks.push(undefined); + } + return stacks; + } + _getStackCount(index) { + return this._getStacks(undefined, index).length; + } + _getStackIndex(datasetIndex, name, dataIndex) { + const stacks = this._getStacks(datasetIndex, dataIndex); + const index = (name !== undefined) + ? stacks.indexOf(name) + : -1; + return (index === -1) + ? stacks.length - 1 + : index; + } + _getRuler() { + const opts = this.options; + const meta = this._cachedMeta; + const iScale = meta.iScale; + const pixels = []; + let i, ilen; + for (i = 0, ilen = meta.data.length; i < ilen; ++i) { + pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); + } + const barThickness = opts.barThickness; + const min = barThickness || computeMinSampleSize(meta); + return { + min, + pixels, + start: iScale._startPixel, + end: iScale._endPixel, + stackCount: this._getStackCount(), + scale: iScale, + grouped: opts.grouped, + ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage + }; + } + _calculateBarValuePixels(index) { + const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; + const actualBase = baseValue || 0; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const floating = isFloatBar(custom); + let value = parsed[vScale.axis]; + let start = 0; + let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; + let head, size; + if (length !== value) { + start = length - value; + length = value; + } + if (floating) { + value = custom.barStart; + length = custom.barEnd - custom.barStart; + if (value !== 0 && sign(value) !== sign(custom.barEnd)) { + start = 0; + } + start += value; + } + const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; + let base = vScale.getPixelForValue(startValue); + if (this.chart.getDataVisibility(index)) { + head = vScale.getPixelForValue(start + length); + } else { + head = base; + } + size = head - base; + if (Math.abs(size) < minBarLength) { + size = barSign(size, vScale, actualBase) * minBarLength; + if (value === actualBase) { + base -= size / 2; + } + head = base + size; + } + if (base === vScale.getPixelForValue(actualBase)) { + const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; + base += halfGrid; + size -= halfGrid; + } + return { + size, + base, + head, + center: head + size / 2 + }; + } + _calculateBarIndexPixels(index, ruler) { + const scale = ruler.scale; + const options = this.options; + const skipNull = options.skipNull; + const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); + let center, size; + if (ruler.grouped) { + const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; + const range = options.barThickness === 'flex' + ? computeFlexCategoryTraits(index, ruler, options, stackCount) + : computeFitCategoryTraits(index, ruler, options, stackCount); + const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); + center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); + size = Math.min(maxBarThickness, range.chunk * range.ratio); + } else { + center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); + size = Math.min(maxBarThickness, ruler.min * ruler.ratio); + } + return { + base: center - size / 2, + head: center + size / 2, + center, + size + }; + } + draw() { + const meta = this._cachedMeta; + const vScale = meta.vScale; + const rects = meta.data; + const ilen = rects.length; + let i = 0; + for (; i < ilen; ++i) { + if (this.getParsed(i)[vScale.axis] !== null) { + rects[i].draw(this._ctx); + } + } + } +} +BarController.id = 'bar'; +BarController.defaults = { + datasetElementType: false, + dataElementType: 'bar', + categoryPercentage: 0.8, + barPercentage: 0.9, + grouped: true, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'base', 'width', 'height'] + } + } +}; +BarController.overrides = { + scales: { + _index_: { + type: 'category', + offset: true, + grid: { + offset: true + } + }, + _value_: { + type: 'linear', + beginAtZero: true, + } + } +}; + +class BubbleController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + parsePrimitiveData(meta, data, start, count) { + const parsed = super.parsePrimitiveData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; + } + return parsed; + } + parseArrayData(meta, data, start, count) { + const parsed = super.parseArrayData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const parsed = super.parseObjectData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + getMaxOverflow() { + const data = this._cachedMeta.data; + let max = 0; + for (let i = data.length - 1; i >= 0; --i) { + max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); + } + return max > 0 && max; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const {xScale, yScale} = meta; + const parsed = this.getParsed(index); + const x = xScale.getLabelForValue(parsed.x); + const y = yScale.getLabelForValue(parsed.y); + const r = parsed._custom; + return { + label: meta.label, + value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + }; + } + update(mode) { + const points = this._cachedMeta.data; + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const {iScale, vScale} = this._cachedMeta; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + for (let i = start; i < start + count; i++) { + const point = points[i]; + const parsed = !reset && this.getParsed(i); + const properties = {}; + const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); + const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); + properties.skip = isNaN(iPixel) || isNaN(vPixel); + if (includeOptions) { + properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); + if (reset) { + properties.options.radius = 0; + } + } + this.updateElement(point, i, properties, mode); + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + resolveDataElementOptions(index, mode) { + const parsed = this.getParsed(index); + let values = super.resolveDataElementOptions(index, mode); + if (values.$shared) { + values = Object.assign({}, values, {$shared: false}); + } + const radius = values.radius; + if (mode !== 'active') { + values.radius = 0; + } + values.radius += valueOrDefault(parsed && parsed._custom, radius); + return values; + } +} +BubbleController.id = 'bubble'; +BubbleController.defaults = { + datasetElementType: false, + dataElementType: 'point', + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'borderWidth', 'radius'] + } + } +}; +BubbleController.overrides = { + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + plugins: { + tooltip: { + callbacks: { + title() { + return ''; + } + } + } + } +}; + +function getRatioAndOffset(rotation, circumference, cutout) { + let ratioX = 1; + let ratioY = 1; + let offsetX = 0; + let offsetY = 0; + if (circumference < TAU) { + const startAngle = rotation; + const endAngle = startAngle + circumference; + const startX = Math.cos(startAngle); + const startY = Math.sin(startAngle); + const endX = Math.cos(endAngle); + const endY = Math.sin(endAngle); + const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); + const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); + const maxX = calcMax(0, startX, endX); + const maxY = calcMax(HALF_PI, startY, endY); + const minX = calcMin(PI, startX, endX); + const minY = calcMin(PI + HALF_PI, startY, endY); + ratioX = (maxX - minX) / 2; + ratioY = (maxY - minY) / 2; + offsetX = -(maxX + minX) / 2; + offsetY = -(maxY + minY) / 2; + } + return {ratioX, ratioY, offsetX, offsetY}; +} +class DoughnutController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.enableOptionSharing = true; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.offsetX = undefined; + this.offsetY = undefined; + } + linkScales() {} + parse(start, count) { + const data = this.getDataset().data; + const meta = this._cachedMeta; + if (this._parsing === false) { + meta._parsed = data; + } else { + let getter = (i) => +data[i]; + if (isObject(data[start])) { + const {key = 'value'} = this._parsing; + getter = (i) => +resolveObjectKey(data[i], key); + } + let i, ilen; + for (i = start, ilen = start + count; i < ilen; ++i) { + meta._parsed[i] = getter(i); + } + } + } + _getRotation() { + return toRadians(this.options.rotation - 90); + } + _getCircumference() { + return toRadians(this.options.circumference); + } + _getRotationExtents() { + let min = TAU; + let max = -TAU; + for (let i = 0; i < this.chart.data.datasets.length; ++i) { + if (this.chart.isDatasetVisible(i)) { + const controller = this.chart.getDatasetMeta(i).controller; + const rotation = controller._getRotation(); + const circumference = controller._getCircumference(); + min = Math.min(min, rotation); + max = Math.max(max, rotation + circumference); + } + } + return { + rotation: min, + circumference: max - min, + }; + } + update(mode) { + const chart = this.chart; + const {chartArea} = chart; + const meta = this._cachedMeta; + const arcs = meta.data; + const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; + const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); + const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); + const chartWeight = this._getRingWeight(this.index); + const {circumference, rotation} = this._getRotationExtents(); + const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout); + const maxWidth = (chartArea.width - spacing) / ratioX; + const maxHeight = (chartArea.height - spacing) / ratioY; + const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); + const outerRadius = toDimension(this.options.radius, maxRadius); + const innerRadius = Math.max(outerRadius * cutout, 0); + const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); + this.offsetX = offsetX * outerRadius; + this.offsetY = offsetY * outerRadius; + meta.total = this.calculateTotal(); + this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); + this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); + this.updateElements(arcs, 0, arcs.length, mode); + } + _circumference(i, reset) { + const opts = this.options; + const meta = this._cachedMeta; + const circumference = this._getCircumference(); + if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { + return 0; + } + return this.calculateCircumference(meta._parsed[i] * circumference / TAU); + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const animationOpts = opts.animation; + const centerX = (chartArea.left + chartArea.right) / 2; + const centerY = (chartArea.top + chartArea.bottom) / 2; + const animateScale = reset && animationOpts.animateScale; + const innerRadius = animateScale ? 0 : this.innerRadius; + const outerRadius = animateScale ? 0 : this.outerRadius; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + let startAngle = this._getRotation(); + let i; + for (i = 0; i < start; ++i) { + startAngle += this._circumference(i, reset); + } + for (i = start; i < start + count; ++i) { + const circumference = this._circumference(i, reset); + const arc = arcs[i]; + const properties = { + x: centerX + this.offsetX, + y: centerY + this.offsetY, + startAngle, + endAngle: startAngle + circumference, + circumference, + outerRadius, + innerRadius + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); + } + startAngle += circumference; + this.updateElement(arc, i, properties, mode); + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + calculateTotal() { + const meta = this._cachedMeta; + const metaData = meta.data; + let total = 0; + let i; + for (i = 0; i < metaData.length; i++) { + const value = meta._parsed[i]; + if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { + total += Math.abs(value); + } + } + return total; + } + calculateCircumference(value) { + const total = this._cachedMeta.total; + if (total > 0 && !isNaN(value)) { + return TAU * (Math.abs(value) / total); + } + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index], chart.options.locale); + return { + label: labels[index] || '', + value, + }; + } + getMaxBorderWidth(arcs) { + let max = 0; + const chart = this.chart; + let i, ilen, meta, controller, options; + if (!arcs) { + for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + if (chart.isDatasetVisible(i)) { + meta = chart.getDatasetMeta(i); + arcs = meta.data; + controller = meta.controller; + break; + } + } + } + if (!arcs) { + return 0; + } + for (i = 0, ilen = arcs.length; i < ilen; ++i) { + options = controller.resolveDataElementOptions(i); + if (options.borderAlign !== 'inner') { + max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); + } + } + return max; + } + getMaxOffset(arcs) { + let max = 0; + for (let i = 0, ilen = arcs.length; i < ilen; ++i) { + const options = this.resolveDataElementOptions(i); + max = Math.max(max, options.offset || 0, options.hoverOffset || 0); + } + return max; + } + _getRingWeightOffset(datasetIndex) { + let ringWeightOffset = 0; + for (let i = 0; i < datasetIndex; ++i) { + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + return ringWeightOffset; + } + _getRingWeight(datasetIndex) { + return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); + } + _getVisibleDatasetWeightTotal() { + return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; + } +} +DoughnutController.id = 'doughnut'; +DoughnutController.defaults = { + datasetElementType: false, + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: false + }, + animations: { + numbers: { + type: 'number', + properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing'] + }, + }, + cutout: '50%', + rotation: 0, + circumference: 360, + radius: '100%', + spacing: 0, + indexAxis: 'r', +}; +DoughnutController.descriptors = { + _scriptable: (name) => name !== 'spacing', + _indexable: (name) => name !== 'spacing', +}; +DoughnutController.overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const {labels: {pointStyle}} = chart.legend.options; + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltip: { + callbacks: { + title() { + return ''; + }, + label(tooltipItem) { + let dataLabel = tooltipItem.label; + const value = ': ' + tooltipItem.formattedValue; + if (isArray(dataLabel)) { + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; + } + return dataLabel; + } + } + } + } +}; + +class LineController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + update(mode) { + const meta = this._cachedMeta; + const {dataset: line, data: points = [], _dataset} = meta; + const animationsDisabled = this.chart._animationsDisabled; + let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); + this._drawStart = start; + this._drawCount = count; + if (scaleRangesChanged(meta)) { + start = 0; + count = points.length; + } + line._chart = this.chart; + line._datasetIndex = this.index; + line._decimated = !!_dataset._decimated; + line.points = points; + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + options.segment = this.options.segment; + this.updateElement(line, undefined, { + animated: !animationsDisabled, + options + }, mode); + this.updateElements(points, start, count, mode); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const {iScale, vScale, _stacked, _dataset} = this._cachedMeta; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const {spanGaps, segment} = this.options; + const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; + let prevParsed = start > 0 && this.getParsed(start - 1); + for (let i = start; i < start + count; ++i) { + const point = points[i]; + const parsed = this.getParsed(i); + const properties = directUpdate ? point : {}; + const nullData = isNullOrUndef(parsed[vAxis]); + const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); + const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); + properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; + properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; + if (segment) { + properties.parsed = parsed; + properties.raw = _dataset.data[i]; + } + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); + } + if (!directUpdate) { + this.updateElement(point, i, properties, mode); + } + prevParsed = parsed; + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + getMaxOverflow() { + const meta = this._cachedMeta; + const dataset = meta.dataset; + const border = dataset.options && dataset.options.borderWidth || 0; + const data = meta.data || []; + if (!data.length) { + return border; + } + const firstPoint = data[0].size(this.resolveDataElementOptions(0)); + const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); + return Math.max(border, firstPoint, lastPoint) / 2; + } + draw() { + const meta = this._cachedMeta; + meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); + super.draw(); + } +} +LineController.id = 'line'; +LineController.defaults = { + datasetElementType: 'line', + dataElementType: 'point', + showLine: true, + spanGaps: false, +}; +LineController.overrides = { + scales: { + _index_: { + type: 'category', + }, + _value_: { + type: 'linear', + }, + } +}; +function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { + const pointCount = points.length; + let start = 0; + let count = pointCount; + if (meta._sorted) { + const {iScale, _parsed} = meta; + const axis = iScale.axis; + const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(Math.min( + _lookupByKey(_parsed, iScale.axis, min).lo, + animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), + 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(Math.max( + _lookupByKey(_parsed, iScale.axis, max).hi + 1, + animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), + start, pointCount) - start; + } else { + count = pointCount - start; + } + } + return {start, count}; +} +function scaleRangesChanged(meta) { + const {xScale, yScale, _scaleRanges} = meta; + const newRanges = { + xmin: xScale.min, + xmax: xScale.max, + ymin: yScale.min, + ymax: yScale.max + }; + if (!_scaleRanges) { + meta._scaleRanges = newRanges; + return true; + } + const changed = _scaleRanges.xmin !== xScale.min + || _scaleRanges.xmax !== xScale.max + || _scaleRanges.ymin !== yScale.min + || _scaleRanges.ymax !== yScale.max; + Object.assign(_scaleRanges, newRanges); + return changed; +} + +class PolarAreaController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.innerRadius = undefined; + this.outerRadius = undefined; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index].r, chart.options.locale); + return { + label: labels[index] || '', + value, + }; + } + update(mode) { + const arcs = this._cachedMeta.data; + this._updateRadius(); + this.updateElements(arcs, 0, arcs.length, mode); + } + _updateRadius() { + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + const outerRadius = Math.max(minSize / 2, 0); + const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); + this.outerRadius = outerRadius - (radiusLength * this.index); + this.innerRadius = this.outerRadius - radiusLength; + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const dataset = this.getDataset(); + const opts = chart.options; + const animationOpts = opts.animation; + const scale = this._cachedMeta.rScale; + const centerX = scale.xCenter; + const centerY = scale.yCenter; + const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; + let angle = datasetStartAngle; + let i; + const defaultAngle = 360 / this.countVisibleElements(); + for (i = 0; i < start; ++i) { + angle += this._computeAngle(i, mode, defaultAngle); + } + for (i = start; i < start + count; i++) { + const arc = arcs[i]; + let startAngle = angle; + let endAngle = angle + this._computeAngle(i, mode, defaultAngle); + let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; + angle = endAngle; + if (reset) { + if (animationOpts.animateScale) { + outerRadius = 0; + } + if (animationOpts.animateRotate) { + startAngle = endAngle = datasetStartAngle; + } + } + const properties = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius, + startAngle, + endAngle, + options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) + }; + this.updateElement(arc, i, properties, mode); + } + } + countVisibleElements() { + const dataset = this.getDataset(); + const meta = this._cachedMeta; + let count = 0; + meta.data.forEach((element, index) => { + if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { + count++; + } + }); + return count; + } + _computeAngle(index, mode, defaultAngle) { + return this.chart.getDataVisibility(index) + ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) + : 0; + } +} +PolarAreaController.id = 'polarArea'; +PolarAreaController.defaults = { + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: true + }, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] + }, + }, + indexAxis: 'r', + startAngle: 0, +}; +PolarAreaController.overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const {labels: {pointStyle}} = chart.legend.options; + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltip: { + callbacks: { + title() { + return ''; + }, + label(context) { + return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; + } + } + } + }, + scales: { + r: { + type: 'radialLinear', + angleLines: { + display: false + }, + beginAtZero: true, + grid: { + circular: true + }, + pointLabels: { + display: false + }, + startAngle: 0 + } + } +}; + +class PieController extends DoughnutController { +} +PieController.id = 'pie'; +PieController.defaults = { + cutout: 0, + rotation: 0, + circumference: 360, + radius: '100%' +}; + +class RadarController extends DatasetController { + getLabelAndValue(index) { + const vScale = this._cachedMeta.vScale; + const parsed = this.getParsed(index); + return { + label: vScale.getLabels()[index], + value: '' + vScale.getLabelForValue(parsed[vScale.axis]) + }; + } + update(mode) { + const meta = this._cachedMeta; + const line = meta.dataset; + const points = meta.data || []; + const labels = meta.iScale.getLabels(); + line.points = points; + if (mode !== 'resize') { + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + const properties = { + _loop: true, + _fullLoop: labels.length === points.length, + options + }; + this.updateElement(line, undefined, properties, mode); + } + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const dataset = this.getDataset(); + const scale = this._cachedMeta.rScale; + const reset = mode === 'reset'; + for (let i = start; i < start + count; i++) { + const point = points[i]; + const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); + const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); + const x = reset ? scale.xCenter : pointPosition.x; + const y = reset ? scale.yCenter : pointPosition.y; + const properties = { + x, + y, + angle: pointPosition.angle, + skip: isNaN(x) || isNaN(y), + options + }; + this.updateElement(point, i, properties, mode); + } + } +} +RadarController.id = 'radar'; +RadarController.defaults = { + datasetElementType: 'line', + dataElementType: 'point', + indexAxis: 'r', + showLine: true, + elements: { + line: { + fill: 'start' + } + }, +}; +RadarController.overrides = { + aspectRatio: 1, + scales: { + r: { + type: 'radialLinear', + } + } +}; + +class ScatterController extends LineController { +} +ScatterController.id = 'scatter'; +ScatterController.defaults = { + showLine: false, + fill: false +}; +ScatterController.overrides = { + interaction: { + mode: 'point' + }, + plugins: { + tooltip: { + callbacks: { + title() { + return ''; + }, + label(item) { + return '(' + item.label + ', ' + item.formattedValue + ')'; + } + } + } + }, + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + } +}; + +var controllers = /*#__PURE__*/Object.freeze({ +__proto__: null, +BarController: BarController, +BubbleController: BubbleController, +DoughnutController: DoughnutController, +LineController: LineController, +PolarAreaController: PolarAreaController, +PieController: PieController, +RadarController: RadarController, +ScatterController: ScatterController +}); + +function abstract() { + throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); +} +class DateAdapter { + constructor(options) { + this.options = options || {}; + } + formats() { + return abstract(); + } + parse(value, format) { + return abstract(); + } + format(timestamp, format) { + return abstract(); + } + add(timestamp, amount, unit) { + return abstract(); + } + diff(a, b, unit) { + return abstract(); + } + startOf(timestamp, unit, weekday) { + return abstract(); + } + endOf(timestamp, unit) { + return abstract(); + } +} +DateAdapter.override = function(members) { + Object.assign(DateAdapter.prototype, members); +}; +var adapters = { + _date: DateAdapter +}; + +function getRelativePosition(e, chart) { + if ('native' in e) { + return { + x: e.x, + y: e.y + }; + } + return getRelativePosition$1(e, chart); +} +function evaluateAllVisibleItems(chart, handler) { + const metasets = chart.getSortedVisibleDatasetMetas(); + let index, data, element; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + ({index, data} = metasets[i]); + for (let j = 0, jlen = data.length; j < jlen; ++j) { + element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function binarySearch(metaset, axis, value, intersect) { + const {controller, data, _sorted} = metaset; + const iScale = controller._cachedMeta.iScale; + if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { + const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; + if (!intersect) { + return lookupMethod(data, axis, value); + } else if (controller._sharedOptions) { + const el = data[0]; + const range = typeof el.getRange === 'function' && el.getRange(axis); + if (range) { + const start = lookupMethod(data, axis, value - range); + const end = lookupMethod(data, axis, value + range); + return {lo: start.lo, hi: end.hi}; + } + } + } + return {lo: 0, hi: data.length - 1}; +} +function optimizedEvaluateItems(chart, axis, position, handler, intersect) { + const metasets = chart.getSortedVisibleDatasetMetas(); + const value = position[axis]; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + const {index, data} = metasets[i]; + const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); + for (let j = lo; j <= hi; ++j) { + const element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function getDistanceMetricForAxis(axis) { + const useX = axis.indexOf('x') !== -1; + const useY = axis.indexOf('y') !== -1; + return function(pt1, pt2) { + const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} +function getIntersectItems(chart, position, axis, useFinalPosition) { + const items = []; + if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { + return items; + } + const evaluationFunc = function(element, datasetIndex, index) { + if (element.inRange(position.x, position.y, useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); + return items; +} +function getNearestRadialItems(chart, position, axis, useFinalPosition) { + let items = []; + function evaluationFunc(element, datasetIndex, index) { + const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition); + const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y}); + if (_angleBetween(angle, startAngle, endAngle)) { + items.push({element, datasetIndex, index}); + } + } + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) { + let items = []; + const distanceMetric = getDistanceMetricForAxis(axis); + let minDistance = Number.POSITIVE_INFINITY; + function evaluationFunc(element, datasetIndex, index) { + const inRange = element.inRange(position.x, position.y, useFinalPosition); + if (intersect && !inRange) { + return; + } + const center = element.getCenterPoint(useFinalPosition); + const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding); + if (!pointInArea && !inRange) { + return; + } + const distance = distanceMetric(position, center); + if (distance < minDistance) { + items = [{element, datasetIndex, index}]; + minDistance = distance; + } else if (distance === minDistance) { + items.push({element, datasetIndex, index}); + } + } + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getNearestItems(chart, position, axis, intersect, useFinalPosition) { + if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { + return []; + } + return axis === 'r' && !intersect + ? getNearestRadialItems(chart, position, axis, useFinalPosition) + : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition); +} +function getAxisItems(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const items = []; + const axis = options.axis; + const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; + let intersectsItem = false; + evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { + if (element[rangeMethod](position[axis], useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + if (element.inRange(position.x, position.y, useFinalPosition)) { + intersectsItem = true; + } + }); + if (options.intersect && !intersectsItem) { + return []; + } + return items; +} +var Interaction = { + modes: { + index(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'x'; + const items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) + : getNearestItems(chart, position, axis, false, useFinalPosition); + const elements = []; + if (!items.length) { + return []; + } + chart.getSortedVisibleDatasetMetas().forEach((meta) => { + const index = items[0].index; + const element = meta.data[index]; + if (element && !element.skip) { + elements.push({element, datasetIndex: meta.index, index}); + } + }); + return elements; + }, + dataset(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + let items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) : + getNearestItems(chart, position, axis, false, useFinalPosition); + if (items.length > 0) { + const datasetIndex = items[0].datasetIndex; + const data = chart.getDatasetMeta(datasetIndex).data; + items = []; + for (let i = 0; i < data.length; ++i) { + items.push({element: data[i], datasetIndex, index: i}); + } + } + return items; + }, + point(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getIntersectItems(chart, position, axis, useFinalPosition); + }, + nearest(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); + }, + x(chart, e, options, useFinalPosition) { + return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition); + }, + y(chart, e, options, useFinalPosition) { + return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition); + } + } +}; + +const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; +function filterByPosition(array, position) { + return array.filter(v => v.pos === position); +} +function filterDynamicPositionByAxis(array, axis) { + return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); +} +function sortByWeight(array, reverse) { + return array.sort((a, b) => { + const v0 = reverse ? b : a; + const v1 = reverse ? a : b; + return v0.weight === v1.weight ? + v0.index - v1.index : + v0.weight - v1.weight; + }); +} +function wrapBoxes(boxes) { + const layoutBoxes = []; + let i, ilen, box, pos, stack, stackWeight; + for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { + box = boxes[i]; + ({position: pos, options: {stack, stackWeight = 1}} = box); + layoutBoxes.push({ + index: i, + box, + pos, + horizontal: box.isHorizontal(), + weight: box.weight, + stack: stack && (pos + stack), + stackWeight + }); + } + return layoutBoxes; +} +function buildStacks(layouts) { + const stacks = {}; + for (const wrap of layouts) { + const {stack, pos, stackWeight} = wrap; + if (!stack || !STATIC_POSITIONS.includes(pos)) { + continue; + } + const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0}); + _stack.count++; + _stack.weight += stackWeight; + } + return stacks; +} +function setLayoutDims(layouts, params) { + const stacks = buildStacks(layouts); + const {vBoxMaxWidth, hBoxMaxHeight} = params; + let i, ilen, layout; + for (i = 0, ilen = layouts.length; i < ilen; ++i) { + layout = layouts[i]; + const {fullSize} = layout.box; + const stack = stacks[layout.stack]; + const factor = stack && layout.stackWeight / stack.weight; + if (layout.horizontal) { + layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; + layout.height = hBoxMaxHeight; + } else { + layout.width = vBoxMaxWidth; + layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; + } + } + return stacks; +} +function buildLayoutBoxes(boxes) { + const layoutBoxes = wrapBoxes(boxes); + const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true); + const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); + const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); + const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); + const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); + const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); + const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); + return { + fullSize, + leftAndTop: left.concat(top), + rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), + chartArea: filterByPosition(layoutBoxes, 'chartArea'), + vertical: left.concat(right).concat(centerVertical), + horizontal: top.concat(bottom).concat(centerHorizontal) + }; +} +function getCombinedMax(maxPadding, chartArea, a, b) { + return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); +} +function updateMaxPadding(maxPadding, boxPadding) { + maxPadding.top = Math.max(maxPadding.top, boxPadding.top); + maxPadding.left = Math.max(maxPadding.left, boxPadding.left); + maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); + maxPadding.right = Math.max(maxPadding.right, boxPadding.right); +} +function updateDims(chartArea, params, layout, stacks) { + const {pos, box} = layout; + const maxPadding = chartArea.maxPadding; + if (!isObject(pos)) { + if (layout.size) { + chartArea[pos] -= layout.size; + } + const stack = stacks[layout.stack] || {size: 0, count: 1}; + stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); + layout.size = stack.size / stack.count; + chartArea[pos] += layout.size; + } + if (box.getPadding) { + updateMaxPadding(maxPadding, box.getPadding()); + } + const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); + const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); + const widthChanged = newWidth !== chartArea.w; + const heightChanged = newHeight !== chartArea.h; + chartArea.w = newWidth; + chartArea.h = newHeight; + return layout.horizontal + ? {same: widthChanged, other: heightChanged} + : {same: heightChanged, other: widthChanged}; +} +function handleMaxPadding(chartArea) { + const maxPadding = chartArea.maxPadding; + function updatePos(pos) { + const change = Math.max(maxPadding[pos] - chartArea[pos], 0); + chartArea[pos] += change; + return change; + } + chartArea.y += updatePos('top'); + chartArea.x += updatePos('left'); + updatePos('right'); + updatePos('bottom'); +} +function getMargins(horizontal, chartArea) { + const maxPadding = chartArea.maxPadding; + function marginForPositions(positions) { + const margin = {left: 0, top: 0, right: 0, bottom: 0}; + positions.forEach((pos) => { + margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); + }); + return margin; + } + return horizontal + ? marginForPositions(['left', 'right']) + : marginForPositions(['top', 'bottom']); +} +function fitBoxes(boxes, chartArea, params, stacks) { + const refitBoxes = []; + let i, ilen, layout, box, refit, changed; + for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + box.update( + layout.width || chartArea.w, + layout.height || chartArea.h, + getMargins(layout.horizontal, chartArea) + ); + const {same, other} = updateDims(chartArea, params, layout, stacks); + refit |= same && refitBoxes.length; + changed = changed || other; + if (!box.fullSize) { + refitBoxes.push(layout); + } + } + return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; +} +function setBoxDims(box, left, top, width, height) { + box.top = top; + box.left = left; + box.right = left + width; + box.bottom = top + height; + box.width = width; + box.height = height; +} +function placeBoxes(boxes, chartArea, params, stacks) { + const userPadding = params.padding; + let {x, y} = chartArea; + for (const layout of boxes) { + const box = layout.box; + const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1}; + const weight = (layout.stackWeight / stack.weight) || 1; + if (layout.horizontal) { + const width = chartArea.w * weight; + const height = stack.size || box.height; + if (defined(stack.start)) { + y = stack.start; + } + if (box.fullSize) { + setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); + } else { + setBoxDims(box, chartArea.left + stack.placed, y, width, height); + } + stack.start = y; + stack.placed += width; + y = box.bottom; + } else { + const height = chartArea.h * weight; + const width = stack.size || box.width; + if (defined(stack.start)) { + x = stack.start; + } + if (box.fullSize) { + setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); + } else { + setBoxDims(box, x, chartArea.top + stack.placed, width, height); + } + stack.start = x; + stack.placed += height; + x = box.right; + } + } + chartArea.x = x; + chartArea.y = y; +} +defaults.set('layout', { + autoPadding: true, + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } +}); +var layouts = { + addBox(chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + item.fullSize = item.fullSize || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + item._layers = item._layers || function() { + return [{ + z: 0, + draw(chartArea) { + item.draw(chartArea); + } + }]; + }; + chart.boxes.push(item); + }, + removeBox(chart, layoutItem) { + const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + configure(chart, item, options) { + item.fullSize = options.fullSize; + item.position = options.position; + item.weight = options.weight; + }, + update(chart, width, height, minPadding) { + if (!chart) { + return; + } + const padding = toPadding(chart.options.layout.padding); + const availableWidth = Math.max(width - padding.width, 0); + const availableHeight = Math.max(height - padding.height, 0); + const boxes = buildLayoutBoxes(chart.boxes); + const verticalBoxes = boxes.vertical; + const horizontalBoxes = boxes.horizontal; + each(chart.boxes, box => { + if (typeof box.beforeLayout === 'function') { + box.beforeLayout(); + } + }); + const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => + wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; + const params = Object.freeze({ + outerWidth: width, + outerHeight: height, + padding, + availableWidth, + availableHeight, + vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, + hBoxMaxHeight: availableHeight / 2 + }); + const maxPadding = Object.assign({}, padding); + updateMaxPadding(maxPadding, toPadding(minPadding)); + const chartArea = Object.assign({ + maxPadding, + w: availableWidth, + h: availableHeight, + x: padding.left, + y: padding.top + }, padding); + const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); + fitBoxes(boxes.fullSize, chartArea, params, stacks); + fitBoxes(verticalBoxes, chartArea, params, stacks); + if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { + fitBoxes(verticalBoxes, chartArea, params, stacks); + } + handleMaxPadding(chartArea); + placeBoxes(boxes.leftAndTop, chartArea, params, stacks); + chartArea.x += chartArea.w; + chartArea.y += chartArea.h; + placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); + chart.chartArea = { + left: chartArea.left, + top: chartArea.top, + right: chartArea.left + chartArea.w, + bottom: chartArea.top + chartArea.h, + height: chartArea.h, + width: chartArea.w, + }; + each(boxes.chartArea, (layout) => { + const box = layout.box; + Object.assign(box, chart.chartArea); + box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0}); + }); + } +}; + +class BasePlatform { + acquireContext(canvas, aspectRatio) {} + releaseContext(context) { + return false; + } + addEventListener(chart, type, listener) {} + removeEventListener(chart, type, listener) {} + getDevicePixelRatio() { + return 1; + } + getMaximumSize(element, width, height, aspectRatio) { + width = Math.max(0, width || element.width); + height = height || element.height; + return { + width, + height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) + }; + } + isAttached(canvas) { + return true; + } + updateConfig(config) { + } +} + +class BasicPlatform extends BasePlatform { + acquireContext(item) { + return item && item.getContext && item.getContext('2d') || null; + } + updateConfig(config) { + config.options.animation = false; + } +} + +const EXPANDO_KEY = '$chartjs'; +const EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; +const isNullOrEmpty = value => value === null || value === ''; +function initCanvas(canvas, aspectRatio) { + const style = canvas.style; + const renderHeight = canvas.getAttribute('height'); + const renderWidth = canvas.getAttribute('width'); + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + style.display = style.display || 'block'; + style.boxSizing = style.boxSizing || 'border-box'; + if (isNullOrEmpty(renderWidth)) { + const displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + if (isNullOrEmpty(renderHeight)) { + if (canvas.style.height === '') { + canvas.height = canvas.width / (aspectRatio || 2); + } else { + const displayHeight = readUsedSize(canvas, 'height'); + if (displayHeight !== undefined) { + canvas.height = displayHeight; + } + } + } + return canvas; +} +const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; +function addListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} +function removeListener(chart, type, listener) { + chart.canvas.removeEventListener(type, listener, eventListenerOptions); +} +function fromNativeEvent(event, chart) { + const type = EVENT_TYPES[event.type] || event.type; + const {x, y} = getRelativePosition$1(event, chart); + return { + type, + chart, + native: event, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null, + }; +} +function nodeListContains(nodeList, canvas) { + for (const node of nodeList) { + if (node === canvas || node.contains(canvas)) { + return true; + } + } +} +function createAttachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver(entries => { + let trigger = false; + for (const entry of entries) { + trigger = trigger || nodeListContains(entry.addedNodes, canvas); + trigger = trigger && !nodeListContains(entry.removedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, {childList: true, subtree: true}); + return observer; +} +function createDetachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver(entries => { + let trigger = false; + for (const entry of entries) { + trigger = trigger || nodeListContains(entry.removedNodes, canvas); + trigger = trigger && !nodeListContains(entry.addedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, {childList: true, subtree: true}); + return observer; +} +const drpListeningCharts = new Map(); +let oldDevicePixelRatio = 0; +function onWindowResize() { + const dpr = window.devicePixelRatio; + if (dpr === oldDevicePixelRatio) { + return; + } + oldDevicePixelRatio = dpr; + drpListeningCharts.forEach((resize, chart) => { + if (chart.currentDevicePixelRatio !== dpr) { + resize(); + } + }); +} +function listenDevicePixelRatioChanges(chart, resize) { + if (!drpListeningCharts.size) { + window.addEventListener('resize', onWindowResize); + } + drpListeningCharts.set(chart, resize); +} +function unlistenDevicePixelRatioChanges(chart) { + drpListeningCharts.delete(chart); + if (!drpListeningCharts.size) { + window.removeEventListener('resize', onWindowResize); + } +} +function createResizeObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + const resize = throttled((width, height) => { + const w = container.clientWidth; + listener(width, height); + if (w < container.clientWidth) { + listener(); + } + }, window); + const observer = new ResizeObserver(entries => { + const entry = entries[0]; + const width = entry.contentRect.width; + const height = entry.contentRect.height; + if (width === 0 && height === 0) { + return; + } + resize(width, height); + }); + observer.observe(container); + listenDevicePixelRatioChanges(chart, resize); + return observer; +} +function releaseObserver(chart, type, observer) { + if (observer) { + observer.disconnect(); + } + if (type === 'resize') { + unlistenDevicePixelRatioChanges(chart); + } +} +function createProxyAndListen(chart, type, listener) { + const canvas = chart.canvas; + const proxy = throttled((event) => { + if (chart.ctx !== null) { + listener(fromNativeEvent(event, chart)); + } + }, chart, (args) => { + const event = args[0]; + return [event, event.offsetX, event.offsetY]; + }); + addListener(canvas, type, proxy); + return proxy; +} +class DomPlatform extends BasePlatform { + acquireContext(canvas, aspectRatio) { + const context = canvas && canvas.getContext && canvas.getContext('2d'); + if (context && context.canvas === canvas) { + initCanvas(canvas, aspectRatio); + return context; + } + return null; + } + releaseContext(context) { + const canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return false; + } + const initial = canvas[EXPANDO_KEY].initial; + ['height', 'width'].forEach((prop) => { + const value = initial[prop]; + if (isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + const style = initial.style || {}; + Object.keys(style).forEach((key) => { + canvas.style[key] = style[key]; + }); + canvas.width = canvas.width; + delete canvas[EXPANDO_KEY]; + return true; + } + addEventListener(chart, type, listener) { + this.removeEventListener(chart, type); + const proxies = chart.$proxies || (chart.$proxies = {}); + const handlers = { + attach: createAttachObserver, + detach: createDetachObserver, + resize: createResizeObserver + }; + const handler = handlers[type] || createProxyAndListen; + proxies[type] = handler(chart, type, listener); + } + removeEventListener(chart, type) { + const proxies = chart.$proxies || (chart.$proxies = {}); + const proxy = proxies[type]; + if (!proxy) { + return; + } + const handlers = { + attach: releaseObserver, + detach: releaseObserver, + resize: releaseObserver + }; + const handler = handlers[type] || removeListener; + handler(chart, type, proxy); + proxies[type] = undefined; + } + getDevicePixelRatio() { + return window.devicePixelRatio; + } + getMaximumSize(canvas, width, height, aspectRatio) { + return getMaximumSize(canvas, width, height, aspectRatio); + } + isAttached(canvas) { + const container = _getParentNode(canvas); + return !!(container && container.isConnected); + } +} + +function _detectPlatform(canvas) { + if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { + return BasicPlatform; + } + return DomPlatform; +} + +class Element { + constructor() { + this.x = undefined; + this.y = undefined; + this.active = false; + this.options = undefined; + this.$animations = undefined; + } + tooltipPosition(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + hasValue() { + return isNumber(this.x) && isNumber(this.y); + } + getProps(props, final) { + const anims = this.$animations; + if (!final || !anims) { + return this; + } + const ret = {}; + props.forEach(prop => { + ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; + }); + return ret; + } +} +Element.defaults = {}; +Element.defaultRoutes = undefined; + +const formatters = { + values(value) { + return isArray(value) ? value : '' + value; + }, + numeric(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const locale = this.chart.options.locale; + let notation; + let delta = tickValue; + if (ticks.length > 1) { + const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); + if (maxTick < 1e-4 || maxTick > 1e+15) { + notation = 'scientific'; + } + delta = calculateDelta(tickValue, ticks); + } + const logDelta = log10(Math.abs(delta)); + const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); + const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; + Object.assign(options, this.options.ticks.format); + return formatNumber(tickValue, locale, options); + }, + logarithmic(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); + if (remain === 1 || remain === 2 || remain === 5) { + return formatters.numeric.call(this, tickValue, index, ticks); + } + return ''; + } +}; +function calculateDelta(tickValue, ticks) { + let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; + if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { + delta = tickValue - Math.floor(tickValue); + } + return delta; +} +var Ticks = {formatters}; + +defaults.set('scale', { + display: true, + offset: false, + reverse: false, + beginAtZero: false, + bounds: 'ticks', + grace: 0, + grid: { + display: true, + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickLength: 8, + tickWidth: (_ctx, options) => options.lineWidth, + tickColor: (_ctx, options) => options.color, + offset: false, + borderDash: [], + borderDashOffset: 0.0, + borderWidth: 1 + }, + title: { + display: false, + text: '', + padding: { + top: 4, + bottom: 4 + } + }, + ticks: { + minRotation: 0, + maxRotation: 50, + mirror: false, + textStrokeWidth: 0, + textStrokeColor: '', + padding: 3, + display: true, + autoSkip: true, + autoSkipPadding: 3, + labelOffset: 0, + callback: Ticks.formatters.values, + minor: {}, + major: {}, + align: 'center', + crossAlign: 'near', + showLabelBackdrop: false, + backdropColor: 'rgba(255, 255, 255, 0.75)', + backdropPadding: 2, + } +}); +defaults.route('scale.ticks', 'color', '', 'color'); +defaults.route('scale.grid', 'color', '', 'borderColor'); +defaults.route('scale.grid', 'borderColor', '', 'borderColor'); +defaults.route('scale.title', 'color', '', 'color'); +defaults.describe('scale', { + _fallback: false, + _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', + _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash', +}); +defaults.describe('scales', { + _fallback: 'scale', +}); +defaults.describe('scale.ticks', { + _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback', + _indexable: (name) => name !== 'backdropPadding', +}); + +function autoSkip(scale, ticks) { + const tickOpts = scale.options.ticks; + const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale); + const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; + const numMajorIndices = majorIndices.length; + const first = majorIndices[0]; + const last = majorIndices[numMajorIndices - 1]; + const newTicks = []; + if (numMajorIndices > ticksLimit) { + skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); + return newTicks; + } + const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); + if (numMajorIndices > 0) { + let i, ilen; + const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; + skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); + for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { + skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); + } + skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); + return newTicks; + } + skip(ticks, newTicks, spacing); + return newTicks; +} +function determineMaxTicks(scale) { + const offset = scale.options.offset; + const tickLength = scale._tickSize(); + const maxScale = scale._length / tickLength + (offset ? 0 : 1); + const maxChart = scale._maxLength / tickLength; + return Math.floor(Math.min(maxScale, maxChart)); +} +function calculateSpacing(majorIndices, ticks, ticksLimit) { + const evenMajorSpacing = getEvenSpacing(majorIndices); + const spacing = ticks.length / ticksLimit; + if (!evenMajorSpacing) { + return Math.max(spacing, 1); + } + const factors = _factorize(evenMajorSpacing); + for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { + const factor = factors[i]; + if (factor > spacing) { + return factor; + } + } + return Math.max(spacing, 1); +} +function getMajorIndices(ticks) { + const result = []; + let i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (ticks[i].major) { + result.push(i); + } + } + return result; +} +function skipMajors(ticks, newTicks, majorIndices, spacing) { + let count = 0; + let next = majorIndices[0]; + let i; + spacing = Math.ceil(spacing); + for (i = 0; i < ticks.length; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = majorIndices[count * spacing]; + } + } +} +function skip(ticks, newTicks, spacing, majorStart, majorEnd) { + const start = valueOrDefault(majorStart, 0); + const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); + let count = 0; + let length, i, next; + spacing = Math.ceil(spacing); + if (majorEnd) { + length = majorEnd - majorStart; + spacing = length / Math.floor(length / spacing); + } + next = start; + while (next < 0) { + count++; + next = Math.round(start + count * spacing); + } + for (i = Math.max(start, 0); i < end; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = Math.round(start + count * spacing); + } + } +} +function getEvenSpacing(arr) { + const len = arr.length; + let i, diff; + if (len < 2) { + return false; + } + for (diff = arr[0], i = 1; i < len; ++i) { + if (arr[i] - arr[i - 1] !== diff) { + return false; + } + } + return diff; +} + +const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align; +const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; +function sample(arr, numItems) { + const result = []; + const increment = arr.length / numItems; + const len = arr.length; + let i = 0; + for (; i < len; i += increment) { + result.push(arr[Math.floor(i)]); + } + return result; +} +function getPixelForGridLine(scale, index, offsetGridLines) { + const length = scale.ticks.length; + const validIndex = Math.min(index, length - 1); + const start = scale._startPixel; + const end = scale._endPixel; + const epsilon = 1e-6; + let lineValue = scale.getPixelForTick(validIndex); + let offset; + if (offsetGridLines) { + if (length === 1) { + offset = Math.max(lineValue - start, end - lineValue); + } else if (index === 0) { + offset = (scale.getPixelForTick(1) - lineValue) / 2; + } else { + offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; + } + lineValue += validIndex < index ? offset : -offset; + if (lineValue < start - epsilon || lineValue > end + epsilon) { + return; + } + } + return lineValue; +} +function garbageCollect(caches, length) { + each(caches, (cache) => { + const gc = cache.gc; + const gcLen = gc.length / 2; + let i; + if (gcLen > length) { + for (i = 0; i < gcLen; ++i) { + delete cache.data[gc[i]]; + } + gc.splice(0, gcLen); + } + }); +} +function getTickMarkLength(options) { + return options.drawTicks ? options.tickLength : 0; +} +function getTitleHeight(options, fallback) { + if (!options.display) { + return 0; + } + const font = toFont(options.font, fallback); + const padding = toPadding(options.padding); + const lines = isArray(options.text) ? options.text.length : 1; + return (lines * font.lineHeight) + padding.height; +} +function createScaleContext(parent, scale) { + return createContext(parent, { + scale, + type: 'scale' + }); +} +function createTickContext(parent, index, tick) { + return createContext(parent, { + tick, + index, + type: 'tick' + }); +} +function titleAlign(align, position, reverse) { + let ret = _toLeftRightCenter(align); + if ((reverse && position !== 'right') || (!reverse && position === 'right')) { + ret = reverseAlign(ret); + } + return ret; +} +function titleArgs(scale, offset, position, align) { + const {top, left, bottom, right, chart} = scale; + const {chartArea, scales} = chart; + let rotation = 0; + let maxWidth, titleX, titleY; + const height = bottom - top; + const width = right - left; + if (scale.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; + } else if (position === 'center') { + titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; + } else { + titleY = offsetFromEdge(scale, position, offset); + } + maxWidth = right - left; + } else { + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; + } else if (position === 'center') { + titleX = (chartArea.left + chartArea.right) / 2 - width + offset; + } else { + titleX = offsetFromEdge(scale, position, offset); + } + titleY = _alignStartEnd(align, bottom, top); + rotation = position === 'left' ? -HALF_PI : HALF_PI; + } + return {titleX, titleY, maxWidth, rotation}; +} +class Scale extends Element { + constructor(cfg) { + super(); + this.id = cfg.id; + this.type = cfg.type; + this.options = undefined; + this.ctx = cfg.ctx; + this.chart = cfg.chart; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this._margins = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + this.maxWidth = undefined; + this.maxHeight = undefined; + this.paddingTop = undefined; + this.paddingBottom = undefined; + this.paddingLeft = undefined; + this.paddingRight = undefined; + this.axis = undefined; + this.labelRotation = undefined; + this.min = undefined; + this.max = undefined; + this._range = undefined; + this.ticks = []; + this._gridLineItems = null; + this._labelItems = null; + this._labelSizes = null; + this._length = 0; + this._maxLength = 0; + this._longestTextCache = {}; + this._startPixel = undefined; + this._endPixel = undefined; + this._reversePixels = false; + this._userMax = undefined; + this._userMin = undefined; + this._suggestedMax = undefined; + this._suggestedMin = undefined; + this._ticksLength = 0; + this._borderValue = 0; + this._cache = {}; + this._dataLimitsCached = false; + this.$context = undefined; + } + init(options) { + this.options = options.setContext(this.getContext()); + this.axis = options.axis; + this._userMin = this.parse(options.min); + this._userMax = this.parse(options.max); + this._suggestedMin = this.parse(options.suggestedMin); + this._suggestedMax = this.parse(options.suggestedMax); + } + parse(raw, index) { + return raw; + } + getUserBounds() { + let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this; + _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); + _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); + _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); + _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); + return { + min: finiteOrDefault(_userMin, _suggestedMin), + max: finiteOrDefault(_userMax, _suggestedMax), + minDefined: isNumberFinite(_userMin), + maxDefined: isNumberFinite(_userMax) + }; + } + getMinMax(canStack) { + let {min, max, minDefined, maxDefined} = this.getUserBounds(); + let range; + if (minDefined && maxDefined) { + return {min, max}; + } + const metas = this.getMatchingVisibleMetas(); + for (let i = 0, ilen = metas.length; i < ilen; ++i) { + range = metas[i].controller.getMinMax(this, canStack); + if (!minDefined) { + min = Math.min(min, range.min); + } + if (!maxDefined) { + max = Math.max(max, range.max); + } + } + min = maxDefined && min > max ? max : min; + max = minDefined && min > max ? min : max; + return { + min: finiteOrDefault(min, finiteOrDefault(max, min)), + max: finiteOrDefault(max, finiteOrDefault(min, max)) + }; + } + getPadding() { + return { + left: this.paddingLeft || 0, + top: this.paddingTop || 0, + right: this.paddingRight || 0, + bottom: this.paddingBottom || 0 + }; + } + getTicks() { + return this.ticks; + } + getLabels() { + const data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; + } + beforeLayout() { + this._cache = {}; + this._dataLimitsCached = false; + } + beforeUpdate() { + callback(this.options.beforeUpdate, [this]); + } + update(maxWidth, maxHeight, margins) { + const {beginAtZero, grace, ticks: tickOpts} = this.options; + const sampleSize = tickOpts.sampleSize; + this.beforeUpdate(); + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins = Object.assign({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + this.ticks = null; + this._labelSizes = null; + this._gridLineItems = null; + this._labelItems = null; + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + this._maxLength = this.isHorizontal() + ? this.width + margins.left + margins.right + : this.height + margins.top + margins.bottom; + if (!this._dataLimitsCached) { + this.beforeDataLimits(); + this.determineDataLimits(); + this.afterDataLimits(); + this._range = _addGrace(this, grace, beginAtZero); + this._dataLimitsCached = true; + } + this.beforeBuildTicks(); + this.ticks = this.buildTicks() || []; + this.afterBuildTicks(); + const samplingEnabled = sampleSize < this.ticks.length; + this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); + this.configure(); + this.beforeCalculateLabelRotation(); + this.calculateLabelRotation(); + this.afterCalculateLabelRotation(); + if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { + this.ticks = autoSkip(this, this.ticks); + this._labelSizes = null; + } + if (samplingEnabled) { + this._convertTicksToLabels(this.ticks); + } + this.beforeFit(); + this.fit(); + this.afterFit(); + this.afterUpdate(); + } + configure() { + let reversePixels = this.options.reverse; + let startPixel, endPixel; + if (this.isHorizontal()) { + startPixel = this.left; + endPixel = this.right; + } else { + startPixel = this.top; + endPixel = this.bottom; + reversePixels = !reversePixels; + } + this._startPixel = startPixel; + this._endPixel = endPixel; + this._reversePixels = reversePixels; + this._length = endPixel - startPixel; + this._alignToPixels = this.options.alignToPixels; + } + afterUpdate() { + callback(this.options.afterUpdate, [this]); + } + beforeSetDimensions() { + callback(this.options.beforeSetDimensions, [this]); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = 0; + this.bottom = this.height; + } + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + } + afterSetDimensions() { + callback(this.options.afterSetDimensions, [this]); + } + _callHooks(name) { + this.chart.notifyPlugins(name, this.getContext()); + callback(this.options[name], [this]); + } + beforeDataLimits() { + this._callHooks('beforeDataLimits'); + } + determineDataLimits() {} + afterDataLimits() { + this._callHooks('afterDataLimits'); + } + beforeBuildTicks() { + this._callHooks('beforeBuildTicks'); + } + buildTicks() { + return []; + } + afterBuildTicks() { + this._callHooks('afterBuildTicks'); + } + beforeTickToLabelConversion() { + callback(this.options.beforeTickToLabelConversion, [this]); + } + generateTickLabels(ticks) { + const tickOpts = this.options.ticks; + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + tick = ticks[i]; + tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this); + } + } + afterTickToLabelConversion() { + callback(this.options.afterTickToLabelConversion, [this]); + } + beforeCalculateLabelRotation() { + callback(this.options.beforeCalculateLabelRotation, [this]); + } + calculateLabelRotation() { + const options = this.options; + const tickOpts = options.ticks; + const numTicks = this.ticks.length; + const minRotation = tickOpts.minRotation || 0; + const maxRotation = tickOpts.maxRotation; + let labelRotation = minRotation; + let tickWidth, maxHeight, maxLabelDiagonal; + if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { + this.labelRotation = minRotation; + return; + } + const labelSizes = this._getLabelSizes(); + const maxLabelWidth = labelSizes.widest.width; + const maxLabelHeight = labelSizes.highest.height; + const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); + tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); + if (maxLabelWidth + 6 > tickWidth) { + tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); + maxHeight = this.maxHeight - getTickMarkLength(options.grid) + - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); + maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); + labelRotation = toDegrees(Math.min( + Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), + Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)) + )); + labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); + } + this.labelRotation = labelRotation; + } + afterCalculateLabelRotation() { + callback(this.options.afterCalculateLabelRotation, [this]); + } + beforeFit() { + callback(this.options.beforeFit, [this]); + } + fit() { + const minSize = { + width: 0, + height: 0 + }; + const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this; + const display = this._isVisible(); + const isHorizontal = this.isHorizontal(); + if (display) { + const titleHeight = getTitleHeight(titleOpts, chart.options.font); + if (isHorizontal) { + minSize.width = this.maxWidth; + minSize.height = getTickMarkLength(gridOpts) + titleHeight; + } else { + minSize.height = this.maxHeight; + minSize.width = getTickMarkLength(gridOpts) + titleHeight; + } + if (tickOpts.display && this.ticks.length) { + const {first, last, widest, highest} = this._getLabelSizes(); + const tickPadding = tickOpts.padding * 2; + const angleRadians = toRadians(this.labelRotation); + const cos = Math.cos(angleRadians); + const sin = Math.sin(angleRadians); + if (isHorizontal) { + const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; + minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); + } else { + const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; + minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); + } + this._calculatePadding(first, last, sin, cos); + } + } + this._handleMargins(); + if (isHorizontal) { + this.width = this._length = chart.width - this._margins.left - this._margins.right; + this.height = minSize.height; + } else { + this.width = minSize.width; + this.height = this._length = chart.height - this._margins.top - this._margins.bottom; + } + } + _calculatePadding(first, last, sin, cos) { + const {ticks: {align, padding}, position} = this.options; + const isRotated = this.labelRotation !== 0; + const labelsBelowTicks = position !== 'top' && this.axis === 'x'; + if (this.isHorizontal()) { + const offsetLeft = this.getPixelForTick(0) - this.left; + const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); + let paddingLeft = 0; + let paddingRight = 0; + if (isRotated) { + if (labelsBelowTicks) { + paddingLeft = cos * first.width; + paddingRight = sin * last.height; + } else { + paddingLeft = sin * first.height; + paddingRight = cos * last.width; + } + } else if (align === 'start') { + paddingRight = last.width; + } else if (align === 'end') { + paddingLeft = first.width; + } else { + paddingLeft = first.width / 2; + paddingRight = last.width / 2; + } + this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); + this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); + } else { + let paddingTop = last.height / 2; + let paddingBottom = first.height / 2; + if (align === 'start') { + paddingTop = 0; + paddingBottom = first.height; + } else if (align === 'end') { + paddingTop = last.height; + paddingBottom = 0; + } + this.paddingTop = paddingTop + padding; + this.paddingBottom = paddingBottom + padding; + } + } + _handleMargins() { + if (this._margins) { + this._margins.left = Math.max(this.paddingLeft, this._margins.left); + this._margins.top = Math.max(this.paddingTop, this._margins.top); + this._margins.right = Math.max(this.paddingRight, this._margins.right); + this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); + } + } + afterFit() { + callback(this.options.afterFit, [this]); + } + isHorizontal() { + const {axis, position} = this.options; + return position === 'top' || position === 'bottom' || axis === 'x'; + } + isFullSize() { + return this.options.fullSize; + } + _convertTicksToLabels(ticks) { + this.beforeTickToLabelConversion(); + this.generateTickLabels(ticks); + let i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (isNullOrUndef(ticks[i].label)) { + ticks.splice(i, 1); + ilen--; + i--; + } + } + this.afterTickToLabelConversion(); + } + _getLabelSizes() { + let labelSizes = this._labelSizes; + if (!labelSizes) { + const sampleSize = this.options.ticks.sampleSize; + let ticks = this.ticks; + if (sampleSize < ticks.length) { + ticks = sample(ticks, sampleSize); + } + this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length); + } + return labelSizes; + } + _computeLabelSizes(ticks, length) { + const {ctx, _longestTextCache: caches} = this; + const widths = []; + const heights = []; + let widestLabelSize = 0; + let highestLabelSize = 0; + let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; + for (i = 0; i < length; ++i) { + label = ticks[i].label; + tickFont = this._resolveTickFontOptions(i); + ctx.font = fontString = tickFont.string; + cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; + lineHeight = tickFont.lineHeight; + width = height = 0; + if (!isNullOrUndef(label) && !isArray(label)) { + width = _measureText(ctx, cache.data, cache.gc, width, label); + height = lineHeight; + } else if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + nestedLabel = label[j]; + if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { + width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); + height += lineHeight; + } + } + } + widths.push(width); + heights.push(height); + widestLabelSize = Math.max(width, widestLabelSize); + highestLabelSize = Math.max(height, highestLabelSize); + } + garbageCollect(caches, length); + const widest = widths.indexOf(widestLabelSize); + const highest = heights.indexOf(highestLabelSize); + const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0}); + return { + first: valueAt(0), + last: valueAt(length - 1), + widest: valueAt(widest), + highest: valueAt(highest), + widths, + heights, + }; + } + getLabelForValue(value) { + return value; + } + getPixelForValue(value, index) { + return NaN; + } + getValueForPixel(pixel) {} + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getPixelForDecimal(decimal) { + if (this._reversePixels) { + decimal = 1 - decimal; + } + const pixel = this._startPixel + decimal * this._length; + return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); + } + getDecimalForPixel(pixel) { + const decimal = (pixel - this._startPixel) / this._length; + return this._reversePixels ? 1 - decimal : decimal; + } + getBasePixel() { + return this.getPixelForValue(this.getBaseValue()); + } + getBaseValue() { + const {min, max} = this; + return min < 0 && max < 0 ? max : + min > 0 && max > 0 ? min : + 0; + } + getContext(index) { + const ticks = this.ticks || []; + if (index >= 0 && index < ticks.length) { + const tick = ticks[index]; + return tick.$context || + (tick.$context = createTickContext(this.getContext(), index, tick)); + } + return this.$context || + (this.$context = createScaleContext(this.chart.getContext(), this)); + } + _tickSize() { + const optionTicks = this.options.ticks; + const rot = toRadians(this.labelRotation); + const cos = Math.abs(Math.cos(rot)); + const sin = Math.abs(Math.sin(rot)); + const labelSizes = this._getLabelSizes(); + const padding = optionTicks.autoSkipPadding || 0; + const w = labelSizes ? labelSizes.widest.width + padding : 0; + const h = labelSizes ? labelSizes.highest.height + padding : 0; + return this.isHorizontal() + ? h * cos > w * sin ? w / cos : h / sin + : h * sin < w * cos ? h / cos : w / sin; + } + _isVisible() { + const display = this.options.display; + if (display !== 'auto') { + return !!display; + } + return this.getMatchingVisibleMetas().length > 0; + } + _computeGridLineItems(chartArea) { + const axis = this.axis; + const chart = this.chart; + const options = this.options; + const {grid, position} = options; + const offset = grid.offset; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const ticksLength = ticks.length + (offset ? 1 : 0); + const tl = getTickMarkLength(grid); + const items = []; + const borderOpts = grid.setContext(this.getContext()); + const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0; + const axisHalfWidth = axisWidth / 2; + const alignBorderValue = function(pixel) { + return _alignPixel(chart, pixel, axisWidth); + }; + let borderValue, i, lineValue, alignedLineValue; + let tx1, ty1, tx2, ty2, x1, y1, x2, y2; + if (position === 'top') { + borderValue = alignBorderValue(this.bottom); + ty1 = this.bottom - tl; + ty2 = borderValue - axisHalfWidth; + y1 = alignBorderValue(chartArea.top) + axisHalfWidth; + y2 = chartArea.bottom; + } else if (position === 'bottom') { + borderValue = alignBorderValue(this.top); + y1 = chartArea.top; + y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; + ty1 = borderValue + axisHalfWidth; + ty2 = this.top + tl; + } else if (position === 'left') { + borderValue = alignBorderValue(this.right); + tx1 = this.right - tl; + tx2 = borderValue - axisHalfWidth; + x1 = alignBorderValue(chartArea.left) + axisHalfWidth; + x2 = chartArea.right; + } else if (position === 'right') { + borderValue = alignBorderValue(this.left); + x1 = chartArea.left; + x2 = alignBorderValue(chartArea.right) - axisHalfWidth; + tx1 = borderValue + axisHalfWidth; + tx2 = this.left + tl; + } else if (axis === 'x') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + y1 = chartArea.top; + y2 = chartArea.bottom; + ty1 = borderValue + axisHalfWidth; + ty2 = ty1 + tl; + } else if (axis === 'y') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + tx1 = borderValue - axisHalfWidth; + tx2 = tx1 - tl; + x1 = chartArea.left; + x2 = chartArea.right; + } + const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); + const step = Math.max(1, Math.ceil(ticksLength / limit)); + for (i = 0; i < ticksLength; i += step) { + const optsAtIndex = grid.setContext(this.getContext(i)); + const lineWidth = optsAtIndex.lineWidth; + const lineColor = optsAtIndex.color; + const borderDash = grid.borderDash || []; + const borderDashOffset = optsAtIndex.borderDashOffset; + const tickWidth = optsAtIndex.tickWidth; + const tickColor = optsAtIndex.tickColor; + const tickBorderDash = optsAtIndex.tickBorderDash || []; + const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; + lineValue = getPixelForGridLine(this, i, offset); + if (lineValue === undefined) { + continue; + } + alignedLineValue = _alignPixel(chart, lineValue, lineWidth); + if (isHorizontal) { + tx1 = tx2 = x1 = x2 = alignedLineValue; + } else { + ty1 = ty2 = y1 = y2 = alignedLineValue; + } + items.push({ + tx1, + ty1, + tx2, + ty2, + x1, + y1, + x2, + y2, + width: lineWidth, + color: lineColor, + borderDash, + borderDashOffset, + tickWidth, + tickColor, + tickBorderDash, + tickBorderDashOffset, + }); + } + this._ticksLength = ticksLength; + this._borderValue = borderValue; + return items; + } + _computeLabelItems(chartArea) { + const axis = this.axis; + const options = this.options; + const {position, ticks: optionTicks} = options; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const {align, crossAlign, padding, mirror} = optionTicks; + const tl = getTickMarkLength(options.grid); + const tickAndPadding = tl + padding; + const hTickAndPadding = mirror ? -padding : tickAndPadding; + const rotation = -toRadians(this.labelRotation); + const items = []; + let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; + let textBaseline = 'middle'; + if (position === 'top') { + y = this.bottom - hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'bottom') { + y = this.top + hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'left') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (position === 'right') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (axis === 'x') { + if (position === 'center') { + y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; + } + textAlign = this._getXAxisLabelAlignment(); + } else if (axis === 'y') { + if (position === 'center') { + x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + x = this.chart.scales[positionAxisID].getPixelForValue(value); + } + textAlign = this._getYAxisLabelAlignment(tl).textAlign; + } + if (axis === 'y') { + if (align === 'start') { + textBaseline = 'top'; + } else if (align === 'end') { + textBaseline = 'bottom'; + } + } + const labelSizes = this._getLabelSizes(); + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + label = tick.label; + const optsAtIndex = optionTicks.setContext(this.getContext(i)); + pixel = this.getPixelForTick(i) + optionTicks.labelOffset; + font = this._resolveTickFontOptions(i); + lineHeight = font.lineHeight; + lineCount = isArray(label) ? label.length : 1; + const halfCount = lineCount / 2; + const color = optsAtIndex.color; + const strokeColor = optsAtIndex.textStrokeColor; + const strokeWidth = optsAtIndex.textStrokeWidth; + if (isHorizontal) { + x = pixel; + if (position === 'top') { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = -lineCount * lineHeight + lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; + } else { + textOffset = -labelSizes.highest.height + lineHeight / 2; + } + } else { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; + } else { + textOffset = labelSizes.highest.height - lineCount * lineHeight; + } + } + if (mirror) { + textOffset *= -1; + } + } else { + y = pixel; + textOffset = (1 - lineCount) * lineHeight / 2; + } + let backdrop; + if (optsAtIndex.showLabelBackdrop) { + const labelPadding = toPadding(optsAtIndex.backdropPadding); + const height = labelSizes.heights[i]; + const width = labelSizes.widths[i]; + let top = y + textOffset - labelPadding.top; + let left = x - labelPadding.left; + switch (textBaseline) { + case 'middle': + top -= height / 2; + break; + case 'bottom': + top -= height; + break; + } + switch (textAlign) { + case 'center': + left -= width / 2; + break; + case 'right': + left -= width; + break; + } + backdrop = { + left, + top, + width: width + labelPadding.width, + height: height + labelPadding.height, + color: optsAtIndex.backdropColor, + }; + } + items.push({ + rotation, + label, + font, + color, + strokeColor, + strokeWidth, + textOffset, + textAlign, + textBaseline, + translation: [x, y], + backdrop, + }); + } + return items; + } + _getXAxisLabelAlignment() { + const {position, ticks} = this.options; + const rotation = -toRadians(this.labelRotation); + if (rotation) { + return position === 'top' ? 'left' : 'right'; + } + let align = 'center'; + if (ticks.align === 'start') { + align = 'left'; + } else if (ticks.align === 'end') { + align = 'right'; + } + return align; + } + _getYAxisLabelAlignment(tl) { + const {position, ticks: {crossAlign, mirror, padding}} = this.options; + const labelSizes = this._getLabelSizes(); + const tickAndPadding = tl + padding; + const widest = labelSizes.widest.width; + let textAlign; + let x; + if (position === 'left') { + if (mirror) { + x = this.right + padding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += (widest / 2); + } else { + textAlign = 'right'; + x += widest; + } + } else { + x = this.right - tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= (widest / 2); + } else { + textAlign = 'left'; + x = this.left; + } + } + } else if (position === 'right') { + if (mirror) { + x = this.left + padding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= (widest / 2); + } else { + textAlign = 'left'; + x -= widest; + } + } else { + x = this.left + tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += widest / 2; + } else { + textAlign = 'right'; + x = this.right; + } + } + } else { + textAlign = 'right'; + } + return {textAlign, x}; + } + _computeLabelArea() { + if (this.options.ticks.mirror) { + return; + } + const chart = this.chart; + const position = this.options.position; + if (position === 'left' || position === 'right') { + return {top: 0, left: this.left, bottom: chart.height, right: this.right}; + } if (position === 'top' || position === 'bottom') { + return {top: this.top, left: 0, bottom: this.bottom, right: chart.width}; + } + } + drawBackground() { + const {ctx, options: {backgroundColor}, left, top, width, height} = this; + if (backgroundColor) { + ctx.save(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(left, top, width, height); + ctx.restore(); + } + } + getLineWidthForValue(value) { + const grid = this.options.grid; + if (!this._isVisible() || !grid.display) { + return 0; + } + const ticks = this.ticks; + const index = ticks.findIndex(t => t.value === value); + if (index >= 0) { + const opts = grid.setContext(this.getContext(index)); + return opts.lineWidth; + } + return 0; + } + drawGrid(chartArea) { + const grid = this.options.grid; + const ctx = this.ctx; + const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); + let i, ilen; + const drawLine = (p1, p2, style) => { + if (!style.width || !style.color) { + return; + } + ctx.save(); + ctx.lineWidth = style.width; + ctx.strokeStyle = style.color; + ctx.setLineDash(style.borderDash || []); + ctx.lineDashOffset = style.borderDashOffset; + ctx.beginPath(); + ctx.moveTo(p1.x, p1.y); + ctx.lineTo(p2.x, p2.y); + ctx.stroke(); + ctx.restore(); + }; + if (grid.display) { + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + if (grid.drawOnChartArea) { + drawLine( + {x: item.x1, y: item.y1}, + {x: item.x2, y: item.y2}, + item + ); + } + if (grid.drawTicks) { + drawLine( + {x: item.tx1, y: item.ty1}, + {x: item.tx2, y: item.ty2}, + { + color: item.tickColor, + width: item.tickWidth, + borderDash: item.tickBorderDash, + borderDashOffset: item.tickBorderDashOffset + } + ); + } + } + } + } + drawBorder() { + const {chart, ctx, options: {grid}} = this; + const borderOpts = grid.setContext(this.getContext()); + const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0; + if (!axisWidth) { + return; + } + const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; + const borderValue = this._borderValue; + let x1, x2, y1, y2; + if (this.isHorizontal()) { + x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; + x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; + y1 = y2 = borderValue; + } else { + y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; + y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; + x1 = x2 = borderValue; + } + ctx.save(); + ctx.lineWidth = borderOpts.borderWidth; + ctx.strokeStyle = borderOpts.borderColor; + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + ctx.restore(); + } + drawLabels(chartArea) { + const optionTicks = this.options.ticks; + if (!optionTicks.display) { + return; + } + const ctx = this.ctx; + const area = this._computeLabelArea(); + if (area) { + clipArea(ctx, area); + } + const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); + let i, ilen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + const tickFont = item.font; + const label = item.label; + if (item.backdrop) { + ctx.fillStyle = item.backdrop.color; + ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); + } + let y = item.textOffset; + renderText(ctx, label, 0, y, tickFont, item); + } + if (area) { + unclipArea(ctx); + } + } + drawTitle() { + const {ctx, options: {position, title, reverse}} = this; + if (!title.display) { + return; + } + const font = toFont(title.font); + const padding = toPadding(title.padding); + const align = title.align; + let offset = font.lineHeight / 2; + if (position === 'bottom' || position === 'center' || isObject(position)) { + offset += padding.bottom; + if (isArray(title.text)) { + offset += font.lineHeight * (title.text.length - 1); + } + } else { + offset += padding.top; + } + const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align); + renderText(ctx, title.text, 0, 0, font, { + color: title.color, + maxWidth, + rotation, + textAlign: titleAlign(align, position, reverse), + textBaseline: 'middle', + translation: [titleX, titleY], + }); + } + draw(chartArea) { + if (!this._isVisible()) { + return; + } + this.drawBackground(); + this.drawGrid(chartArea); + this.drawBorder(); + this.drawTitle(); + this.drawLabels(chartArea); + } + _layers() { + const opts = this.options; + const tz = opts.ticks && opts.ticks.z || 0; + const gz = valueOrDefault(opts.grid && opts.grid.z, -1); + if (!this._isVisible() || this.draw !== Scale.prototype.draw) { + return [{ + z: tz, + draw: (chartArea) => { + this.draw(chartArea); + } + }]; + } + return [{ + z: gz, + draw: (chartArea) => { + this.drawBackground(); + this.drawGrid(chartArea); + this.drawTitle(); + } + }, { + z: gz + 1, + draw: () => { + this.drawBorder(); + } + }, { + z: tz, + draw: (chartArea) => { + this.drawLabels(chartArea); + } + }]; + } + getMatchingVisibleMetas(type) { + const metas = this.chart.getSortedVisibleDatasetMetas(); + const axisID = this.axis + 'AxisID'; + const result = []; + let i, ilen; + for (i = 0, ilen = metas.length; i < ilen; ++i) { + const meta = metas[i]; + if (meta[axisID] === this.id && (!type || meta.type === type)) { + result.push(meta); + } + } + return result; + } + _resolveTickFontOptions(index) { + const opts = this.options.ticks.setContext(this.getContext(index)); + return toFont(opts.font); + } + _maxDigits() { + const fontSize = this._resolveTickFontOptions(0).lineHeight; + return (this.isHorizontal() ? this.width : this.height) / fontSize; + } +} + +class TypedRegistry { + constructor(type, scope, override) { + this.type = type; + this.scope = scope; + this.override = override; + this.items = Object.create(null); + } + isForType(type) { + return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); + } + register(item) { + const proto = Object.getPrototypeOf(item); + let parentScope; + if (isIChartComponent(proto)) { + parentScope = this.register(proto); + } + const items = this.items; + const id = item.id; + const scope = this.scope + '.' + id; + if (!id) { + throw new Error('class does not have id: ' + item); + } + if (id in items) { + return scope; + } + items[id] = item; + registerDefaults(item, scope, parentScope); + if (this.override) { + defaults.override(item.id, item.overrides); + } + return scope; + } + get(id) { + return this.items[id]; + } + unregister(item) { + const items = this.items; + const id = item.id; + const scope = this.scope; + if (id in items) { + delete items[id]; + } + if (scope && id in defaults[scope]) { + delete defaults[scope][id]; + if (this.override) { + delete overrides[id]; + } + } + } +} +function registerDefaults(item, scope, parentScope) { + const itemDefaults = merge(Object.create(null), [ + parentScope ? defaults.get(parentScope) : {}, + defaults.get(scope), + item.defaults + ]); + defaults.set(scope, itemDefaults); + if (item.defaultRoutes) { + routeDefaults(scope, item.defaultRoutes); + } + if (item.descriptors) { + defaults.describe(scope, item.descriptors); + } +} +function routeDefaults(scope, routes) { + Object.keys(routes).forEach(property => { + const propertyParts = property.split('.'); + const sourceName = propertyParts.pop(); + const sourceScope = [scope].concat(propertyParts).join('.'); + const parts = routes[property].split('.'); + const targetName = parts.pop(); + const targetScope = parts.join('.'); + defaults.route(sourceScope, sourceName, targetScope, targetName); + }); +} +function isIChartComponent(proto) { + return 'id' in proto && 'defaults' in proto; +} + +class Registry { + constructor() { + this.controllers = new TypedRegistry(DatasetController, 'datasets', true); + this.elements = new TypedRegistry(Element, 'elements'); + this.plugins = new TypedRegistry(Object, 'plugins'); + this.scales = new TypedRegistry(Scale, 'scales'); + this._typedRegistries = [this.controllers, this.scales, this.elements]; + } + add(...args) { + this._each('register', args); + } + remove(...args) { + this._each('unregister', args); + } + addControllers(...args) { + this._each('register', args, this.controllers); + } + addElements(...args) { + this._each('register', args, this.elements); + } + addPlugins(...args) { + this._each('register', args, this.plugins); + } + addScales(...args) { + this._each('register', args, this.scales); + } + getController(id) { + return this._get(id, this.controllers, 'controller'); + } + getElement(id) { + return this._get(id, this.elements, 'element'); + } + getPlugin(id) { + return this._get(id, this.plugins, 'plugin'); + } + getScale(id) { + return this._get(id, this.scales, 'scale'); + } + removeControllers(...args) { + this._each('unregister', args, this.controllers); + } + removeElements(...args) { + this._each('unregister', args, this.elements); + } + removePlugins(...args) { + this._each('unregister', args, this.plugins); + } + removeScales(...args) { + this._each('unregister', args, this.scales); + } + _each(method, args, typedRegistry) { + [...args].forEach(arg => { + const reg = typedRegistry || this._getRegistryForType(arg); + if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) { + this._exec(method, reg, arg); + } else { + each(arg, item => { + const itemReg = typedRegistry || this._getRegistryForType(item); + this._exec(method, itemReg, item); + }); + } + }); + } + _exec(method, registry, component) { + const camelMethod = _capitalize(method); + callback(component['before' + camelMethod], [], component); + registry[method](component); + callback(component['after' + camelMethod], [], component); + } + _getRegistryForType(type) { + for (let i = 0; i < this._typedRegistries.length; i++) { + const reg = this._typedRegistries[i]; + if (reg.isForType(type)) { + return reg; + } + } + return this.plugins; + } + _get(id, typedRegistry, type) { + const item = typedRegistry.get(id); + if (item === undefined) { + throw new Error('"' + id + '" is not a registered ' + type + '.'); + } + return item; + } +} +var registry = new Registry(); + +class PluginService { + constructor() { + this._init = []; + } + notify(chart, hook, args, filter) { + if (hook === 'beforeInit') { + this._init = this._createDescriptors(chart, true); + this._notify(this._init, chart, 'install'); + } + const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); + const result = this._notify(descriptors, chart, hook, args); + if (hook === 'afterDestroy') { + this._notify(descriptors, chart, 'stop'); + this._notify(this._init, chart, 'uninstall'); + } + return result; + } + _notify(descriptors, chart, hook, args) { + args = args || {}; + for (const descriptor of descriptors) { + const plugin = descriptor.plugin; + const method = plugin[hook]; + const params = [chart, args, descriptor.options]; + if (callback(method, params, plugin) === false && args.cancelable) { + return false; + } + } + return true; + } + invalidate() { + if (!isNullOrUndef(this._cache)) { + this._oldCache = this._cache; + this._cache = undefined; + } + } + _descriptors(chart) { + if (this._cache) { + return this._cache; + } + const descriptors = this._cache = this._createDescriptors(chart); + this._notifyStateChanges(chart); + return descriptors; + } + _createDescriptors(chart, all) { + const config = chart && chart.config; + const options = valueOrDefault(config.options && config.options.plugins, {}); + const plugins = allPlugins(config); + return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); + } + _notifyStateChanges(chart) { + const previousDescriptors = this._oldCache || []; + const descriptors = this._cache; + const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id)); + this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); + this._notify(diff(descriptors, previousDescriptors), chart, 'start'); + } +} +function allPlugins(config) { + const plugins = []; + const keys = Object.keys(registry.plugins.items); + for (let i = 0; i < keys.length; i++) { + plugins.push(registry.getPlugin(keys[i])); + } + const local = config.plugins || []; + for (let i = 0; i < local.length; i++) { + const plugin = local[i]; + if (plugins.indexOf(plugin) === -1) { + plugins.push(plugin); + } + } + return plugins; +} +function getOpts(options, all) { + if (!all && options === false) { + return null; + } + if (options === true) { + return {}; + } + return options; +} +function createDescriptors(chart, plugins, options, all) { + const result = []; + const context = chart.getContext(); + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + const id = plugin.id; + const opts = getOpts(options[id], all); + if (opts === null) { + continue; + } + result.push({ + plugin, + options: pluginOpts(chart.config, plugin, opts, context) + }); + } + return result; +} +function pluginOpts(config, plugin, opts, context) { + const keys = config.pluginScopeKeys(plugin); + const scopes = config.getOptionScopes(opts, keys); + return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true}); +} + +function getIndexAxis(type, options) { + const datasetDefaults = defaults.datasets[type] || {}; + const datasetOptions = (options.datasets || {})[type] || {}; + return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; +} +function getAxisFromDefaultScaleID(id, indexAxis) { + let axis = id; + if (id === '_index_') { + axis = indexAxis; + } else if (id === '_value_') { + axis = indexAxis === 'x' ? 'y' : 'x'; + } + return axis; +} +function getDefaultScaleIDFromAxis(axis, indexAxis) { + return axis === indexAxis ? '_index_' : '_value_'; +} +function axisFromPosition(position) { + if (position === 'top' || position === 'bottom') { + return 'x'; + } + if (position === 'left' || position === 'right') { + return 'y'; + } +} +function determineAxis(id, scaleOptions) { + if (id === 'x' || id === 'y') { + return id; + } + return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); +} +function mergeScaleConfig(config, options) { + const chartDefaults = overrides[config.type] || {scales: {}}; + const configScales = options.scales || {}; + const chartIndexAxis = getIndexAxis(config.type, options); + const firstIDs = Object.create(null); + const scales = Object.create(null); + Object.keys(configScales).forEach(id => { + const scaleConf = configScales[id]; + if (!isObject(scaleConf)) { + return console.error(`Invalid scale configuration for scale: ${id}`); + } + if (scaleConf._proxy) { + return console.warn(`Ignoring resolver passed as options for scale: ${id}`); + } + const axis = determineAxis(id, scaleConf); + const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); + const defaultScaleOptions = chartDefaults.scales || {}; + firstIDs[axis] = firstIDs[axis] || id; + scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]); + }); + config.data.datasets.forEach(dataset => { + const type = dataset.type || config.type; + const indexAxis = dataset.indexAxis || getIndexAxis(type, options); + const datasetDefaults = overrides[type] || {}; + const defaultScaleOptions = datasetDefaults.scales || {}; + Object.keys(defaultScaleOptions).forEach(defaultID => { + const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); + const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; + scales[id] = scales[id] || Object.create(null); + mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); + }); + }); + Object.keys(scales).forEach(key => { + const scale = scales[key]; + mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); + }); + return scales; +} +function initOptions(config) { + const options = config.options || (config.options = {}); + options.plugins = valueOrDefault(options.plugins, {}); + options.scales = mergeScaleConfig(config, options); +} +function initData(data) { + data = data || {}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + return data; +} +function initConfig(config) { + config = config || {}; + config.data = initData(config.data); + initOptions(config); + return config; +} +const keyCache = new Map(); +const keysCached = new Set(); +function cachedKeys(cacheKey, generate) { + let keys = keyCache.get(cacheKey); + if (!keys) { + keys = generate(); + keyCache.set(cacheKey, keys); + keysCached.add(keys); + } + return keys; +} +const addIfFound = (set, obj, key) => { + const opts = resolveObjectKey(obj, key); + if (opts !== undefined) { + set.add(opts); + } +}; +class Config { + constructor(config) { + this._config = initConfig(config); + this._scopeCache = new Map(); + this._resolverCache = new Map(); + } + get platform() { + return this._config.platform; + } + get type() { + return this._config.type; + } + set type(type) { + this._config.type = type; + } + get data() { + return this._config.data; + } + set data(data) { + this._config.data = initData(data); + } + get options() { + return this._config.options; + } + set options(options) { + this._config.options = options; + } + get plugins() { + return this._config.plugins; + } + update() { + const config = this._config; + this.clearCache(); + initOptions(config); + } + clearCache() { + this._scopeCache.clear(); + this._resolverCache.clear(); + } + datasetScopeKeys(datasetType) { + return cachedKeys(datasetType, + () => [[ + `datasets.${datasetType}`, + '' + ]]); + } + datasetAnimationScopeKeys(datasetType, transition) { + return cachedKeys(`${datasetType}.transition.${transition}`, + () => [ + [ + `datasets.${datasetType}.transitions.${transition}`, + `transitions.${transition}`, + ], + [ + `datasets.${datasetType}`, + '' + ] + ]); + } + datasetElementScopeKeys(datasetType, elementType) { + return cachedKeys(`${datasetType}-${elementType}`, + () => [[ + `datasets.${datasetType}.elements.${elementType}`, + `datasets.${datasetType}`, + `elements.${elementType}`, + '' + ]]); + } + pluginScopeKeys(plugin) { + const id = plugin.id; + const type = this.type; + return cachedKeys(`${type}-plugin-${id}`, + () => [[ + `plugins.${id}`, + ...plugin.additionalOptionScopes || [], + ]]); + } + _cachedScopes(mainScope, resetCache) { + const _scopeCache = this._scopeCache; + let cache = _scopeCache.get(mainScope); + if (!cache || resetCache) { + cache = new Map(); + _scopeCache.set(mainScope, cache); + } + return cache; + } + getOptionScopes(mainScope, keyLists, resetCache) { + const {options, type} = this; + const cache = this._cachedScopes(mainScope, resetCache); + const cached = cache.get(keyLists); + if (cached) { + return cached; + } + const scopes = new Set(); + keyLists.forEach(keys => { + if (mainScope) { + scopes.add(mainScope); + keys.forEach(key => addIfFound(scopes, mainScope, key)); + } + keys.forEach(key => addIfFound(scopes, options, key)); + keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); + keys.forEach(key => addIfFound(scopes, defaults, key)); + keys.forEach(key => addIfFound(scopes, descriptors, key)); + }); + const array = Array.from(scopes); + if (array.length === 0) { + array.push(Object.create(null)); + } + if (keysCached.has(keyLists)) { + cache.set(keyLists, array); + } + return array; + } + chartOptionScopes() { + const {options, type} = this; + return [ + options, + overrides[type] || {}, + defaults.datasets[type] || {}, + {type}, + defaults, + descriptors + ]; + } + resolveNamedOptions(scopes, names, context, prefixes = ['']) { + const result = {$shared: true}; + const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes); + let options = resolver; + if (needContext(resolver, names)) { + result.$shared = false; + context = isFunction(context) ? context() : context; + const subResolver = this.createResolver(scopes, context, subPrefixes); + options = _attachContext(resolver, context, subResolver); + } + for (const prop of names) { + result[prop] = options[prop]; + } + return result; + } + createResolver(scopes, context, prefixes = [''], descriptorDefaults) { + const {resolver} = getResolver(this._resolverCache, scopes, prefixes); + return isObject(context) + ? _attachContext(resolver, context, undefined, descriptorDefaults) + : resolver; + } +} +function getResolver(resolverCache, scopes, prefixes) { + let cache = resolverCache.get(scopes); + if (!cache) { + cache = new Map(); + resolverCache.set(scopes, cache); + } + const cacheKey = prefixes.join(); + let cached = cache.get(cacheKey); + if (!cached) { + const resolver = _createResolver(scopes, prefixes); + cached = { + resolver, + subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover')) + }; + cache.set(cacheKey, cached); + } + return cached; +} +const hasFunction = value => isObject(value) + && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false); +function needContext(proxy, names) { + const {isScriptable, isIndexable} = _descriptors(proxy); + for (const prop of names) { + const scriptable = isScriptable(prop); + const indexable = isIndexable(prop); + const value = (indexable || scriptable) && proxy[prop]; + if ((scriptable && (isFunction(value) || hasFunction(value))) + || (indexable && isArray(value))) { + return true; + } + } + return false; +} + +var version = "3.7.1"; + +const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; +function positionIsHorizontal(position, axis) { + return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); +} +function compare2Level(l1, l2) { + return function(a, b) { + return a[l1] === b[l1] + ? a[l2] - b[l2] + : a[l1] - b[l1]; + }; +} +function onAnimationsComplete(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + chart.notifyPlugins('afterRender'); + callback(animationOptions && animationOptions.onComplete, [context], chart); +} +function onAnimationProgress(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + callback(animationOptions && animationOptions.onProgress, [context], chart); +} +function getCanvas(item) { + if (_isDomSupported() && typeof item === 'string') { + item = document.getElementById(item); + } else if (item && item.length) { + item = item[0]; + } + if (item && item.canvas) { + item = item.canvas; + } + return item; +} +const instances = {}; +const getChart = (key) => { + const canvas = getCanvas(key); + return Object.values(instances).filter((c) => c.canvas === canvas).pop(); +}; +function moveNumericKeys(obj, start, move) { + const keys = Object.keys(obj); + for (const key of keys) { + const intKey = +key; + if (intKey >= start) { + const value = obj[key]; + delete obj[key]; + if (move > 0 || intKey > start) { + obj[intKey + move] = value; + } + } + } +} +function determineLastEvent(e, lastEvent, inChartArea, isClick) { + if (!inChartArea || e.type === 'mouseout') { + return null; + } + if (isClick) { + return lastEvent; + } + return e; +} +class Chart { + constructor(item, userConfig) { + const config = this.config = new Config(userConfig); + const initialCanvas = getCanvas(item); + const existingChart = getChart(initialCanvas); + if (existingChart) { + throw new Error( + 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + + ' must be destroyed before the canvas can be reused.' + ); + } + const options = config.createResolver(config.chartOptionScopes(), this.getContext()); + this.platform = new (config.platform || _detectPlatform(initialCanvas))(); + this.platform.updateConfig(config); + const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); + const canvas = context && context.canvas; + const height = canvas && canvas.height; + const width = canvas && canvas.width; + this.id = uid(); + this.ctx = context; + this.canvas = canvas; + this.width = width; + this.height = height; + this._options = options; + this._aspectRatio = this.aspectRatio; + this._layers = []; + this._metasets = []; + this._stacks = undefined; + this.boxes = []; + this.currentDevicePixelRatio = undefined; + this.chartArea = undefined; + this._active = []; + this._lastEvent = undefined; + this._listeners = {}; + this._responsiveListeners = undefined; + this._sortedMetasets = []; + this.scales = {}; + this._plugins = new PluginService(); + this.$proxies = {}; + this._hiddenIndices = {}; + this.attached = false; + this._animationsDisabled = undefined; + this.$context = undefined; + this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0); + this._dataChanges = []; + instances[this.id] = this; + if (!context || !canvas) { + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + animator.listen(this, 'complete', onAnimationsComplete); + animator.listen(this, 'progress', onAnimationProgress); + this._initialize(); + if (this.attached) { + this.update(); + } + } + get aspectRatio() { + const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this; + if (!isNullOrUndef(aspectRatio)) { + return aspectRatio; + } + if (maintainAspectRatio && _aspectRatio) { + return _aspectRatio; + } + return height ? width / height : null; + } + get data() { + return this.config.data; + } + set data(data) { + this.config.data = data; + } + get options() { + return this._options; + } + set options(options) { + this.config.options = options; + } + _initialize() { + this.notifyPlugins('beforeInit'); + if (this.options.responsive) { + this.resize(); + } else { + retinaScale(this, this.options.devicePixelRatio); + } + this.bindEvents(); + this.notifyPlugins('afterInit'); + return this; + } + clear() { + clearCanvas(this.canvas, this.ctx); + return this; + } + stop() { + animator.stop(this); + return this; + } + resize(width, height) { + if (!animator.running(this)) { + this._resize(width, height); + } else { + this._resizeBeforeDraw = {width, height}; + } + } + _resize(width, height) { + const options = this.options; + const canvas = this.canvas; + const aspectRatio = options.maintainAspectRatio && this.aspectRatio; + const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); + const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); + const mode = this.width ? 'resize' : 'attach'; + this.width = newSize.width; + this.height = newSize.height; + this._aspectRatio = this.aspectRatio; + if (!retinaScale(this, newRatio, true)) { + return; + } + this.notifyPlugins('resize', {size: newSize}); + callback(options.onResize, [this, newSize], this); + if (this.attached) { + if (this._doResize(mode)) { + this.render(); + } + } + } + ensureScalesHaveIDs() { + const options = this.options; + const scalesOptions = options.scales || {}; + each(scalesOptions, (axisOptions, axisID) => { + axisOptions.id = axisID; + }); + } + buildOrUpdateScales() { + const options = this.options; + const scaleOpts = options.scales; + const scales = this.scales; + const updated = Object.keys(scales).reduce((obj, id) => { + obj[id] = false; + return obj; + }, {}); + let items = []; + if (scaleOpts) { + items = items.concat( + Object.keys(scaleOpts).map((id) => { + const scaleOptions = scaleOpts[id]; + const axis = determineAxis(id, scaleOptions); + const isRadial = axis === 'r'; + const isHorizontal = axis === 'x'; + return { + options: scaleOptions, + dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', + dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' + }; + }) + ); + } + each(items, (item) => { + const scaleOptions = item.options; + const id = scaleOptions.id; + const axis = determineAxis(id, scaleOptions); + const scaleType = valueOrDefault(scaleOptions.type, item.dtype); + if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + updated[id] = true; + let scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + } else { + const scaleClass = registry.getScale(scaleType); + scale = new scaleClass({ + id, + type: scaleType, + ctx: this.ctx, + chart: this + }); + scales[scale.id] = scale; + } + scale.init(scaleOptions, options); + }); + each(updated, (hasUpdated, id) => { + if (!hasUpdated) { + delete scales[id]; + } + }); + each(scales, (scale) => { + layouts.configure(this, scale, scale.options); + layouts.addBox(this, scale); + }); + } + _updateMetasets() { + const metasets = this._metasets; + const numData = this.data.datasets.length; + const numMeta = metasets.length; + metasets.sort((a, b) => a.index - b.index); + if (numMeta > numData) { + for (let i = numData; i < numMeta; ++i) { + this._destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + } + _removeUnreferencedMetasets() { + const {_metasets: metasets, data: {datasets}} = this; + if (metasets.length > datasets.length) { + delete this._stacks; + } + metasets.forEach((meta, index) => { + if (datasets.filter(x => x === meta._dataset).length === 0) { + this._destroyDatasetMeta(index); + } + }); + } + buildOrUpdateControllers() { + const newControllers = []; + const datasets = this.data.datasets; + let i, ilen; + this._removeUnreferencedMetasets(); + for (i = 0, ilen = datasets.length; i < ilen; i++) { + const dataset = datasets[i]; + let meta = this.getDatasetMeta(i); + const type = dataset.type || this.config.type; + if (meta.type && meta.type !== type) { + this._destroyDatasetMeta(i); + meta = this.getDatasetMeta(i); + } + meta.type = type; + meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); + meta.order = dataset.order || 0; + meta.index = i; + meta.label = '' + dataset.label; + meta.visible = this.isDatasetVisible(i); + if (meta.controller) { + meta.controller.updateIndex(i); + meta.controller.linkScales(); + } else { + const ControllerClass = registry.getController(type); + const {datasetElementType, dataElementType} = defaults.datasets[type]; + Object.assign(ControllerClass.prototype, { + dataElementType: registry.getElement(dataElementType), + datasetElementType: datasetElementType && registry.getElement(datasetElementType) + }); + meta.controller = new ControllerClass(this, i); + newControllers.push(meta.controller); + } + } + this._updateMetasets(); + return newControllers; + } + _resetElements() { + each(this.data.datasets, (dataset, datasetIndex) => { + this.getDatasetMeta(datasetIndex).controller.reset(); + }, this); + } + reset() { + this._resetElements(); + this.notifyPlugins('reset'); + } + update(mode) { + const config = this.config; + config.update(); + const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); + const animsDisabled = this._animationsDisabled = !options.animation; + this._updateScales(); + this._checkEventBindings(); + this._updateHiddenIndices(); + this._plugins.invalidate(); + if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) { + return; + } + const newControllers = this.buildOrUpdateControllers(); + this.notifyPlugins('beforeElementsUpdate'); + let minPadding = 0; + for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) { + const {controller} = this.getDatasetMeta(i); + const reset = !animsDisabled && newControllers.indexOf(controller) === -1; + controller.buildOrUpdateElements(reset); + minPadding = Math.max(+controller.getMaxOverflow(), minPadding); + } + minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; + this._updateLayout(minPadding); + if (!animsDisabled) { + each(newControllers, (controller) => { + controller.reset(); + }); + } + this._updateDatasets(mode); + this.notifyPlugins('afterUpdate', {mode}); + this._layers.sort(compare2Level('z', '_idx')); + const {_active, _lastEvent} = this; + if (_lastEvent) { + this._eventHandler(_lastEvent, true); + } else if (_active.length) { + this._updateHoverStyles(_active, _active, true); + } + this.render(); + } + _updateScales() { + each(this.scales, (scale) => { + layouts.removeBox(this, scale); + }); + this.ensureScalesHaveIDs(); + this.buildOrUpdateScales(); + } + _checkEventBindings() { + const options = this.options; + const existingEvents = new Set(Object.keys(this._listeners)); + const newEvents = new Set(options.events); + if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { + this.unbindEvents(); + this.bindEvents(); + } + } + _updateHiddenIndices() { + const {_hiddenIndices} = this; + const changes = this._getUniformDataChanges() || []; + for (const {method, start, count} of changes) { + const move = method === '_removeElements' ? -count : count; + moveNumericKeys(_hiddenIndices, start, move); + } + } + _getUniformDataChanges() { + const _dataChanges = this._dataChanges; + if (!_dataChanges || !_dataChanges.length) { + return; + } + this._dataChanges = []; + const datasetCount = this.data.datasets.length; + const makeSet = (idx) => new Set( + _dataChanges + .filter(c => c[0] === idx) + .map((c, i) => i + ',' + c.splice(1).join(',')) + ); + const changeSet = makeSet(0); + for (let i = 1; i < datasetCount; i++) { + if (!setsEqual(changeSet, makeSet(i))) { + return; + } + } + return Array.from(changeSet) + .map(c => c.split(',')) + .map(a => ({method: a[1], start: +a[2], count: +a[3]})); + } + _updateLayout(minPadding) { + if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) { + return; + } + layouts.update(this, this.width, this.height, minPadding); + const area = this.chartArea; + const noArea = area.width <= 0 || area.height <= 0; + this._layers = []; + each(this.boxes, (box) => { + if (noArea && box.position === 'chartArea') { + return; + } + if (box.configure) { + box.configure(); + } + this._layers.push(...box._layers()); + }, this); + this._layers.forEach((item, index) => { + item._idx = index; + }); + this.notifyPlugins('afterLayout'); + } + _updateDatasets(mode) { + if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { + return; + } + for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this.getDatasetMeta(i).controller.configure(); + } + for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); + } + this.notifyPlugins('afterDatasetsUpdate', {mode}); + } + _updateDataset(index, mode) { + const meta = this.getDatasetMeta(index); + const args = {meta, index, mode, cancelable: true}; + if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { + return; + } + meta.controller._update(mode); + args.cancelable = false; + this.notifyPlugins('afterDatasetUpdate', args); + } + render() { + if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) { + return; + } + if (animator.has(this)) { + if (this.attached && !animator.running(this)) { + animator.start(this); + } + } else { + this.draw(); + onAnimationsComplete({chart: this}); + } + } + draw() { + let i; + if (this._resizeBeforeDraw) { + const {width, height} = this._resizeBeforeDraw; + this._resize(width, height); + this._resizeBeforeDraw = null; + } + this.clear(); + if (this.width <= 0 || this.height <= 0) { + return; + } + if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) { + return; + } + const layers = this._layers; + for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { + layers[i].draw(this.chartArea); + } + this._drawDatasets(); + for (; i < layers.length; ++i) { + layers[i].draw(this.chartArea); + } + this.notifyPlugins('afterDraw'); + } + _getSortedDatasetMetas(filterVisible) { + const metasets = this._sortedMetasets; + const result = []; + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + const meta = metasets[i]; + if (!filterVisible || meta.visible) { + result.push(meta); + } + } + return result; + } + getSortedVisibleDatasetMetas() { + return this._getSortedDatasetMetas(true); + } + _drawDatasets() { + if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) { + return; + } + const metasets = this.getSortedVisibleDatasetMetas(); + for (let i = metasets.length - 1; i >= 0; --i) { + this._drawDataset(metasets[i]); + } + this.notifyPlugins('afterDatasetsDraw'); + } + _drawDataset(meta) { + const ctx = this.ctx; + const clip = meta._clip; + const useClip = !clip.disabled; + const area = this.chartArea; + const args = { + meta, + index: meta.index, + cancelable: true + }; + if (this.notifyPlugins('beforeDatasetDraw', args) === false) { + return; + } + if (useClip) { + clipArea(ctx, { + left: clip.left === false ? 0 : area.left - clip.left, + right: clip.right === false ? this.width : area.right + clip.right, + top: clip.top === false ? 0 : area.top - clip.top, + bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom + }); + } + meta.controller.draw(); + if (useClip) { + unclipArea(ctx); + } + args.cancelable = false; + this.notifyPlugins('afterDatasetDraw', args); + } + getElementsAtEventForMode(e, mode, options, useFinalPosition) { + const method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options, useFinalPosition); + } + return []; + } + getDatasetMeta(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + const metasets = this._metasets; + let meta = metasets.filter(x => x && x._dataset === dataset).pop(); + if (!meta) { + meta = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, + xAxisID: null, + yAxisID: null, + order: dataset && dataset.order || 0, + index: datasetIndex, + _dataset: dataset, + _parsed: [], + _sorted: false + }; + metasets.push(meta); + } + return meta; + } + getContext() { + return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'})); + } + getVisibleDatasetCount() { + return this.getSortedVisibleDatasetMetas().length; + } + isDatasetVisible(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + if (!dataset) { + return false; + } + const meta = this.getDatasetMeta(datasetIndex); + return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; + } + setDatasetVisibility(datasetIndex, visible) { + const meta = this.getDatasetMeta(datasetIndex); + meta.hidden = !visible; + } + toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + } + getDataVisibility(index) { + return !this._hiddenIndices[index]; + } + _updateVisibility(datasetIndex, dataIndex, visible) { + const mode = visible ? 'show' : 'hide'; + const meta = this.getDatasetMeta(datasetIndex); + const anims = meta.controller._resolveAnimations(undefined, mode); + if (defined(dataIndex)) { + meta.data[dataIndex].hidden = !visible; + this.update(); + } else { + this.setDatasetVisibility(datasetIndex, visible); + anims.update(meta, {visible}); + this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); + } + } + hide(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, false); + } + show(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, true); + } + _destroyDatasetMeta(datasetIndex) { + const meta = this._metasets[datasetIndex]; + if (meta && meta.controller) { + meta.controller._destroy(); + } + delete this._metasets[datasetIndex]; + } + _stop() { + let i, ilen; + this.stop(); + animator.remove(this); + for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this._destroyDatasetMeta(i); + } + } + destroy() { + this.notifyPlugins('beforeDestroy'); + const {canvas, ctx} = this; + this._stop(); + this.config.clearCache(); + if (canvas) { + this.unbindEvents(); + clearCanvas(canvas, ctx); + this.platform.releaseContext(ctx); + this.canvas = null; + this.ctx = null; + } + this.notifyPlugins('destroy'); + delete instances[this.id]; + this.notifyPlugins('afterDestroy'); + } + toBase64Image(...args) { + return this.canvas.toDataURL(...args); + } + bindEvents() { + this.bindUserEvents(); + if (this.options.responsive) { + this.bindResponsiveEvents(); + } else { + this.attached = true; + } + } + bindUserEvents() { + const listeners = this._listeners; + const platform = this.platform; + const _add = (type, listener) => { + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const listener = (e, x, y) => { + e.offsetX = x; + e.offsetY = y; + this._eventHandler(e); + }; + each(this.options.events, (type) => _add(type, listener)); + } + bindResponsiveEvents() { + if (!this._responsiveListeners) { + this._responsiveListeners = {}; + } + const listeners = this._responsiveListeners; + const platform = this.platform; + const _add = (type, listener) => { + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const _remove = (type, listener) => { + if (listeners[type]) { + platform.removeEventListener(this, type, listener); + delete listeners[type]; + } + }; + const listener = (width, height) => { + if (this.canvas) { + this.resize(width, height); + } + }; + let detached; + const attached = () => { + _remove('attach', attached); + this.attached = true; + this.resize(); + _add('resize', listener); + _add('detach', detached); + }; + detached = () => { + this.attached = false; + _remove('resize', listener); + this._stop(); + this._resize(0, 0); + _add('attach', attached); + }; + if (platform.isAttached(this.canvas)) { + attached(); + } else { + detached(); + } + } + unbindEvents() { + each(this._listeners, (listener, type) => { + this.platform.removeEventListener(this, type, listener); + }); + this._listeners = {}; + each(this._responsiveListeners, (listener, type) => { + this.platform.removeEventListener(this, type, listener); + }); + this._responsiveListeners = undefined; + } + updateHoverStyle(items, mode, enabled) { + const prefix = enabled ? 'set' : 'remove'; + let meta, item, i, ilen; + if (mode === 'dataset') { + meta = this.getDatasetMeta(items[0].datasetIndex); + meta.controller['_' + prefix + 'DatasetHoverStyle'](); + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + item = items[i]; + const controller = item && this.getDatasetMeta(item.datasetIndex).controller; + if (controller) { + controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); + } + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements) { + const lastActive = this._active || []; + const active = activeElements.map(({datasetIndex, index}) => { + const meta = this.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('No dataset found at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index, + }; + }); + const changed = !_elementsEqual(active, lastActive); + if (changed) { + this._active = active; + this._lastEvent = null; + this._updateHoverStyles(active, lastActive); + } + } + notifyPlugins(hook, args, filter) { + return this._plugins.notify(this, hook, args, filter); + } + _updateHoverStyles(active, lastActive, replay) { + const hoverOptions = this.options.hover; + const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index)); + const deactivated = diff(lastActive, active); + const activated = replay ? active : diff(active, lastActive); + if (deactivated.length) { + this.updateHoverStyle(deactivated, hoverOptions.mode, false); + } + if (activated.length && hoverOptions.mode) { + this.updateHoverStyle(activated, hoverOptions.mode, true); + } + } + _eventHandler(e, replay) { + const args = { + event: e, + replay, + cancelable: true, + inChartArea: _isPointInArea(e, this.chartArea, this._minPadding) + }; + const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type); + if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { + return; + } + const changed = this._handleEvent(e, replay, args.inChartArea); + args.cancelable = false; + this.notifyPlugins('afterEvent', args, eventFilter); + if (changed || args.changed) { + this.render(); + } + return this; + } + _handleEvent(e, replay, inChartArea) { + const {_active: lastActive = [], options} = this; + const useFinalPosition = replay; + const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); + const isClick = _isClickEvent(e); + const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); + if (inChartArea) { + this._lastEvent = null; + callback(options.onHover, [e, active, this], this); + if (isClick) { + callback(options.onClick, [e, active, this], this); + } + } + const changed = !_elementsEqual(active, lastActive); + if (changed || replay) { + this._active = active; + this._updateHoverStyles(active, lastActive, replay); + } + this._lastEvent = lastEvent; + return changed; + } + _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const hoverOptions = this.options.hover; + return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); + } +} +const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); +const enumerable = true; +Object.defineProperties(Chart, { + defaults: { + enumerable, + value: defaults + }, + instances: { + enumerable, + value: instances + }, + overrides: { + enumerable, + value: overrides + }, + registry: { + enumerable, + value: registry + }, + version: { + enumerable, + value: version + }, + getChart: { + enumerable, + value: getChart + }, + register: { + enumerable, + value: (...items) => { + registry.add(...items); + invalidatePlugins(); + } + }, + unregister: { + enumerable, + value: (...items) => { + registry.remove(...items); + invalidatePlugins(); + } + } +}); + +function clipArc(ctx, element, endAngle) { + const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; + let angleMargin = pixelMargin / outerRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (innerRadius > pixelMargin) { + angleMargin = pixelMargin / innerRadius; + ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); + } + ctx.closePath(); + ctx.clip(); +} +function toRadiusCorners(value) { + return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']); +} +function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { + const o = toRadiusCorners(arc.options.borderRadius); + const halfThickness = (outerRadius - innerRadius) / 2; + const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); + const computeOuterLimit = (val) => { + const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; + return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); + }; + return { + outerStart: computeOuterLimit(o.outerStart), + outerEnd: computeOuterLimit(o.outerEnd), + innerStart: _limitValue(o.innerStart, 0, innerLimit), + innerEnd: _limitValue(o.innerEnd, 0, innerLimit), + }; +} +function rThetaToXY(r, theta, x, y) { + return { + x: x + r * Math.cos(theta), + y: y + r * Math.sin(theta), + }; +} +function pathArc(ctx, element, offset, spacing, end) { + const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element; + const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); + const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; + let spacingOffset = 0; + const alpha = end - start; + if (spacing) { + const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; + const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; + const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; + const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha; + spacingOffset = (alpha - adjustedAngle) / 2; + } + const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; + const angleOffset = (alpha - beta) / 2; + const startAngle = start + angleOffset + spacingOffset; + const endAngle = end - angleOffset - spacingOffset; + const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); + const outerStartAdjustedRadius = outerRadius - outerStart; + const outerEndAdjustedRadius = outerRadius - outerEnd; + const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; + const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; + const innerStartAdjustedRadius = innerRadius + innerStart; + const innerEndAdjustedRadius = innerRadius + innerEnd; + const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; + const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle); + if (outerEnd > 0) { + const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); + } + const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); + ctx.lineTo(p4.x, p4.y); + if (innerEnd > 0) { + const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); + } + ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true); + if (innerStart > 0) { + const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); + } + const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); + ctx.lineTo(p8.x, p8.y); + if (outerStart > 0) { + const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); + } + ctx.closePath(); +} +function drawArc(ctx, element, offset, spacing) { + const {fullCircles, startAngle, circumference} = element; + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, startAngle + TAU); + for (let i = 0; i < fullCircles; ++i) { + ctx.fill(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + circumference % TAU; + if (circumference % TAU === 0) { + endAngle += TAU; + } + } + } + pathArc(ctx, element, offset, spacing, endAngle); + ctx.fill(); + return endAngle; +} +function drawFullCircleBorders(ctx, element, inner) { + const {x, y, startAngle, pixelMargin, fullCircles} = element; + const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + const innerRadius = element.innerRadius + pixelMargin; + let i; + if (inner) { + clipArc(ctx, element, startAngle + TAU); + } + ctx.beginPath(); + ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); + for (i = 0; i < fullCircles; ++i) { + ctx.stroke(); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); + for (i = 0; i < fullCircles; ++i) { + ctx.stroke(); + } +} +function drawBorder(ctx, element, offset, spacing, endAngle) { + const {options} = element; + const {borderWidth, borderJoinStyle} = options; + const inner = options.borderAlign === 'inner'; + if (!borderWidth) { + return; + } + if (inner) { + ctx.lineWidth = borderWidth * 2; + ctx.lineJoin = borderJoinStyle || 'round'; + } else { + ctx.lineWidth = borderWidth; + ctx.lineJoin = borderJoinStyle || 'bevel'; + } + if (element.fullCircles) { + drawFullCircleBorders(ctx, element, inner); + } + if (inner) { + clipArc(ctx, element, endAngle); + } + pathArc(ctx, element, offset, spacing, endAngle); + ctx.stroke(); +} +class ArcElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.circumference = undefined; + this.startAngle = undefined; + this.endAngle = undefined; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.pixelMargin = 0; + this.fullCircles = 0; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(chartX, chartY, useFinalPosition) { + const point = this.getProps(['x', 'y'], useFinalPosition); + const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); + const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference' + ], useFinalPosition); + const rAdjust = this.options.spacing / 2; + const _circumference = valueOrDefault(circumference, endAngle - startAngle); + const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); + const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); + return (betweenAngles && withinRadius); + } + getCenterPoint(useFinalPosition) { + const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference', + ], useFinalPosition); + const {offset, spacing} = this.options; + const halfAngle = (startAngle + endAngle) / 2; + const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + } + draw(ctx) { + const {options, circumference} = this; + const offset = (options.offset || 0) / 2; + const spacing = (options.spacing || 0) / 2; + this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; + this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; + if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { + return; + } + ctx.save(); + let radiusOffset = 0; + if (offset) { + radiusOffset = offset / 2; + const halfAngle = (this.startAngle + this.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset); + if (this.circumference >= PI) { + radiusOffset = offset; + } + } + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + const endAngle = drawArc(ctx, this, radiusOffset, spacing); + drawBorder(ctx, this, radiusOffset, spacing, endAngle); + ctx.restore(); + } +} +ArcElement.id = 'arc'; +ArcElement.defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderJoinStyle: undefined, + borderRadius: 0, + borderWidth: 2, + offset: 0, + spacing: 0, + angle: undefined, +}; +ArcElement.defaultRoutes = { + backgroundColor: 'backgroundColor' +}; + +function setStyle(ctx, options, style = options) { + ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); + ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); + ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); + ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); + ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); + ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); +} +function lineTo(ctx, previous, target) { + ctx.lineTo(target.x, target.y); +} +function getLineMethod(options) { + if (options.stepped) { + return _steppedLineTo; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierCurveTo; + } + return lineTo; +} +function pathVars(points, segment, params = {}) { + const count = points.length; + const {start: paramsStart = 0, end: paramsEnd = count - 1} = params; + const {start: segmentStart, end: segmentEnd} = segment; + const start = Math.max(paramsStart, segmentStart); + const end = Math.min(paramsEnd, segmentEnd); + const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; + return { + count, + start, + loop: segment.loop, + ilen: end < start && !outside ? count + end - start : end - start + }; +} +function pathSegment(ctx, line, segment, params) { + const {points, options} = line; + const {count, start, loop, ilen} = pathVars(points, segment, params); + const lineMethod = getLineMethod(options); + let {move = true, reverse} = params || {}; + let i, point, prev; + for (i = 0; i <= ilen; ++i) { + point = points[(start + (reverse ? ilen - i : i)) % count]; + if (point.skip) { + continue; + } else if (move) { + ctx.moveTo(point.x, point.y); + move = false; + } else { + lineMethod(ctx, prev, point, reverse, options.stepped); + } + prev = point; + } + if (loop) { + point = points[(start + (reverse ? ilen : 0)) % count]; + lineMethod(ctx, prev, point, reverse, options.stepped); + } + return !!loop; +} +function fastPathSegment(ctx, line, segment, params) { + const points = line.points; + const {count, start, ilen} = pathVars(points, segment, params); + const {move = true, reverse} = params || {}; + let avgX = 0; + let countX = 0; + let i, point, prevX, minY, maxY, lastY; + const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; + const drawX = () => { + if (minY !== maxY) { + ctx.lineTo(avgX, maxY); + ctx.lineTo(avgX, minY); + ctx.lineTo(avgX, lastY); + } + }; + if (move) { + point = points[pointIndex(0)]; + ctx.moveTo(point.x, point.y); + } + for (i = 0; i <= ilen; ++i) { + point = points[pointIndex(i)]; + if (point.skip) { + continue; + } + const x = point.x; + const y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + avgX = (countX * avgX + x) / ++countX; + } else { + drawX(); + ctx.lineTo(x, y); + prevX = truncX; + countX = 0; + minY = maxY = y; + } + lastY = y; + } + drawX(); +} +function _getSegmentMethod(line) { + const opts = line.options; + const borderDash = opts.borderDash && opts.borderDash.length; + const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; + return useFastPath ? fastPathSegment : pathSegment; +} +function _getInterpolationMethod(options) { + if (options.stepped) { + return _steppedInterpolation; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierInterpolation; + } + return _pointInLine; +} +function strokePathWithCache(ctx, line, start, count) { + let path = line._path; + if (!path) { + path = line._path = new Path2D(); + if (line.path(path, start, count)) { + path.closePath(); + } + } + setStyle(ctx, line.options); + ctx.stroke(path); +} +function strokePathDirect(ctx, line, start, count) { + const {segments, options} = line; + const segmentMethod = _getSegmentMethod(line); + for (const segment of segments) { + setStyle(ctx, options, segment.style); + ctx.beginPath(); + if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) { + ctx.closePath(); + } + ctx.stroke(); + } +} +const usePath2D = typeof Path2D === 'function'; +function draw(ctx, line, start, count) { + if (usePath2D && !line.options.segment) { + strokePathWithCache(ctx, line, start, count); + } else { + strokePathDirect(ctx, line, start, count); + } +} +class LineElement extends Element { + constructor(cfg) { + super(); + this.animated = true; + this.options = undefined; + this._chart = undefined; + this._loop = undefined; + this._fullLoop = undefined; + this._path = undefined; + this._points = undefined; + this._segments = undefined; + this._decimated = false; + this._pointsUpdated = false; + this._datasetIndex = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + updateControlPoints(chartArea, indexAxis) { + const options = this.options; + if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { + const loop = options.spanGaps ? this._loop : this._fullLoop; + _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); + this._pointsUpdated = true; + } + } + set points(points) { + this._points = points; + delete this._segments; + delete this._path; + this._pointsUpdated = false; + } + get points() { + return this._points; + } + get segments() { + return this._segments || (this._segments = _computeSegments(this, this.options.segment)); + } + first() { + const segments = this.segments; + const points = this.points; + return segments.length && points[segments[0].start]; + } + last() { + const segments = this.segments; + const points = this.points; + const count = segments.length; + return count && points[segments[count - 1].end]; + } + interpolate(point, property) { + const options = this.options; + const value = point[property]; + const points = this.points; + const segments = _boundSegments(this, {property, start: value, end: value}); + if (!segments.length) { + return; + } + const result = []; + const _interpolate = _getInterpolationMethod(options); + let i, ilen; + for (i = 0, ilen = segments.length; i < ilen; ++i) { + const {start, end} = segments[i]; + const p1 = points[start]; + const p2 = points[end]; + if (p1 === p2) { + result.push(p1); + continue; + } + const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); + const interpolated = _interpolate(p1, p2, t, options.stepped); + interpolated[property] = point[property]; + result.push(interpolated); + } + return result.length === 1 ? result[0] : result; + } + pathSegment(ctx, segment, params) { + const segmentMethod = _getSegmentMethod(this); + return segmentMethod(ctx, this, segment, params); + } + path(ctx, start, count) { + const segments = this.segments; + const segmentMethod = _getSegmentMethod(this); + let loop = this._loop; + start = start || 0; + count = count || (this.points.length - start); + for (const segment of segments) { + loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1}); + } + return !!loop; + } + draw(ctx, chartArea, start, count) { + const options = this.options || {}; + const points = this.points || []; + if (points.length && options.borderWidth) { + ctx.save(); + draw(ctx, this, start, count); + ctx.restore(); + } + if (this.animated) { + this._pointsUpdated = false; + this._path = undefined; + } + } +} +LineElement.id = 'line'; +LineElement.defaults = { + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: 'miter', + borderWidth: 3, + capBezierPoints: true, + cubicInterpolationMode: 'default', + fill: false, + spanGaps: false, + stepped: false, + tension: 0, +}; +LineElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; +LineElement.descriptors = { + _scriptable: true, + _indexable: (name) => name !== 'borderDash' && name !== 'fill', +}; + +function inRange$1(el, pos, axis, useFinalPosition) { + const options = el.options; + const {[axis]: value} = el.getProps([axis], useFinalPosition); + return (Math.abs(pos - value) < options.radius + options.hitRadius); +} +class PointElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.parsed = undefined; + this.skip = undefined; + this.stop = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(mouseX, mouseY, useFinalPosition) { + const options = this.options; + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); + } + inXRange(mouseX, useFinalPosition) { + return inRange$1(this, mouseX, 'x', useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange$1(this, mouseY, 'y', useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + size(options) { + options = options || this.options || {}; + let radius = options.radius || 0; + radius = Math.max(radius, radius && options.hoverRadius || 0); + const borderWidth = radius && options.borderWidth || 0; + return (radius + borderWidth) * 2; + } + draw(ctx, area) { + const options = this.options; + if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { + return; + } + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.fillStyle = options.backgroundColor; + drawPoint(ctx, options, this.x, this.y); + } + getRange() { + const options = this.options || {}; + return options.radius + options.hitRadius; + } +} +PointElement.id = 'point'; +PointElement.defaults = { + borderWidth: 1, + hitRadius: 1, + hoverBorderWidth: 1, + hoverRadius: 4, + pointStyle: 'circle', + radius: 3, + rotation: 0 +}; +PointElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; + +function getBarBounds(bar, useFinalPosition) { + const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); + let left, right, top, bottom, half; + if (bar.horizontal) { + half = height / 2; + left = Math.min(x, base); + right = Math.max(x, base); + top = y - half; + bottom = y + half; + } else { + half = width / 2; + left = x - half; + right = x + half; + top = Math.min(y, base); + bottom = Math.max(y, base); + } + return {left, top, right, bottom}; +} +function skipOrLimit(skip, value, min, max) { + return skip ? 0 : _limitValue(value, min, max); +} +function parseBorderWidth(bar, maxW, maxH) { + const value = bar.options.borderWidth; + const skip = bar.borderSkipped; + const o = toTRBL(value); + return { + t: skipOrLimit(skip.top, o.top, 0, maxH), + r: skipOrLimit(skip.right, o.right, 0, maxW), + b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), + l: skipOrLimit(skip.left, o.left, 0, maxW) + }; +} +function parseBorderRadius(bar, maxW, maxH) { + const {enableBorderRadius} = bar.getProps(['enableBorderRadius']); + const value = bar.options.borderRadius; + const o = toTRBLCorners(value); + const maxR = Math.min(maxW, maxH); + const skip = bar.borderSkipped; + const enableBorder = enableBorderRadius || isObject(value); + return { + topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), + topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), + bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), + bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) + }; +} +function boundingRects(bar) { + const bounds = getBarBounds(bar); + const width = bounds.right - bounds.left; + const height = bounds.bottom - bounds.top; + const border = parseBorderWidth(bar, width / 2, height / 2); + const radius = parseBorderRadius(bar, width / 2, height / 2); + return { + outer: { + x: bounds.left, + y: bounds.top, + w: width, + h: height, + radius + }, + inner: { + x: bounds.left + border.l, + y: bounds.top + border.t, + w: width - border.l - border.r, + h: height - border.t - border.b, + radius: { + topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), + topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), + bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), + bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)), + } + } + }; +} +function inRange(bar, x, y, useFinalPosition) { + const skipX = x === null; + const skipY = y === null; + const skipBoth = skipX && skipY; + const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); + return bounds + && (skipX || _isBetween(x, bounds.left, bounds.right)) + && (skipY || _isBetween(y, bounds.top, bounds.bottom)); +} +function hasRadius(radius) { + return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; +} +function addNormalRectPath(ctx, rect) { + ctx.rect(rect.x, rect.y, rect.w, rect.h); +} +function inflateRect(rect, amount, refRect = {}) { + const x = rect.x !== refRect.x ? -amount : 0; + const y = rect.y !== refRect.y ? -amount : 0; + const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; + const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; + return { + x: rect.x + x, + y: rect.y + y, + w: rect.w + w, + h: rect.h + h, + radius: rect.radius + }; +} +class BarElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.horizontal = undefined; + this.base = undefined; + this.width = undefined; + this.height = undefined; + this.inflateAmount = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + draw(ctx) { + const {inflateAmount, options: {borderColor, backgroundColor}} = this; + const {inner, outer} = boundingRects(this); + const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; + ctx.save(); + if (outer.w !== inner.w || outer.h !== inner.h) { + ctx.beginPath(); + addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); + ctx.clip(); + addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); + ctx.fillStyle = borderColor; + ctx.fill('evenodd'); + } + ctx.beginPath(); + addRectPath(ctx, inflateRect(inner, inflateAmount)); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + inRange(mouseX, mouseY, useFinalPosition) { + return inRange(this, mouseX, mouseY, useFinalPosition); + } + inXRange(mouseX, useFinalPosition) { + return inRange(this, mouseX, null, useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange(this, null, mouseY, useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); + return { + x: horizontal ? (x + base) / 2 : x, + y: horizontal ? y : (y + base) / 2 + }; + } + getRange(axis) { + return axis === 'x' ? this.width / 2 : this.height / 2; + } +} +BarElement.id = 'bar'; +BarElement.defaults = { + borderSkipped: 'start', + borderWidth: 0, + borderRadius: 0, + inflateAmount: 'auto', + pointStyle: undefined +}; +BarElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; + +var elements = /*#__PURE__*/Object.freeze({ +__proto__: null, +ArcElement: ArcElement, +LineElement: LineElement, +PointElement: PointElement, +BarElement: BarElement +}); + +function lttbDecimation(data, start, count, availableWidth, options) { + const samples = options.samples || availableWidth; + if (samples >= count) { + return data.slice(start, start + count); + } + const decimated = []; + const bucketWidth = (count - 2) / (samples - 2); + let sampledIndex = 0; + const endIndex = start + count - 1; + let a = start; + let i, maxAreaPoint, maxArea, area, nextA; + decimated[sampledIndex++] = data[a]; + for (i = 0; i < samples - 2; i++) { + let avgX = 0; + let avgY = 0; + let j; + const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; + const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; + const avgRangeLength = avgRangeEnd - avgRangeStart; + for (j = avgRangeStart; j < avgRangeEnd; j++) { + avgX += data[j].x; + avgY += data[j].y; + } + avgX /= avgRangeLength; + avgY /= avgRangeLength; + const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; + const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; + const {x: pointAx, y: pointAy} = data[a]; + maxArea = area = -1; + for (j = rangeOffs; j < rangeTo; j++) { + area = 0.5 * Math.abs( + (pointAx - avgX) * (data[j].y - pointAy) - + (pointAx - data[j].x) * (avgY - pointAy) + ); + if (area > maxArea) { + maxArea = area; + maxAreaPoint = data[j]; + nextA = j; + } + } + decimated[sampledIndex++] = maxAreaPoint; + a = nextA; + } + decimated[sampledIndex++] = data[endIndex]; + return decimated; +} +function minMaxDecimation(data, start, count, availableWidth) { + let avgX = 0; + let countX = 0; + let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; + const decimated = []; + const endIndex = start + count - 1; + const xMin = data[start].x; + const xMax = data[endIndex].x; + const dx = xMax - xMin; + for (i = start; i < start + count; ++i) { + point = data[i]; + x = (point.x - xMin) / dx * availableWidth; + y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + minIndex = i; + } else if (y > maxY) { + maxY = y; + maxIndex = i; + } + avgX = (countX * avgX + point.x) / ++countX; + } else { + const lastIndex = i - 1; + if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { + const intermediateIndex1 = Math.min(minIndex, maxIndex); + const intermediateIndex2 = Math.max(minIndex, maxIndex); + if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex1], + x: avgX, + }); + } + if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex2], + x: avgX + }); + } + } + if (i > 0 && lastIndex !== startIndex) { + decimated.push(data[lastIndex]); + } + decimated.push(point); + prevX = truncX; + countX = 0; + minY = maxY = y; + minIndex = maxIndex = startIndex = i; + } + } + return decimated; +} +function cleanDecimatedDataset(dataset) { + if (dataset._decimated) { + const data = dataset._data; + delete dataset._decimated; + delete dataset._data; + Object.defineProperty(dataset, 'data', {value: data}); + } +} +function cleanDecimatedData(chart) { + chart.data.datasets.forEach((dataset) => { + cleanDecimatedDataset(dataset); + }); +} +function getStartAndCountOfVisiblePointsSimplified(meta, points) { + const pointCount = points.length; + let start = 0; + let count; + const {iScale} = meta; + const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; + } else { + count = pointCount - start; + } + return {start, count}; +} +var plugin_decimation = { + id: 'decimation', + defaults: { + algorithm: 'min-max', + enabled: false, + }, + beforeElementsUpdate: (chart, args, options) => { + if (!options.enabled) { + cleanDecimatedData(chart); + return; + } + const availableWidth = chart.width; + chart.data.datasets.forEach((dataset, datasetIndex) => { + const {_data, indexAxis} = dataset; + const meta = chart.getDatasetMeta(datasetIndex); + const data = _data || dataset.data; + if (resolve([indexAxis, chart.options.indexAxis]) === 'y') { + return; + } + if (meta.type !== 'line') { + return; + } + const xAxis = chart.scales[meta.xAxisID]; + if (xAxis.type !== 'linear' && xAxis.type !== 'time') { + return; + } + if (chart.options.parsing) { + return; + } + let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data); + const threshold = options.threshold || 4 * availableWidth; + if (count <= threshold) { + cleanDecimatedDataset(dataset); + return; + } + if (isNullOrUndef(_data)) { + dataset._data = data; + delete dataset.data; + Object.defineProperty(dataset, 'data', { + configurable: true, + enumerable: true, + get: function() { + return this._decimated; + }, + set: function(d) { + this._data = d; + } + }); + } + let decimated; + switch (options.algorithm) { + case 'lttb': + decimated = lttbDecimation(data, start, count, availableWidth, options); + break; + case 'min-max': + decimated = minMaxDecimation(data, start, count, availableWidth); + break; + default: + throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); + } + dataset._decimated = decimated; + }); + }, + destroy(chart) { + cleanDecimatedData(chart); + } +}; + +function getLineByIndex(chart, index) { + const meta = chart.getDatasetMeta(index); + const visible = meta && chart.isDatasetVisible(index); + return visible ? meta.dataset : null; +} +function parseFillOption(line) { + const options = line.options; + const fillOption = options.fill; + let fill = valueOrDefault(fillOption && fillOption.target, fillOption); + if (fill === undefined) { + fill = !!options.backgroundColor; + } + if (fill === false || fill === null) { + return false; + } + if (fill === true) { + return 'origin'; + } + return fill; +} +function decodeFill(line, index, count) { + const fill = parseFillOption(line); + if (isObject(fill)) { + return isNaN(fill.value) ? false : fill; + } + let target = parseFloat(fill); + if (isNumberFinite(target) && Math.floor(target) === target) { + if (fill[0] === '-' || fill[0] === '+') { + target = index + target; + } + if (target === index || target < 0 || target >= count) { + return false; + } + return target; + } + return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill; +} +function computeLinearBoundary(source) { + const {scale = {}, fill} = source; + let target = null; + let horizontal; + if (fill === 'start') { + target = scale.bottom; + } else if (fill === 'end') { + target = scale.top; + } else if (isObject(fill)) { + target = scale.getPixelForValue(fill.value); + } else if (scale.getBasePixel) { + target = scale.getBasePixel(); + } + if (isNumberFinite(target)) { + horizontal = scale.isHorizontal(); + return { + x: horizontal ? target : null, + y: horizontal ? null : target + }; + } + return null; +} +class simpleArc { + constructor(opts) { + this.x = opts.x; + this.y = opts.y; + this.radius = opts.radius; + } + pathSegment(ctx, bounds, opts) { + const {x, y, radius} = this; + bounds = bounds || {start: 0, end: TAU}; + ctx.arc(x, y, radius, bounds.end, bounds.start, true); + return !opts.bounds; + } + interpolate(point) { + const {x, y, radius} = this; + const angle = point.angle; + return { + x: x + Math.cos(angle) * radius, + y: y + Math.sin(angle) * radius, + angle + }; + } +} +function computeCircularBoundary(source) { + const {scale, fill} = source; + const options = scale.options; + const length = scale.getLabels().length; + const target = []; + const start = options.reverse ? scale.max : scale.min; + const end = options.reverse ? scale.min : scale.max; + let i, center, value; + if (fill === 'start') { + value = start; + } else if (fill === 'end') { + value = end; + } else if (isObject(fill)) { + value = fill.value; + } else { + value = scale.getBaseValue(); + } + if (options.grid.circular) { + center = scale.getPointPositionForValue(0, start); + return new simpleArc({ + x: center.x, + y: center.y, + radius: scale.getDistanceFromCenterForValue(value) + }); + } + for (i = 0; i < length; ++i) { + target.push(scale.getPointPositionForValue(i, value)); + } + return target; +} +function computeBoundary(source) { + const scale = source.scale || {}; + if (scale.getPointPositionForValue) { + return computeCircularBoundary(source); + } + return computeLinearBoundary(source); +} +function findSegmentEnd(start, end, points) { + for (;end > start; end--) { + const point = points[end]; + if (!isNaN(point.x) && !isNaN(point.y)) { + break; + } + } + return end; +} +function pointsFromSegments(boundary, line) { + const {x = null, y = null} = boundary || {}; + const linePoints = line.points; + const points = []; + line.segments.forEach(({start, end}) => { + end = findSegmentEnd(start, end, linePoints); + const first = linePoints[start]; + const last = linePoints[end]; + if (y !== null) { + points.push({x: first.x, y}); + points.push({x: last.x, y}); + } else if (x !== null) { + points.push({x, y: first.y}); + points.push({x, y: last.y}); + } + }); + return points; +} +function buildStackLine(source) { + const {scale, index, line} = source; + const points = []; + const segments = line.segments; + const sourcePoints = line.points; + const linesBelow = getLinesBelow(scale, index); + linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + for (let j = segment.start; j <= segment.end; j++) { + addPointsBelow(points, sourcePoints[j], linesBelow); + } + } + return new LineElement({points, options: {}}); +} +function getLinesBelow(scale, index) { + const below = []; + const metas = scale.getMatchingVisibleMetas('line'); + for (let i = 0; i < metas.length; i++) { + const meta = metas[i]; + if (meta.index === index) { + break; + } + if (!meta.hidden) { + below.unshift(meta.dataset); + } + } + return below; +} +function addPointsBelow(points, sourcePoint, linesBelow) { + const postponed = []; + for (let j = 0; j < linesBelow.length; j++) { + const line = linesBelow[j]; + const {first, last, point} = findPoint(line, sourcePoint, 'x'); + if (!point || (first && last)) { + continue; + } + if (first) { + postponed.unshift(point); + } else { + points.push(point); + if (!last) { + break; + } + } + } + points.push(...postponed); +} +function findPoint(line, sourcePoint, property) { + const point = line.interpolate(sourcePoint, property); + if (!point) { + return {}; + } + const pointValue = point[property]; + const segments = line.segments; + const linePoints = line.points; + let first = false; + let last = false; + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + const firstValue = linePoints[segment.start][property]; + const lastValue = linePoints[segment.end][property]; + if (_isBetween(pointValue, firstValue, lastValue)) { + first = pointValue === firstValue; + last = pointValue === lastValue; + break; + } + } + return {first, last, point}; +} +function getTarget(source) { + const {chart, fill, line} = source; + if (isNumberFinite(fill)) { + return getLineByIndex(chart, fill); + } + if (fill === 'stack') { + return buildStackLine(source); + } + if (fill === 'shape') { + return true; + } + const boundary = computeBoundary(source); + if (boundary instanceof simpleArc) { + return boundary; + } + return createBoundaryLine(boundary, line); +} +function createBoundaryLine(boundary, line) { + let points = []; + let _loop = false; + if (isArray(boundary)) { + _loop = true; + points = boundary; + } else { + points = pointsFromSegments(boundary, line); + } + return points.length ? new LineElement({ + points, + options: {tension: 0}, + _loop, + _fullLoop: _loop + }) : null; +} +function resolveTarget(sources, index, propagate) { + const source = sources[index]; + let fill = source.fill; + const visited = [index]; + let target; + if (!propagate) { + return fill; + } + while (fill !== false && visited.indexOf(fill) === -1) { + if (!isNumberFinite(fill)) { + return fill; + } + target = sources[fill]; + if (!target) { + return false; + } + if (target.visible) { + return fill; + } + visited.push(fill); + fill = target.fill; + } + return false; +} +function _clip(ctx, target, clipY) { + const {segments, points} = target; + let first = true; + let lineLoop = false; + ctx.beginPath(); + for (const segment of segments) { + const {start, end} = segment; + const firstPoint = points[start]; + const lastPoint = points[findSegmentEnd(start, end, points)]; + if (first) { + ctx.moveTo(firstPoint.x, firstPoint.y); + first = false; + } else { + ctx.lineTo(firstPoint.x, clipY); + ctx.lineTo(firstPoint.x, firstPoint.y); + } + lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop}); + if (lineLoop) { + ctx.closePath(); + } else { + ctx.lineTo(lastPoint.x, clipY); + } + } + ctx.lineTo(target.first().x, clipY); + ctx.closePath(); + ctx.clip(); +} +function getBounds(property, first, last, loop) { + if (loop) { + return; + } + let start = first[property]; + let end = last[property]; + if (property === 'angle') { + start = _normalizeAngle(start); + end = _normalizeAngle(end); + } + return {property, start, end}; +} +function _getEdge(a, b, prop, fn) { + if (a && b) { + return fn(a[prop], b[prop]); + } + return a ? a[prop] : b ? b[prop] : 0; +} +function _segments(line, target, property) { + const segments = line.segments; + const points = line.points; + const tpoints = target.points; + const parts = []; + for (const segment of segments) { + let {start, end} = segment; + end = findSegmentEnd(start, end, points); + const bounds = getBounds(property, points[start], points[end], segment.loop); + if (!target.segments) { + parts.push({ + source: segment, + target: bounds, + start: points[start], + end: points[end] + }); + continue; + } + const targetSegments = _boundSegments(target, bounds); + for (const tgt of targetSegments) { + const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); + const fillSources = _boundSegment(segment, points, subBounds); + for (const fillSource of fillSources) { + parts.push({ + source: fillSource, + target: tgt, + start: { + [property]: _getEdge(bounds, subBounds, 'start', Math.max) + }, + end: { + [property]: _getEdge(bounds, subBounds, 'end', Math.min) + } + }); + } + } + } + return parts; +} +function clipBounds(ctx, scale, bounds) { + const {top, bottom} = scale.chart.chartArea; + const {property, start, end} = bounds || {}; + if (property === 'x') { + ctx.beginPath(); + ctx.rect(start, top, end - start, bottom - top); + ctx.clip(); + } +} +function interpolatedLineTo(ctx, target, point, property) { + const interpolatedPoint = target.interpolate(point, property); + if (interpolatedPoint) { + ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); + } +} +function _fill(ctx, cfg) { + const {line, target, property, color, scale} = cfg; + const segments = _segments(line, target, property); + for (const {source: src, target: tgt, start, end} of segments) { + const {style: {backgroundColor = color} = {}} = src; + const notShape = target !== true; + ctx.save(); + ctx.fillStyle = backgroundColor; + clipBounds(ctx, scale, notShape && getBounds(property, start, end)); + ctx.beginPath(); + const lineLoop = !!line.pathSegment(ctx, src); + let loop; + if (notShape) { + if (lineLoop) { + ctx.closePath(); + } else { + interpolatedLineTo(ctx, target, end, property); + } + const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); + loop = lineLoop && targetLoop; + if (!loop) { + interpolatedLineTo(ctx, target, start, property); + } + } + ctx.closePath(); + ctx.fill(loop ? 'evenodd' : 'nonzero'); + ctx.restore(); + } +} +function doFill(ctx, cfg) { + const {line, target, above, below, area, scale} = cfg; + const property = line._loop ? 'angle' : cfg.axis; + ctx.save(); + if (property === 'x' && below !== above) { + _clip(ctx, target, area.top); + _fill(ctx, {line, target, color: above, scale, property}); + ctx.restore(); + ctx.save(); + _clip(ctx, target, area.bottom); + } + _fill(ctx, {line, target, color: below, scale, property}); + ctx.restore(); +} +function drawfill(ctx, source, area) { + const target = getTarget(source); + const {line, scale, axis} = source; + const lineOpts = line.options; + const fillOption = lineOpts.fill; + const color = lineOpts.backgroundColor; + const {above = color, below = color} = fillOption || {}; + if (target && line.points.length) { + clipArea(ctx, area); + doFill(ctx, {line, target, above, below, area, scale, axis}); + unclipArea(ctx); + } +} +var plugin_filler = { + id: 'filler', + afterDatasetsUpdate(chart, _args, options) { + const count = (chart.data.datasets || []).length; + const sources = []; + let meta, i, line, source; + for (i = 0; i < count; ++i) { + meta = chart.getDatasetMeta(i); + line = meta.dataset; + source = null; + if (line && line.options && line instanceof LineElement) { + source = { + visible: chart.isDatasetVisible(i), + index: i, + fill: decodeFill(line, i, count), + chart, + axis: meta.controller.options.indexAxis, + scale: meta.vScale, + line, + }; + } + meta.$filler = source; + sources.push(source); + } + for (i = 0; i < count; ++i) { + source = sources[i]; + if (!source || source.fill === false) { + continue; + } + source.fill = resolveTarget(sources, i, options.propagate); + } + }, + beforeDraw(chart, _args, options) { + const draw = options.drawTime === 'beforeDraw'; + const metasets = chart.getSortedVisibleDatasetMetas(); + const area = chart.chartArea; + for (let i = metasets.length - 1; i >= 0; --i) { + const source = metasets[i].$filler; + if (!source) { + continue; + } + source.line.updateControlPoints(area, source.axis); + if (draw) { + drawfill(chart.ctx, source, area); + } + } + }, + beforeDatasetsDraw(chart, _args, options) { + if (options.drawTime !== 'beforeDatasetsDraw') { + return; + } + const metasets = chart.getSortedVisibleDatasetMetas(); + for (let i = metasets.length - 1; i >= 0; --i) { + const source = metasets[i].$filler; + if (source) { + drawfill(chart.ctx, source, chart.chartArea); + } + } + }, + beforeDatasetDraw(chart, args, options) { + const source = args.meta.$filler; + if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') { + return; + } + drawfill(chart.ctx, source, chart.chartArea); + }, + defaults: { + propagate: true, + drawTime: 'beforeDatasetDraw' + } +}; + +const getBoxSize = (labelOpts, fontSize) => { + let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts; + if (labelOpts.usePointStyle) { + boxHeight = Math.min(boxHeight, fontSize); + boxWidth = Math.min(boxWidth, fontSize); + } + return { + boxWidth, + boxHeight, + itemHeight: Math.max(fontSize, boxHeight) + }; +}; +const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; +class Legend extends Element { + constructor(config) { + super(); + this._added = false; + this.legendHitBoxes = []; + this._hoveredItem = null; + this.doughnutMode = false; + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this.legendItems = undefined; + this.columnSizes = undefined; + this.lineWidths = undefined; + this.maxHeight = undefined; + this.maxWidth = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.height = undefined; + this.width = undefined; + this._margins = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; + } + update(maxWidth, maxHeight, margins) { + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins; + this.setDimensions(); + this.buildLabels(); + this.fit(); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = this._margins.left; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = this._margins.top; + this.bottom = this.height; + } + } + buildLabels() { + const labelOpts = this.options.labels || {}; + let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || []; + if (labelOpts.filter) { + legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data)); + } + if (labelOpts.sort) { + legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data)); + } + if (this.options.reverse) { + legendItems.reverse(); + } + this.legendItems = legendItems; + } + fit() { + const {options, ctx} = this; + if (!options.display) { + this.width = this.height = 0; + return; + } + const labelOpts = options.labels; + const labelFont = toFont(labelOpts.font); + const fontSize = labelFont.size; + const titleHeight = this._computeTitleHeight(); + const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize); + let width, height; + ctx.font = labelFont.string; + if (this.isHorizontal()) { + width = this.maxWidth; + height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; + } else { + height = this.maxHeight; + width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10; + } + this.width = Math.min(width, options.maxWidth || this.maxWidth); + this.height = Math.min(height, options.maxHeight || this.maxHeight); + } + _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { + const {ctx, maxWidth, options: {labels: {padding}}} = this; + const hitboxes = this.legendHitBoxes = []; + const lineWidths = this.lineWidths = [0]; + const lineHeight = itemHeight + padding; + let totalHeight = titleHeight; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + let row = -1; + let top = -lineHeight; + this.legendItems.forEach((legendItem, i) => { + const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { + totalHeight += lineHeight; + lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; + top += lineHeight; + row++; + } + hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight}; + lineWidths[lineWidths.length - 1] += itemWidth + padding; + }); + return totalHeight; + } + _fitCols(titleHeight, fontSize, boxWidth, itemHeight) { + const {ctx, maxHeight, options: {labels: {padding}}} = this; + const hitboxes = this.legendHitBoxes = []; + const columnSizes = this.columnSizes = []; + const heightLimit = maxHeight - titleHeight; + let totalWidth = padding; + let currentColWidth = 0; + let currentColHeight = 0; + let left = 0; + let col = 0; + this.legendItems.forEach((legendItem, i) => { + const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { + totalWidth += currentColWidth + padding; + columnSizes.push({width: currentColWidth, height: currentColHeight}); + left += currentColWidth + padding; + col++; + currentColWidth = currentColHeight = 0; + } + hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight}; + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += itemHeight + padding; + }); + totalWidth += currentColWidth; + columnSizes.push({width: currentColWidth, height: currentColHeight}); + return totalWidth; + } + adjustHitBoxes() { + if (!this.options.display) { + return; + } + const titleHeight = this._computeTitleHeight(); + const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this; + const rtlHelper = getRtlAdapter(rtl, this.left, this.width); + if (this.isHorizontal()) { + let row = 0; + let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + for (const hitbox of hitboxes) { + if (row !== hitbox.row) { + row = hitbox.row; + left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + } + hitbox.top += this.top + titleHeight + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); + left += hitbox.width + padding; + } + } else { + let col = 0; + let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + for (const hitbox of hitboxes) { + if (hitbox.col !== col) { + col = hitbox.col; + top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + } + hitbox.top = top; + hitbox.left += this.left + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); + top += hitbox.height + padding; + } + } + } + isHorizontal() { + return this.options.position === 'top' || this.options.position === 'bottom'; + } + draw() { + if (this.options.display) { + const ctx = this.ctx; + clipArea(ctx, this); + this._draw(); + unclipArea(ctx); + } + } + _draw() { + const {options: opts, columnSizes, lineWidths, ctx} = this; + const {align, labels: labelOpts} = opts; + const defaultColor = defaults.color; + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const labelFont = toFont(labelOpts.font); + const {color: fontColor, padding} = labelOpts; + const fontSize = labelFont.size; + const halfFontSize = fontSize / 2; + let cursor; + this.drawTitle(); + ctx.textAlign = rtlHelper.textAlign('left'); + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.font = labelFont.string; + const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize); + const drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { + return; + } + ctx.save(); + const lineWidth = valueOrDefault(legendItem.lineWidth, 1); + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); + ctx.lineWidth = lineWidth; + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); + ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); + if (labelOpts.usePointStyle) { + const drawOptions = { + radius: boxWidth * Math.SQRT2 / 2, + pointStyle: legendItem.pointStyle, + rotation: legendItem.rotation, + borderWidth: lineWidth + }; + const centerX = rtlHelper.xPlus(x, boxWidth / 2); + const centerY = y + halfFontSize; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); + const borderRadius = toTRBLCorners(legendItem.borderRadius); + ctx.beginPath(); + if (Object.values(borderRadius).some(v => v !== 0)) { + addRoundedRectPath(ctx, { + x: xBoxLeft, + y: yBoxTop, + w: boxWidth, + h: boxHeight, + radius: borderRadius, + }); + } else { + ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); + } + ctx.fill(); + if (lineWidth !== 0) { + ctx.stroke(); + } + } + ctx.restore(); + }; + const fillText = function(x, y, legendItem) { + renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, { + strikethrough: legendItem.hidden, + textAlign: rtlHelper.textAlign(legendItem.textAlign) + }); + }; + const isHorizontal = this.isHorizontal(); + const titleHeight = this._computeTitleHeight(); + if (isHorizontal) { + cursor = { + x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), + y: this.top + padding + titleHeight, + line: 0 + }; + } else { + cursor = { + x: this.left + padding, + y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), + line: 0 + }; + } + overrideTextDirection(this.ctx, opts.textDirection); + const lineHeight = itemHeight + padding; + this.legendItems.forEach((legendItem, i) => { + ctx.strokeStyle = legendItem.fontColor || fontColor; + ctx.fillStyle = legendItem.fontColor || fontColor; + const textWidth = ctx.measureText(legendItem.text).width; + const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); + const width = boxWidth + halfFontSize + textWidth; + let x = cursor.x; + let y = cursor.y; + rtlHelper.setWidth(this.width); + if (isHorizontal) { + if (i > 0 && x + width + padding > this.right) { + y = cursor.y += lineHeight; + cursor.line++; + x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); + } + } else if (i > 0 && y + lineHeight > this.bottom) { + x = cursor.x = x + columnSizes[cursor.line].width + padding; + cursor.line++; + y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); + } + const realX = rtlHelper.x(x); + drawLegendBox(realX, y, legendItem); + x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); + fillText(rtlHelper.x(x), y, legendItem); + if (isHorizontal) { + cursor.x += width + padding; + } else { + cursor.y += lineHeight; + } + }); + restoreTextDirection(this.ctx, opts.textDirection); + } + drawTitle() { + const opts = this.options; + const titleOpts = opts.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + if (!titleOpts.display) { + return; + } + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const ctx = this.ctx; + const position = titleOpts.position; + const halfFontSize = titleFont.size / 2; + const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; + let y; + let left = this.left; + let maxWidth = this.width; + if (this.isHorizontal()) { + maxWidth = Math.max(...this.lineWidths); + y = this.top + topPaddingPlusHalfFontSize; + left = _alignStartEnd(opts.align, left, this.right - maxWidth); + } else { + const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0); + y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); + } + const x = _alignStartEnd(position, left, left + maxWidth); + ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); + ctx.textBaseline = 'middle'; + ctx.strokeStyle = titleOpts.color; + ctx.fillStyle = titleOpts.color; + ctx.font = titleFont.string; + renderText(ctx, titleOpts.text, x, y, titleFont); + } + _computeTitleHeight() { + const titleOpts = this.options.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; + } + _getLegendItemAt(x, y) { + let i, hitBox, lh; + if (_isBetween(x, this.left, this.right) + && _isBetween(y, this.top, this.bottom)) { + lh = this.legendHitBoxes; + for (i = 0; i < lh.length; ++i) { + hitBox = lh[i]; + if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) + && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { + return this.legendItems[i]; + } + } + } + return null; + } + handleEvent(e) { + const opts = this.options; + if (!isListened(e.type, opts)) { + return; + } + const hoveredItem = this._getLegendItemAt(e.x, e.y); + if (e.type === 'mousemove') { + const previous = this._hoveredItem; + const sameItem = itemsEqual(previous, hoveredItem); + if (previous && !sameItem) { + callback(opts.onLeave, [e, previous, this], this); + } + this._hoveredItem = hoveredItem; + if (hoveredItem && !sameItem) { + callback(opts.onHover, [e, hoveredItem, this], this); + } + } else if (hoveredItem) { + callback(opts.onClick, [e, hoveredItem, this], this); + } + } +} +function isListened(type, opts) { + if (type === 'mousemove' && (opts.onHover || opts.onLeave)) { + return true; + } + if (opts.onClick && (type === 'click' || type === 'mouseup')) { + return true; + } + return false; +} +var plugin_legend = { + id: 'legend', + _element: Legend, + start(chart, _args, options) { + const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart}); + layouts.configure(chart, legend, options); + layouts.addBox(chart, legend); + }, + stop(chart) { + layouts.removeBox(chart, chart.legend); + delete chart.legend; + }, + beforeUpdate(chart, _args, options) { + const legend = chart.legend; + layouts.configure(chart, legend, options); + legend.options = options; + }, + afterUpdate(chart) { + const legend = chart.legend; + legend.buildLabels(); + legend.adjustHitBoxes(); + }, + afterEvent(chart, args) { + if (!args.replay) { + chart.legend.handleEvent(args.event); + } + }, + defaults: { + display: true, + position: 'top', + align: 'center', + fullSize: true, + reverse: false, + weight: 1000, + onClick(e, legendItem, legend) { + const index = legendItem.datasetIndex; + const ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } + }, + onHover: null, + onLeave: null, + labels: { + color: (ctx) => ctx.chart.options.color, + boxWidth: 40, + padding: 10, + generateLabels(chart) { + const datasets = chart.data.datasets; + const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options; + return chart._getSortedDatasetMetas().map((meta) => { + const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); + const borderWidth = toPadding(style.borderWidth); + return { + text: datasets[meta.index].label, + fillStyle: style.backgroundColor, + fontColor: color, + hidden: !meta.visible, + lineCap: style.borderCapStyle, + lineDash: style.borderDash, + lineDashOffset: style.borderDashOffset, + lineJoin: style.borderJoinStyle, + lineWidth: (borderWidth.width + borderWidth.height) / 4, + strokeStyle: style.borderColor, + pointStyle: pointStyle || style.pointStyle, + rotation: style.rotation, + textAlign: textAlign || style.textAlign, + borderRadius: 0, + datasetIndex: meta.index + }; + }, this); + } + }, + title: { + color: (ctx) => ctx.chart.options.color, + display: false, + position: 'center', + text: '', + } + }, + descriptors: { + _scriptable: (name) => !name.startsWith('on'), + labels: { + _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name), + } + }, +}; + +class Title extends Element { + constructor(config) { + super(); + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this._padding = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; + } + update(maxWidth, maxHeight) { + const opts = this.options; + this.left = 0; + this.top = 0; + if (!opts.display) { + this.width = this.height = this.right = this.bottom = 0; + return; + } + this.width = this.right = maxWidth; + this.height = this.bottom = maxHeight; + const lineCount = isArray(opts.text) ? opts.text.length : 1; + this._padding = toPadding(opts.padding); + const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; + if (this.isHorizontal()) { + this.height = textSize; + } else { + this.width = textSize; + } + } + isHorizontal() { + const pos = this.options.position; + return pos === 'top' || pos === 'bottom'; + } + _drawArgs(offset) { + const {top, left, bottom, right, options} = this; + const align = options.align; + let rotation = 0; + let maxWidth, titleX, titleY; + if (this.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + titleY = top + offset; + maxWidth = right - left; + } else { + if (options.position === 'left') { + titleX = left + offset; + titleY = _alignStartEnd(align, bottom, top); + rotation = PI * -0.5; + } else { + titleX = right - offset; + titleY = _alignStartEnd(align, top, bottom); + rotation = PI * 0.5; + } + maxWidth = bottom - top; + } + return {titleX, titleY, maxWidth, rotation}; + } + draw() { + const ctx = this.ctx; + const opts = this.options; + if (!opts.display) { + return; + } + const fontOpts = toFont(opts.font); + const lineHeight = fontOpts.lineHeight; + const offset = lineHeight / 2 + this._padding.top; + const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset); + renderText(ctx, opts.text, 0, 0, fontOpts, { + color: opts.color, + maxWidth, + rotation, + textAlign: _toLeftRightCenter(opts.align), + textBaseline: 'middle', + translation: [titleX, titleY], + }); + } +} +function createTitle(chart, titleOpts) { + const title = new Title({ + ctx: chart.ctx, + options: titleOpts, + chart + }); + layouts.configure(chart, title, titleOpts); + layouts.addBox(chart, title); + chart.titleBlock = title; +} +var plugin_title = { + id: 'title', + _element: Title, + start(chart, _args, options) { + createTitle(chart, options); + }, + stop(chart) { + const titleBlock = chart.titleBlock; + layouts.removeBox(chart, titleBlock); + delete chart.titleBlock; + }, + beforeUpdate(chart, _args, options) { + const title = chart.titleBlock; + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'bold', + }, + fullSize: true, + padding: 10, + position: 'top', + text: '', + weight: 2000 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false, + }, +}; + +const map = new WeakMap(); +var plugin_subtitle = { + id: 'subtitle', + start(chart, _args, options) { + const title = new Title({ + ctx: chart.ctx, + options, + chart + }); + layouts.configure(chart, title, options); + layouts.addBox(chart, title); + map.set(chart, title); + }, + stop(chart) { + layouts.removeBox(chart, map.get(chart)); + map.delete(chart); + }, + beforeUpdate(chart, _args, options) { + const title = map.get(chart); + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'normal', + }, + fullSize: true, + padding: 0, + position: 'top', + text: '', + weight: 1500 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false, + }, +}; + +const positioners = { + average(items) { + if (!items.length) { + return false; + } + let i, len; + let x = 0; + let y = 0; + let count = 0; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest(items, eventPosition) { + if (!items.length) { + return false; + } + let x = eventPosition.x; + let y = eventPosition.y; + let minDistance = Number.POSITIVE_INFINITY; + let i, len, nearestElement; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const center = el.getCenterPoint(); + const d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + const tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x, + y + }; + } +}; +function pushOrConcat(base, toPush) { + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + return base; +} +function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} +function createTooltipItem(chart, item) { + const {element, datasetIndex, index} = item; + const controller = chart.getDatasetMeta(datasetIndex).controller; + const {label, value} = controller.getLabelAndValue(index); + return { + chart, + label, + parsed: controller.getParsed(index), + raw: chart.data.datasets[datasetIndex].data[index], + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex, + element + }; +} +function getTooltipSize(tooltip, options) { + const ctx = tooltip.chart.ctx; + const {body, footer, title} = tooltip; + const {boxWidth, boxHeight} = options; + const bodyFont = toFont(options.bodyFont); + const titleFont = toFont(options.titleFont); + const footerFont = toFont(options.footerFont); + const titleLineCount = title.length; + const footerLineCount = footer.length; + const bodyLineItemCount = body.length; + const padding = toPadding(options.padding); + let height = padding.height; + let width = 0; + let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.lineHeight + + (titleLineCount - 1) * options.titleSpacing + + options.titleMarginBottom; + } + if (combinedBodyLength) { + const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; + height += bodyLineItemCount * bodyLineHeight + + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + + footerLineCount * footerFont.lineHeight + + (footerLineCount - 1) * options.footerSpacing; + } + let widthPadding = 0; + const maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0; + each(body, (bodyItem) => { + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += padding.width; + return {width, height}; +} +function determineYAlign(chart, size) { + const {y, height} = size; + if (y < height / 2) { + return 'top'; + } else if (y > (chart.height - height / 2)) { + return 'bottom'; + } + return 'center'; +} +function doesNotFitWithAlign(xAlign, chart, options, size) { + const {x, width} = size; + const caret = options.caretSize + options.caretPadding; + if (xAlign === 'left' && x + width + caret > chart.width) { + return true; + } + if (xAlign === 'right' && x - width - caret < 0) { + return true; + } +} +function determineXAlign(chart, options, size, yAlign) { + const {x, width} = size; + const {width: chartWidth, chartArea: {left, right}} = chart; + let xAlign = 'center'; + if (yAlign === 'center') { + xAlign = x <= (left + right) / 2 ? 'left' : 'right'; + } else if (x <= width / 2) { + xAlign = 'left'; + } else if (x >= chartWidth - width / 2) { + xAlign = 'right'; + } + if (doesNotFitWithAlign(xAlign, chart, options, size)) { + xAlign = 'center'; + } + return xAlign; +} +function determineAlignment(chart, options, size) { + const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); + return { + xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), + yAlign + }; +} +function alignX(size, xAlign) { + let {x, width} = size; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= (width / 2); + } + return x; +} +function alignY(size, yAlign, paddingAndSize) { + let {y, height} = size; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= (height / 2); + } + return y; +} +function getBackgroundPoint(options, size, alignment, chart) { + const {caretSize, caretPadding, cornerRadius} = options; + const {xAlign, yAlign} = alignment; + const paddingAndSize = caretSize + caretPadding; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); + let x = alignX(size, xAlign); + const y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x += Math.max(topRight, bottomRight) + caretSize; + } + return { + x: _limitValue(x, 0, chart.width - size.width), + y: _limitValue(y, 0, chart.height - size.height) + }; +} +function getAlignedX(tooltip, align, options) { + const padding = toPadding(options.padding); + return align === 'center' + ? tooltip.x + tooltip.width / 2 + : align === 'right' + ? tooltip.x + tooltip.width - padding.right + : tooltip.x + padding.left; +} +function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} +function createTooltipContext(parent, tooltip, tooltipItems) { + return createContext(parent, { + tooltip, + tooltipItems, + type: 'tooltip' + }); +} +function overrideCallbacks(callbacks, context) { + const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; + return override ? callbacks.override(override) : callbacks; +} +class Tooltip extends Element { + constructor(config) { + super(); + this.opacity = 0; + this._active = []; + this._eventPosition = undefined; + this._size = undefined; + this._cachedAnimations = undefined; + this._tooltipItems = []; + this.$animations = undefined; + this.$context = undefined; + this.chart = config.chart || config._chart; + this._chart = this.chart; + this.options = config.options; + this.dataPoints = undefined; + this.title = undefined; + this.beforeBody = undefined; + this.body = undefined; + this.afterBody = undefined; + this.footer = undefined; + this.xAlign = undefined; + this.yAlign = undefined; + this.x = undefined; + this.y = undefined; + this.height = undefined; + this.width = undefined; + this.caretX = undefined; + this.caretY = undefined; + this.labelColors = undefined; + this.labelPointStyles = undefined; + this.labelTextColors = undefined; + } + initialize(options) { + this.options = options; + this._cachedAnimations = undefined; + this.$context = undefined; + } + _resolveAnimations() { + const cached = this._cachedAnimations; + if (cached) { + return cached; + } + const chart = this.chart; + const options = this.options.setContext(this.getContext()); + const opts = options.enabled && chart.options.animation && options.animations; + const animations = new Animations(this.chart, opts); + if (opts._cacheable) { + this._cachedAnimations = Object.freeze(animations); + } + return animations; + } + getContext() { + return this.$context || + (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); + } + getTitle(context, options) { + const {callbacks} = options; + const beforeTitle = callbacks.beforeTitle.apply(this, [context]); + const title = callbacks.title.apply(this, [context]); + const afterTitle = callbacks.afterTitle.apply(this, [context]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + } + getBeforeBody(tooltipItems, options) { + return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems])); + } + getBody(tooltipItems, options) { + const {callbacks} = options; + const bodyItems = []; + each(tooltipItems, (context) => { + const bodyItem = { + before: [], + lines: [], + after: [] + }; + const scoped = overrideCallbacks(callbacks, context); + pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context))); + pushOrConcat(bodyItem.lines, scoped.label.call(this, context)); + pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + } + getAfterBody(tooltipItems, options) { + return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems])); + } + getFooter(tooltipItems, options) { + const {callbacks} = options; + const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]); + const footer = callbacks.footer.apply(this, [tooltipItems]); + const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + _createItems(options) { + const active = this._active; + const data = this.chart.data; + const labelColors = []; + const labelPointStyles = []; + const labelTextColors = []; + let tooltipItems = []; + let i, len; + for (i = 0, len = active.length; i < len; ++i) { + tooltipItems.push(createTooltipItem(this.chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); + } + each(tooltipItems, (context) => { + const scoped = overrideCallbacks(options.callbacks, context); + labelColors.push(scoped.labelColor.call(this, context)); + labelPointStyles.push(scoped.labelPointStyle.call(this, context)); + labelTextColors.push(scoped.labelTextColor.call(this, context)); + }); + this.labelColors = labelColors; + this.labelPointStyles = labelPointStyles; + this.labelTextColors = labelTextColors; + this.dataPoints = tooltipItems; + return tooltipItems; + } + update(changed, replay) { + const options = this.options.setContext(this.getContext()); + const active = this._active; + let properties; + let tooltipItems = []; + if (!active.length) { + if (this.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + const position = positioners[options.position].call(this, active, this._eventPosition); + tooltipItems = this._createItems(options); + this.title = this.getTitle(tooltipItems, options); + this.beforeBody = this.getBeforeBody(tooltipItems, options); + this.body = this.getBody(tooltipItems, options); + this.afterBody = this.getAfterBody(tooltipItems, options); + this.footer = this.getFooter(tooltipItems, options); + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, size); + const alignment = determineAlignment(this.chart, options, positionAndSize); + const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + this._tooltipItems = tooltipItems; + this.$context = undefined; + if (properties) { + this._resolveAnimations().update(this, properties); + } + if (changed && options.external) { + options.external.call(this, {chart: this.chart, tooltip: this, replay}); + } + } + drawCaret(tooltipPoint, ctx, size, options) { + const caretPosition = this.getCaretPosition(tooltipPoint, size, options); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + } + getCaretPosition(tooltipPoint, size, options) { + const {xAlign, yAlign} = this; + const {caretSize, cornerRadius} = options; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); + const {x: ptX, y: ptY} = tooltipPoint; + const {width, height} = size; + let x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + (height / 2); + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize); + } else if (xAlign === 'right') { + x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return {x1, x2, x3, y1, y2, y3}; + } + drawTitle(pt, ctx, options) { + const title = this.title; + const length = title.length; + let titleFont, titleSpacing, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.titleAlign, options); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = toFont(options.titleFont); + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleColor; + ctx.font = titleFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); + pt.y += titleFont.lineHeight + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + _drawColorBox(ctx, pt, i, rtlHelper, options) { + const labelColors = this.labelColors[i]; + const labelPointStyle = this.labelPointStyles[i]; + const {boxHeight, boxWidth, boxPadding} = options; + const bodyFont = toFont(options.bodyFont); + const colorX = getAlignedX(this, 'left', options); + const rtlColorX = rtlHelper.x(colorX); + const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; + const colorY = pt.y + yOffSet; + if (options.usePointStyle) { + const drawOptions = { + radius: Math.min(boxWidth, boxHeight) / 2, + pointStyle: labelPointStyle.pointStyle, + rotation: labelPointStyle.rotation, + borderWidth: 1 + }; + const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; + const centerY = colorY + boxHeight / 2; + ctx.strokeStyle = options.multiKeyBackground; + ctx.fillStyle = options.multiKeyBackground; + drawPoint(ctx, drawOptions, centerX, centerY); + ctx.strokeStyle = labelColors.borderColor; + ctx.fillStyle = labelColors.backgroundColor; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + ctx.lineWidth = labelColors.borderWidth || 1; + ctx.strokeStyle = labelColors.borderColor; + ctx.setLineDash(labelColors.borderDash || []); + ctx.lineDashOffset = labelColors.borderDashOffset || 0; + const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding); + const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2); + const borderRadius = toTRBLCorners(labelColors.borderRadius); + if (Object.values(borderRadius).some(v => v !== 0)) { + ctx.beginPath(); + ctx.fillStyle = options.multiKeyBackground; + addRoundedRectPath(ctx, { + x: outerX, + y: colorY, + w: boxWidth, + h: boxHeight, + radius: borderRadius, + }); + ctx.fill(); + ctx.stroke(); + ctx.fillStyle = labelColors.backgroundColor; + ctx.beginPath(); + addRoundedRectPath(ctx, { + x: innerX, + y: colorY + 1, + w: boxWidth - 2, + h: boxHeight - 2, + radius: borderRadius, + }); + ctx.fill(); + } else { + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(outerX, colorY, boxWidth, boxHeight); + ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColors.backgroundColor; + ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); + } + } + ctx.fillStyle = this.labelTextColors[i]; + } + drawBody(pt, ctx, options) { + const {body} = this; + const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options; + const bodyFont = toFont(options.bodyFont); + let bodyLineHeight = bodyFont.lineHeight; + let xLinePadding = 0; + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + const fillLineOfText = function(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + let bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(this, bodyAlignForCalculation, options); + ctx.fillStyle = options.bodyColor; + each(this.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' + ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding) + : 0; + for (i = 0, ilen = body.length; i < ilen; ++i) { + bodyItem = body[i]; + textColor = this.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + this._drawColorBox(ctx, pt, i, rtlHelper, options); + bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); + } + for (j = 0, jlen = lines.length; j < jlen; ++j) { + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.lineHeight; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.lineHeight; + each(this.afterBody, fillLineOfText); + pt.y -= bodySpacing; + } + drawFooter(pt, ctx, options) { + const footer = this.footer; + const length = footer.length; + let footerFont, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.footerAlign, options); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = toFont(options.footerFont); + ctx.fillStyle = options.footerColor; + ctx.font = footerFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); + pt.y += footerFont.lineHeight + options.footerSpacing; + } + } + } + drawBackground(pt, ctx, tooltipSize, options) { + const {xAlign, yAlign} = this; + const {x, y} = pt; + const {width, height} = tooltipSize; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius); + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + topLeft, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width - topRight, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width, y + height - bottomRight); + ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + bottomLeft, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x, y + topLeft); + ctx.quadraticCurveTo(x, y, x + topLeft, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + _updateAnimationTarget(options) { + const chart = this.chart; + const anims = this.$animations; + const animX = anims && anims.x; + const animY = anims && anims.y; + if (animX || animY) { + const position = positioners[options.position].call(this, this._active, this._eventPosition); + if (!position) { + return; + } + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, this._size); + const alignment = determineAlignment(chart, options, positionAndSize); + const point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + this.width = size.width; + this.height = size.height; + this.caretX = position.x; + this.caretY = position.y; + this._resolveAnimations().update(this, point); + } + } + } + draw(ctx) { + const options = this.options.setContext(this.getContext()); + let opacity = this.opacity; + if (!opacity) { + return; + } + this._updateAnimationTarget(options); + const tooltipSize = { + width: this.width, + height: this.height + }; + const pt = { + x: this.x, + y: this.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + const padding = toPadding(options.padding); + const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + this.drawBackground(pt, ctx, tooltipSize, options); + overrideTextDirection(ctx, options.textDirection); + pt.y += padding.top; + this.drawTitle(pt, ctx, options); + this.drawBody(pt, ctx, options); + this.drawFooter(pt, ctx, options); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements, eventPosition) { + const lastActive = this._active; + const active = activeElements.map(({datasetIndex, index}) => { + const meta = this.chart.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('Cannot find a dataset at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index, + }; + }); + const changed = !_elementsEqual(lastActive, active); + const positionChanged = this._positionChanged(active, eventPosition); + if (changed || positionChanged) { + this._active = active; + this._eventPosition = eventPosition; + this._ignoreReplayEvents = true; + this.update(true); + } + } + handleEvent(e, replay, inChartArea = true) { + if (replay && this._ignoreReplayEvents) { + return false; + } + this._ignoreReplayEvents = false; + const options = this.options; + const lastActive = this._active || []; + const active = this._getActiveElements(e, lastActive, replay, inChartArea); + const positionChanged = this._positionChanged(active, e); + const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + this._active = active; + if (options.enabled || options.external) { + this._eventPosition = { + x: e.x, + y: e.y + }; + this.update(true, replay); + } + } + return changed; + } + _getActiveElements(e, lastActive, replay, inChartArea) { + const options = this.options; + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + return active; + } + _positionChanged(active, e) { + const {caretX, caretY, options} = this; + const position = positioners[options.position].call(this, active, e); + return position !== false && (caretX !== position.x || caretY !== position.y); + } +} +Tooltip.positioners = positioners; +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners, + afterInit(chart, _args, options) { + if (options) { + chart.tooltip = new Tooltip({chart, options}); + } + }, + beforeUpdate(chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + reset(chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + afterDraw(chart) { + const tooltip = chart.tooltip; + const args = { + tooltip + }; + if (chart.notifyPlugins('beforeTooltipDraw', args) === false) { + return; + } + if (tooltip) { + tooltip.draw(chart.ctx); + } + chart.notifyPlugins('afterTooltipDraw', args); + }, + afterEvent(chart, args) { + if (chart.tooltip) { + const useFinalPosition = args.replay; + if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { + args.changed = true; + } + } + }, + defaults: { + enabled: true, + external: null, + position: 'average', + backgroundColor: 'rgba(0,0,0,0.8)', + titleColor: '#fff', + titleFont: { + weight: 'bold', + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodyColor: '#fff', + bodySpacing: 2, + bodyFont: { + }, + bodyAlign: 'left', + footerColor: '#fff', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + weight: 'bold', + }, + footerAlign: 'left', + padding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + boxHeight: (ctx, opts) => opts.bodyFont.size, + boxWidth: (ctx, opts) => opts.bodyFont.size, + multiKeyBackground: '#fff', + displayColors: true, + boxPadding: 0, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart', + }, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: { + beforeTitle: noop, + title(tooltipItems) { + if (tooltipItems.length > 0) { + const item = tooltipItems[0]; + const labels = item.chart.data.labels; + const labelCount = labels ? labels.length : 0; + if (this && this.options && this.options.mode === 'dataset') { + return item.dataset.label || ''; + } else if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } + } + return ''; + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label(tooltipItem) { + if (this && this.options && this.options.mode === 'dataset') { + return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; + } + let label = tooltipItem.dataset.label || ''; + if (label) { + label += ': '; + } + const value = tooltipItem.formattedValue; + if (!isNullOrUndef(value)) { + label += value; + } + return label; + }, + labelColor(tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + borderColor: options.borderColor, + backgroundColor: options.backgroundColor, + borderWidth: options.borderWidth, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderRadius: 0, + }; + }, + labelTextColor() { + return this.options.bodyColor; + }, + labelPointStyle(tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + pointStyle: options.pointStyle, + rotation: options.rotation, + }; + }, + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop + } + }, + defaultRoutes: { + bodyFont: 'font', + footerFont: 'font', + titleFont: 'font' + }, + descriptors: { + _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external', + _indexable: false, + callbacks: { + _scriptable: false, + _indexable: false, + }, + animation: { + _fallback: false + }, + animations: { + _fallback: 'animation' + } + }, + additionalOptionScopes: ['interaction'] +}; + +var plugins = /*#__PURE__*/Object.freeze({ +__proto__: null, +Decimation: plugin_decimation, +Filler: plugin_filler, +Legend: plugin_legend, +SubTitle: plugin_subtitle, +Title: plugin_title, +Tooltip: plugin_tooltip +}); + +const addIfString = (labels, raw, index, addedLabels) => { + if (typeof raw === 'string') { + index = labels.push(raw) - 1; + addedLabels.unshift({index, label: raw}); + } else if (isNaN(raw)) { + index = null; + } + return index; +}; +function findOrAddLabel(labels, raw, index, addedLabels) { + const first = labels.indexOf(raw); + if (first === -1) { + return addIfString(labels, raw, index, addedLabels); + } + const last = labels.lastIndexOf(raw); + return first !== last ? index : first; +} +const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max); +class CategoryScale extends Scale { + constructor(cfg) { + super(cfg); + this._startValue = undefined; + this._valueRange = 0; + this._addedLabels = []; + } + init(scaleOptions) { + const added = this._addedLabels; + if (added.length) { + const labels = this.getLabels(); + for (const {index, label} of added) { + if (labels[index] === label) { + labels.splice(index, 1); + } + } + this._addedLabels = []; + } + super.init(scaleOptions); + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + const labels = this.getLabels(); + index = isFinite(index) && labels[index] === raw ? index + : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); + return validIndex(index, labels.length - 1); + } + determineDataLimits() { + const {minDefined, maxDefined} = this.getUserBounds(); + let {min, max} = this.getMinMax(true); + if (this.options.bounds === 'ticks') { + if (!minDefined) { + min = 0; + } + if (!maxDefined) { + max = this.getLabels().length - 1; + } + } + this.min = min; + this.max = max; + } + buildTicks() { + const min = this.min; + const max = this.max; + const offset = this.options.offset; + const ticks = []; + let labels = this.getLabels(); + labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); + this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); + this._startValue = this.min - (offset ? 0.5 : 0); + for (let value = min; value <= max; value++) { + ticks.push({value}); + } + return ticks; + } + getLabelForValue(value) { + const labels = this.getLabels(); + if (value >= 0 && value < labels.length) { + return labels[value]; + } + return value; + } + configure() { + super.configure(); + if (!this.isHorizontal()) { + this._reversePixels = !this._reversePixels; + } + } + getPixelForValue(value) { + if (typeof value !== 'number') { + value = this.parse(value); + } + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getValueForPixel(pixel) { + return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); + } + getBasePixel() { + return this.bottom; + } +} +CategoryScale.id = 'category'; +CategoryScale.defaults = { + ticks: { + callback: CategoryScale.prototype.getLabelForValue + } +}; + +function generateTicks$1(generationOptions, dataRange) { + const ticks = []; + const MIN_SPACING = 1e-14; + const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions; + const unit = step || 1; + const maxSpaces = maxTicks - 1; + const {min: rmin, max: rmax} = dataRange; + const minDefined = !isNullOrUndef(min); + const maxDefined = !isNullOrUndef(max); + const countDefined = !isNullOrUndef(count); + const minSpacing = (rmax - rmin) / (maxDigits + 1); + let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; + let factor, niceMin, niceMax, numSpaces; + if (spacing < MIN_SPACING && !minDefined && !maxDefined) { + return [{value: rmin}, {value: rmax}]; + } + numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); + if (numSpaces > maxSpaces) { + spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; + } + if (!isNullOrUndef(precision)) { + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } + if (bounds === 'ticks') { + niceMin = Math.floor(rmin / spacing) * spacing; + niceMax = Math.ceil(rmax / spacing) * spacing; + } else { + niceMin = rmin; + niceMax = rmax; + } + if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { + numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); + spacing = (max - min) / numSpaces; + niceMin = min; + niceMax = max; + } else if (countDefined) { + niceMin = minDefined ? min : niceMin; + niceMax = maxDefined ? max : niceMax; + numSpaces = count - 1; + spacing = (niceMax - niceMin) / numSpaces; + } else { + numSpaces = (niceMax - niceMin) / spacing; + if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + } + const decimalPlaces = Math.max( + _decimalPlaces(spacing), + _decimalPlaces(niceMin) + ); + factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); + niceMin = Math.round(niceMin * factor) / factor; + niceMax = Math.round(niceMax * factor) / factor; + let j = 0; + if (minDefined) { + if (includeBounds && niceMin !== min) { + ticks.push({value: min}); + if (niceMin < min) { + j++; + } + if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { + j++; + } + } else if (niceMin < min) { + j++; + } + } + for (; j < numSpaces; ++j) { + ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); + } + if (maxDefined && includeBounds && niceMax !== max) { + if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { + ticks[ticks.length - 1].value = max; + } else { + ticks.push({value: max}); + } + } else if (!maxDefined || niceMax === max) { + ticks.push({value: niceMax}); + } + return ticks; +} +function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) { + const rad = toRadians(minRotation); + const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; + const length = 0.75 * minSpacing * ('' + value).length; + return Math.min(minSpacing / ratio, length); +} +class LinearScaleBase extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._endValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { + return null; + } + return +raw; + } + handleTickRangeOptions() { + const {beginAtZero} = this.options; + const {minDefined, maxDefined} = this.getUserBounds(); + let {min, max} = this; + const setMin = v => (min = minDefined ? min : v); + const setMax = v => (max = maxDefined ? max : v); + if (beginAtZero) { + const minSign = sign(min); + const maxSign = sign(max); + if (minSign < 0 && maxSign < 0) { + setMax(0); + } else if (minSign > 0 && maxSign > 0) { + setMin(0); + } + } + if (min === max) { + let offset = 1; + if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) { + offset = Math.abs(max * 0.05); + } + setMax(max + offset); + if (!beginAtZero) { + setMin(min - offset); + } + } + this.min = min; + this.max = max; + } + getTickLimit() { + const tickOpts = this.options.ticks; + let {maxTicksLimit, stepSize} = tickOpts; + let maxTicks; + if (stepSize) { + maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; + if (maxTicks > 1000) { + console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); + maxTicks = 1000; + } + } else { + maxTicks = this.computeTickLimit(); + maxTicksLimit = maxTicksLimit || 11; + } + if (maxTicksLimit) { + maxTicks = Math.min(maxTicksLimit, maxTicks); + } + return maxTicks; + } + computeTickLimit() { + return Number.POSITIVE_INFINITY; + } + buildTicks() { + const opts = this.options; + const tickOpts = opts.ticks; + let maxTicks = this.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + const numericGeneratorOptions = { + maxTicks, + bounds: opts.bounds, + min: opts.min, + max: opts.max, + precision: tickOpts.precision, + step: tickOpts.stepSize, + count: tickOpts.count, + maxDigits: this._maxDigits(), + horizontal: this.isHorizontal(), + minRotation: tickOpts.minRotation || 0, + includeBounds: tickOpts.includeBounds !== false + }; + const dataRange = this._range || this; + const ticks = generateTicks$1(numericGeneratorOptions, dataRange); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + configure() { + const ticks = this.ticks; + let start = this.min; + let end = this.max; + super.configure(); + if (this.options.offset && ticks.length) { + const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; + start -= offset; + end += offset; + } + this._startValue = start; + this._endValue = end; + this._valueRange = end - start; + } + getLabelForValue(value) { + return formatNumber(value, this.chart.options.locale, this.options.ticks.format); + } +} + +class LinearScale extends LinearScaleBase { + determineDataLimits() { + const {min, max} = this.getMinMax(true); + this.min = isNumberFinite(min) ? min : 0; + this.max = isNumberFinite(max) ? max : 1; + this.handleTickRangeOptions(); + } + computeTickLimit() { + const horizontal = this.isHorizontal(); + const length = horizontal ? this.width : this.height; + const minRotation = toRadians(this.options.ticks.minRotation); + const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; + const tickFont = this._resolveTickFontOptions(0); + return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); + } + getPixelForValue(value) { + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; + } +} +LinearScale.id = 'linear'; +LinearScale.defaults = { + ticks: { + callback: Ticks.formatters.numeric + } +}; + +function isMajor(tickVal) { + const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); + return remain === 1; +} +function generateTicks(generationOptions, dataRange) { + const endExp = Math.floor(log10(dataRange.max)); + const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + const ticks = []; + let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); + let exp = Math.floor(log10(tickVal)); + let significand = Math.floor(tickVal / Math.pow(10, exp)); + let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; + do { + ticks.push({value: tickVal, major: isMajor(tickVal)}); + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + precision = exp >= 0 ? 1 : precision; + } + tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; + } while (exp < endExp || (exp === endExp && significand < endSignificand)); + const lastTick = finiteOrDefault(generationOptions.max, tickVal); + ticks.push({value: lastTick, major: isMajor(tickVal)}); + return ticks; +} +class LogarithmicScale extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); + if (value === 0) { + this._zero = true; + return undefined; + } + return isNumberFinite(value) && value > 0 ? value : null; + } + determineDataLimits() { + const {min, max} = this.getMinMax(true); + this.min = isNumberFinite(min) ? Math.max(0, min) : null; + this.max = isNumberFinite(max) ? Math.max(0, max) : null; + if (this.options.beginAtZero) { + this._zero = true; + } + this.handleTickRangeOptions(); + } + handleTickRangeOptions() { + const {minDefined, maxDefined} = this.getUserBounds(); + let min = this.min; + let max = this.max; + const setMin = v => (min = minDefined ? min : v); + const setMax = v => (max = maxDefined ? max : v); + const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m); + if (min === max) { + if (min <= 0) { + setMin(1); + setMax(10); + } else { + setMin(exp(min, -1)); + setMax(exp(max, +1)); + } + } + if (min <= 0) { + setMin(exp(max, -1)); + } + if (max <= 0) { + setMax(exp(min, +1)); + } + if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) { + setMin(exp(min, -1)); + } + this.min = min; + this.max = max; + } + buildTicks() { + const opts = this.options; + const generationOptions = { + min: this._userMin, + max: this._userMax + }; + const ticks = generateTicks(generationOptions, this); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + getLabelForValue(value) { + return value === undefined + ? '0' + : formatNumber(value, this.chart.options.locale, this.options.ticks.format); + } + configure() { + const start = this.min; + super.configure(); + this._startValue = log10(start); + this._valueRange = log10(this.max) - log10(start); + } + getPixelForValue(value) { + if (value === undefined || value === 0) { + value = this.min; + } + if (value === null || isNaN(value)) { + return NaN; + } + return this.getPixelForDecimal(value === this.min + ? 0 + : (log10(value) - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + const decimal = this.getDecimalForPixel(pixel); + return Math.pow(10, this._startValue + decimal * this._valueRange); + } +} +LogarithmicScale.id = 'logarithmic'; +LogarithmicScale.defaults = { + ticks: { + callback: Ticks.formatters.logarithmic, + major: { + enabled: true + } + } +}; + +function getTickBackdropHeight(opts) { + const tickOpts = opts.ticks; + if (tickOpts.display && opts.display) { + const padding = toPadding(tickOpts.backdropPadding); + return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; + } + return 0; +} +function measureLabelSize(ctx, font, label) { + label = isArray(label) ? label : [label]; + return { + w: _longestText(ctx, font.string, label), + h: label.length * font.lineHeight + }; +} +function determineLimits(angle, pos, size, min, max) { + if (angle === min || angle === max) { + return { + start: pos - (size / 2), + end: pos + (size / 2) + }; + } else if (angle < min || angle > max) { + return { + start: pos - size, + end: pos + }; + } + return { + start: pos, + end: pos + size + }; +} +function fitWithPointLabels(scale) { + const orig = { + l: scale.left + scale._padding.left, + r: scale.right - scale._padding.right, + t: scale.top + scale._padding.top, + b: scale.bottom - scale._padding.bottom + }; + const limits = Object.assign({}, orig); + const labelSizes = []; + const padding = []; + const valueCount = scale._pointLabels.length; + const pointLabelOpts = scale.options.pointLabels; + const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; + for (let i = 0; i < valueCount; i++) { + const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); + padding[i] = opts.padding; + const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); + const plFont = toFont(opts.font); + const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); + labelSizes[i] = textSize; + const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); + const angle = Math.round(toDegrees(angleRadians)); + const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + updateLimits(limits, orig, angleRadians, hLimits, vLimits); + } + scale.setCenterPoint( + orig.l - limits.l, + limits.r - orig.r, + orig.t - limits.t, + limits.b - orig.b + ); + scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); +} +function updateLimits(limits, orig, angle, hLimits, vLimits) { + const sin = Math.abs(Math.sin(angle)); + const cos = Math.abs(Math.cos(angle)); + let x = 0; + let y = 0; + if (hLimits.start < orig.l) { + x = (orig.l - hLimits.start) / sin; + limits.l = Math.min(limits.l, orig.l - x); + } else if (hLimits.end > orig.r) { + x = (hLimits.end - orig.r) / sin; + limits.r = Math.max(limits.r, orig.r + x); + } + if (vLimits.start < orig.t) { + y = (orig.t - vLimits.start) / cos; + limits.t = Math.min(limits.t, orig.t - y); + } else if (vLimits.end > orig.b) { + y = (vLimits.end - orig.b) / cos; + limits.b = Math.max(limits.b, orig.b + y); + } +} +function buildPointLabelItems(scale, labelSizes, padding) { + const items = []; + const valueCount = scale._pointLabels.length; + const opts = scale.options; + const extra = getTickBackdropHeight(opts) / 2; + const outerDistance = scale.drawingArea; + const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0; + for (let i = 0; i < valueCount; i++) { + const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle); + const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); + const size = labelSizes[i]; + const y = yForAngle(pointLabelPosition.y, size.h, angle); + const textAlign = getTextAlignForAngle(angle); + const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); + items.push({ + x: pointLabelPosition.x, + y, + textAlign, + left, + top: y, + right: left + size.w, + bottom: y + size.h + }); + } + return items; +} +function getTextAlignForAngle(angle) { + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + return 'right'; +} +function leftForTextAlign(x, w, align) { + if (align === 'right') { + x -= w; + } else if (align === 'center') { + x -= (w / 2); + } + return x; +} +function yForAngle(y, h, angle) { + if (angle === 90 || angle === 270) { + y -= (h / 2); + } else if (angle > 270 || angle < 90) { + y -= h; + } + return y; +} +function drawPointLabels(scale, labelCount) { + const {ctx, options: {pointLabels}} = scale; + for (let i = labelCount - 1; i >= 0; i--) { + const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); + const plFont = toFont(optsAtIndex.font); + const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i]; + const {backdropColor} = optsAtIndex; + if (!isNullOrUndef(backdropColor)) { + const padding = toPadding(optsAtIndex.backdropPadding); + ctx.fillStyle = backdropColor; + ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height); + } + renderText( + ctx, + scale._pointLabels[i], + x, + y + (plFont.lineHeight / 2), + plFont, + { + color: optsAtIndex.color, + textAlign: textAlign, + textBaseline: 'middle' + } + ); + } +} +function pathRadiusLine(scale, radius, circular, labelCount) { + const {ctx} = scale; + if (circular) { + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); + } else { + let pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + for (let i = 1; i < labelCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } +} +function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { + const ctx = scale.ctx; + const circular = gridLineOpts.circular; + const {color, lineWidth} = gridLineOpts; + if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { + return; + } + ctx.save(); + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.setLineDash(gridLineOpts.borderDash); + ctx.lineDashOffset = gridLineOpts.borderDashOffset; + ctx.beginPath(); + pathRadiusLine(scale, radius, circular, labelCount); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); +} +function createPointLabelContext(parent, index, label) { + return createContext(parent, { + label, + index, + type: 'pointLabel' + }); +} +class RadialLinearScale extends LinearScaleBase { + constructor(cfg) { + super(cfg); + this.xCenter = undefined; + this.yCenter = undefined; + this.drawingArea = undefined; + this._pointLabels = []; + this._pointLabelItems = []; + } + setDimensions() { + const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); + const w = this.width = this.maxWidth - padding.width; + const h = this.height = this.maxHeight - padding.height; + this.xCenter = Math.floor(this.left + w / 2 + padding.left); + this.yCenter = Math.floor(this.top + h / 2 + padding.top); + this.drawingArea = Math.floor(Math.min(w, h) / 2); + } + determineDataLimits() { + const {min, max} = this.getMinMax(false); + this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; + this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; + this.handleTickRangeOptions(); + } + computeTickLimit() { + return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); + } + generateTickLabels(ticks) { + LinearScaleBase.prototype.generateTickLabels.call(this, ticks); + this._pointLabels = this.getLabels() + .map((value, index) => { + const label = callback(this.options.pointLabels.callback, [value, index], this); + return label || label === 0 ? label : ''; + }) + .filter((v, i) => this.chart.getDataVisibility(i)); + } + fit() { + const opts = this.options; + if (opts.display && opts.pointLabels.display) { + fitWithPointLabels(this); + } else { + this.setCenterPoint(0, 0, 0, 0); + } + } + setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { + this.xCenter += Math.floor((leftMovement - rightMovement) / 2); + this.yCenter += Math.floor((topMovement - bottomMovement) / 2); + this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); + } + getIndexAngle(index) { + const angleMultiplier = TAU / (this._pointLabels.length || 1); + const startAngle = this.options.startAngle || 0; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); + } + getDistanceFromCenterForValue(value) { + if (isNullOrUndef(value)) { + return NaN; + } + const scalingFactor = this.drawingArea / (this.max - this.min); + if (this.options.reverse) { + return (this.max - value) * scalingFactor; + } + return (value - this.min) * scalingFactor; + } + getValueForDistanceFromCenter(distance) { + if (isNullOrUndef(distance)) { + return NaN; + } + const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); + return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; + } + getPointLabelContext(index) { + const pointLabels = this._pointLabels || []; + if (index >= 0 && index < pointLabels.length) { + const pointLabel = pointLabels[index]; + return createPointLabelContext(this.getContext(), index, pointLabel); + } + } + getPointPosition(index, distanceFromCenter, additionalAngle = 0) { + const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; + return { + x: Math.cos(angle) * distanceFromCenter + this.xCenter, + y: Math.sin(angle) * distanceFromCenter + this.yCenter, + angle + }; + } + getPointPositionForValue(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + } + getBasePosition(index) { + return this.getPointPositionForValue(index || 0, this.getBaseValue()); + } + getPointLabelPosition(index) { + const {left, top, right, bottom} = this._pointLabelItems[index]; + return { + left, + top, + right, + bottom, + }; + } + drawBackground() { + const {backgroundColor, grid: {circular}} = this.options; + if (backgroundColor) { + const ctx = this.ctx; + ctx.save(); + ctx.beginPath(); + pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); + ctx.closePath(); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + } + drawGrid() { + const ctx = this.ctx; + const opts = this.options; + const {angleLines, grid} = opts; + const labelCount = this._pointLabels.length; + let i, offset, position; + if (opts.pointLabels.display) { + drawPointLabels(this, labelCount); + } + if (grid.display) { + this.ticks.forEach((tick, index) => { + if (index !== 0) { + offset = this.getDistanceFromCenterForValue(tick.value); + const optsAtIndex = grid.setContext(this.getContext(index - 1)); + drawRadiusLine(this, optsAtIndex, offset, labelCount); + } + }); + } + if (angleLines.display) { + ctx.save(); + for (i = labelCount - 1; i >= 0; i--) { + const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); + const {color, lineWidth} = optsAtIndex; + if (!lineWidth || !color) { + continue; + } + ctx.lineWidth = lineWidth; + ctx.strokeStyle = color; + ctx.setLineDash(optsAtIndex.borderDash); + ctx.lineDashOffset = optsAtIndex.borderDashOffset; + offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); + position = this.getPointPosition(i, offset); + ctx.beginPath(); + ctx.moveTo(this.xCenter, this.yCenter); + ctx.lineTo(position.x, position.y); + ctx.stroke(); + } + ctx.restore(); + } + } + drawBorder() {} + drawLabels() { + const ctx = this.ctx; + const opts = this.options; + const tickOpts = opts.ticks; + if (!tickOpts.display) { + return; + } + const startAngle = this.getIndexAngle(0); + let offset, width; + ctx.save(); + ctx.translate(this.xCenter, this.yCenter); + ctx.rotate(startAngle); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + this.ticks.forEach((tick, index) => { + if (index === 0 && !opts.reverse) { + return; + } + const optsAtIndex = tickOpts.setContext(this.getContext(index)); + const tickFont = toFont(optsAtIndex.font); + offset = this.getDistanceFromCenterForValue(this.ticks[index].value); + if (optsAtIndex.showLabelBackdrop) { + ctx.font = tickFont.string; + width = ctx.measureText(tick.label).width; + ctx.fillStyle = optsAtIndex.backdropColor; + const padding = toPadding(optsAtIndex.backdropPadding); + ctx.fillRect( + -width / 2 - padding.left, + -offset - tickFont.size / 2 - padding.top, + width + padding.width, + tickFont.size + padding.height + ); + } + renderText(ctx, tick.label, 0, -offset, tickFont, { + color: optsAtIndex.color, + }); + }); + ctx.restore(); + } + drawTitle() {} +} +RadialLinearScale.id = 'radialLinear'; +RadialLinearScale.defaults = { + display: true, + animate: true, + position: 'chartArea', + angleLines: { + display: true, + lineWidth: 1, + borderDash: [], + borderDashOffset: 0.0 + }, + grid: { + circular: false + }, + startAngle: 0, + ticks: { + showLabelBackdrop: true, + callback: Ticks.formatters.numeric + }, + pointLabels: { + backdropColor: undefined, + backdropPadding: 2, + display: true, + font: { + size: 10 + }, + callback(label) { + return label; + }, + padding: 5, + centerPointLabels: false + } +}; +RadialLinearScale.defaultRoutes = { + 'angleLines.color': 'borderColor', + 'pointLabels.color': 'color', + 'ticks.color': 'color' +}; +RadialLinearScale.descriptors = { + angleLines: { + _fallback: 'grid' + } +}; + +const INTERVALS = { + millisecond: {common: true, size: 1, steps: 1000}, + second: {common: true, size: 1000, steps: 60}, + minute: {common: true, size: 60000, steps: 60}, + hour: {common: true, size: 3600000, steps: 24}, + day: {common: true, size: 86400000, steps: 30}, + week: {common: false, size: 604800000, steps: 4}, + month: {common: true, size: 2.628e9, steps: 12}, + quarter: {common: false, size: 7.884e9, steps: 4}, + year: {common: true, size: 3.154e10} +}; +const UNITS = (Object.keys(INTERVALS)); +function sorter(a, b) { + return a - b; +} +function parse(scale, input) { + if (isNullOrUndef(input)) { + return null; + } + const adapter = scale._adapter; + const {parser, round, isoWeekday} = scale._parseOpts; + let value = input; + if (typeof parser === 'function') { + value = parser(value); + } + if (!isNumberFinite(value)) { + value = typeof parser === 'string' + ? adapter.parse(value, parser) + : adapter.parse(value); + } + if (value === null) { + return null; + } + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) + ? adapter.startOf(value, 'isoWeek', isoWeekday) + : adapter.startOf(value, round); + } + return +value; +} +function determineUnitForAutoTicks(minUnit, min, max, capacity) { + const ilen = UNITS.length; + for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { + const interval = INTERVALS[UNITS[i]]; + const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} +function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { + const unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} +function determineMajorUnit(unit) { + for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} +function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + const {lo, hi} = _lookup(timestamps, time); + const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} +function setMajorTicks(scale, ticks, map, majorUnit) { + const adapter = scale._adapter; + const first = +adapter.startOf(ticks[0].value, majorUnit); + const last = ticks[ticks.length - 1].value; + let major, index; + for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} +function ticksFromTimestamps(scale, values, majorUnit) { + const ticks = []; + const map = {}; + const ilen = values.length; + let i, value; + for (i = 0; i < ilen; ++i) { + value = values[i]; + map[value] = i; + ticks.push({ + value, + major: false + }); + } + return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); +} +class TimeScale extends Scale { + constructor(props) { + super(props); + this._cache = { + data: [], + labels: [], + all: [] + }; + this._unit = 'day'; + this._majorUnit = undefined; + this._offsets = {}; + this._normalized = false; + this._parseOpts = undefined; + } + init(scaleOpts, opts) { + const time = scaleOpts.time || (scaleOpts.time = {}); + const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); + mergeIf(time.displayFormats, adapter.formats()); + this._parseOpts = { + parser: time.parser, + round: time.round, + isoWeekday: time.isoWeekday + }; + super.init(scaleOpts); + this._normalized = opts.normalized; + } + parse(raw, index) { + if (raw === undefined) { + return null; + } + return parse(this, raw); + } + beforeLayout() { + super.beforeLayout(); + this._cache = { + data: [], + labels: [], + all: [] + }; + } + determineDataLimits() { + const options = this.options; + const adapter = this._adapter; + const unit = options.time.unit || 'day'; + let {min, max, minDefined, maxDefined} = this.getUserBounds(); + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(this._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(this.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + this.min = Math.min(min, max - 1); + this.max = Math.max(min + 1, max); + } + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return {min, max}; + } + buildTicks() { + const options = this.options; + const timeOpts = options.time; + const tickOpts = options.ticks; + const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + this.min = this._userMin || timestamps[0]; + this.max = this._userMax || timestamps[timestamps.length - 1]; + } + const min = this.min; + const max = this.max; + const ticks = _filterBetween(timestamps, min, max); + this._unit = timeOpts.unit || (tickOpts.autoSkip + ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) + : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); + this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined + : determineMajorUnit(this._unit); + this.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(this, ticks, this._majorUnit); + } + initOffsets(timestamps) { + let start = 0; + let end = 0; + let first, last; + if (this.options.offset && timestamps.length) { + first = this.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (this.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = this.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + const limit = timestamps.length < 3 ? 0.5 : 0.25; + start = _limitValue(start, 0, limit); + end = _limitValue(end, 0, limit); + this._offsets = {start, end, factor: 1 / (start + 1 + end)}; + } + _generate() { + const adapter = this._adapter; + const min = this.min; + const max = this.max; + const options = this.options; + const timeOpts = options.time; + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); + const stepSize = valueOrDefault(timeOpts.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const hasWeekday = isNumber(weekday) || weekday === true; + const ticks = {}; + let first = min; + let time, count; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); + for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) { + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks' || count === 1) { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); + } + getLabelForValue(value) { + const adapter = this._adapter; + const timeOpts = this.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); + } + _tickFormatFunction(time, index, ticks, format) { + const options = this.options; + const formats = options.time.displayFormats; + const unit = this._unit; + const majorUnit = this._majorUnit; + const minorFormat = unit && formats[unit]; + const majorFormat = majorUnit && formats[majorUnit]; + const tick = ticks[index]; + const major = majorUnit && majorFormat && tick && tick.major; + const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat)); + const formatter = options.ticks.callback; + return formatter ? callback(formatter, [label, index, ticks], this) : label; + } + generateTickLabels(ticks) { + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } + } + getDecimalForValue(value) { + return value === null ? NaN : (value - this.min) / (this.max - this.min); + } + getPixelForValue(value) { + const offsets = this._offsets; + const pos = this.getDecimalForValue(value); + return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return this.min + pos * (this.max - this.min); + } + _getLabelSize(label) { + const ticksOpts = this.options.ticks; + const tickLabelWidth = this.ctx.measureText(label).width; + const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + const cosRotation = Math.cos(angle); + const sinRotation = Math.sin(angle); + const tickFontSize = this._resolveTickFontOptions(0).size; + return { + w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), + h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) + }; + } + _getLabelCapacity(exampleTime) { + const timeOpts = this.options.time; + const displayFormats = timeOpts.displayFormats; + const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format); + const size = this._getLabelSize(exampleLabel); + const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + getDataTimestamps() { + let timestamps = this._cache.data || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const metas = this.getMatchingVisibleMetas(); + if (this._normalized && metas.length) { + return (this._cache.data = metas[0].controller.getAllParsedValues(this)); + } + for (i = 0, ilen = metas.length; i < ilen; ++i) { + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); + } + return (this._cache.data = this.normalize(timestamps)); + } + getLabelTimestamps() { + const timestamps = this._cache.labels || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const labels = this.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(parse(this, labels[i])); + } + return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps)); + } + normalize(values) { + return _arrayUnique(values.sort(sorter)); + } +} +TimeScale.id = 'time'; +TimeScale.defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + major: { + enabled: false + } + } +}; + +function interpolate(table, val, reverse) { + let lo = 0; + let hi = table.length - 1; + let prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + if (val >= table[lo].pos && val <= table[hi].pos) { + ({lo, hi} = _lookupByKey(table, 'pos', val)); + } + ({pos: prevSource, time: prevTarget} = table[lo]); + ({pos: nextSource, time: nextTarget} = table[hi]); + } else { + if (val >= table[lo].time && val <= table[hi].time) { + ({lo, hi} = _lookupByKey(table, 'time', val)); + } + ({time: prevSource, pos: prevTarget} = table[lo]); + ({time: nextSource, pos: nextTarget} = table[hi]); + } + const span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; +} +class TimeSeriesScale extends TimeScale { + constructor(props) { + super(props); + this._table = []; + this._minPos = undefined; + this._tableRange = undefined; + } + initOffsets() { + const timestamps = this._getTimestampsForTable(); + const table = this._table = this.buildLookupTable(timestamps); + this._minPos = interpolate(table, this.min); + this._tableRange = interpolate(table, this.max) - this._minPos; + super.initOffsets(timestamps); + } + buildLookupTable(timestamps) { + const {min, max} = this; + const items = []; + const table = []; + let i, ilen, prev, curr, next; + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr >= min && curr <= max) { + items.push(curr); + } + } + if (items.length < 2) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + if (Math.round((next + prev) / 2) !== curr) { + table.push({time: curr, pos: i / (ilen - 1)}); + } + } + return table; + } + _getTimestampsForTable() { + let timestamps = this._cache.all || []; + if (timestamps.length) { + return timestamps; + } + const data = this.getDataTimestamps(); + const label = this.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = this.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = this._cache.all = timestamps; + return timestamps; + } + getDecimalForValue(value) { + return (interpolate(this._table, value) - this._minPos) / this._tableRange; + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(this._table, decimal * this._tableRange + this._minPos, true); + } +} +TimeSeriesScale.id = 'timeseries'; +TimeSeriesScale.defaults = TimeScale.defaults; + +var scales = /*#__PURE__*/Object.freeze({ +__proto__: null, +CategoryScale: CategoryScale, +LinearScale: LinearScale, +LogarithmicScale: LogarithmicScale, +RadialLinearScale: RadialLinearScale, +TimeScale: TimeScale, +TimeSeriesScale: TimeSeriesScale +}); + +const registerables = [ + controllers, + elements, + plugins, + scales, +]; + +export { Animation, Animations, ArcElement, BarController, BarElement, BasePlatform, BasicPlatform, BubbleController, CategoryScale, Chart, DatasetController, plugin_decimation as Decimation, DomPlatform, DoughnutController, Element, plugin_filler as Filler, Interaction, plugin_legend as Legend, LineController, LineElement, LinearScale, LogarithmicScale, PieController, PointElement, PolarAreaController, RadarController, RadialLinearScale, Scale, ScatterController, plugin_subtitle as SubTitle, Ticks, TimeScale, TimeSeriesScale, plugin_title as Title, plugin_tooltip as Tooltip, adapters as _adapters, _detectPlatform, animator, controllers, elements, layouts, plugins, registerables, registry, scales }; diff --git a/node_modules/chart.js/dist/chart.js b/node_modules/chart.js/dist/chart.js new file mode 100644 index 00000000..58990616 --- /dev/null +++ b/node_modules/chart.js/dist/chart.js @@ -0,0 +1,13269 @@ +/*! + * Chart.js v3.7.1 + * https://www.chartjs.org + * (c) 2022 Chart.js Contributors + * Released under the MIT License + */ +(function (global, factory) { +typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : +typeof define === 'function' && define.amd ? define(factory) : +(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chart = factory()); +})(this, (function () { 'use strict'; + +function fontString(pixelSize, fontStyle, fontFamily) { + return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; +} +const requestAnimFrame = (function() { + if (typeof window === 'undefined') { + return function(callback) { + return callback(); + }; + } + return window.requestAnimationFrame; +}()); +function throttled(fn, thisArg, updateFn) { + const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args)); + let ticking = false; + let args = []; + return function(...rest) { + args = updateArgs(rest); + if (!ticking) { + ticking = true; + requestAnimFrame.call(window, () => { + ticking = false; + fn.apply(thisArg, args); + }); + } + }; +} +function debounce(fn, delay) { + let timeout; + return function(...args) { + if (delay) { + clearTimeout(timeout); + timeout = setTimeout(fn, delay, args); + } else { + fn.apply(this, args); + } + return delay; + }; +} +const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; +const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; +const _textX = (align, left, right, rtl) => { + const check = rtl ? 'left' : 'right'; + return align === check ? right : align === 'center' ? (left + right) / 2 : left; +}; + +class Animator { + constructor() { + this._request = null; + this._charts = new Map(); + this._running = false; + this._lastDate = undefined; + } + _notify(chart, anims, date, type) { + const callbacks = anims.listeners[type]; + const numSteps = anims.duration; + callbacks.forEach(fn => fn({ + chart, + initial: anims.initial, + numSteps, + currentStep: Math.min(date - anims.start, numSteps) + })); + } + _refresh() { + if (this._request) { + return; + } + this._running = true; + this._request = requestAnimFrame.call(window, () => { + this._update(); + this._request = null; + if (this._running) { + this._refresh(); + } + }); + } + _update(date = Date.now()) { + let remaining = 0; + this._charts.forEach((anims, chart) => { + if (!anims.running || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + let draw = false; + let item; + for (; i >= 0; --i) { + item = items[i]; + if (item._active) { + if (item._total > anims.duration) { + anims.duration = item._total; + } + item.tick(date); + draw = true; + } else { + items[i] = items[items.length - 1]; + items.pop(); + } + } + if (draw) { + chart.draw(); + this._notify(chart, anims, date, 'progress'); + } + if (!items.length) { + anims.running = false; + this._notify(chart, anims, date, 'complete'); + anims.initial = false; + } + remaining += items.length; + }); + this._lastDate = date; + if (remaining === 0) { + this._running = false; + } + } + _getAnims(chart) { + const charts = this._charts; + let anims = charts.get(chart); + if (!anims) { + anims = { + running: false, + initial: true, + items: [], + listeners: { + complete: [], + progress: [] + } + }; + charts.set(chart, anims); + } + return anims; + } + listen(chart, event, cb) { + this._getAnims(chart).listeners[event].push(cb); + } + add(chart, items) { + if (!items || !items.length) { + return; + } + this._getAnims(chart).items.push(...items); + } + has(chart) { + return this._getAnims(chart).items.length > 0; + } + start(chart) { + const anims = this._charts.get(chart); + if (!anims) { + return; + } + anims.running = true; + anims.start = Date.now(); + anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); + this._refresh(); + } + running(chart) { + if (!this._running) { + return false; + } + const anims = this._charts.get(chart); + if (!anims || !anims.running || !anims.items.length) { + return false; + } + return true; + } + stop(chart) { + const anims = this._charts.get(chart); + if (!anims || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + for (; i >= 0; --i) { + items[i].cancel(); + } + anims.items = []; + this._notify(chart, anims, Date.now(), 'complete'); + } + remove(chart) { + return this._charts.delete(chart); + } +} +var animator = new Animator(); + +/*! + * @kurkle/color v0.1.9 + * https://github.com/kurkle/color#readme + * (c) 2020 Jukka Kurkela + * Released under the MIT License + */ +const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; +const hex = '0123456789ABCDEF'; +const h1 = (b) => hex[b & 0xF]; +const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; +const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF)); +function isShort(v) { + return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); +} +function hexParse(str) { + var len = str.length; + var ret; + if (str[0] === '#') { + if (len === 4 || len === 5) { + ret = { + r: 255 & map$1[str[1]] * 17, + g: 255 & map$1[str[2]] * 17, + b: 255 & map$1[str[3]] * 17, + a: len === 5 ? map$1[str[4]] * 17 : 255 + }; + } else if (len === 7 || len === 9) { + ret = { + r: map$1[str[1]] << 4 | map$1[str[2]], + g: map$1[str[3]] << 4 | map$1[str[4]], + b: map$1[str[5]] << 4 | map$1[str[6]], + a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255 + }; + } + } + return ret; +} +function hexString(v) { + var f = isShort(v) ? h1 : h2; + return v + ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') + : v; +} +function round(v) { + return v + 0.5 | 0; +} +const lim = (v, l, h) => Math.max(Math.min(v, h), l); +function p2b(v) { + return lim(round(v * 2.55), 0, 255); +} +function n2b(v) { + return lim(round(v * 255), 0, 255); +} +function b2n(v) { + return lim(round(v / 2.55) / 100, 0, 1); +} +function n2p(v) { + return lim(round(v * 100), 0, 100); +} +const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; +function rgbParse(str) { + const m = RGB_RE.exec(str); + let a = 255; + let r, g, b; + if (!m) { + return; + } + if (m[7] !== r) { + const v = +m[7]; + a = 255 & (m[8] ? p2b(v) : v * 255); + } + r = +m[1]; + g = +m[3]; + b = +m[5]; + r = 255 & (m[2] ? p2b(r) : r); + g = 255 & (m[4] ? p2b(g) : g); + b = 255 & (m[6] ? p2b(b) : b); + return { + r: r, + g: g, + b: b, + a: a + }; +} +function rgbString(v) { + return v && ( + v.a < 255 + ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` + : `rgb(${v.r}, ${v.g}, ${v.b})` + ); +} +const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; +function hsl2rgbn(h, s, l) { + const a = s * Math.min(l, 1 - l); + const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return [f(0), f(8), f(4)]; +} +function hsv2rgbn(h, s, v) { + const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); + return [f(5), f(3), f(1)]; +} +function hwb2rgbn(h, w, b) { + const rgb = hsl2rgbn(h, 1, 0.5); + let i; + if (w + b > 1) { + i = 1 / (w + b); + w *= i; + b *= i; + } + for (i = 0; i < 3; i++) { + rgb[i] *= 1 - w - b; + rgb[i] += w; + } + return rgb; +} +function rgb2hsl(v) { + const range = 255; + const r = v.r / range; + const g = v.g / range; + const b = v.b / range; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + const l = (max + min) / 2; + let h, s, d; + if (max !== min) { + d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + h = max === r + ? ((g - b) / d) + (g < b ? 6 : 0) + : max === g + ? (b - r) / d + 2 + : (r - g) / d + 4; + h = h * 60 + 0.5; + } + return [h | 0, s || 0, l]; +} +function calln(f, a, b, c) { + return ( + Array.isArray(a) + ? f(a[0], a[1], a[2]) + : f(a, b, c) + ).map(n2b); +} +function hsl2rgb(h, s, l) { + return calln(hsl2rgbn, h, s, l); +} +function hwb2rgb(h, w, b) { + return calln(hwb2rgbn, h, w, b); +} +function hsv2rgb(h, s, v) { + return calln(hsv2rgbn, h, s, v); +} +function hue(h) { + return (h % 360 + 360) % 360; +} +function hueParse(str) { + const m = HUE_RE.exec(str); + let a = 255; + let v; + if (!m) { + return; + } + if (m[5] !== v) { + a = m[6] ? p2b(+m[5]) : n2b(+m[5]); + } + const h = hue(+m[2]); + const p1 = +m[3] / 100; + const p2 = +m[4] / 100; + if (m[1] === 'hwb') { + v = hwb2rgb(h, p1, p2); + } else if (m[1] === 'hsv') { + v = hsv2rgb(h, p1, p2); + } else { + v = hsl2rgb(h, p1, p2); + } + return { + r: v[0], + g: v[1], + b: v[2], + a: a + }; +} +function rotate(v, deg) { + var h = rgb2hsl(v); + h[0] = hue(h[0] + deg); + h = hsl2rgb(h); + v.r = h[0]; + v.g = h[1]; + v.b = h[2]; +} +function hslString(v) { + if (!v) { + return; + } + const a = rgb2hsl(v); + const h = a[0]; + const s = n2p(a[1]); + const l = n2p(a[2]); + return v.a < 255 + ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` + : `hsl(${h}, ${s}%, ${l}%)`; +} +const map$1$1 = { + x: 'dark', + Z: 'light', + Y: 're', + X: 'blu', + W: 'gr', + V: 'medium', + U: 'slate', + A: 'ee', + T: 'ol', + S: 'or', + B: 'ra', + C: 'lateg', + D: 'ights', + R: 'in', + Q: 'turquois', + E: 'hi', + P: 'ro', + O: 'al', + N: 'le', + M: 'de', + L: 'yello', + F: 'en', + K: 'ch', + G: 'arks', + H: 'ea', + I: 'ightg', + J: 'wh' +}; +const names = { + OiceXe: 'f0f8ff', + antiquewEte: 'faebd7', + aqua: 'ffff', + aquamarRe: '7fffd4', + azuY: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '0', + blanKedOmond: 'ffebcd', + Xe: 'ff', + XeviTet: '8a2be2', + bPwn: 'a52a2a', + burlywood: 'deb887', + caMtXe: '5f9ea0', + KartYuse: '7fff00', + KocTate: 'd2691e', + cSO: 'ff7f50', + cSnflowerXe: '6495ed', + cSnsilk: 'fff8dc', + crimson: 'dc143c', + cyan: 'ffff', + xXe: '8b', + xcyan: '8b8b', + xgTMnPd: 'b8860b', + xWay: 'a9a9a9', + xgYF: '6400', + xgYy: 'a9a9a9', + xkhaki: 'bdb76b', + xmagFta: '8b008b', + xTivegYF: '556b2f', + xSange: 'ff8c00', + xScEd: '9932cc', + xYd: '8b0000', + xsOmon: 'e9967a', + xsHgYF: '8fbc8f', + xUXe: '483d8b', + xUWay: '2f4f4f', + xUgYy: '2f4f4f', + xQe: 'ced1', + xviTet: '9400d3', + dAppRk: 'ff1493', + dApskyXe: 'bfff', + dimWay: '696969', + dimgYy: '696969', + dodgerXe: '1e90ff', + fiYbrick: 'b22222', + flSOwEte: 'fffaf0', + foYstWAn: '228b22', + fuKsia: 'ff00ff', + gaRsbSo: 'dcdcdc', + ghostwEte: 'f8f8ff', + gTd: 'ffd700', + gTMnPd: 'daa520', + Way: '808080', + gYF: '8000', + gYFLw: 'adff2f', + gYy: '808080', + honeyMw: 'f0fff0', + hotpRk: 'ff69b4', + RdianYd: 'cd5c5c', + Rdigo: '4b0082', + ivSy: 'fffff0', + khaki: 'f0e68c', + lavFMr: 'e6e6fa', + lavFMrXsh: 'fff0f5', + lawngYF: '7cfc00', + NmoncEffon: 'fffacd', + ZXe: 'add8e6', + ZcSO: 'f08080', + Zcyan: 'e0ffff', + ZgTMnPdLw: 'fafad2', + ZWay: 'd3d3d3', + ZgYF: '90ee90', + ZgYy: 'd3d3d3', + ZpRk: 'ffb6c1', + ZsOmon: 'ffa07a', + ZsHgYF: '20b2aa', + ZskyXe: '87cefa', + ZUWay: '778899', + ZUgYy: '778899', + ZstAlXe: 'b0c4de', + ZLw: 'ffffe0', + lime: 'ff00', + limegYF: '32cd32', + lRF: 'faf0e6', + magFta: 'ff00ff', + maPon: '800000', + VaquamarRe: '66cdaa', + VXe: 'cd', + VScEd: 'ba55d3', + VpurpN: '9370db', + VsHgYF: '3cb371', + VUXe: '7b68ee', + VsprRggYF: 'fa9a', + VQe: '48d1cc', + VviTetYd: 'c71585', + midnightXe: '191970', + mRtcYam: 'f5fffa', + mistyPse: 'ffe4e1', + moccasR: 'ffe4b5', + navajowEte: 'ffdead', + navy: '80', + Tdlace: 'fdf5e6', + Tive: '808000', + TivedBb: '6b8e23', + Sange: 'ffa500', + SangeYd: 'ff4500', + ScEd: 'da70d6', + pOegTMnPd: 'eee8aa', + pOegYF: '98fb98', + pOeQe: 'afeeee', + pOeviTetYd: 'db7093', + papayawEp: 'ffefd5', + pHKpuff: 'ffdab9', + peru: 'cd853f', + pRk: 'ffc0cb', + plum: 'dda0dd', + powMrXe: 'b0e0e6', + purpN: '800080', + YbeccapurpN: '663399', + Yd: 'ff0000', + Psybrown: 'bc8f8f', + PyOXe: '4169e1', + saddNbPwn: '8b4513', + sOmon: 'fa8072', + sandybPwn: 'f4a460', + sHgYF: '2e8b57', + sHshell: 'fff5ee', + siFna: 'a0522d', + silver: 'c0c0c0', + skyXe: '87ceeb', + UXe: '6a5acd', + UWay: '708090', + UgYy: '708090', + snow: 'fffafa', + sprRggYF: 'ff7f', + stAlXe: '4682b4', + tan: 'd2b48c', + teO: '8080', + tEstN: 'd8bfd8', + tomato: 'ff6347', + Qe: '40e0d0', + viTet: 'ee82ee', + JHt: 'f5deb3', + wEte: 'ffffff', + wEtesmoke: 'f5f5f5', + Lw: 'ffff00', + LwgYF: '9acd32' +}; +function unpack() { + const unpacked = {}; + const keys = Object.keys(names); + const tkeys = Object.keys(map$1$1); + let i, j, k, ok, nk; + for (i = 0; i < keys.length; i++) { + ok = nk = keys[i]; + for (j = 0; j < tkeys.length; j++) { + k = tkeys[j]; + nk = nk.replace(k, map$1$1[k]); + } + k = parseInt(names[ok], 16); + unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; + } + return unpacked; +} +let names$1; +function nameParse(str) { + if (!names$1) { + names$1 = unpack(); + names$1.transparent = [0, 0, 0, 0]; + } + const a = names$1[str.toLowerCase()]; + return a && { + r: a[0], + g: a[1], + b: a[2], + a: a.length === 4 ? a[3] : 255 + }; +} +function modHSL(v, i, ratio) { + if (v) { + let tmp = rgb2hsl(v); + tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); + tmp = hsl2rgb(tmp); + v.r = tmp[0]; + v.g = tmp[1]; + v.b = tmp[2]; + } +} +function clone$1(v, proto) { + return v ? Object.assign(proto || {}, v) : v; +} +function fromObject(input) { + var v = {r: 0, g: 0, b: 0, a: 255}; + if (Array.isArray(input)) { + if (input.length >= 3) { + v = {r: input[0], g: input[1], b: input[2], a: 255}; + if (input.length > 3) { + v.a = n2b(input[3]); + } + } + } else { + v = clone$1(input, {r: 0, g: 0, b: 0, a: 1}); + v.a = n2b(v.a); + } + return v; +} +function functionParse(str) { + if (str.charAt(0) === 'r') { + return rgbParse(str); + } + return hueParse(str); +} +class Color { + constructor(input) { + if (input instanceof Color) { + return input; + } + const type = typeof input; + let v; + if (type === 'object') { + v = fromObject(input); + } else if (type === 'string') { + v = hexParse(input) || nameParse(input) || functionParse(input); + } + this._rgb = v; + this._valid = !!v; + } + get valid() { + return this._valid; + } + get rgb() { + var v = clone$1(this._rgb); + if (v) { + v.a = b2n(v.a); + } + return v; + } + set rgb(obj) { + this._rgb = fromObject(obj); + } + rgbString() { + return this._valid ? rgbString(this._rgb) : this._rgb; + } + hexString() { + return this._valid ? hexString(this._rgb) : this._rgb; + } + hslString() { + return this._valid ? hslString(this._rgb) : this._rgb; + } + mix(color, weight) { + const me = this; + if (color) { + const c1 = me.rgb; + const c2 = color.rgb; + let w2; + const p = weight === w2 ? 0.5 : weight; + const w = 2 * p - 1; + const a = c1.a - c2.a; + const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + w2 = 1 - w1; + c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; + c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; + c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; + c1.a = p * c1.a + (1 - p) * c2.a; + me.rgb = c1; + } + return me; + } + clone() { + return new Color(this.rgb); + } + alpha(a) { + this._rgb.a = n2b(a); + return this; + } + clearer(ratio) { + const rgb = this._rgb; + rgb.a *= 1 - ratio; + return this; + } + greyscale() { + const rgb = this._rgb; + const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); + rgb.r = rgb.g = rgb.b = val; + return this; + } + opaquer(ratio) { + const rgb = this._rgb; + rgb.a *= 1 + ratio; + return this; + } + negate() { + const v = this._rgb; + v.r = 255 - v.r; + v.g = 255 - v.g; + v.b = 255 - v.b; + return this; + } + lighten(ratio) { + modHSL(this._rgb, 2, ratio); + return this; + } + darken(ratio) { + modHSL(this._rgb, 2, -ratio); + return this; + } + saturate(ratio) { + modHSL(this._rgb, 1, ratio); + return this; + } + desaturate(ratio) { + modHSL(this._rgb, 1, -ratio); + return this; + } + rotate(deg) { + rotate(this._rgb, deg); + return this; + } +} +function index_esm(input) { + return new Color(input); +} + +const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern; +function color(value) { + return isPatternOrGradient(value) ? value : index_esm(value); +} +function getHoverColor(value) { + return isPatternOrGradient(value) + ? value + : index_esm(value).saturate(0.5).darken(0.1).hexString(); +} + +function noop() {} +const uid = (function() { + let id = 0; + return function() { + return id++; + }; +}()); +function isNullOrUndef(value) { + return value === null || typeof value === 'undefined'; +} +function isArray(value) { + if (Array.isArray && Array.isArray(value)) { + return true; + } + const type = Object.prototype.toString.call(value); + if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { + return true; + } + return false; +} +function isObject(value) { + return value !== null && Object.prototype.toString.call(value) === '[object Object]'; +} +const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value); +function finiteOrDefault(value, defaultValue) { + return isNumberFinite(value) ? value : defaultValue; +} +function valueOrDefault(value, defaultValue) { + return typeof value === 'undefined' ? defaultValue : value; +} +const toPercentage = (value, dimension) => + typeof value === 'string' && value.endsWith('%') ? + parseFloat(value) / 100 + : value / dimension; +const toDimension = (value, dimension) => + typeof value === 'string' && value.endsWith('%') ? + parseFloat(value) / 100 * dimension + : +value; +function callback(fn, args, thisArg) { + if (fn && typeof fn.call === 'function') { + return fn.apply(thisArg, args); + } +} +function each(loopable, fn, thisArg, reverse) { + let i, len, keys; + if (isArray(loopable)) { + len = loopable.length; + if (reverse) { + for (i = len - 1; i >= 0; i--) { + fn.call(thisArg, loopable[i], i); + } + } else { + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[i], i); + } + } + } else if (isObject(loopable)) { + keys = Object.keys(loopable); + len = keys.length; + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[keys[i]], keys[i]); + } + } +} +function _elementsEqual(a0, a1) { + let i, ilen, v0, v1; + if (!a0 || !a1 || a0.length !== a1.length) { + return false; + } + for (i = 0, ilen = a0.length; i < ilen; ++i) { + v0 = a0[i]; + v1 = a1[i]; + if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { + return false; + } + } + return true; +} +function clone(source) { + if (isArray(source)) { + return source.map(clone); + } + if (isObject(source)) { + const target = Object.create(null); + const keys = Object.keys(source); + const klen = keys.length; + let k = 0; + for (; k < klen; ++k) { + target[keys[k]] = clone(source[keys[k]]); + } + return target; + } + return source; +} +function isValidKey(key) { + return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; +} +function _merger(key, target, source, options) { + if (!isValidKey(key)) { + return; + } + const tval = target[key]; + const sval = source[key]; + if (isObject(tval) && isObject(sval)) { + merge(tval, sval, options); + } else { + target[key] = clone(sval); + } +} +function merge(target, source, options) { + const sources = isArray(source) ? source : [source]; + const ilen = sources.length; + if (!isObject(target)) { + return target; + } + options = options || {}; + const merger = options.merger || _merger; + for (let i = 0; i < ilen; ++i) { + source = sources[i]; + if (!isObject(source)) { + continue; + } + const keys = Object.keys(source); + for (let k = 0, klen = keys.length; k < klen; ++k) { + merger(keys[k], target, source, options); + } + } + return target; +} +function mergeIf(target, source) { + return merge(target, source, {merger: _mergerIf}); +} +function _mergerIf(key, target, source) { + if (!isValidKey(key)) { + return; + } + const tval = target[key]; + const sval = source[key]; + if (isObject(tval) && isObject(sval)) { + mergeIf(tval, sval); + } else if (!Object.prototype.hasOwnProperty.call(target, key)) { + target[key] = clone(sval); + } +} +function _deprecated(scope, value, previous, current) { + if (value !== undefined) { + console.warn(scope + ': "' + previous + + '" is deprecated. Please use "' + current + '" instead'); + } +} +const emptyString = ''; +const dot = '.'; +function indexOfDotOrLength(key, start) { + const idx = key.indexOf(dot, start); + return idx === -1 ? key.length : idx; +} +function resolveObjectKey(obj, key) { + if (key === emptyString) { + return obj; + } + let pos = 0; + let idx = indexOfDotOrLength(key, pos); + while (obj && idx > pos) { + obj = obj[key.substr(pos, idx - pos)]; + pos = idx + 1; + idx = indexOfDotOrLength(key, pos); + } + return obj; +} +function _capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); +} +const defined = (value) => typeof value !== 'undefined'; +const isFunction = (value) => typeof value === 'function'; +const setsEqual = (a, b) => { + if (a.size !== b.size) { + return false; + } + for (const item of a) { + if (!b.has(item)) { + return false; + } + } + return true; +}; +function _isClickEvent(e) { + return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; +} + +const overrides = Object.create(null); +const descriptors = Object.create(null); +function getScope$1(node, key) { + if (!key) { + return node; + } + const keys = key.split('.'); + for (let i = 0, n = keys.length; i < n; ++i) { + const k = keys[i]; + node = node[k] || (node[k] = Object.create(null)); + } + return node; +} +function set(root, scope, values) { + if (typeof scope === 'string') { + return merge(getScope$1(root, scope), values); + } + return merge(getScope$1(root, ''), scope); +} +class Defaults { + constructor(_descriptors) { + this.animation = undefined; + this.backgroundColor = 'rgba(0,0,0,0.1)'; + this.borderColor = 'rgba(0,0,0,0.1)'; + this.color = '#666'; + this.datasets = {}; + this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); + this.elements = {}; + this.events = [ + 'mousemove', + 'mouseout', + 'click', + 'touchstart', + 'touchmove' + ]; + this.font = { + family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + size: 12, + style: 'normal', + lineHeight: 1.2, + weight: null + }; + this.hover = {}; + this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); + this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); + this.hoverColor = (ctx, options) => getHoverColor(options.color); + this.indexAxis = 'x'; + this.interaction = { + mode: 'nearest', + intersect: true + }; + this.maintainAspectRatio = true; + this.onHover = null; + this.onClick = null; + this.parsing = true; + this.plugins = {}; + this.responsive = true; + this.scale = undefined; + this.scales = {}; + this.showLine = true; + this.drawActiveElementsOnTop = true; + this.describe(_descriptors); + } + set(scope, values) { + return set(this, scope, values); + } + get(scope) { + return getScope$1(this, scope); + } + describe(scope, values) { + return set(descriptors, scope, values); + } + override(scope, values) { + return set(overrides, scope, values); + } + route(scope, name, targetScope, targetName) { + const scopeObject = getScope$1(this, scope); + const targetScopeObject = getScope$1(this, targetScope); + const privateName = '_' + name; + Object.defineProperties(scopeObject, { + [privateName]: { + value: scopeObject[name], + writable: true + }, + [name]: { + enumerable: true, + get() { + const local = this[privateName]; + const target = targetScopeObject[targetName]; + if (isObject(local)) { + return Object.assign({}, target, local); + } + return valueOrDefault(local, target); + }, + set(value) { + this[privateName] = value; + } + } + }); + } +} +var defaults = new Defaults({ + _scriptable: (name) => !name.startsWith('on'), + _indexable: (name) => name !== 'events', + hover: { + _fallback: 'interaction' + }, + interaction: { + _scriptable: false, + _indexable: false, + } +}); + +const PI = Math.PI; +const TAU = 2 * PI; +const PITAU = TAU + PI; +const INFINITY = Number.POSITIVE_INFINITY; +const RAD_PER_DEG = PI / 180; +const HALF_PI = PI / 2; +const QUARTER_PI = PI / 4; +const TWO_THIRDS_PI = PI * 2 / 3; +const log10 = Math.log10; +const sign = Math.sign; +function niceNum(range) { + const roundedRange = Math.round(range); + range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; + const niceRange = Math.pow(10, Math.floor(log10(range))); + const fraction = range / niceRange; + const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; + return niceFraction * niceRange; +} +function _factorize(value) { + const result = []; + const sqrt = Math.sqrt(value); + let i; + for (i = 1; i < sqrt; i++) { + if (value % i === 0) { + result.push(i); + result.push(value / i); + } + } + if (sqrt === (sqrt | 0)) { + result.push(sqrt); + } + result.sort((a, b) => a - b).pop(); + return result; +} +function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} +function almostEquals(x, y, epsilon) { + return Math.abs(x - y) < epsilon; +} +function almostWhole(x, epsilon) { + const rounded = Math.round(x); + return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x); +} +function _setMinAndMaxByKey(array, target, property) { + let i, ilen, value; + for (i = 0, ilen = array.length; i < ilen; i++) { + value = array[i][property]; + if (!isNaN(value)) { + target.min = Math.min(target.min, value); + target.max = Math.max(target.max, value); + } + } +} +function toRadians(degrees) { + return degrees * (PI / 180); +} +function toDegrees(radians) { + return radians * (180 / PI); +} +function _decimalPlaces(x) { + if (!isNumberFinite(x)) { + return; + } + let e = 1; + let p = 0; + while (Math.round(x * e) / e !== x) { + e *= 10; + p++; + } + return p; +} +function getAngleFromPoint(centrePoint, anglePoint) { + const distanceFromXCenter = anglePoint.x - centrePoint.x; + const distanceFromYCenter = anglePoint.y - centrePoint.y; + const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); + if (angle < (-0.5 * PI)) { + angle += TAU; + } + return { + angle, + distance: radialDistanceFromCenter + }; +} +function distanceBetweenPoints(pt1, pt2) { + return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); +} +function _angleDiff(a, b) { + return (a - b + PITAU) % TAU - PI; +} +function _normalizeAngle(a) { + return (a % TAU + TAU) % TAU; +} +function _angleBetween(angle, start, end, sameAngleIsFullCircle) { + const a = _normalizeAngle(angle); + const s = _normalizeAngle(start); + const e = _normalizeAngle(end); + const angleToStart = _normalizeAngle(s - a); + const angleToEnd = _normalizeAngle(e - a); + const startToAngle = _normalizeAngle(a - s); + const endToAngle = _normalizeAngle(a - e); + return a === s || a === e || (sameAngleIsFullCircle && s === e) + || (angleToStart > angleToEnd && startToAngle < endToAngle); +} +function _limitValue(value, min, max) { + return Math.max(min, Math.min(max, value)); +} +function _int16Range(value) { + return _limitValue(value, -32768, 32767); +} +function _isBetween(value, start, end, epsilon = 1e-6) { + return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; +} + +function toFontString(font) { + if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { + return null; + } + return (font.style ? font.style + ' ' : '') + + (font.weight ? font.weight + ' ' : '') + + font.size + 'px ' + + font.family; +} +function _measureText(ctx, data, gc, longest, string) { + let textWidth = data[string]; + if (!textWidth) { + textWidth = data[string] = ctx.measureText(string).width; + gc.push(string); + } + if (textWidth > longest) { + longest = textWidth; + } + return longest; +} +function _longestText(ctx, font, arrayOfThings, cache) { + cache = cache || {}; + let data = cache.data = cache.data || {}; + let gc = cache.garbageCollect = cache.garbageCollect || []; + if (cache.font !== font) { + data = cache.data = {}; + gc = cache.garbageCollect = []; + cache.font = font; + } + ctx.save(); + ctx.font = font; + let longest = 0; + const ilen = arrayOfThings.length; + let i, j, jlen, thing, nestedThing; + for (i = 0; i < ilen; i++) { + thing = arrayOfThings[i]; + if (thing !== undefined && thing !== null && isArray(thing) !== true) { + longest = _measureText(ctx, data, gc, longest, thing); + } else if (isArray(thing)) { + for (j = 0, jlen = thing.length; j < jlen; j++) { + nestedThing = thing[j]; + if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { + longest = _measureText(ctx, data, gc, longest, nestedThing); + } + } + } + } + ctx.restore(); + const gcLen = gc.length / 2; + if (gcLen > arrayOfThings.length) { + for (i = 0; i < gcLen; i++) { + delete data[gc[i]]; + } + gc.splice(0, gcLen); + } + return longest; +} +function _alignPixel(chart, pixel, width) { + const devicePixelRatio = chart.currentDevicePixelRatio; + const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; + return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; +} +function clearCanvas(canvas, ctx) { + ctx = ctx || canvas.getContext('2d'); + ctx.save(); + ctx.resetTransform(); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.restore(); +} +function drawPoint(ctx, options, x, y) { + let type, xOffset, yOffset, size, cornerRadius; + const style = options.pointStyle; + const rotation = options.rotation; + const radius = options.radius; + let rad = (rotation || 0) * RAD_PER_DEG; + if (style && typeof style === 'object') { + type = style.toString(); + if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { + ctx.save(); + ctx.translate(x, y); + ctx.rotate(rad); + ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); + ctx.restore(); + return; + } + } + if (isNaN(radius) || radius <= 0) { + return; + } + ctx.beginPath(); + switch (style) { + default: + ctx.arc(x, y, radius, 0, TAU); + ctx.closePath(); + break; + case 'triangle': + ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + ctx.closePath(); + break; + case 'rectRounded': + cornerRadius = radius * 0.516; + size = radius - cornerRadius; + xOffset = Math.cos(rad + QUARTER_PI) * size; + yOffset = Math.sin(rad + QUARTER_PI) * size; + ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); + ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); + ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); + ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); + ctx.closePath(); + break; + case 'rect': + if (!rotation) { + size = Math.SQRT1_2 * radius; + ctx.rect(x - size, y - size, 2 * size, 2 * size); + break; + } + rad += QUARTER_PI; + case 'rectRot': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + yOffset, y - xOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.lineTo(x - yOffset, y + xOffset); + ctx.closePath(); + break; + case 'crossRot': + rad += QUARTER_PI; + case 'cross': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'star': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + rad += QUARTER_PI; + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'line': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + break; + case 'dash': + ctx.moveTo(x, y); + ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); + break; + } + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } +} +function _isPointInArea(point, area, margin) { + margin = margin || 0.5; + return !area || (point && point.x > area.left - margin && point.x < area.right + margin && + point.y > area.top - margin && point.y < area.bottom + margin); +} +function clipArea(ctx, area) { + ctx.save(); + ctx.beginPath(); + ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); + ctx.clip(); +} +function unclipArea(ctx) { + ctx.restore(); +} +function _steppedLineTo(ctx, previous, target, flip, mode) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + if (mode === 'middle') { + const midpoint = (previous.x + target.x) / 2.0; + ctx.lineTo(midpoint, previous.y); + ctx.lineTo(midpoint, target.y); + } else if (mode === 'after' !== !!flip) { + ctx.lineTo(previous.x, target.y); + } else { + ctx.lineTo(target.x, previous.y); + } + ctx.lineTo(target.x, target.y); +} +function _bezierCurveTo(ctx, previous, target, flip) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + ctx.bezierCurveTo( + flip ? previous.cp1x : previous.cp2x, + flip ? previous.cp1y : previous.cp2y, + flip ? target.cp2x : target.cp1x, + flip ? target.cp2y : target.cp1y, + target.x, + target.y); +} +function renderText(ctx, text, x, y, font, opts = {}) { + const lines = isArray(text) ? text : [text]; + const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; + let i, line; + ctx.save(); + ctx.font = font.string; + setRenderOpts(ctx, opts); + for (i = 0; i < lines.length; ++i) { + line = lines[i]; + if (stroke) { + if (opts.strokeColor) { + ctx.strokeStyle = opts.strokeColor; + } + if (!isNullOrUndef(opts.strokeWidth)) { + ctx.lineWidth = opts.strokeWidth; + } + ctx.strokeText(line, x, y, opts.maxWidth); + } + ctx.fillText(line, x, y, opts.maxWidth); + decorateText(ctx, x, y, line, opts); + y += font.lineHeight; + } + ctx.restore(); +} +function setRenderOpts(ctx, opts) { + if (opts.translation) { + ctx.translate(opts.translation[0], opts.translation[1]); + } + if (!isNullOrUndef(opts.rotation)) { + ctx.rotate(opts.rotation); + } + if (opts.color) { + ctx.fillStyle = opts.color; + } + if (opts.textAlign) { + ctx.textAlign = opts.textAlign; + } + if (opts.textBaseline) { + ctx.textBaseline = opts.textBaseline; + } +} +function decorateText(ctx, x, y, line, opts) { + if (opts.strikethrough || opts.underline) { + const metrics = ctx.measureText(line); + const left = x - metrics.actualBoundingBoxLeft; + const right = x + metrics.actualBoundingBoxRight; + const top = y - metrics.actualBoundingBoxAscent; + const bottom = y + metrics.actualBoundingBoxDescent; + const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; + ctx.strokeStyle = ctx.fillStyle; + ctx.beginPath(); + ctx.lineWidth = opts.decorationWidth || 2; + ctx.moveTo(left, yDecoration); + ctx.lineTo(right, yDecoration); + ctx.stroke(); + } +} +function addRoundedRectPath(ctx, rect) { + const {x, y, w, h, radius} = rect; + ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true); + ctx.lineTo(x, y + h - radius.bottomLeft); + ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); + ctx.lineTo(x + w - radius.bottomRight, y + h); + ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); + ctx.lineTo(x + w, y + radius.topRight); + ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); + ctx.lineTo(x + radius.topLeft, y); +} + +function _lookup(table, value, cmp) { + cmp = cmp || ((index) => table[index] < value); + let hi = table.length - 1; + let lo = 0; + let mid; + while (hi - lo > 1) { + mid = (lo + hi) >> 1; + if (cmp(mid)) { + lo = mid; + } else { + hi = mid; + } + } + return {lo, hi}; +} +const _lookupByKey = (table, key, value) => + _lookup(table, value, index => table[index][key] < value); +const _rlookupByKey = (table, key, value) => + _lookup(table, value, index => table[index][key] >= value); +function _filterBetween(values, min, max) { + let start = 0; + let end = values.length; + while (start < end && values[start] < min) { + start++; + } + while (end > start && values[end - 1] > max) { + end--; + } + return start > 0 || end < values.length + ? values.slice(start, end) + : values; +} +const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; +function listenArrayEvents(array, listener) { + if (array._chartjs) { + array._chartjs.listeners.push(listener); + return; + } + Object.defineProperty(array, '_chartjs', { + configurable: true, + enumerable: false, + value: { + listeners: [listener] + } + }); + arrayEvents.forEach((key) => { + const method = '_onData' + _capitalize(key); + const base = array[key]; + Object.defineProperty(array, key, { + configurable: true, + enumerable: false, + value(...args) { + const res = base.apply(this, args); + array._chartjs.listeners.forEach((object) => { + if (typeof object[method] === 'function') { + object[method](...args); + } + }); + return res; + } + }); + }); +} +function unlistenArrayEvents(array, listener) { + const stub = array._chartjs; + if (!stub) { + return; + } + const listeners = stub.listeners; + const index = listeners.indexOf(listener); + if (index !== -1) { + listeners.splice(index, 1); + } + if (listeners.length > 0) { + return; + } + arrayEvents.forEach((key) => { + delete array[key]; + }); + delete array._chartjs; +} +function _arrayUnique(items) { + const set = new Set(); + let i, ilen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + set.add(items[i]); + } + if (set.size === ilen) { + return items; + } + return Array.from(set); +} + +function _isDomSupported() { + return typeof window !== 'undefined' && typeof document !== 'undefined'; +} +function _getParentNode(domNode) { + let parent = domNode.parentNode; + if (parent && parent.toString() === '[object ShadowRoot]') { + parent = parent.host; + } + return parent; +} +function parseMaxStyle(styleValue, node, parentProperty) { + let valueInPixels; + if (typeof styleValue === 'string') { + valueInPixels = parseInt(styleValue, 10); + if (styleValue.indexOf('%') !== -1) { + valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; + } + } else { + valueInPixels = styleValue; + } + return valueInPixels; +} +const getComputedStyle = (element) => window.getComputedStyle(element, null); +function getStyle(el, property) { + return getComputedStyle(el).getPropertyValue(property); +} +const positions = ['top', 'right', 'bottom', 'left']; +function getPositionedStyle(styles, style, suffix) { + const result = {}; + suffix = suffix ? '-' + suffix : ''; + for (let i = 0; i < 4; i++) { + const pos = positions[i]; + result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; + } + result.width = result.left + result.right; + result.height = result.top + result.bottom; + return result; +} +const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot); +function getCanvasPosition(evt, canvas) { + const e = evt.native || evt; + const touches = e.touches; + const source = touches && touches.length ? touches[0] : e; + const {offsetX, offsetY} = source; + let box = false; + let x, y; + if (useOffsetPos(offsetX, offsetY, e.target)) { + x = offsetX; + y = offsetY; + } else { + const rect = canvas.getBoundingClientRect(); + x = source.clientX - rect.left; + y = source.clientY - rect.top; + box = true; + } + return {x, y, box}; +} +function getRelativePosition$1(evt, chart) { + const {canvas, currentDevicePixelRatio} = chart; + const style = getComputedStyle(canvas); + const borderBox = style.boxSizing === 'border-box'; + const paddings = getPositionedStyle(style, 'padding'); + const borders = getPositionedStyle(style, 'border', 'width'); + const {x, y, box} = getCanvasPosition(evt, canvas); + const xOffset = paddings.left + (box && borders.left); + const yOffset = paddings.top + (box && borders.top); + let {width, height} = chart; + if (borderBox) { + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + return { + x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), + y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) + }; +} +function getContainerSize(canvas, width, height) { + let maxWidth, maxHeight; + if (width === undefined || height === undefined) { + const container = _getParentNode(canvas); + if (!container) { + width = canvas.clientWidth; + height = canvas.clientHeight; + } else { + const rect = container.getBoundingClientRect(); + const containerStyle = getComputedStyle(container); + const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); + const containerPadding = getPositionedStyle(containerStyle, 'padding'); + width = rect.width - containerPadding.width - containerBorder.width; + height = rect.height - containerPadding.height - containerBorder.height; + maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); + maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); + } + } + return { + width, + height, + maxWidth: maxWidth || INFINITY, + maxHeight: maxHeight || INFINITY + }; +} +const round1 = v => Math.round(v * 10) / 10; +function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { + const style = getComputedStyle(canvas); + const margins = getPositionedStyle(style, 'margin'); + const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; + const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; + const containerSize = getContainerSize(canvas, bbWidth, bbHeight); + let {width, height} = containerSize; + if (style.boxSizing === 'content-box') { + const borders = getPositionedStyle(style, 'border', 'width'); + const paddings = getPositionedStyle(style, 'padding'); + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + width = Math.max(0, width - margins.width); + height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); + width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); + height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); + if (width && !height) { + height = round1(width / 2); + } + return { + width, + height + }; +} +function retinaScale(chart, forceRatio, forceStyle) { + const pixelRatio = forceRatio || 1; + const deviceHeight = Math.floor(chart.height * pixelRatio); + const deviceWidth = Math.floor(chart.width * pixelRatio); + chart.height = deviceHeight / pixelRatio; + chart.width = deviceWidth / pixelRatio; + const canvas = chart.canvas; + if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) { + canvas.style.height = `${chart.height}px`; + canvas.style.width = `${chart.width}px`; + } + if (chart.currentDevicePixelRatio !== pixelRatio + || canvas.height !== deviceHeight + || canvas.width !== deviceWidth) { + chart.currentDevicePixelRatio = pixelRatio; + canvas.height = deviceHeight; + canvas.width = deviceWidth; + chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + return true; + } + return false; +} +const supportsEventListenerOptions = (function() { + let passiveSupported = false; + try { + const options = { + get passive() { + passiveSupported = true; + return false; + } + }; + window.addEventListener('test', null, options); + window.removeEventListener('test', null, options); + } catch (e) { + } + return passiveSupported; +}()); +function readUsedSize(element, property) { + const value = getStyle(element, property); + const matches = value && value.match(/^(\d+)(\.\d+)?px$/); + return matches ? +matches[1] : undefined; +} + +function getRelativePosition(e, chart) { + if ('native' in e) { + return { + x: e.x, + y: e.y + }; + } + return getRelativePosition$1(e, chart); +} +function evaluateAllVisibleItems(chart, handler) { + const metasets = chart.getSortedVisibleDatasetMetas(); + let index, data, element; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + ({index, data} = metasets[i]); + for (let j = 0, jlen = data.length; j < jlen; ++j) { + element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function binarySearch(metaset, axis, value, intersect) { + const {controller, data, _sorted} = metaset; + const iScale = controller._cachedMeta.iScale; + if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { + const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; + if (!intersect) { + return lookupMethod(data, axis, value); + } else if (controller._sharedOptions) { + const el = data[0]; + const range = typeof el.getRange === 'function' && el.getRange(axis); + if (range) { + const start = lookupMethod(data, axis, value - range); + const end = lookupMethod(data, axis, value + range); + return {lo: start.lo, hi: end.hi}; + } + } + } + return {lo: 0, hi: data.length - 1}; +} +function optimizedEvaluateItems(chart, axis, position, handler, intersect) { + const metasets = chart.getSortedVisibleDatasetMetas(); + const value = position[axis]; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + const {index, data} = metasets[i]; + const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); + for (let j = lo; j <= hi; ++j) { + const element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function getDistanceMetricForAxis(axis) { + const useX = axis.indexOf('x') !== -1; + const useY = axis.indexOf('y') !== -1; + return function(pt1, pt2) { + const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} +function getIntersectItems(chart, position, axis, useFinalPosition) { + const items = []; + if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { + return items; + } + const evaluationFunc = function(element, datasetIndex, index) { + if (element.inRange(position.x, position.y, useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); + return items; +} +function getNearestRadialItems(chart, position, axis, useFinalPosition) { + let items = []; + function evaluationFunc(element, datasetIndex, index) { + const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition); + const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y}); + if (_angleBetween(angle, startAngle, endAngle)) { + items.push({element, datasetIndex, index}); + } + } + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) { + let items = []; + const distanceMetric = getDistanceMetricForAxis(axis); + let minDistance = Number.POSITIVE_INFINITY; + function evaluationFunc(element, datasetIndex, index) { + const inRange = element.inRange(position.x, position.y, useFinalPosition); + if (intersect && !inRange) { + return; + } + const center = element.getCenterPoint(useFinalPosition); + const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding); + if (!pointInArea && !inRange) { + return; + } + const distance = distanceMetric(position, center); + if (distance < minDistance) { + items = [{element, datasetIndex, index}]; + minDistance = distance; + } else if (distance === minDistance) { + items.push({element, datasetIndex, index}); + } + } + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getNearestItems(chart, position, axis, intersect, useFinalPosition) { + if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { + return []; + } + return axis === 'r' && !intersect + ? getNearestRadialItems(chart, position, axis, useFinalPosition) + : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition); +} +function getAxisItems(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const items = []; + const axis = options.axis; + const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; + let intersectsItem = false; + evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { + if (element[rangeMethod](position[axis], useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + if (element.inRange(position.x, position.y, useFinalPosition)) { + intersectsItem = true; + } + }); + if (options.intersect && !intersectsItem) { + return []; + } + return items; +} +var Interaction = { + modes: { + index(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'x'; + const items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) + : getNearestItems(chart, position, axis, false, useFinalPosition); + const elements = []; + if (!items.length) { + return []; + } + chart.getSortedVisibleDatasetMetas().forEach((meta) => { + const index = items[0].index; + const element = meta.data[index]; + if (element && !element.skip) { + elements.push({element, datasetIndex: meta.index, index}); + } + }); + return elements; + }, + dataset(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + let items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) : + getNearestItems(chart, position, axis, false, useFinalPosition); + if (items.length > 0) { + const datasetIndex = items[0].datasetIndex; + const data = chart.getDatasetMeta(datasetIndex).data; + items = []; + for (let i = 0; i < data.length; ++i) { + items.push({element: data[i], datasetIndex, index: i}); + } + } + return items; + }, + point(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getIntersectItems(chart, position, axis, useFinalPosition); + }, + nearest(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); + }, + x(chart, e, options, useFinalPosition) { + return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition); + }, + y(chart, e, options, useFinalPosition) { + return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition); + } + } +}; + +const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); +const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/); +function toLineHeight(value, size) { + const matches = ('' + value).match(LINE_HEIGHT); + if (!matches || matches[1] === 'normal') { + return size * 1.2; + } + value = +matches[2]; + switch (matches[3]) { + case 'px': + return value; + case '%': + value /= 100; + break; + } + return size * value; +} +const numberOrZero = v => +v || 0; +function _readValueToProps(value, props) { + const ret = {}; + const objProps = isObject(props); + const keys = objProps ? Object.keys(props) : props; + const read = isObject(value) + ? objProps + ? prop => valueOrDefault(value[prop], value[props[prop]]) + : prop => value[prop] + : () => value; + for (const prop of keys) { + ret[prop] = numberOrZero(read(prop)); + } + return ret; +} +function toTRBL(value) { + return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'}); +} +function toTRBLCorners(value) { + return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']); +} +function toPadding(value) { + const obj = toTRBL(value); + obj.width = obj.left + obj.right; + obj.height = obj.top + obj.bottom; + return obj; +} +function toFont(options, fallback) { + options = options || {}; + fallback = fallback || defaults.font; + let size = valueOrDefault(options.size, fallback.size); + if (typeof size === 'string') { + size = parseInt(size, 10); + } + let style = valueOrDefault(options.style, fallback.style); + if (style && !('' + style).match(FONT_STYLE)) { + console.warn('Invalid font style specified: "' + style + '"'); + style = ''; + } + const font = { + family: valueOrDefault(options.family, fallback.family), + lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), + size, + style, + weight: valueOrDefault(options.weight, fallback.weight), + string: '' + }; + font.string = toFontString(font); + return font; +} +function resolve(inputs, context, index, info) { + let cacheable = true; + let i, ilen, value; + for (i = 0, ilen = inputs.length; i < ilen; ++i) { + value = inputs[i]; + if (value === undefined) { + continue; + } + if (context !== undefined && typeof value === 'function') { + value = value(context); + cacheable = false; + } + if (index !== undefined && isArray(value)) { + value = value[index % value.length]; + cacheable = false; + } + if (value !== undefined) { + if (info && !cacheable) { + info.cacheable = false; + } + return value; + } + } +} +function _addGrace(minmax, grace, beginAtZero) { + const {min, max} = minmax; + const change = toDimension(grace, (max - min) / 2); + const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; + return { + min: keepZero(min, -Math.abs(change)), + max: keepZero(max, change) + }; +} +function createContext(parentContext, context) { + return Object.assign(Object.create(parentContext), context); +} + +const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; +function filterByPosition(array, position) { + return array.filter(v => v.pos === position); +} +function filterDynamicPositionByAxis(array, axis) { + return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); +} +function sortByWeight(array, reverse) { + return array.sort((a, b) => { + const v0 = reverse ? b : a; + const v1 = reverse ? a : b; + return v0.weight === v1.weight ? + v0.index - v1.index : + v0.weight - v1.weight; + }); +} +function wrapBoxes(boxes) { + const layoutBoxes = []; + let i, ilen, box, pos, stack, stackWeight; + for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { + box = boxes[i]; + ({position: pos, options: {stack, stackWeight = 1}} = box); + layoutBoxes.push({ + index: i, + box, + pos, + horizontal: box.isHorizontal(), + weight: box.weight, + stack: stack && (pos + stack), + stackWeight + }); + } + return layoutBoxes; +} +function buildStacks(layouts) { + const stacks = {}; + for (const wrap of layouts) { + const {stack, pos, stackWeight} = wrap; + if (!stack || !STATIC_POSITIONS.includes(pos)) { + continue; + } + const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0}); + _stack.count++; + _stack.weight += stackWeight; + } + return stacks; +} +function setLayoutDims(layouts, params) { + const stacks = buildStacks(layouts); + const {vBoxMaxWidth, hBoxMaxHeight} = params; + let i, ilen, layout; + for (i = 0, ilen = layouts.length; i < ilen; ++i) { + layout = layouts[i]; + const {fullSize} = layout.box; + const stack = stacks[layout.stack]; + const factor = stack && layout.stackWeight / stack.weight; + if (layout.horizontal) { + layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; + layout.height = hBoxMaxHeight; + } else { + layout.width = vBoxMaxWidth; + layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; + } + } + return stacks; +} +function buildLayoutBoxes(boxes) { + const layoutBoxes = wrapBoxes(boxes); + const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true); + const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); + const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); + const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); + const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); + const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); + const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); + return { + fullSize, + leftAndTop: left.concat(top), + rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), + chartArea: filterByPosition(layoutBoxes, 'chartArea'), + vertical: left.concat(right).concat(centerVertical), + horizontal: top.concat(bottom).concat(centerHorizontal) + }; +} +function getCombinedMax(maxPadding, chartArea, a, b) { + return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); +} +function updateMaxPadding(maxPadding, boxPadding) { + maxPadding.top = Math.max(maxPadding.top, boxPadding.top); + maxPadding.left = Math.max(maxPadding.left, boxPadding.left); + maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); + maxPadding.right = Math.max(maxPadding.right, boxPadding.right); +} +function updateDims(chartArea, params, layout, stacks) { + const {pos, box} = layout; + const maxPadding = chartArea.maxPadding; + if (!isObject(pos)) { + if (layout.size) { + chartArea[pos] -= layout.size; + } + const stack = stacks[layout.stack] || {size: 0, count: 1}; + stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); + layout.size = stack.size / stack.count; + chartArea[pos] += layout.size; + } + if (box.getPadding) { + updateMaxPadding(maxPadding, box.getPadding()); + } + const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); + const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); + const widthChanged = newWidth !== chartArea.w; + const heightChanged = newHeight !== chartArea.h; + chartArea.w = newWidth; + chartArea.h = newHeight; + return layout.horizontal + ? {same: widthChanged, other: heightChanged} + : {same: heightChanged, other: widthChanged}; +} +function handleMaxPadding(chartArea) { + const maxPadding = chartArea.maxPadding; + function updatePos(pos) { + const change = Math.max(maxPadding[pos] - chartArea[pos], 0); + chartArea[pos] += change; + return change; + } + chartArea.y += updatePos('top'); + chartArea.x += updatePos('left'); + updatePos('right'); + updatePos('bottom'); +} +function getMargins(horizontal, chartArea) { + const maxPadding = chartArea.maxPadding; + function marginForPositions(positions) { + const margin = {left: 0, top: 0, right: 0, bottom: 0}; + positions.forEach((pos) => { + margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); + }); + return margin; + } + return horizontal + ? marginForPositions(['left', 'right']) + : marginForPositions(['top', 'bottom']); +} +function fitBoxes(boxes, chartArea, params, stacks) { + const refitBoxes = []; + let i, ilen, layout, box, refit, changed; + for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + box.update( + layout.width || chartArea.w, + layout.height || chartArea.h, + getMargins(layout.horizontal, chartArea) + ); + const {same, other} = updateDims(chartArea, params, layout, stacks); + refit |= same && refitBoxes.length; + changed = changed || other; + if (!box.fullSize) { + refitBoxes.push(layout); + } + } + return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; +} +function setBoxDims(box, left, top, width, height) { + box.top = top; + box.left = left; + box.right = left + width; + box.bottom = top + height; + box.width = width; + box.height = height; +} +function placeBoxes(boxes, chartArea, params, stacks) { + const userPadding = params.padding; + let {x, y} = chartArea; + for (const layout of boxes) { + const box = layout.box; + const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1}; + const weight = (layout.stackWeight / stack.weight) || 1; + if (layout.horizontal) { + const width = chartArea.w * weight; + const height = stack.size || box.height; + if (defined(stack.start)) { + y = stack.start; + } + if (box.fullSize) { + setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); + } else { + setBoxDims(box, chartArea.left + stack.placed, y, width, height); + } + stack.start = y; + stack.placed += width; + y = box.bottom; + } else { + const height = chartArea.h * weight; + const width = stack.size || box.width; + if (defined(stack.start)) { + x = stack.start; + } + if (box.fullSize) { + setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); + } else { + setBoxDims(box, x, chartArea.top + stack.placed, width, height); + } + stack.start = x; + stack.placed += height; + x = box.right; + } + } + chartArea.x = x; + chartArea.y = y; +} +defaults.set('layout', { + autoPadding: true, + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } +}); +var layouts = { + addBox(chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + item.fullSize = item.fullSize || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + item._layers = item._layers || function() { + return [{ + z: 0, + draw(chartArea) { + item.draw(chartArea); + } + }]; + }; + chart.boxes.push(item); + }, + removeBox(chart, layoutItem) { + const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + configure(chart, item, options) { + item.fullSize = options.fullSize; + item.position = options.position; + item.weight = options.weight; + }, + update(chart, width, height, minPadding) { + if (!chart) { + return; + } + const padding = toPadding(chart.options.layout.padding); + const availableWidth = Math.max(width - padding.width, 0); + const availableHeight = Math.max(height - padding.height, 0); + const boxes = buildLayoutBoxes(chart.boxes); + const verticalBoxes = boxes.vertical; + const horizontalBoxes = boxes.horizontal; + each(chart.boxes, box => { + if (typeof box.beforeLayout === 'function') { + box.beforeLayout(); + } + }); + const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => + wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; + const params = Object.freeze({ + outerWidth: width, + outerHeight: height, + padding, + availableWidth, + availableHeight, + vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, + hBoxMaxHeight: availableHeight / 2 + }); + const maxPadding = Object.assign({}, padding); + updateMaxPadding(maxPadding, toPadding(minPadding)); + const chartArea = Object.assign({ + maxPadding, + w: availableWidth, + h: availableHeight, + x: padding.left, + y: padding.top + }, padding); + const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); + fitBoxes(boxes.fullSize, chartArea, params, stacks); + fitBoxes(verticalBoxes, chartArea, params, stacks); + if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { + fitBoxes(verticalBoxes, chartArea, params, stacks); + } + handleMaxPadding(chartArea); + placeBoxes(boxes.leftAndTop, chartArea, params, stacks); + chartArea.x += chartArea.w; + chartArea.y += chartArea.h; + placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); + chart.chartArea = { + left: chartArea.left, + top: chartArea.top, + right: chartArea.left + chartArea.w, + bottom: chartArea.top + chartArea.h, + height: chartArea.h, + width: chartArea.w, + }; + each(boxes.chartArea, (layout) => { + const box = layout.box; + Object.assign(box, chart.chartArea); + box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0}); + }); + } +}; + +function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) { + if (!defined(fallback)) { + fallback = _resolve('_fallback', scopes); + } + const cache = { + [Symbol.toStringTag]: 'Object', + _cacheable: true, + _scopes: scopes, + _rootScopes: rootScopes, + _fallback: fallback, + _getTarget: getTarget, + override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback), + }; + return new Proxy(cache, { + deleteProperty(target, prop) { + delete target[prop]; + delete target._keys; + delete scopes[0][prop]; + return true; + }, + get(target, prop) { + return _cached(target, prop, + () => _resolveWithPrefixes(prop, prefixes, scopes, target)); + }, + getOwnPropertyDescriptor(target, prop) { + return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); + }, + getPrototypeOf() { + return Reflect.getPrototypeOf(scopes[0]); + }, + has(target, prop) { + return getKeysFromAllScopes(target).includes(prop); + }, + ownKeys(target) { + return getKeysFromAllScopes(target); + }, + set(target, prop, value) { + const storage = target._storage || (target._storage = getTarget()); + target[prop] = storage[prop] = value; + delete target._keys; + return true; + } + }); +} +function _attachContext(proxy, context, subProxy, descriptorDefaults) { + const cache = { + _cacheable: false, + _proxy: proxy, + _context: context, + _subProxy: subProxy, + _stack: new Set(), + _descriptors: _descriptors(proxy, descriptorDefaults), + setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults), + override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) + }; + return new Proxy(cache, { + deleteProperty(target, prop) { + delete target[prop]; + delete proxy[prop]; + return true; + }, + get(target, prop, receiver) { + return _cached(target, prop, + () => _resolveWithContext(target, prop, receiver)); + }, + getOwnPropertyDescriptor(target, prop) { + return target._descriptors.allKeys + ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined + : Reflect.getOwnPropertyDescriptor(proxy, prop); + }, + getPrototypeOf() { + return Reflect.getPrototypeOf(proxy); + }, + has(target, prop) { + return Reflect.has(proxy, prop); + }, + ownKeys() { + return Reflect.ownKeys(proxy); + }, + set(target, prop, value) { + proxy[prop] = value; + delete target[prop]; + return true; + } + }); +} +function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) { + const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy; + return { + allKeys: _allKeys, + scriptable: _scriptable, + indexable: _indexable, + isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable, + isIndexable: isFunction(_indexable) ? _indexable : () => _indexable + }; +} +const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name; +const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' && + (Object.getPrototypeOf(value) === null || value.constructor === Object); +function _cached(target, prop, resolve) { + if (Object.prototype.hasOwnProperty.call(target, prop)) { + return target[prop]; + } + const value = resolve(); + target[prop] = value; + return value; +} +function _resolveWithContext(target, prop, receiver) { + const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; + let value = _proxy[prop]; + if (isFunction(value) && descriptors.isScriptable(prop)) { + value = _resolveScriptable(prop, value, target, receiver); + } + if (isArray(value) && value.length) { + value = _resolveArray(prop, value, target, descriptors.isIndexable); + } + if (needsSubResolver(prop, value)) { + value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); + } + return value; +} +function _resolveScriptable(prop, value, target, receiver) { + const {_proxy, _context, _subProxy, _stack} = target; + if (_stack.has(prop)) { + throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); + } + _stack.add(prop); + value = value(_context, _subProxy || receiver); + _stack.delete(prop); + if (needsSubResolver(prop, value)) { + value = createSubResolver(_proxy._scopes, _proxy, prop, value); + } + return value; +} +function _resolveArray(prop, value, target, isIndexable) { + const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; + if (defined(_context.index) && isIndexable(prop)) { + value = value[_context.index % value.length]; + } else if (isObject(value[0])) { + const arr = value; + const scopes = _proxy._scopes.filter(s => s !== arr); + value = []; + for (const item of arr) { + const resolver = createSubResolver(scopes, _proxy, prop, item); + value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); + } + } + return value; +} +function resolveFallback(fallback, prop, value) { + return isFunction(fallback) ? fallback(prop, value) : fallback; +} +const getScope = (key, parent) => key === true ? parent + : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; +function addScopes(set, parentScopes, key, parentFallback, value) { + for (const parent of parentScopes) { + const scope = getScope(key, parent); + if (scope) { + set.add(scope); + const fallback = resolveFallback(scope._fallback, key, value); + if (defined(fallback) && fallback !== key && fallback !== parentFallback) { + return fallback; + } + } else if (scope === false && defined(parentFallback) && key !== parentFallback) { + return null; + } + } + return false; +} +function createSubResolver(parentScopes, resolver, prop, value) { + const rootScopes = resolver._rootScopes; + const fallback = resolveFallback(resolver._fallback, prop, value); + const allScopes = [...parentScopes, ...rootScopes]; + const set = new Set(); + set.add(value); + let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); + if (key === null) { + return false; + } + if (defined(fallback) && fallback !== prop) { + key = addScopesFromKey(set, allScopes, fallback, key, value); + if (key === null) { + return false; + } + } + return _createResolver(Array.from(set), [''], rootScopes, fallback, + () => subGetTarget(resolver, prop, value)); +} +function addScopesFromKey(set, allScopes, key, fallback, item) { + while (key) { + key = addScopes(set, allScopes, key, fallback, item); + } + return key; +} +function subGetTarget(resolver, prop, value) { + const parent = resolver._getTarget(); + if (!(prop in parent)) { + parent[prop] = {}; + } + const target = parent[prop]; + if (isArray(target) && isObject(value)) { + return value; + } + return target; +} +function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { + let value; + for (const prefix of prefixes) { + value = _resolve(readKey(prefix, prop), scopes); + if (defined(value)) { + return needsSubResolver(prop, value) + ? createSubResolver(scopes, proxy, prop, value) + : value; + } + } +} +function _resolve(key, scopes) { + for (const scope of scopes) { + if (!scope) { + continue; + } + const value = scope[key]; + if (defined(value)) { + return value; + } + } +} +function getKeysFromAllScopes(target) { + let keys = target._keys; + if (!keys) { + keys = target._keys = resolveKeysFromAllScopes(target._scopes); + } + return keys; +} +function resolveKeysFromAllScopes(scopes) { + const set = new Set(); + for (const scope of scopes) { + for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) { + set.add(key); + } + } + return Array.from(set); +} + +const EPSILON = Number.EPSILON || 1e-14; +const getPoint = (points, i) => i < points.length && !points[i].skip && points[i]; +const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x'; +function splineCurve(firstPoint, middlePoint, afterPoint, t) { + const previous = firstPoint.skip ? middlePoint : firstPoint; + const current = middlePoint; + const next = afterPoint.skip ? middlePoint : afterPoint; + const d01 = distanceBetweenPoints(current, previous); + const d12 = distanceBetweenPoints(next, current); + let s01 = d01 / (d01 + d12); + let s12 = d12 / (d01 + d12); + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + const fa = t * s01; + const fb = t * s12; + return { + previous: { + x: current.x - fa * (next.x - previous.x), + y: current.y - fa * (next.y - previous.y) + }, + next: { + x: current.x + fb * (next.x - previous.x), + y: current.y + fb * (next.y - previous.y) + } + }; +} +function monotoneAdjust(points, deltaK, mK) { + const pointsLen = points.length; + let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; + let pointAfter = getPoint(points, 0); + for (let i = 0; i < pointsLen - 1; ++i) { + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent || !pointAfter) { + continue; + } + if (almostEquals(deltaK[i], 0, EPSILON)) { + mK[i] = mK[i + 1] = 0; + continue; + } + alphaK = mK[i] / deltaK[i]; + betaK = mK[i + 1] / deltaK[i]; + squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); + if (squaredMagnitude <= 9) { + continue; + } + tauK = 3 / Math.sqrt(squaredMagnitude); + mK[i] = alphaK * tauK * deltaK[i]; + mK[i + 1] = betaK * tauK * deltaK[i]; + } +} +function monotoneCompute(points, mK, indexAxis = 'x') { + const valueAxis = getValueAxis(indexAxis); + const pointsLen = points.length; + let delta, pointBefore, pointCurrent; + let pointAfter = getPoint(points, 0); + for (let i = 0; i < pointsLen; ++i) { + pointBefore = pointCurrent; + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent) { + continue; + } + const iPixel = pointCurrent[indexAxis]; + const vPixel = pointCurrent[valueAxis]; + if (pointBefore) { + delta = (iPixel - pointBefore[indexAxis]) / 3; + pointCurrent[`cp1${indexAxis}`] = iPixel - delta; + pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; + } + if (pointAfter) { + delta = (pointAfter[indexAxis] - iPixel) / 3; + pointCurrent[`cp2${indexAxis}`] = iPixel + delta; + pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; + } + } +} +function splineCurveMonotone(points, indexAxis = 'x') { + const valueAxis = getValueAxis(indexAxis); + const pointsLen = points.length; + const deltaK = Array(pointsLen).fill(0); + const mK = Array(pointsLen); + let i, pointBefore, pointCurrent; + let pointAfter = getPoint(points, 0); + for (i = 0; i < pointsLen; ++i) { + pointBefore = pointCurrent; + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent) { + continue; + } + if (pointAfter) { + const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; + deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; + } + mK[i] = !pointBefore ? deltaK[i] + : !pointAfter ? deltaK[i - 1] + : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0 + : (deltaK[i - 1] + deltaK[i]) / 2; + } + monotoneAdjust(points, deltaK, mK); + monotoneCompute(points, mK, indexAxis); +} +function capControlPoint(pt, min, max) { + return Math.max(Math.min(pt, max), min); +} +function capBezierPoints(points, area) { + let i, ilen, point, inArea, inAreaPrev; + let inAreaNext = _isPointInArea(points[0], area); + for (i = 0, ilen = points.length; i < ilen; ++i) { + inAreaPrev = inArea; + inArea = inAreaNext; + inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); + if (!inArea) { + continue; + } + point = points[i]; + if (inAreaPrev) { + point.cp1x = capControlPoint(point.cp1x, area.left, area.right); + point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); + } + if (inAreaNext) { + point.cp2x = capControlPoint(point.cp2x, area.left, area.right); + point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); + } + } +} +function _updateBezierControlPoints(points, options, area, loop, indexAxis) { + let i, ilen, point, controlPoints; + if (options.spanGaps) { + points = points.filter((pt) => !pt.skip); + } + if (options.cubicInterpolationMode === 'monotone') { + splineCurveMonotone(points, indexAxis); + } else { + let prev = loop ? points[points.length - 1] : points[0]; + for (i = 0, ilen = points.length; i < ilen; ++i) { + point = points[i]; + controlPoints = splineCurve( + prev, + point, + points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], + options.tension + ); + point.cp1x = controlPoints.previous.x; + point.cp1y = controlPoints.previous.y; + point.cp2x = controlPoints.next.x; + point.cp2y = controlPoints.next.y; + prev = point; + } + } + if (options.capBezierPoints) { + capBezierPoints(points, area); + } +} + +const atEdge = (t) => t === 0 || t === 1; +const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); +const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; +const effects = { + linear: t => t, + easeInQuad: t => t * t, + easeOutQuad: t => -t * (t - 2), + easeInOutQuad: t => ((t /= 0.5) < 1) + ? 0.5 * t * t + : -0.5 * ((--t) * (t - 2) - 1), + easeInCubic: t => t * t * t, + easeOutCubic: t => (t -= 1) * t * t + 1, + easeInOutCubic: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t + : 0.5 * ((t -= 2) * t * t + 2), + easeInQuart: t => t * t * t * t, + easeOutQuart: t => -((t -= 1) * t * t * t - 1), + easeInOutQuart: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t * t + : -0.5 * ((t -= 2) * t * t * t - 2), + easeInQuint: t => t * t * t * t * t, + easeOutQuint: t => (t -= 1) * t * t * t * t + 1, + easeInOutQuint: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t * t * t + : 0.5 * ((t -= 2) * t * t * t * t + 2), + easeInSine: t => -Math.cos(t * HALF_PI) + 1, + easeOutSine: t => Math.sin(t * HALF_PI), + easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1), + easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)), + easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1, + easeInOutExpo: t => atEdge(t) ? t : t < 0.5 + ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) + : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), + easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1), + easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t), + easeInOutCirc: t => ((t /= 0.5) < 1) + ? -0.5 * (Math.sqrt(1 - t * t) - 1) + : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), + easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3), + easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3), + easeInOutElastic(t) { + const s = 0.1125; + const p = 0.45; + return atEdge(t) ? t : + t < 0.5 + ? 0.5 * elasticIn(t * 2, s, p) + : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); + }, + easeInBack(t) { + const s = 1.70158; + return t * t * ((s + 1) * t - s); + }, + easeOutBack(t) { + const s = 1.70158; + return (t -= 1) * t * ((s + 1) * t + s) + 1; + }, + easeInOutBack(t) { + let s = 1.70158; + if ((t /= 0.5) < 1) { + return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); + } + return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); + }, + easeInBounce: t => 1 - effects.easeOutBounce(1 - t), + easeOutBounce(t) { + const m = 7.5625; + const d = 2.75; + if (t < (1 / d)) { + return m * t * t; + } + if (t < (2 / d)) { + return m * (t -= (1.5 / d)) * t + 0.75; + } + if (t < (2.5 / d)) { + return m * (t -= (2.25 / d)) * t + 0.9375; + } + return m * (t -= (2.625 / d)) * t + 0.984375; + }, + easeInOutBounce: t => (t < 0.5) + ? effects.easeInBounce(t * 2) * 0.5 + : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5, +}; + +function _pointInLine(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: p1.y + t * (p2.y - p1.y) + }; +} +function _steppedInterpolation(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y + : mode === 'after' ? t < 1 ? p1.y : p2.y + : t > 0 ? p2.y : p1.y + }; +} +function _bezierInterpolation(p1, p2, t, mode) { + const cp1 = {x: p1.cp2x, y: p1.cp2y}; + const cp2 = {x: p2.cp1x, y: p2.cp1y}; + const a = _pointInLine(p1, cp1, t); + const b = _pointInLine(cp1, cp2, t); + const c = _pointInLine(cp2, p2, t); + const d = _pointInLine(a, b, t); + const e = _pointInLine(b, c, t); + return _pointInLine(d, e, t); +} + +const intlCache = new Map(); +function getNumberFormat(locale, options) { + options = options || {}; + const cacheKey = locale + JSON.stringify(options); + let formatter = intlCache.get(cacheKey); + if (!formatter) { + formatter = new Intl.NumberFormat(locale, options); + intlCache.set(cacheKey, formatter); + } + return formatter; +} +function formatNumber(num, locale, options) { + return getNumberFormat(locale, options).format(num); +} + +const getRightToLeftAdapter = function(rectX, width) { + return { + x(x) { + return rectX + rectX + width - x; + }, + setWidth(w) { + width = w; + }, + textAlign(align) { + if (align === 'center') { + return align; + } + return align === 'right' ? 'left' : 'right'; + }, + xPlus(x, value) { + return x - value; + }, + leftForLtr(x, itemWidth) { + return x - itemWidth; + }, + }; +}; +const getLeftToRightAdapter = function() { + return { + x(x) { + return x; + }, + setWidth(w) { + }, + textAlign(align) { + return align; + }, + xPlus(x, value) { + return x + value; + }, + leftForLtr(x, _itemWidth) { + return x; + }, + }; +}; +function getRtlAdapter(rtl, rectX, width) { + return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); +} +function overrideTextDirection(ctx, direction) { + let style, original; + if (direction === 'ltr' || direction === 'rtl') { + style = ctx.canvas.style; + original = [ + style.getPropertyValue('direction'), + style.getPropertyPriority('direction'), + ]; + style.setProperty('direction', direction, 'important'); + ctx.prevTextDirection = original; + } +} +function restoreTextDirection(ctx, original) { + if (original !== undefined) { + delete ctx.prevTextDirection; + ctx.canvas.style.setProperty('direction', original[0], original[1]); + } +} + +function propertyFn(property) { + if (property === 'angle') { + return { + between: _angleBetween, + compare: _angleDiff, + normalize: _normalizeAngle, + }; + } + return { + between: _isBetween, + compare: (a, b) => a - b, + normalize: x => x + }; +} +function normalizeSegment({start, end, count, loop, style}) { + return { + start: start % count, + end: end % count, + loop: loop && (end - start + 1) % count === 0, + style + }; +} +function getSegment(segment, points, bounds) { + const {property, start: startBound, end: endBound} = bounds; + const {between, normalize} = propertyFn(property); + const count = points.length; + let {start, end, loop} = segment; + let i, ilen; + if (loop) { + start += count; + end += count; + for (i = 0, ilen = count; i < ilen; ++i) { + if (!between(normalize(points[start % count][property]), startBound, endBound)) { + break; + } + start--; + end--; + } + start %= count; + end %= count; + } + if (end < start) { + end += count; + } + return {start, end, loop, style: segment.style}; +} +function _boundSegment(segment, points, bounds) { + if (!bounds) { + return [segment]; + } + const {property, start: startBound, end: endBound} = bounds; + const count = points.length; + const {compare, between, normalize} = propertyFn(property); + const {start, end, loop, style} = getSegment(segment, points, bounds); + const result = []; + let inside = false; + let subStart = null; + let value, point, prevValue; + const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; + const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value); + const shouldStart = () => inside || startIsBefore(); + const shouldStop = () => !inside || endIsBefore(); + for (let i = start, prev = start; i <= end; ++i) { + point = points[i % count]; + if (point.skip) { + continue; + } + value = normalize(point[property]); + if (value === prevValue) { + continue; + } + inside = between(value, startBound, endBound); + if (subStart === null && shouldStart()) { + subStart = compare(value, startBound) === 0 ? i : prev; + } + if (subStart !== null && shouldStop()) { + result.push(normalizeSegment({start: subStart, end: i, loop, count, style})); + subStart = null; + } + prev = i; + prevValue = value; + } + if (subStart !== null) { + result.push(normalizeSegment({start: subStart, end, loop, count, style})); + } + return result; +} +function _boundSegments(line, bounds) { + const result = []; + const segments = line.segments; + for (let i = 0; i < segments.length; i++) { + const sub = _boundSegment(segments[i], line.points, bounds); + if (sub.length) { + result.push(...sub); + } + } + return result; +} +function findStartAndEnd(points, count, loop, spanGaps) { + let start = 0; + let end = count - 1; + if (loop && !spanGaps) { + while (start < count && !points[start].skip) { + start++; + } + } + while (start < count && points[start].skip) { + start++; + } + start %= count; + if (loop) { + end += start; + } + while (end > start && points[end % count].skip) { + end--; + } + end %= count; + return {start, end}; +} +function solidSegments(points, start, max, loop) { + const count = points.length; + const result = []; + let last = start; + let prev = points[start]; + let end; + for (end = start + 1; end <= max; ++end) { + const cur = points[end % count]; + if (cur.skip || cur.stop) { + if (!prev.skip) { + loop = false; + result.push({start: start % count, end: (end - 1) % count, loop}); + start = last = cur.stop ? end : null; + } + } else { + last = end; + if (prev.skip) { + start = end; + } + } + prev = cur; + } + if (last !== null) { + result.push({start: start % count, end: last % count, loop}); + } + return result; +} +function _computeSegments(line, segmentOptions) { + const points = line.points; + const spanGaps = line.options.spanGaps; + const count = points.length; + if (!count) { + return []; + } + const loop = !!line._loop; + const {start, end} = findStartAndEnd(points, count, loop, spanGaps); + if (spanGaps === true) { + return splitByStyles(line, [{start, end, loop}], points, segmentOptions); + } + const max = end < start ? end + count : end; + const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; + return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); +} +function splitByStyles(line, segments, points, segmentOptions) { + if (!segmentOptions || !segmentOptions.setContext || !points) { + return segments; + } + return doSplitByStyles(line, segments, points, segmentOptions); +} +function doSplitByStyles(line, segments, points, segmentOptions) { + const chartContext = line._chart.getContext(); + const baseStyle = readStyle(line.options); + const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; + const count = points.length; + const result = []; + let prevStyle = baseStyle; + let start = segments[0].start; + let i = start; + function addStyle(s, e, l, st) { + const dir = spanGaps ? -1 : 1; + if (s === e) { + return; + } + s += count; + while (points[s % count].skip) { + s -= dir; + } + while (points[e % count].skip) { + e += dir; + } + if (s % count !== e % count) { + result.push({start: s % count, end: e % count, loop: l, style: st}); + prevStyle = st; + start = e % count; + } + } + for (const segment of segments) { + start = spanGaps ? start : segment.start; + let prev = points[start % count]; + let style; + for (i = start + 1; i <= segment.end; i++) { + const pt = points[i % count]; + style = readStyle(segmentOptions.setContext(createContext(chartContext, { + type: 'segment', + p0: prev, + p1: pt, + p0DataIndex: (i - 1) % count, + p1DataIndex: i % count, + datasetIndex + }))); + if (styleChanged(style, prevStyle)) { + addStyle(start, i - 1, segment.loop, prevStyle); + } + prev = pt; + prevStyle = style; + } + if (start < i - 1) { + addStyle(start, i - 1, segment.loop, prevStyle); + } + } + return result; +} +function readStyle(options) { + return { + backgroundColor: options.backgroundColor, + borderCapStyle: options.borderCapStyle, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderJoinStyle: options.borderJoinStyle, + borderWidth: options.borderWidth, + borderColor: options.borderColor + }; +} +function styleChanged(style, prevStyle) { + return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle); +} + +var helpers = /*#__PURE__*/Object.freeze({ +__proto__: null, +easingEffects: effects, +color: color, +getHoverColor: getHoverColor, +noop: noop, +uid: uid, +isNullOrUndef: isNullOrUndef, +isArray: isArray, +isObject: isObject, +isFinite: isNumberFinite, +finiteOrDefault: finiteOrDefault, +valueOrDefault: valueOrDefault, +toPercentage: toPercentage, +toDimension: toDimension, +callback: callback, +each: each, +_elementsEqual: _elementsEqual, +clone: clone, +_merger: _merger, +merge: merge, +mergeIf: mergeIf, +_mergerIf: _mergerIf, +_deprecated: _deprecated, +resolveObjectKey: resolveObjectKey, +_capitalize: _capitalize, +defined: defined, +isFunction: isFunction, +setsEqual: setsEqual, +_isClickEvent: _isClickEvent, +toFontString: toFontString, +_measureText: _measureText, +_longestText: _longestText, +_alignPixel: _alignPixel, +clearCanvas: clearCanvas, +drawPoint: drawPoint, +_isPointInArea: _isPointInArea, +clipArea: clipArea, +unclipArea: unclipArea, +_steppedLineTo: _steppedLineTo, +_bezierCurveTo: _bezierCurveTo, +renderText: renderText, +addRoundedRectPath: addRoundedRectPath, +_lookup: _lookup, +_lookupByKey: _lookupByKey, +_rlookupByKey: _rlookupByKey, +_filterBetween: _filterBetween, +listenArrayEvents: listenArrayEvents, +unlistenArrayEvents: unlistenArrayEvents, +_arrayUnique: _arrayUnique, +_createResolver: _createResolver, +_attachContext: _attachContext, +_descriptors: _descriptors, +splineCurve: splineCurve, +splineCurveMonotone: splineCurveMonotone, +_updateBezierControlPoints: _updateBezierControlPoints, +_isDomSupported: _isDomSupported, +_getParentNode: _getParentNode, +getStyle: getStyle, +getRelativePosition: getRelativePosition$1, +getMaximumSize: getMaximumSize, +retinaScale: retinaScale, +supportsEventListenerOptions: supportsEventListenerOptions, +readUsedSize: readUsedSize, +fontString: fontString, +requestAnimFrame: requestAnimFrame, +throttled: throttled, +debounce: debounce, +_toLeftRightCenter: _toLeftRightCenter, +_alignStartEnd: _alignStartEnd, +_textX: _textX, +_pointInLine: _pointInLine, +_steppedInterpolation: _steppedInterpolation, +_bezierInterpolation: _bezierInterpolation, +formatNumber: formatNumber, +toLineHeight: toLineHeight, +_readValueToProps: _readValueToProps, +toTRBL: toTRBL, +toTRBLCorners: toTRBLCorners, +toPadding: toPadding, +toFont: toFont, +resolve: resolve, +_addGrace: _addGrace, +createContext: createContext, +PI: PI, +TAU: TAU, +PITAU: PITAU, +INFINITY: INFINITY, +RAD_PER_DEG: RAD_PER_DEG, +HALF_PI: HALF_PI, +QUARTER_PI: QUARTER_PI, +TWO_THIRDS_PI: TWO_THIRDS_PI, +log10: log10, +sign: sign, +niceNum: niceNum, +_factorize: _factorize, +isNumber: isNumber, +almostEquals: almostEquals, +almostWhole: almostWhole, +_setMinAndMaxByKey: _setMinAndMaxByKey, +toRadians: toRadians, +toDegrees: toDegrees, +_decimalPlaces: _decimalPlaces, +getAngleFromPoint: getAngleFromPoint, +distanceBetweenPoints: distanceBetweenPoints, +_angleDiff: _angleDiff, +_normalizeAngle: _normalizeAngle, +_angleBetween: _angleBetween, +_limitValue: _limitValue, +_int16Range: _int16Range, +_isBetween: _isBetween, +getRtlAdapter: getRtlAdapter, +overrideTextDirection: overrideTextDirection, +restoreTextDirection: restoreTextDirection, +_boundSegment: _boundSegment, +_boundSegments: _boundSegments, +_computeSegments: _computeSegments +}); + +class BasePlatform { + acquireContext(canvas, aspectRatio) {} + releaseContext(context) { + return false; + } + addEventListener(chart, type, listener) {} + removeEventListener(chart, type, listener) {} + getDevicePixelRatio() { + return 1; + } + getMaximumSize(element, width, height, aspectRatio) { + width = Math.max(0, width || element.width); + height = height || element.height; + return { + width, + height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) + }; + } + isAttached(canvas) { + return true; + } + updateConfig(config) { + } +} + +class BasicPlatform extends BasePlatform { + acquireContext(item) { + return item && item.getContext && item.getContext('2d') || null; + } + updateConfig(config) { + config.options.animation = false; + } +} + +const EXPANDO_KEY = '$chartjs'; +const EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; +const isNullOrEmpty = value => value === null || value === ''; +function initCanvas(canvas, aspectRatio) { + const style = canvas.style; + const renderHeight = canvas.getAttribute('height'); + const renderWidth = canvas.getAttribute('width'); + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + style.display = style.display || 'block'; + style.boxSizing = style.boxSizing || 'border-box'; + if (isNullOrEmpty(renderWidth)) { + const displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + if (isNullOrEmpty(renderHeight)) { + if (canvas.style.height === '') { + canvas.height = canvas.width / (aspectRatio || 2); + } else { + const displayHeight = readUsedSize(canvas, 'height'); + if (displayHeight !== undefined) { + canvas.height = displayHeight; + } + } + } + return canvas; +} +const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; +function addListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} +function removeListener(chart, type, listener) { + chart.canvas.removeEventListener(type, listener, eventListenerOptions); +} +function fromNativeEvent(event, chart) { + const type = EVENT_TYPES[event.type] || event.type; + const {x, y} = getRelativePosition$1(event, chart); + return { + type, + chart, + native: event, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null, + }; +} +function nodeListContains(nodeList, canvas) { + for (const node of nodeList) { + if (node === canvas || node.contains(canvas)) { + return true; + } + } +} +function createAttachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver(entries => { + let trigger = false; + for (const entry of entries) { + trigger = trigger || nodeListContains(entry.addedNodes, canvas); + trigger = trigger && !nodeListContains(entry.removedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, {childList: true, subtree: true}); + return observer; +} +function createDetachObserver(chart, type, listener) { + const canvas = chart.canvas; + const observer = new MutationObserver(entries => { + let trigger = false; + for (const entry of entries) { + trigger = trigger || nodeListContains(entry.removedNodes, canvas); + trigger = trigger && !nodeListContains(entry.addedNodes, canvas); + } + if (trigger) { + listener(); + } + }); + observer.observe(document, {childList: true, subtree: true}); + return observer; +} +const drpListeningCharts = new Map(); +let oldDevicePixelRatio = 0; +function onWindowResize() { + const dpr = window.devicePixelRatio; + if (dpr === oldDevicePixelRatio) { + return; + } + oldDevicePixelRatio = dpr; + drpListeningCharts.forEach((resize, chart) => { + if (chart.currentDevicePixelRatio !== dpr) { + resize(); + } + }); +} +function listenDevicePixelRatioChanges(chart, resize) { + if (!drpListeningCharts.size) { + window.addEventListener('resize', onWindowResize); + } + drpListeningCharts.set(chart, resize); +} +function unlistenDevicePixelRatioChanges(chart) { + drpListeningCharts.delete(chart); + if (!drpListeningCharts.size) { + window.removeEventListener('resize', onWindowResize); + } +} +function createResizeObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + const resize = throttled((width, height) => { + const w = container.clientWidth; + listener(width, height); + if (w < container.clientWidth) { + listener(); + } + }, window); + const observer = new ResizeObserver(entries => { + const entry = entries[0]; + const width = entry.contentRect.width; + const height = entry.contentRect.height; + if (width === 0 && height === 0) { + return; + } + resize(width, height); + }); + observer.observe(container); + listenDevicePixelRatioChanges(chart, resize); + return observer; +} +function releaseObserver(chart, type, observer) { + if (observer) { + observer.disconnect(); + } + if (type === 'resize') { + unlistenDevicePixelRatioChanges(chart); + } +} +function createProxyAndListen(chart, type, listener) { + const canvas = chart.canvas; + const proxy = throttled((event) => { + if (chart.ctx !== null) { + listener(fromNativeEvent(event, chart)); + } + }, chart, (args) => { + const event = args[0]; + return [event, event.offsetX, event.offsetY]; + }); + addListener(canvas, type, proxy); + return proxy; +} +class DomPlatform extends BasePlatform { + acquireContext(canvas, aspectRatio) { + const context = canvas && canvas.getContext && canvas.getContext('2d'); + if (context && context.canvas === canvas) { + initCanvas(canvas, aspectRatio); + return context; + } + return null; + } + releaseContext(context) { + const canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return false; + } + const initial = canvas[EXPANDO_KEY].initial; + ['height', 'width'].forEach((prop) => { + const value = initial[prop]; + if (isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + const style = initial.style || {}; + Object.keys(style).forEach((key) => { + canvas.style[key] = style[key]; + }); + canvas.width = canvas.width; + delete canvas[EXPANDO_KEY]; + return true; + } + addEventListener(chart, type, listener) { + this.removeEventListener(chart, type); + const proxies = chart.$proxies || (chart.$proxies = {}); + const handlers = { + attach: createAttachObserver, + detach: createDetachObserver, + resize: createResizeObserver + }; + const handler = handlers[type] || createProxyAndListen; + proxies[type] = handler(chart, type, listener); + } + removeEventListener(chart, type) { + const proxies = chart.$proxies || (chart.$proxies = {}); + const proxy = proxies[type]; + if (!proxy) { + return; + } + const handlers = { + attach: releaseObserver, + detach: releaseObserver, + resize: releaseObserver + }; + const handler = handlers[type] || removeListener; + handler(chart, type, proxy); + proxies[type] = undefined; + } + getDevicePixelRatio() { + return window.devicePixelRatio; + } + getMaximumSize(canvas, width, height, aspectRatio) { + return getMaximumSize(canvas, width, height, aspectRatio); + } + isAttached(canvas) { + const container = _getParentNode(canvas); + return !!(container && container.isConnected); + } +} + +function _detectPlatform(canvas) { + if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { + return BasicPlatform; + } + return DomPlatform; +} + +var platforms = /*#__PURE__*/Object.freeze({ +__proto__: null, +_detectPlatform: _detectPlatform, +BasePlatform: BasePlatform, +BasicPlatform: BasicPlatform, +DomPlatform: DomPlatform +}); + +const transparent = 'transparent'; +const interpolators = { + boolean(from, to, factor) { + return factor > 0.5 ? to : from; + }, + color(from, to, factor) { + const c0 = color(from || transparent); + const c1 = c0.valid && color(to || transparent); + return c1 && c1.valid + ? c1.mix(c0, factor).hexString() + : to; + }, + number(from, to, factor) { + return from + (to - from) * factor; + } +}; +class Animation { + constructor(cfg, target, prop, to) { + const currentValue = target[prop]; + to = resolve([cfg.to, to, currentValue, cfg.from]); + const from = resolve([cfg.from, currentValue, to]); + this._active = true; + this._fn = cfg.fn || interpolators[cfg.type || typeof from]; + this._easing = effects[cfg.easing] || effects.linear; + this._start = Math.floor(Date.now() + (cfg.delay || 0)); + this._duration = this._total = Math.floor(cfg.duration); + this._loop = !!cfg.loop; + this._target = target; + this._prop = prop; + this._from = from; + this._to = to; + this._promises = undefined; + } + active() { + return this._active; + } + update(cfg, to, date) { + if (this._active) { + this._notify(false); + const currentValue = this._target[this._prop]; + const elapsed = date - this._start; + const remain = this._duration - elapsed; + this._start = date; + this._duration = Math.floor(Math.max(remain, cfg.duration)); + this._total += elapsed; + this._loop = !!cfg.loop; + this._to = resolve([cfg.to, to, currentValue, cfg.from]); + this._from = resolve([cfg.from, currentValue, to]); + } + } + cancel() { + if (this._active) { + this.tick(Date.now()); + this._active = false; + this._notify(false); + } + } + tick(date) { + const elapsed = date - this._start; + const duration = this._duration; + const prop = this._prop; + const from = this._from; + const loop = this._loop; + const to = this._to; + let factor; + this._active = from !== to && (loop || (elapsed < duration)); + if (!this._active) { + this._target[prop] = to; + this._notify(true); + return; + } + if (elapsed < 0) { + this._target[prop] = from; + return; + } + factor = (elapsed / duration) % 2; + factor = loop && factor > 1 ? 2 - factor : factor; + factor = this._easing(Math.min(1, Math.max(0, factor))); + this._target[prop] = this._fn(from, to, factor); + } + wait() { + const promises = this._promises || (this._promises = []); + return new Promise((res, rej) => { + promises.push({res, rej}); + }); + } + _notify(resolved) { + const method = resolved ? 'res' : 'rej'; + const promises = this._promises || []; + for (let i = 0; i < promises.length; i++) { + promises[i][method](); + } + } +} + +const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; +const colors = ['color', 'borderColor', 'backgroundColor']; +defaults.set('animation', { + delay: undefined, + duration: 1000, + easing: 'easeOutQuart', + fn: undefined, + from: undefined, + loop: undefined, + to: undefined, + type: undefined, +}); +const animationOptions = Object.keys(defaults.animation); +defaults.describe('animation', { + _fallback: false, + _indexable: false, + _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn', +}); +defaults.set('animations', { + colors: { + type: 'color', + properties: colors + }, + numbers: { + type: 'number', + properties: numbers + }, +}); +defaults.describe('animations', { + _fallback: 'animation', +}); +defaults.set('transitions', { + active: { + animation: { + duration: 400 + } + }, + resize: { + animation: { + duration: 0 + } + }, + show: { + animations: { + colors: { + from: 'transparent' + }, + visible: { + type: 'boolean', + duration: 0 + }, + } + }, + hide: { + animations: { + colors: { + to: 'transparent' + }, + visible: { + type: 'boolean', + easing: 'linear', + fn: v => v | 0 + }, + } + } +}); +class Animations { + constructor(chart, config) { + this._chart = chart; + this._properties = new Map(); + this.configure(config); + } + configure(config) { + if (!isObject(config)) { + return; + } + const animatedProps = this._properties; + Object.getOwnPropertyNames(config).forEach(key => { + const cfg = config[key]; + if (!isObject(cfg)) { + return; + } + const resolved = {}; + for (const option of animationOptions) { + resolved[option] = cfg[option]; + } + (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => { + if (prop === key || !animatedProps.has(prop)) { + animatedProps.set(prop, resolved); + } + }); + }); + } + _animateOptions(target, values) { + const newOptions = values.options; + const options = resolveTargetOptions(target, newOptions); + if (!options) { + return []; + } + const animations = this._createAnimations(options, newOptions); + if (newOptions.$shared) { + awaitAll(target.options.$animations, newOptions).then(() => { + target.options = newOptions; + }, () => { + }); + } + return animations; + } + _createAnimations(target, values) { + const animatedProps = this._properties; + const animations = []; + const running = target.$animations || (target.$animations = {}); + const props = Object.keys(values); + const date = Date.now(); + let i; + for (i = props.length - 1; i >= 0; --i) { + const prop = props[i]; + if (prop.charAt(0) === '$') { + continue; + } + if (prop === 'options') { + animations.push(...this._animateOptions(target, values)); + continue; + } + const value = values[prop]; + let animation = running[prop]; + const cfg = animatedProps.get(prop); + if (animation) { + if (cfg && animation.active()) { + animation.update(cfg, value, date); + continue; + } else { + animation.cancel(); + } + } + if (!cfg || !cfg.duration) { + target[prop] = value; + continue; + } + running[prop] = animation = new Animation(cfg, target, prop, value); + animations.push(animation); + } + return animations; + } + update(target, values) { + if (this._properties.size === 0) { + Object.assign(target, values); + return; + } + const animations = this._createAnimations(target, values); + if (animations.length) { + animator.add(this._chart, animations); + return true; + } + } +} +function awaitAll(animations, properties) { + const running = []; + const keys = Object.keys(properties); + for (let i = 0; i < keys.length; i++) { + const anim = animations[keys[i]]; + if (anim && anim.active()) { + running.push(anim.wait()); + } + } + return Promise.all(running); +} +function resolveTargetOptions(target, newOptions) { + if (!newOptions) { + return; + } + let options = target.options; + if (!options) { + target.options = newOptions; + return; + } + if (options.$shared) { + target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); + } + return options; +} + +function scaleClip(scale, allowedOverflow) { + const opts = scale && scale.options || {}; + const reverse = opts.reverse; + const min = opts.min === undefined ? allowedOverflow : 0; + const max = opts.max === undefined ? allowedOverflow : 0; + return { + start: reverse ? max : min, + end: reverse ? min : max + }; +} +function defaultClip(xScale, yScale, allowedOverflow) { + if (allowedOverflow === false) { + return false; + } + const x = scaleClip(xScale, allowedOverflow); + const y = scaleClip(yScale, allowedOverflow); + return { + top: y.end, + right: x.end, + bottom: y.start, + left: x.start + }; +} +function toClip(value) { + let t, r, b, l; + if (isObject(value)) { + t = value.top; + r = value.right; + b = value.bottom; + l = value.left; + } else { + t = r = b = l = value; + } + return { + top: t, + right: r, + bottom: b, + left: l, + disabled: value === false + }; +} +function getSortedDatasetIndices(chart, filterVisible) { + const keys = []; + const metasets = chart._getSortedDatasetMetas(filterVisible); + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + keys.push(metasets[i].index); + } + return keys; +} +function applyStack(stack, value, dsIndex, options = {}) { + const keys = stack.keys; + const singleMode = options.mode === 'single'; + let i, ilen, datasetIndex, otherValue; + if (value === null) { + return; + } + for (i = 0, ilen = keys.length; i < ilen; ++i) { + datasetIndex = +keys[i]; + if (datasetIndex === dsIndex) { + if (options.all) { + continue; + } + break; + } + otherValue = stack.values[datasetIndex]; + if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) { + value += otherValue; + } + } + return value; +} +function convertObjectDataToArray(data) { + const keys = Object.keys(data); + const adata = new Array(keys.length); + let i, ilen, key; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + adata[i] = { + x: key, + y: data[key] + }; + } + return adata; +} +function isStacked(scale, meta) { + const stacked = scale && scale.options.stacked; + return stacked || (stacked === undefined && meta.stack !== undefined); +} +function getStackKey(indexScale, valueScale, meta) { + return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; +} +function getUserBounds(scale) { + const {min, max, minDefined, maxDefined} = scale.getUserBounds(); + return { + min: minDefined ? min : Number.NEGATIVE_INFINITY, + max: maxDefined ? max : Number.POSITIVE_INFINITY + }; +} +function getOrCreateStack(stacks, stackKey, indexValue) { + const subStack = stacks[stackKey] || (stacks[stackKey] = {}); + return subStack[indexValue] || (subStack[indexValue] = {}); +} +function getLastIndexInStack(stack, vScale, positive, type) { + for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) { + const value = stack[meta.index]; + if ((positive && value > 0) || (!positive && value < 0)) { + return meta.index; + } + } + return null; +} +function updateStacks(controller, parsed) { + const {chart, _cachedMeta: meta} = controller; + const stacks = chart._stacks || (chart._stacks = {}); + const {iScale, vScale, index: datasetIndex} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const key = getStackKey(iScale, vScale, meta); + const ilen = parsed.length; + let stack; + for (let i = 0; i < ilen; ++i) { + const item = parsed[i]; + const {[iAxis]: index, [vAxis]: value} = item; + const itemStacks = item._stacks || (item._stacks = {}); + stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); + stack[datasetIndex] = value; + stack._top = getLastIndexInStack(stack, vScale, true, meta.type); + stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); + } +} +function getFirstScaleId(chart, axis) { + const scales = chart.scales; + return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); +} +function createDatasetContext(parent, index) { + return createContext(parent, + { + active: false, + dataset: undefined, + datasetIndex: index, + index, + mode: 'default', + type: 'dataset' + } + ); +} +function createDataContext(parent, index, element) { + return createContext(parent, { + active: false, + dataIndex: index, + parsed: undefined, + raw: undefined, + element, + index, + mode: 'default', + type: 'data' + }); +} +function clearStacks(meta, items) { + const datasetIndex = meta.controller.index; + const axis = meta.vScale && meta.vScale.axis; + if (!axis) { + return; + } + items = items || meta._parsed; + for (const parsed of items) { + const stacks = parsed._stacks; + if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { + return; + } + delete stacks[axis][datasetIndex]; + } +} +const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none'; +const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached); +const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked + && {keys: getSortedDatasetIndices(chart, true), values: null}; +class DatasetController { + constructor(chart, datasetIndex) { + this.chart = chart; + this._ctx = chart.ctx; + this.index = datasetIndex; + this._cachedDataOpts = {}; + this._cachedMeta = this.getMeta(); + this._type = this._cachedMeta.type; + this.options = undefined; + this._parsing = false; + this._data = undefined; + this._objectData = undefined; + this._sharedOptions = undefined; + this._drawStart = undefined; + this._drawCount = undefined; + this.enableOptionSharing = false; + this.$context = undefined; + this._syncList = []; + this.initialize(); + } + initialize() { + const meta = this._cachedMeta; + this.configure(); + this.linkScales(); + meta._stacked = isStacked(meta.vScale, meta); + this.addElements(); + } + updateIndex(datasetIndex) { + if (this.index !== datasetIndex) { + clearStacks(this._cachedMeta); + } + this.index = datasetIndex; + } + linkScales() { + const chart = this.chart; + const meta = this._cachedMeta; + const dataset = this.getDataset(); + const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; + const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); + const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); + const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); + const indexAxis = meta.indexAxis; + const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); + const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); + meta.xScale = this.getScaleForId(xid); + meta.yScale = this.getScaleForId(yid); + meta.rScale = this.getScaleForId(rid); + meta.iScale = this.getScaleForId(iid); + meta.vScale = this.getScaleForId(vid); + } + getDataset() { + return this.chart.data.datasets[this.index]; + } + getMeta() { + return this.chart.getDatasetMeta(this.index); + } + getScaleForId(scaleID) { + return this.chart.scales[scaleID]; + } + _getOtherScale(scale) { + const meta = this._cachedMeta; + return scale === meta.iScale + ? meta.vScale + : meta.iScale; + } + reset() { + this._update('reset'); + } + _destroy() { + const meta = this._cachedMeta; + if (this._data) { + unlistenArrayEvents(this._data, this); + } + if (meta._stacked) { + clearStacks(meta); + } + } + _dataCheck() { + const dataset = this.getDataset(); + const data = dataset.data || (dataset.data = []); + const _data = this._data; + if (isObject(data)) { + this._data = convertObjectDataToArray(data); + } else if (_data !== data) { + if (_data) { + unlistenArrayEvents(_data, this); + const meta = this._cachedMeta; + clearStacks(meta); + meta._parsed = []; + } + if (data && Object.isExtensible(data)) { + listenArrayEvents(data, this); + } + this._syncList = []; + this._data = data; + } + } + addElements() { + const meta = this._cachedMeta; + this._dataCheck(); + if (this.datasetElementType) { + meta.dataset = new this.datasetElementType(); + } + } + buildOrUpdateElements(resetNewElements) { + const meta = this._cachedMeta; + const dataset = this.getDataset(); + let stackChanged = false; + this._dataCheck(); + const oldStacked = meta._stacked; + meta._stacked = isStacked(meta.vScale, meta); + if (meta.stack !== dataset.stack) { + stackChanged = true; + clearStacks(meta); + meta.stack = dataset.stack; + } + this._resyncElements(resetNewElements); + if (stackChanged || oldStacked !== meta._stacked) { + updateStacks(this, meta._parsed); + } + } + configure() { + const config = this.chart.config; + const scopeKeys = config.datasetScopeKeys(this._type); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); + this.options = config.createResolver(scopes, this.getContext()); + this._parsing = this.options.parsing; + this._cachedDataOpts = {}; + } + parse(start, count) { + const {_cachedMeta: meta, _data: data} = this; + const {iScale, _stacked} = meta; + const iAxis = iScale.axis; + let sorted = start === 0 && count === data.length ? true : meta._sorted; + let prev = start > 0 && meta._parsed[start - 1]; + let i, cur, parsed; + if (this._parsing === false) { + meta._parsed = data; + meta._sorted = true; + parsed = data; + } else { + if (isArray(data[start])) { + parsed = this.parseArrayData(meta, data, start, count); + } else if (isObject(data[start])) { + parsed = this.parseObjectData(meta, data, start, count); + } else { + parsed = this.parsePrimitiveData(meta, data, start, count); + } + const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]); + for (i = 0; i < count; ++i) { + meta._parsed[i + start] = cur = parsed[i]; + if (sorted) { + if (isNotInOrderComparedToPrev()) { + sorted = false; + } + prev = cur; + } + } + meta._sorted = sorted; + } + if (_stacked) { + updateStacks(this, parsed); + } + } + parsePrimitiveData(meta, data, start, count) { + const {iScale, vScale} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = new Array(count); + let i, ilen, index; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + parsed[i] = { + [iAxis]: singleScale || iScale.parse(labels[index], index), + [vAxis]: vScale.parse(data[index], index) + }; + } + return parsed; + } + parseArrayData(meta, data, start, count) { + const {xScale, yScale} = meta; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(item[0], index), + y: yScale.parse(item[1], index) + }; + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const {xScale, yScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(resolveObjectKey(item, xAxisKey), index), + y: yScale.parse(resolveObjectKey(item, yAxisKey), index) + }; + } + return parsed; + } + getParsed(index) { + return this._cachedMeta._parsed[index]; + } + getDataElement(index) { + return this._cachedMeta.data[index]; + } + applyStack(scale, parsed, mode) { + const chart = this.chart; + const meta = this._cachedMeta; + const value = parsed[scale.axis]; + const stack = { + keys: getSortedDatasetIndices(chart, true), + values: parsed._stacks[scale.axis] + }; + return applyStack(stack, value, meta.index, {mode}); + } + updateRangeFromParsed(range, scale, parsed, stack) { + const parsedValue = parsed[scale.axis]; + let value = parsedValue === null ? NaN : parsedValue; + const values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + value = applyStack(stack, parsedValue, this._cachedMeta.index); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + } + getMinMax(scale, canStack) { + const meta = this._cachedMeta; + const _parsed = meta._parsed; + const sorted = meta._sorted && scale === meta.iScale; + const ilen = _parsed.length; + const otherScale = this._getOtherScale(scale); + const stack = createStack(canStack, meta, this.chart); + const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; + const {min: otherMin, max: otherMax} = getUserBounds(otherScale); + let i, parsed; + function _skip() { + parsed = _parsed[i]; + const otherValue = parsed[otherScale.axis]; + return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; + } + for (i = 0; i < ilen; ++i) { + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + if (sorted) { + break; + } + } + if (sorted) { + for (i = ilen - 1; i >= 0; --i) { + if (_skip()) { + continue; + } + this.updateRangeFromParsed(range, scale, parsed, stack); + break; + } + } + return range; + } + getAllParsedValues(scale) { + const parsed = this._cachedMeta._parsed; + const values = []; + let i, ilen, value; + for (i = 0, ilen = parsed.length; i < ilen; ++i) { + value = parsed[i][scale.axis]; + if (isNumberFinite(value)) { + values.push(value); + } + } + return values; + } + getMaxOverflow() { + return false; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const iScale = meta.iScale; + const vScale = meta.vScale; + const parsed = this.getParsed(index); + return { + label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', + value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' + }; + } + _update(mode) { + const meta = this._cachedMeta; + this.update(mode || 'default'); + meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); + } + update(mode) {} + draw() { + const ctx = this._ctx; + const chart = this.chart; + const meta = this._cachedMeta; + const elements = meta.data || []; + const area = chart.chartArea; + const active = []; + const start = this._drawStart || 0; + const count = this._drawCount || (elements.length - start); + const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; + let i; + if (meta.dataset) { + meta.dataset.draw(ctx, area, start, count); + } + for (i = start; i < start + count; ++i) { + const element = elements[i]; + if (element.hidden) { + continue; + } + if (element.active && drawActiveElementsOnTop) { + active.push(element); + } else { + element.draw(ctx, area); + } + } + for (i = 0; i < active.length; ++i) { + active[i].draw(ctx, area); + } + } + getStyle(index, active) { + const mode = active ? 'active' : 'default'; + return index === undefined && this._cachedMeta.dataset + ? this.resolveDatasetElementOptions(mode) + : this.resolveDataElementOptions(index || 0, mode); + } + getContext(index, active, mode) { + const dataset = this.getDataset(); + let context; + if (index >= 0 && index < this._cachedMeta.data.length) { + const element = this._cachedMeta.data[index]; + context = element.$context || + (element.$context = createDataContext(this.getContext(), index, element)); + context.parsed = this.getParsed(index); + context.raw = dataset.data[index]; + context.index = context.dataIndex = index; + } else { + context = this.$context || + (this.$context = createDatasetContext(this.chart.getContext(), this.index)); + context.dataset = dataset; + context.index = context.datasetIndex = this.index; + } + context.active = !!active; + context.mode = mode; + return context; + } + resolveDatasetElementOptions(mode) { + return this._resolveElementOptions(this.datasetElementType.id, mode); + } + resolveDataElementOptions(index, mode) { + return this._resolveElementOptions(this.dataElementType.id, mode, index); + } + _resolveElementOptions(elementType, mode = 'default', index) { + const active = mode === 'active'; + const cache = this._cachedDataOpts; + const cacheKey = elementType + '-' + mode; + const cached = cache[cacheKey]; + const sharing = this.enableOptionSharing && defined(index); + if (cached) { + return cloneIfNotShared(cached, sharing); + } + const config = this.chart.config; + const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); + const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, '']; + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + const names = Object.keys(defaults.elements[elementType]); + const context = () => this.getContext(index, active); + const values = config.resolveNamedOptions(scopes, names, context, prefixes); + if (values.$shared) { + values.$shared = sharing; + cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); + } + return values; + } + _resolveAnimations(index, transition, active) { + const chart = this.chart; + const cache = this._cachedDataOpts; + const cacheKey = `animation-${transition}`; + const cached = cache[cacheKey]; + if (cached) { + return cached; + } + let options; + if (chart.options.animation !== false) { + const config = this.chart.config; + const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); + const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); + options = config.createResolver(scopes, this.getContext(index, active, transition)); + } + const animations = new Animations(chart, options && options.animations); + if (options && options._cacheable) { + cache[cacheKey] = Object.freeze(animations); + } + return animations; + } + getSharedOptions(options) { + if (!options.$shared) { + return; + } + return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); + } + includeOptions(mode, sharedOptions) { + return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; + } + updateElement(element, index, properties, mode) { + if (isDirectUpdateMode(mode)) { + Object.assign(element, properties); + } else { + this._resolveAnimations(index, mode).update(element, properties); + } + } + updateSharedOptions(sharedOptions, mode, newOptions) { + if (sharedOptions && !isDirectUpdateMode(mode)) { + this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); + } + } + _setStyle(element, index, mode, active) { + element.active = active; + const options = this.getStyle(index, active); + this._resolveAnimations(index, mode, active).update(element, { + options: (!active && this.getSharedOptions(options)) || options + }); + } + removeHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', false); + } + setHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', true); + } + _removeDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', false); + } + } + _setDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', true); + } + } + _resyncElements(resetNewElements) { + const data = this._data; + const elements = this._cachedMeta.data; + for (const [method, arg1, arg2] of this._syncList) { + this[method](arg1, arg2); + } + this._syncList = []; + const numMeta = elements.length; + const numData = data.length; + const count = Math.min(numData, numMeta); + if (count) { + this.parse(0, count); + } + if (numData > numMeta) { + this._insertElements(numMeta, numData - numMeta, resetNewElements); + } else if (numData < numMeta) { + this._removeElements(numData, numMeta - numData); + } + } + _insertElements(start, count, resetNewElements = true) { + const meta = this._cachedMeta; + const data = meta.data; + const end = start + count; + let i; + const move = (arr) => { + arr.length += count; + for (i = arr.length - 1; i >= end; i--) { + arr[i] = arr[i - count]; + } + }; + move(data); + for (i = start; i < end; ++i) { + data[i] = new this.dataElementType(); + } + if (this._parsing) { + move(meta._parsed); + } + this.parse(start, count); + if (resetNewElements) { + this.updateElements(data, start, count, 'reset'); + } + } + updateElements(element, start, count, mode) {} + _removeElements(start, count) { + const meta = this._cachedMeta; + if (this._parsing) { + const removed = meta._parsed.splice(start, count); + if (meta._stacked) { + clearStacks(meta, removed); + } + } + meta.data.splice(start, count); + } + _sync(args) { + if (this._parsing) { + this._syncList.push(args); + } else { + const [method, arg1, arg2] = args; + this[method](arg1, arg2); + } + this.chart._dataChanges.push([this.index, ...args]); + } + _onDataPush() { + const count = arguments.length; + this._sync(['_insertElements', this.getDataset().data.length - count, count]); + } + _onDataPop() { + this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]); + } + _onDataShift() { + this._sync(['_removeElements', 0, 1]); + } + _onDataSplice(start, count) { + if (count) { + this._sync(['_removeElements', start, count]); + } + const newCount = arguments.length - 2; + if (newCount) { + this._sync(['_insertElements', start, newCount]); + } + } + _onDataUnshift() { + this._sync(['_insertElements', 0, arguments.length]); + } +} +DatasetController.defaults = {}; +DatasetController.prototype.datasetElementType = null; +DatasetController.prototype.dataElementType = null; + +class Element { + constructor() { + this.x = undefined; + this.y = undefined; + this.active = false; + this.options = undefined; + this.$animations = undefined; + } + tooltipPosition(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + hasValue() { + return isNumber(this.x) && isNumber(this.y); + } + getProps(props, final) { + const anims = this.$animations; + if (!final || !anims) { + return this; + } + const ret = {}; + props.forEach(prop => { + ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; + }); + return ret; + } +} +Element.defaults = {}; +Element.defaultRoutes = undefined; + +const formatters = { + values(value) { + return isArray(value) ? value : '' + value; + }, + numeric(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const locale = this.chart.options.locale; + let notation; + let delta = tickValue; + if (ticks.length > 1) { + const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); + if (maxTick < 1e-4 || maxTick > 1e+15) { + notation = 'scientific'; + } + delta = calculateDelta(tickValue, ticks); + } + const logDelta = log10(Math.abs(delta)); + const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); + const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; + Object.assign(options, this.options.ticks.format); + return formatNumber(tickValue, locale, options); + }, + logarithmic(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); + if (remain === 1 || remain === 2 || remain === 5) { + return formatters.numeric.call(this, tickValue, index, ticks); + } + return ''; + } +}; +function calculateDelta(tickValue, ticks) { + let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; + if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { + delta = tickValue - Math.floor(tickValue); + } + return delta; +} +var Ticks = {formatters}; + +defaults.set('scale', { + display: true, + offset: false, + reverse: false, + beginAtZero: false, + bounds: 'ticks', + grace: 0, + grid: { + display: true, + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickLength: 8, + tickWidth: (_ctx, options) => options.lineWidth, + tickColor: (_ctx, options) => options.color, + offset: false, + borderDash: [], + borderDashOffset: 0.0, + borderWidth: 1 + }, + title: { + display: false, + text: '', + padding: { + top: 4, + bottom: 4 + } + }, + ticks: { + minRotation: 0, + maxRotation: 50, + mirror: false, + textStrokeWidth: 0, + textStrokeColor: '', + padding: 3, + display: true, + autoSkip: true, + autoSkipPadding: 3, + labelOffset: 0, + callback: Ticks.formatters.values, + minor: {}, + major: {}, + align: 'center', + crossAlign: 'near', + showLabelBackdrop: false, + backdropColor: 'rgba(255, 255, 255, 0.75)', + backdropPadding: 2, + } +}); +defaults.route('scale.ticks', 'color', '', 'color'); +defaults.route('scale.grid', 'color', '', 'borderColor'); +defaults.route('scale.grid', 'borderColor', '', 'borderColor'); +defaults.route('scale.title', 'color', '', 'color'); +defaults.describe('scale', { + _fallback: false, + _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', + _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash', +}); +defaults.describe('scales', { + _fallback: 'scale', +}); +defaults.describe('scale.ticks', { + _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback', + _indexable: (name) => name !== 'backdropPadding', +}); + +function autoSkip(scale, ticks) { + const tickOpts = scale.options.ticks; + const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale); + const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; + const numMajorIndices = majorIndices.length; + const first = majorIndices[0]; + const last = majorIndices[numMajorIndices - 1]; + const newTicks = []; + if (numMajorIndices > ticksLimit) { + skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); + return newTicks; + } + const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); + if (numMajorIndices > 0) { + let i, ilen; + const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; + skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); + for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { + skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); + } + skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); + return newTicks; + } + skip(ticks, newTicks, spacing); + return newTicks; +} +function determineMaxTicks(scale) { + const offset = scale.options.offset; + const tickLength = scale._tickSize(); + const maxScale = scale._length / tickLength + (offset ? 0 : 1); + const maxChart = scale._maxLength / tickLength; + return Math.floor(Math.min(maxScale, maxChart)); +} +function calculateSpacing(majorIndices, ticks, ticksLimit) { + const evenMajorSpacing = getEvenSpacing(majorIndices); + const spacing = ticks.length / ticksLimit; + if (!evenMajorSpacing) { + return Math.max(spacing, 1); + } + const factors = _factorize(evenMajorSpacing); + for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { + const factor = factors[i]; + if (factor > spacing) { + return factor; + } + } + return Math.max(spacing, 1); +} +function getMajorIndices(ticks) { + const result = []; + let i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (ticks[i].major) { + result.push(i); + } + } + return result; +} +function skipMajors(ticks, newTicks, majorIndices, spacing) { + let count = 0; + let next = majorIndices[0]; + let i; + spacing = Math.ceil(spacing); + for (i = 0; i < ticks.length; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = majorIndices[count * spacing]; + } + } +} +function skip(ticks, newTicks, spacing, majorStart, majorEnd) { + const start = valueOrDefault(majorStart, 0); + const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); + let count = 0; + let length, i, next; + spacing = Math.ceil(spacing); + if (majorEnd) { + length = majorEnd - majorStart; + spacing = length / Math.floor(length / spacing); + } + next = start; + while (next < 0) { + count++; + next = Math.round(start + count * spacing); + } + for (i = Math.max(start, 0); i < end; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = Math.round(start + count * spacing); + } + } +} +function getEvenSpacing(arr) { + const len = arr.length; + let i, diff; + if (len < 2) { + return false; + } + for (diff = arr[0], i = 1; i < len; ++i) { + if (arr[i] - arr[i - 1] !== diff) { + return false; + } + } + return diff; +} + +const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align; +const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; +function sample(arr, numItems) { + const result = []; + const increment = arr.length / numItems; + const len = arr.length; + let i = 0; + for (; i < len; i += increment) { + result.push(arr[Math.floor(i)]); + } + return result; +} +function getPixelForGridLine(scale, index, offsetGridLines) { + const length = scale.ticks.length; + const validIndex = Math.min(index, length - 1); + const start = scale._startPixel; + const end = scale._endPixel; + const epsilon = 1e-6; + let lineValue = scale.getPixelForTick(validIndex); + let offset; + if (offsetGridLines) { + if (length === 1) { + offset = Math.max(lineValue - start, end - lineValue); + } else if (index === 0) { + offset = (scale.getPixelForTick(1) - lineValue) / 2; + } else { + offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; + } + lineValue += validIndex < index ? offset : -offset; + if (lineValue < start - epsilon || lineValue > end + epsilon) { + return; + } + } + return lineValue; +} +function garbageCollect(caches, length) { + each(caches, (cache) => { + const gc = cache.gc; + const gcLen = gc.length / 2; + let i; + if (gcLen > length) { + for (i = 0; i < gcLen; ++i) { + delete cache.data[gc[i]]; + } + gc.splice(0, gcLen); + } + }); +} +function getTickMarkLength(options) { + return options.drawTicks ? options.tickLength : 0; +} +function getTitleHeight(options, fallback) { + if (!options.display) { + return 0; + } + const font = toFont(options.font, fallback); + const padding = toPadding(options.padding); + const lines = isArray(options.text) ? options.text.length : 1; + return (lines * font.lineHeight) + padding.height; +} +function createScaleContext(parent, scale) { + return createContext(parent, { + scale, + type: 'scale' + }); +} +function createTickContext(parent, index, tick) { + return createContext(parent, { + tick, + index, + type: 'tick' + }); +} +function titleAlign(align, position, reverse) { + let ret = _toLeftRightCenter(align); + if ((reverse && position !== 'right') || (!reverse && position === 'right')) { + ret = reverseAlign(ret); + } + return ret; +} +function titleArgs(scale, offset, position, align) { + const {top, left, bottom, right, chart} = scale; + const {chartArea, scales} = chart; + let rotation = 0; + let maxWidth, titleX, titleY; + const height = bottom - top; + const width = right - left; + if (scale.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; + } else if (position === 'center') { + titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; + } else { + titleY = offsetFromEdge(scale, position, offset); + } + maxWidth = right - left; + } else { + if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; + } else if (position === 'center') { + titleX = (chartArea.left + chartArea.right) / 2 - width + offset; + } else { + titleX = offsetFromEdge(scale, position, offset); + } + titleY = _alignStartEnd(align, bottom, top); + rotation = position === 'left' ? -HALF_PI : HALF_PI; + } + return {titleX, titleY, maxWidth, rotation}; +} +class Scale extends Element { + constructor(cfg) { + super(); + this.id = cfg.id; + this.type = cfg.type; + this.options = undefined; + this.ctx = cfg.ctx; + this.chart = cfg.chart; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this._margins = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + this.maxWidth = undefined; + this.maxHeight = undefined; + this.paddingTop = undefined; + this.paddingBottom = undefined; + this.paddingLeft = undefined; + this.paddingRight = undefined; + this.axis = undefined; + this.labelRotation = undefined; + this.min = undefined; + this.max = undefined; + this._range = undefined; + this.ticks = []; + this._gridLineItems = null; + this._labelItems = null; + this._labelSizes = null; + this._length = 0; + this._maxLength = 0; + this._longestTextCache = {}; + this._startPixel = undefined; + this._endPixel = undefined; + this._reversePixels = false; + this._userMax = undefined; + this._userMin = undefined; + this._suggestedMax = undefined; + this._suggestedMin = undefined; + this._ticksLength = 0; + this._borderValue = 0; + this._cache = {}; + this._dataLimitsCached = false; + this.$context = undefined; + } + init(options) { + this.options = options.setContext(this.getContext()); + this.axis = options.axis; + this._userMin = this.parse(options.min); + this._userMax = this.parse(options.max); + this._suggestedMin = this.parse(options.suggestedMin); + this._suggestedMax = this.parse(options.suggestedMax); + } + parse(raw, index) { + return raw; + } + getUserBounds() { + let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this; + _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); + _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); + _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); + _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); + return { + min: finiteOrDefault(_userMin, _suggestedMin), + max: finiteOrDefault(_userMax, _suggestedMax), + minDefined: isNumberFinite(_userMin), + maxDefined: isNumberFinite(_userMax) + }; + } + getMinMax(canStack) { + let {min, max, minDefined, maxDefined} = this.getUserBounds(); + let range; + if (minDefined && maxDefined) { + return {min, max}; + } + const metas = this.getMatchingVisibleMetas(); + for (let i = 0, ilen = metas.length; i < ilen; ++i) { + range = metas[i].controller.getMinMax(this, canStack); + if (!minDefined) { + min = Math.min(min, range.min); + } + if (!maxDefined) { + max = Math.max(max, range.max); + } + } + min = maxDefined && min > max ? max : min; + max = minDefined && min > max ? min : max; + return { + min: finiteOrDefault(min, finiteOrDefault(max, min)), + max: finiteOrDefault(max, finiteOrDefault(min, max)) + }; + } + getPadding() { + return { + left: this.paddingLeft || 0, + top: this.paddingTop || 0, + right: this.paddingRight || 0, + bottom: this.paddingBottom || 0 + }; + } + getTicks() { + return this.ticks; + } + getLabels() { + const data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; + } + beforeLayout() { + this._cache = {}; + this._dataLimitsCached = false; + } + beforeUpdate() { + callback(this.options.beforeUpdate, [this]); + } + update(maxWidth, maxHeight, margins) { + const {beginAtZero, grace, ticks: tickOpts} = this.options; + const sampleSize = tickOpts.sampleSize; + this.beforeUpdate(); + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins = Object.assign({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + this.ticks = null; + this._labelSizes = null; + this._gridLineItems = null; + this._labelItems = null; + this.beforeSetDimensions(); + this.setDimensions(); + this.afterSetDimensions(); + this._maxLength = this.isHorizontal() + ? this.width + margins.left + margins.right + : this.height + margins.top + margins.bottom; + if (!this._dataLimitsCached) { + this.beforeDataLimits(); + this.determineDataLimits(); + this.afterDataLimits(); + this._range = _addGrace(this, grace, beginAtZero); + this._dataLimitsCached = true; + } + this.beforeBuildTicks(); + this.ticks = this.buildTicks() || []; + this.afterBuildTicks(); + const samplingEnabled = sampleSize < this.ticks.length; + this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); + this.configure(); + this.beforeCalculateLabelRotation(); + this.calculateLabelRotation(); + this.afterCalculateLabelRotation(); + if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { + this.ticks = autoSkip(this, this.ticks); + this._labelSizes = null; + } + if (samplingEnabled) { + this._convertTicksToLabels(this.ticks); + } + this.beforeFit(); + this.fit(); + this.afterFit(); + this.afterUpdate(); + } + configure() { + let reversePixels = this.options.reverse; + let startPixel, endPixel; + if (this.isHorizontal()) { + startPixel = this.left; + endPixel = this.right; + } else { + startPixel = this.top; + endPixel = this.bottom; + reversePixels = !reversePixels; + } + this._startPixel = startPixel; + this._endPixel = endPixel; + this._reversePixels = reversePixels; + this._length = endPixel - startPixel; + this._alignToPixels = this.options.alignToPixels; + } + afterUpdate() { + callback(this.options.afterUpdate, [this]); + } + beforeSetDimensions() { + callback(this.options.beforeSetDimensions, [this]); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = 0; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = 0; + this.bottom = this.height; + } + this.paddingLeft = 0; + this.paddingTop = 0; + this.paddingRight = 0; + this.paddingBottom = 0; + } + afterSetDimensions() { + callback(this.options.afterSetDimensions, [this]); + } + _callHooks(name) { + this.chart.notifyPlugins(name, this.getContext()); + callback(this.options[name], [this]); + } + beforeDataLimits() { + this._callHooks('beforeDataLimits'); + } + determineDataLimits() {} + afterDataLimits() { + this._callHooks('afterDataLimits'); + } + beforeBuildTicks() { + this._callHooks('beforeBuildTicks'); + } + buildTicks() { + return []; + } + afterBuildTicks() { + this._callHooks('afterBuildTicks'); + } + beforeTickToLabelConversion() { + callback(this.options.beforeTickToLabelConversion, [this]); + } + generateTickLabels(ticks) { + const tickOpts = this.options.ticks; + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + tick = ticks[i]; + tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this); + } + } + afterTickToLabelConversion() { + callback(this.options.afterTickToLabelConversion, [this]); + } + beforeCalculateLabelRotation() { + callback(this.options.beforeCalculateLabelRotation, [this]); + } + calculateLabelRotation() { + const options = this.options; + const tickOpts = options.ticks; + const numTicks = this.ticks.length; + const minRotation = tickOpts.minRotation || 0; + const maxRotation = tickOpts.maxRotation; + let labelRotation = minRotation; + let tickWidth, maxHeight, maxLabelDiagonal; + if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { + this.labelRotation = minRotation; + return; + } + const labelSizes = this._getLabelSizes(); + const maxLabelWidth = labelSizes.widest.width; + const maxLabelHeight = labelSizes.highest.height; + const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); + tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); + if (maxLabelWidth + 6 > tickWidth) { + tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); + maxHeight = this.maxHeight - getTickMarkLength(options.grid) + - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); + maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); + labelRotation = toDegrees(Math.min( + Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), + Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)) + )); + labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); + } + this.labelRotation = labelRotation; + } + afterCalculateLabelRotation() { + callback(this.options.afterCalculateLabelRotation, [this]); + } + beforeFit() { + callback(this.options.beforeFit, [this]); + } + fit() { + const minSize = { + width: 0, + height: 0 + }; + const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this; + const display = this._isVisible(); + const isHorizontal = this.isHorizontal(); + if (display) { + const titleHeight = getTitleHeight(titleOpts, chart.options.font); + if (isHorizontal) { + minSize.width = this.maxWidth; + minSize.height = getTickMarkLength(gridOpts) + titleHeight; + } else { + minSize.height = this.maxHeight; + minSize.width = getTickMarkLength(gridOpts) + titleHeight; + } + if (tickOpts.display && this.ticks.length) { + const {first, last, widest, highest} = this._getLabelSizes(); + const tickPadding = tickOpts.padding * 2; + const angleRadians = toRadians(this.labelRotation); + const cos = Math.cos(angleRadians); + const sin = Math.sin(angleRadians); + if (isHorizontal) { + const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; + minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); + } else { + const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; + minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); + } + this._calculatePadding(first, last, sin, cos); + } + } + this._handleMargins(); + if (isHorizontal) { + this.width = this._length = chart.width - this._margins.left - this._margins.right; + this.height = minSize.height; + } else { + this.width = minSize.width; + this.height = this._length = chart.height - this._margins.top - this._margins.bottom; + } + } + _calculatePadding(first, last, sin, cos) { + const {ticks: {align, padding}, position} = this.options; + const isRotated = this.labelRotation !== 0; + const labelsBelowTicks = position !== 'top' && this.axis === 'x'; + if (this.isHorizontal()) { + const offsetLeft = this.getPixelForTick(0) - this.left; + const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); + let paddingLeft = 0; + let paddingRight = 0; + if (isRotated) { + if (labelsBelowTicks) { + paddingLeft = cos * first.width; + paddingRight = sin * last.height; + } else { + paddingLeft = sin * first.height; + paddingRight = cos * last.width; + } + } else if (align === 'start') { + paddingRight = last.width; + } else if (align === 'end') { + paddingLeft = first.width; + } else { + paddingLeft = first.width / 2; + paddingRight = last.width / 2; + } + this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); + this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); + } else { + let paddingTop = last.height / 2; + let paddingBottom = first.height / 2; + if (align === 'start') { + paddingTop = 0; + paddingBottom = first.height; + } else if (align === 'end') { + paddingTop = last.height; + paddingBottom = 0; + } + this.paddingTop = paddingTop + padding; + this.paddingBottom = paddingBottom + padding; + } + } + _handleMargins() { + if (this._margins) { + this._margins.left = Math.max(this.paddingLeft, this._margins.left); + this._margins.top = Math.max(this.paddingTop, this._margins.top); + this._margins.right = Math.max(this.paddingRight, this._margins.right); + this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); + } + } + afterFit() { + callback(this.options.afterFit, [this]); + } + isHorizontal() { + const {axis, position} = this.options; + return position === 'top' || position === 'bottom' || axis === 'x'; + } + isFullSize() { + return this.options.fullSize; + } + _convertTicksToLabels(ticks) { + this.beforeTickToLabelConversion(); + this.generateTickLabels(ticks); + let i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (isNullOrUndef(ticks[i].label)) { + ticks.splice(i, 1); + ilen--; + i--; + } + } + this.afterTickToLabelConversion(); + } + _getLabelSizes() { + let labelSizes = this._labelSizes; + if (!labelSizes) { + const sampleSize = this.options.ticks.sampleSize; + let ticks = this.ticks; + if (sampleSize < ticks.length) { + ticks = sample(ticks, sampleSize); + } + this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length); + } + return labelSizes; + } + _computeLabelSizes(ticks, length) { + const {ctx, _longestTextCache: caches} = this; + const widths = []; + const heights = []; + let widestLabelSize = 0; + let highestLabelSize = 0; + let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; + for (i = 0; i < length; ++i) { + label = ticks[i].label; + tickFont = this._resolveTickFontOptions(i); + ctx.font = fontString = tickFont.string; + cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; + lineHeight = tickFont.lineHeight; + width = height = 0; + if (!isNullOrUndef(label) && !isArray(label)) { + width = _measureText(ctx, cache.data, cache.gc, width, label); + height = lineHeight; + } else if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + nestedLabel = label[j]; + if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { + width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); + height += lineHeight; + } + } + } + widths.push(width); + heights.push(height); + widestLabelSize = Math.max(width, widestLabelSize); + highestLabelSize = Math.max(height, highestLabelSize); + } + garbageCollect(caches, length); + const widest = widths.indexOf(widestLabelSize); + const highest = heights.indexOf(highestLabelSize); + const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0}); + return { + first: valueAt(0), + last: valueAt(length - 1), + widest: valueAt(widest), + highest: valueAt(highest), + widths, + heights, + }; + } + getLabelForValue(value) { + return value; + } + getPixelForValue(value, index) { + return NaN; + } + getValueForPixel(pixel) {} + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getPixelForDecimal(decimal) { + if (this._reversePixels) { + decimal = 1 - decimal; + } + const pixel = this._startPixel + decimal * this._length; + return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); + } + getDecimalForPixel(pixel) { + const decimal = (pixel - this._startPixel) / this._length; + return this._reversePixels ? 1 - decimal : decimal; + } + getBasePixel() { + return this.getPixelForValue(this.getBaseValue()); + } + getBaseValue() { + const {min, max} = this; + return min < 0 && max < 0 ? max : + min > 0 && max > 0 ? min : + 0; + } + getContext(index) { + const ticks = this.ticks || []; + if (index >= 0 && index < ticks.length) { + const tick = ticks[index]; + return tick.$context || + (tick.$context = createTickContext(this.getContext(), index, tick)); + } + return this.$context || + (this.$context = createScaleContext(this.chart.getContext(), this)); + } + _tickSize() { + const optionTicks = this.options.ticks; + const rot = toRadians(this.labelRotation); + const cos = Math.abs(Math.cos(rot)); + const sin = Math.abs(Math.sin(rot)); + const labelSizes = this._getLabelSizes(); + const padding = optionTicks.autoSkipPadding || 0; + const w = labelSizes ? labelSizes.widest.width + padding : 0; + const h = labelSizes ? labelSizes.highest.height + padding : 0; + return this.isHorizontal() + ? h * cos > w * sin ? w / cos : h / sin + : h * sin < w * cos ? h / cos : w / sin; + } + _isVisible() { + const display = this.options.display; + if (display !== 'auto') { + return !!display; + } + return this.getMatchingVisibleMetas().length > 0; + } + _computeGridLineItems(chartArea) { + const axis = this.axis; + const chart = this.chart; + const options = this.options; + const {grid, position} = options; + const offset = grid.offset; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const ticksLength = ticks.length + (offset ? 1 : 0); + const tl = getTickMarkLength(grid); + const items = []; + const borderOpts = grid.setContext(this.getContext()); + const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0; + const axisHalfWidth = axisWidth / 2; + const alignBorderValue = function(pixel) { + return _alignPixel(chart, pixel, axisWidth); + }; + let borderValue, i, lineValue, alignedLineValue; + let tx1, ty1, tx2, ty2, x1, y1, x2, y2; + if (position === 'top') { + borderValue = alignBorderValue(this.bottom); + ty1 = this.bottom - tl; + ty2 = borderValue - axisHalfWidth; + y1 = alignBorderValue(chartArea.top) + axisHalfWidth; + y2 = chartArea.bottom; + } else if (position === 'bottom') { + borderValue = alignBorderValue(this.top); + y1 = chartArea.top; + y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; + ty1 = borderValue + axisHalfWidth; + ty2 = this.top + tl; + } else if (position === 'left') { + borderValue = alignBorderValue(this.right); + tx1 = this.right - tl; + tx2 = borderValue - axisHalfWidth; + x1 = alignBorderValue(chartArea.left) + axisHalfWidth; + x2 = chartArea.right; + } else if (position === 'right') { + borderValue = alignBorderValue(this.left); + x1 = chartArea.left; + x2 = alignBorderValue(chartArea.right) - axisHalfWidth; + tx1 = borderValue + axisHalfWidth; + tx2 = this.left + tl; + } else if (axis === 'x') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + y1 = chartArea.top; + y2 = chartArea.bottom; + ty1 = borderValue + axisHalfWidth; + ty2 = ty1 + tl; + } else if (axis === 'y') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); + } + tx1 = borderValue - axisHalfWidth; + tx2 = tx1 - tl; + x1 = chartArea.left; + x2 = chartArea.right; + } + const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); + const step = Math.max(1, Math.ceil(ticksLength / limit)); + for (i = 0; i < ticksLength; i += step) { + const optsAtIndex = grid.setContext(this.getContext(i)); + const lineWidth = optsAtIndex.lineWidth; + const lineColor = optsAtIndex.color; + const borderDash = grid.borderDash || []; + const borderDashOffset = optsAtIndex.borderDashOffset; + const tickWidth = optsAtIndex.tickWidth; + const tickColor = optsAtIndex.tickColor; + const tickBorderDash = optsAtIndex.tickBorderDash || []; + const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; + lineValue = getPixelForGridLine(this, i, offset); + if (lineValue === undefined) { + continue; + } + alignedLineValue = _alignPixel(chart, lineValue, lineWidth); + if (isHorizontal) { + tx1 = tx2 = x1 = x2 = alignedLineValue; + } else { + ty1 = ty2 = y1 = y2 = alignedLineValue; + } + items.push({ + tx1, + ty1, + tx2, + ty2, + x1, + y1, + x2, + y2, + width: lineWidth, + color: lineColor, + borderDash, + borderDashOffset, + tickWidth, + tickColor, + tickBorderDash, + tickBorderDashOffset, + }); + } + this._ticksLength = ticksLength; + this._borderValue = borderValue; + return items; + } + _computeLabelItems(chartArea) { + const axis = this.axis; + const options = this.options; + const {position, ticks: optionTicks} = options; + const isHorizontal = this.isHorizontal(); + const ticks = this.ticks; + const {align, crossAlign, padding, mirror} = optionTicks; + const tl = getTickMarkLength(options.grid); + const tickAndPadding = tl + padding; + const hTickAndPadding = mirror ? -padding : tickAndPadding; + const rotation = -toRadians(this.labelRotation); + const items = []; + let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; + let textBaseline = 'middle'; + if (position === 'top') { + y = this.bottom - hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'bottom') { + y = this.top + hTickAndPadding; + textAlign = this._getXAxisLabelAlignment(); + } else if (position === 'left') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (position === 'right') { + const ret = this._getYAxisLabelAlignment(tl); + textAlign = ret.textAlign; + x = ret.x; + } else if (axis === 'x') { + if (position === 'center') { + y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; + } + textAlign = this._getXAxisLabelAlignment(); + } else if (axis === 'y') { + if (position === 'center') { + x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + x = this.chart.scales[positionAxisID].getPixelForValue(value); + } + textAlign = this._getYAxisLabelAlignment(tl).textAlign; + } + if (axis === 'y') { + if (align === 'start') { + textBaseline = 'top'; + } else if (align === 'end') { + textBaseline = 'bottom'; + } + } + const labelSizes = this._getLabelSizes(); + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + label = tick.label; + const optsAtIndex = optionTicks.setContext(this.getContext(i)); + pixel = this.getPixelForTick(i) + optionTicks.labelOffset; + font = this._resolveTickFontOptions(i); + lineHeight = font.lineHeight; + lineCount = isArray(label) ? label.length : 1; + const halfCount = lineCount / 2; + const color = optsAtIndex.color; + const strokeColor = optsAtIndex.textStrokeColor; + const strokeWidth = optsAtIndex.textStrokeWidth; + if (isHorizontal) { + x = pixel; + if (position === 'top') { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = -lineCount * lineHeight + lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; + } else { + textOffset = -labelSizes.highest.height + lineHeight / 2; + } + } else { + if (crossAlign === 'near' || rotation !== 0) { + textOffset = lineHeight / 2; + } else if (crossAlign === 'center') { + textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; + } else { + textOffset = labelSizes.highest.height - lineCount * lineHeight; + } + } + if (mirror) { + textOffset *= -1; + } + } else { + y = pixel; + textOffset = (1 - lineCount) * lineHeight / 2; + } + let backdrop; + if (optsAtIndex.showLabelBackdrop) { + const labelPadding = toPadding(optsAtIndex.backdropPadding); + const height = labelSizes.heights[i]; + const width = labelSizes.widths[i]; + let top = y + textOffset - labelPadding.top; + let left = x - labelPadding.left; + switch (textBaseline) { + case 'middle': + top -= height / 2; + break; + case 'bottom': + top -= height; + break; + } + switch (textAlign) { + case 'center': + left -= width / 2; + break; + case 'right': + left -= width; + break; + } + backdrop = { + left, + top, + width: width + labelPadding.width, + height: height + labelPadding.height, + color: optsAtIndex.backdropColor, + }; + } + items.push({ + rotation, + label, + font, + color, + strokeColor, + strokeWidth, + textOffset, + textAlign, + textBaseline, + translation: [x, y], + backdrop, + }); + } + return items; + } + _getXAxisLabelAlignment() { + const {position, ticks} = this.options; + const rotation = -toRadians(this.labelRotation); + if (rotation) { + return position === 'top' ? 'left' : 'right'; + } + let align = 'center'; + if (ticks.align === 'start') { + align = 'left'; + } else if (ticks.align === 'end') { + align = 'right'; + } + return align; + } + _getYAxisLabelAlignment(tl) { + const {position, ticks: {crossAlign, mirror, padding}} = this.options; + const labelSizes = this._getLabelSizes(); + const tickAndPadding = tl + padding; + const widest = labelSizes.widest.width; + let textAlign; + let x; + if (position === 'left') { + if (mirror) { + x = this.right + padding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += (widest / 2); + } else { + textAlign = 'right'; + x += widest; + } + } else { + x = this.right - tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= (widest / 2); + } else { + textAlign = 'left'; + x = this.left; + } + } + } else if (position === 'right') { + if (mirror) { + x = this.left + padding; + if (crossAlign === 'near') { + textAlign = 'right'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x -= (widest / 2); + } else { + textAlign = 'left'; + x -= widest; + } + } else { + x = this.left + tickAndPadding; + if (crossAlign === 'near') { + textAlign = 'left'; + } else if (crossAlign === 'center') { + textAlign = 'center'; + x += widest / 2; + } else { + textAlign = 'right'; + x = this.right; + } + } + } else { + textAlign = 'right'; + } + return {textAlign, x}; + } + _computeLabelArea() { + if (this.options.ticks.mirror) { + return; + } + const chart = this.chart; + const position = this.options.position; + if (position === 'left' || position === 'right') { + return {top: 0, left: this.left, bottom: chart.height, right: this.right}; + } if (position === 'top' || position === 'bottom') { + return {top: this.top, left: 0, bottom: this.bottom, right: chart.width}; + } + } + drawBackground() { + const {ctx, options: {backgroundColor}, left, top, width, height} = this; + if (backgroundColor) { + ctx.save(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(left, top, width, height); + ctx.restore(); + } + } + getLineWidthForValue(value) { + const grid = this.options.grid; + if (!this._isVisible() || !grid.display) { + return 0; + } + const ticks = this.ticks; + const index = ticks.findIndex(t => t.value === value); + if (index >= 0) { + const opts = grid.setContext(this.getContext(index)); + return opts.lineWidth; + } + return 0; + } + drawGrid(chartArea) { + const grid = this.options.grid; + const ctx = this.ctx; + const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); + let i, ilen; + const drawLine = (p1, p2, style) => { + if (!style.width || !style.color) { + return; + } + ctx.save(); + ctx.lineWidth = style.width; + ctx.strokeStyle = style.color; + ctx.setLineDash(style.borderDash || []); + ctx.lineDashOffset = style.borderDashOffset; + ctx.beginPath(); + ctx.moveTo(p1.x, p1.y); + ctx.lineTo(p2.x, p2.y); + ctx.stroke(); + ctx.restore(); + }; + if (grid.display) { + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + if (grid.drawOnChartArea) { + drawLine( + {x: item.x1, y: item.y1}, + {x: item.x2, y: item.y2}, + item + ); + } + if (grid.drawTicks) { + drawLine( + {x: item.tx1, y: item.ty1}, + {x: item.tx2, y: item.ty2}, + { + color: item.tickColor, + width: item.tickWidth, + borderDash: item.tickBorderDash, + borderDashOffset: item.tickBorderDashOffset + } + ); + } + } + } + } + drawBorder() { + const {chart, ctx, options: {grid}} = this; + const borderOpts = grid.setContext(this.getContext()); + const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0; + if (!axisWidth) { + return; + } + const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; + const borderValue = this._borderValue; + let x1, x2, y1, y2; + if (this.isHorizontal()) { + x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; + x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; + y1 = y2 = borderValue; + } else { + y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; + y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; + x1 = x2 = borderValue; + } + ctx.save(); + ctx.lineWidth = borderOpts.borderWidth; + ctx.strokeStyle = borderOpts.borderColor; + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + ctx.restore(); + } + drawLabels(chartArea) { + const optionTicks = this.options.ticks; + if (!optionTicks.display) { + return; + } + const ctx = this.ctx; + const area = this._computeLabelArea(); + if (area) { + clipArea(ctx, area); + } + const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); + let i, ilen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + const tickFont = item.font; + const label = item.label; + if (item.backdrop) { + ctx.fillStyle = item.backdrop.color; + ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); + } + let y = item.textOffset; + renderText(ctx, label, 0, y, tickFont, item); + } + if (area) { + unclipArea(ctx); + } + } + drawTitle() { + const {ctx, options: {position, title, reverse}} = this; + if (!title.display) { + return; + } + const font = toFont(title.font); + const padding = toPadding(title.padding); + const align = title.align; + let offset = font.lineHeight / 2; + if (position === 'bottom' || position === 'center' || isObject(position)) { + offset += padding.bottom; + if (isArray(title.text)) { + offset += font.lineHeight * (title.text.length - 1); + } + } else { + offset += padding.top; + } + const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align); + renderText(ctx, title.text, 0, 0, font, { + color: title.color, + maxWidth, + rotation, + textAlign: titleAlign(align, position, reverse), + textBaseline: 'middle', + translation: [titleX, titleY], + }); + } + draw(chartArea) { + if (!this._isVisible()) { + return; + } + this.drawBackground(); + this.drawGrid(chartArea); + this.drawBorder(); + this.drawTitle(); + this.drawLabels(chartArea); + } + _layers() { + const opts = this.options; + const tz = opts.ticks && opts.ticks.z || 0; + const gz = valueOrDefault(opts.grid && opts.grid.z, -1); + if (!this._isVisible() || this.draw !== Scale.prototype.draw) { + return [{ + z: tz, + draw: (chartArea) => { + this.draw(chartArea); + } + }]; + } + return [{ + z: gz, + draw: (chartArea) => { + this.drawBackground(); + this.drawGrid(chartArea); + this.drawTitle(); + } + }, { + z: gz + 1, + draw: () => { + this.drawBorder(); + } + }, { + z: tz, + draw: (chartArea) => { + this.drawLabels(chartArea); + } + }]; + } + getMatchingVisibleMetas(type) { + const metas = this.chart.getSortedVisibleDatasetMetas(); + const axisID = this.axis + 'AxisID'; + const result = []; + let i, ilen; + for (i = 0, ilen = metas.length; i < ilen; ++i) { + const meta = metas[i]; + if (meta[axisID] === this.id && (!type || meta.type === type)) { + result.push(meta); + } + } + return result; + } + _resolveTickFontOptions(index) { + const opts = this.options.ticks.setContext(this.getContext(index)); + return toFont(opts.font); + } + _maxDigits() { + const fontSize = this._resolveTickFontOptions(0).lineHeight; + return (this.isHorizontal() ? this.width : this.height) / fontSize; + } +} + +class TypedRegistry { + constructor(type, scope, override) { + this.type = type; + this.scope = scope; + this.override = override; + this.items = Object.create(null); + } + isForType(type) { + return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); + } + register(item) { + const proto = Object.getPrototypeOf(item); + let parentScope; + if (isIChartComponent(proto)) { + parentScope = this.register(proto); + } + const items = this.items; + const id = item.id; + const scope = this.scope + '.' + id; + if (!id) { + throw new Error('class does not have id: ' + item); + } + if (id in items) { + return scope; + } + items[id] = item; + registerDefaults(item, scope, parentScope); + if (this.override) { + defaults.override(item.id, item.overrides); + } + return scope; + } + get(id) { + return this.items[id]; + } + unregister(item) { + const items = this.items; + const id = item.id; + const scope = this.scope; + if (id in items) { + delete items[id]; + } + if (scope && id in defaults[scope]) { + delete defaults[scope][id]; + if (this.override) { + delete overrides[id]; + } + } + } +} +function registerDefaults(item, scope, parentScope) { + const itemDefaults = merge(Object.create(null), [ + parentScope ? defaults.get(parentScope) : {}, + defaults.get(scope), + item.defaults + ]); + defaults.set(scope, itemDefaults); + if (item.defaultRoutes) { + routeDefaults(scope, item.defaultRoutes); + } + if (item.descriptors) { + defaults.describe(scope, item.descriptors); + } +} +function routeDefaults(scope, routes) { + Object.keys(routes).forEach(property => { + const propertyParts = property.split('.'); + const sourceName = propertyParts.pop(); + const sourceScope = [scope].concat(propertyParts).join('.'); + const parts = routes[property].split('.'); + const targetName = parts.pop(); + const targetScope = parts.join('.'); + defaults.route(sourceScope, sourceName, targetScope, targetName); + }); +} +function isIChartComponent(proto) { + return 'id' in proto && 'defaults' in proto; +} + +class Registry { + constructor() { + this.controllers = new TypedRegistry(DatasetController, 'datasets', true); + this.elements = new TypedRegistry(Element, 'elements'); + this.plugins = new TypedRegistry(Object, 'plugins'); + this.scales = new TypedRegistry(Scale, 'scales'); + this._typedRegistries = [this.controllers, this.scales, this.elements]; + } + add(...args) { + this._each('register', args); + } + remove(...args) { + this._each('unregister', args); + } + addControllers(...args) { + this._each('register', args, this.controllers); + } + addElements(...args) { + this._each('register', args, this.elements); + } + addPlugins(...args) { + this._each('register', args, this.plugins); + } + addScales(...args) { + this._each('register', args, this.scales); + } + getController(id) { + return this._get(id, this.controllers, 'controller'); + } + getElement(id) { + return this._get(id, this.elements, 'element'); + } + getPlugin(id) { + return this._get(id, this.plugins, 'plugin'); + } + getScale(id) { + return this._get(id, this.scales, 'scale'); + } + removeControllers(...args) { + this._each('unregister', args, this.controllers); + } + removeElements(...args) { + this._each('unregister', args, this.elements); + } + removePlugins(...args) { + this._each('unregister', args, this.plugins); + } + removeScales(...args) { + this._each('unregister', args, this.scales); + } + _each(method, args, typedRegistry) { + [...args].forEach(arg => { + const reg = typedRegistry || this._getRegistryForType(arg); + if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) { + this._exec(method, reg, arg); + } else { + each(arg, item => { + const itemReg = typedRegistry || this._getRegistryForType(item); + this._exec(method, itemReg, item); + }); + } + }); + } + _exec(method, registry, component) { + const camelMethod = _capitalize(method); + callback(component['before' + camelMethod], [], component); + registry[method](component); + callback(component['after' + camelMethod], [], component); + } + _getRegistryForType(type) { + for (let i = 0; i < this._typedRegistries.length; i++) { + const reg = this._typedRegistries[i]; + if (reg.isForType(type)) { + return reg; + } + } + return this.plugins; + } + _get(id, typedRegistry, type) { + const item = typedRegistry.get(id); + if (item === undefined) { + throw new Error('"' + id + '" is not a registered ' + type + '.'); + } + return item; + } +} +var registry = new Registry(); + +class PluginService { + constructor() { + this._init = []; + } + notify(chart, hook, args, filter) { + if (hook === 'beforeInit') { + this._init = this._createDescriptors(chart, true); + this._notify(this._init, chart, 'install'); + } + const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); + const result = this._notify(descriptors, chart, hook, args); + if (hook === 'afterDestroy') { + this._notify(descriptors, chart, 'stop'); + this._notify(this._init, chart, 'uninstall'); + } + return result; + } + _notify(descriptors, chart, hook, args) { + args = args || {}; + for (const descriptor of descriptors) { + const plugin = descriptor.plugin; + const method = plugin[hook]; + const params = [chart, args, descriptor.options]; + if (callback(method, params, plugin) === false && args.cancelable) { + return false; + } + } + return true; + } + invalidate() { + if (!isNullOrUndef(this._cache)) { + this._oldCache = this._cache; + this._cache = undefined; + } + } + _descriptors(chart) { + if (this._cache) { + return this._cache; + } + const descriptors = this._cache = this._createDescriptors(chart); + this._notifyStateChanges(chart); + return descriptors; + } + _createDescriptors(chart, all) { + const config = chart && chart.config; + const options = valueOrDefault(config.options && config.options.plugins, {}); + const plugins = allPlugins(config); + return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); + } + _notifyStateChanges(chart) { + const previousDescriptors = this._oldCache || []; + const descriptors = this._cache; + const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id)); + this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); + this._notify(diff(descriptors, previousDescriptors), chart, 'start'); + } +} +function allPlugins(config) { + const plugins = []; + const keys = Object.keys(registry.plugins.items); + for (let i = 0; i < keys.length; i++) { + plugins.push(registry.getPlugin(keys[i])); + } + const local = config.plugins || []; + for (let i = 0; i < local.length; i++) { + const plugin = local[i]; + if (plugins.indexOf(plugin) === -1) { + plugins.push(plugin); + } + } + return plugins; +} +function getOpts(options, all) { + if (!all && options === false) { + return null; + } + if (options === true) { + return {}; + } + return options; +} +function createDescriptors(chart, plugins, options, all) { + const result = []; + const context = chart.getContext(); + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + const id = plugin.id; + const opts = getOpts(options[id], all); + if (opts === null) { + continue; + } + result.push({ + plugin, + options: pluginOpts(chart.config, plugin, opts, context) + }); + } + return result; +} +function pluginOpts(config, plugin, opts, context) { + const keys = config.pluginScopeKeys(plugin); + const scopes = config.getOptionScopes(opts, keys); + return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true}); +} + +function getIndexAxis(type, options) { + const datasetDefaults = defaults.datasets[type] || {}; + const datasetOptions = (options.datasets || {})[type] || {}; + return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; +} +function getAxisFromDefaultScaleID(id, indexAxis) { + let axis = id; + if (id === '_index_') { + axis = indexAxis; + } else if (id === '_value_') { + axis = indexAxis === 'x' ? 'y' : 'x'; + } + return axis; +} +function getDefaultScaleIDFromAxis(axis, indexAxis) { + return axis === indexAxis ? '_index_' : '_value_'; +} +function axisFromPosition(position) { + if (position === 'top' || position === 'bottom') { + return 'x'; + } + if (position === 'left' || position === 'right') { + return 'y'; + } +} +function determineAxis(id, scaleOptions) { + if (id === 'x' || id === 'y') { + return id; + } + return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); +} +function mergeScaleConfig(config, options) { + const chartDefaults = overrides[config.type] || {scales: {}}; + const configScales = options.scales || {}; + const chartIndexAxis = getIndexAxis(config.type, options); + const firstIDs = Object.create(null); + const scales = Object.create(null); + Object.keys(configScales).forEach(id => { + const scaleConf = configScales[id]; + if (!isObject(scaleConf)) { + return console.error(`Invalid scale configuration for scale: ${id}`); + } + if (scaleConf._proxy) { + return console.warn(`Ignoring resolver passed as options for scale: ${id}`); + } + const axis = determineAxis(id, scaleConf); + const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); + const defaultScaleOptions = chartDefaults.scales || {}; + firstIDs[axis] = firstIDs[axis] || id; + scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]); + }); + config.data.datasets.forEach(dataset => { + const type = dataset.type || config.type; + const indexAxis = dataset.indexAxis || getIndexAxis(type, options); + const datasetDefaults = overrides[type] || {}; + const defaultScaleOptions = datasetDefaults.scales || {}; + Object.keys(defaultScaleOptions).forEach(defaultID => { + const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); + const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; + scales[id] = scales[id] || Object.create(null); + mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); + }); + }); + Object.keys(scales).forEach(key => { + const scale = scales[key]; + mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); + }); + return scales; +} +function initOptions(config) { + const options = config.options || (config.options = {}); + options.plugins = valueOrDefault(options.plugins, {}); + options.scales = mergeScaleConfig(config, options); +} +function initData(data) { + data = data || {}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + return data; +} +function initConfig(config) { + config = config || {}; + config.data = initData(config.data); + initOptions(config); + return config; +} +const keyCache = new Map(); +const keysCached = new Set(); +function cachedKeys(cacheKey, generate) { + let keys = keyCache.get(cacheKey); + if (!keys) { + keys = generate(); + keyCache.set(cacheKey, keys); + keysCached.add(keys); + } + return keys; +} +const addIfFound = (set, obj, key) => { + const opts = resolveObjectKey(obj, key); + if (opts !== undefined) { + set.add(opts); + } +}; +class Config { + constructor(config) { + this._config = initConfig(config); + this._scopeCache = new Map(); + this._resolverCache = new Map(); + } + get platform() { + return this._config.platform; + } + get type() { + return this._config.type; + } + set type(type) { + this._config.type = type; + } + get data() { + return this._config.data; + } + set data(data) { + this._config.data = initData(data); + } + get options() { + return this._config.options; + } + set options(options) { + this._config.options = options; + } + get plugins() { + return this._config.plugins; + } + update() { + const config = this._config; + this.clearCache(); + initOptions(config); + } + clearCache() { + this._scopeCache.clear(); + this._resolverCache.clear(); + } + datasetScopeKeys(datasetType) { + return cachedKeys(datasetType, + () => [[ + `datasets.${datasetType}`, + '' + ]]); + } + datasetAnimationScopeKeys(datasetType, transition) { + return cachedKeys(`${datasetType}.transition.${transition}`, + () => [ + [ + `datasets.${datasetType}.transitions.${transition}`, + `transitions.${transition}`, + ], + [ + `datasets.${datasetType}`, + '' + ] + ]); + } + datasetElementScopeKeys(datasetType, elementType) { + return cachedKeys(`${datasetType}-${elementType}`, + () => [[ + `datasets.${datasetType}.elements.${elementType}`, + `datasets.${datasetType}`, + `elements.${elementType}`, + '' + ]]); + } + pluginScopeKeys(plugin) { + const id = plugin.id; + const type = this.type; + return cachedKeys(`${type}-plugin-${id}`, + () => [[ + `plugins.${id}`, + ...plugin.additionalOptionScopes || [], + ]]); + } + _cachedScopes(mainScope, resetCache) { + const _scopeCache = this._scopeCache; + let cache = _scopeCache.get(mainScope); + if (!cache || resetCache) { + cache = new Map(); + _scopeCache.set(mainScope, cache); + } + return cache; + } + getOptionScopes(mainScope, keyLists, resetCache) { + const {options, type} = this; + const cache = this._cachedScopes(mainScope, resetCache); + const cached = cache.get(keyLists); + if (cached) { + return cached; + } + const scopes = new Set(); + keyLists.forEach(keys => { + if (mainScope) { + scopes.add(mainScope); + keys.forEach(key => addIfFound(scopes, mainScope, key)); + } + keys.forEach(key => addIfFound(scopes, options, key)); + keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); + keys.forEach(key => addIfFound(scopes, defaults, key)); + keys.forEach(key => addIfFound(scopes, descriptors, key)); + }); + const array = Array.from(scopes); + if (array.length === 0) { + array.push(Object.create(null)); + } + if (keysCached.has(keyLists)) { + cache.set(keyLists, array); + } + return array; + } + chartOptionScopes() { + const {options, type} = this; + return [ + options, + overrides[type] || {}, + defaults.datasets[type] || {}, + {type}, + defaults, + descriptors + ]; + } + resolveNamedOptions(scopes, names, context, prefixes = ['']) { + const result = {$shared: true}; + const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes); + let options = resolver; + if (needContext(resolver, names)) { + result.$shared = false; + context = isFunction(context) ? context() : context; + const subResolver = this.createResolver(scopes, context, subPrefixes); + options = _attachContext(resolver, context, subResolver); + } + for (const prop of names) { + result[prop] = options[prop]; + } + return result; + } + createResolver(scopes, context, prefixes = [''], descriptorDefaults) { + const {resolver} = getResolver(this._resolverCache, scopes, prefixes); + return isObject(context) + ? _attachContext(resolver, context, undefined, descriptorDefaults) + : resolver; + } +} +function getResolver(resolverCache, scopes, prefixes) { + let cache = resolverCache.get(scopes); + if (!cache) { + cache = new Map(); + resolverCache.set(scopes, cache); + } + const cacheKey = prefixes.join(); + let cached = cache.get(cacheKey); + if (!cached) { + const resolver = _createResolver(scopes, prefixes); + cached = { + resolver, + subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover')) + }; + cache.set(cacheKey, cached); + } + return cached; +} +const hasFunction = value => isObject(value) + && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false); +function needContext(proxy, names) { + const {isScriptable, isIndexable} = _descriptors(proxy); + for (const prop of names) { + const scriptable = isScriptable(prop); + const indexable = isIndexable(prop); + const value = (indexable || scriptable) && proxy[prop]; + if ((scriptable && (isFunction(value) || hasFunction(value))) + || (indexable && isArray(value))) { + return true; + } + } + return false; +} + +var version = "3.7.1"; + +const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; +function positionIsHorizontal(position, axis) { + return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); +} +function compare2Level(l1, l2) { + return function(a, b) { + return a[l1] === b[l1] + ? a[l2] - b[l2] + : a[l1] - b[l1]; + }; +} +function onAnimationsComplete(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + chart.notifyPlugins('afterRender'); + callback(animationOptions && animationOptions.onComplete, [context], chart); +} +function onAnimationProgress(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + callback(animationOptions && animationOptions.onProgress, [context], chart); +} +function getCanvas(item) { + if (_isDomSupported() && typeof item === 'string') { + item = document.getElementById(item); + } else if (item && item.length) { + item = item[0]; + } + if (item && item.canvas) { + item = item.canvas; + } + return item; +} +const instances = {}; +const getChart = (key) => { + const canvas = getCanvas(key); + return Object.values(instances).filter((c) => c.canvas === canvas).pop(); +}; +function moveNumericKeys(obj, start, move) { + const keys = Object.keys(obj); + for (const key of keys) { + const intKey = +key; + if (intKey >= start) { + const value = obj[key]; + delete obj[key]; + if (move > 0 || intKey > start) { + obj[intKey + move] = value; + } + } + } +} +function determineLastEvent(e, lastEvent, inChartArea, isClick) { + if (!inChartArea || e.type === 'mouseout') { + return null; + } + if (isClick) { + return lastEvent; + } + return e; +} +class Chart { + constructor(item, userConfig) { + const config = this.config = new Config(userConfig); + const initialCanvas = getCanvas(item); + const existingChart = getChart(initialCanvas); + if (existingChart) { + throw new Error( + 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + + ' must be destroyed before the canvas can be reused.' + ); + } + const options = config.createResolver(config.chartOptionScopes(), this.getContext()); + this.platform = new (config.platform || _detectPlatform(initialCanvas))(); + this.platform.updateConfig(config); + const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); + const canvas = context && context.canvas; + const height = canvas && canvas.height; + const width = canvas && canvas.width; + this.id = uid(); + this.ctx = context; + this.canvas = canvas; + this.width = width; + this.height = height; + this._options = options; + this._aspectRatio = this.aspectRatio; + this._layers = []; + this._metasets = []; + this._stacks = undefined; + this.boxes = []; + this.currentDevicePixelRatio = undefined; + this.chartArea = undefined; + this._active = []; + this._lastEvent = undefined; + this._listeners = {}; + this._responsiveListeners = undefined; + this._sortedMetasets = []; + this.scales = {}; + this._plugins = new PluginService(); + this.$proxies = {}; + this._hiddenIndices = {}; + this.attached = false; + this._animationsDisabled = undefined; + this.$context = undefined; + this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0); + this._dataChanges = []; + instances[this.id] = this; + if (!context || !canvas) { + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + animator.listen(this, 'complete', onAnimationsComplete); + animator.listen(this, 'progress', onAnimationProgress); + this._initialize(); + if (this.attached) { + this.update(); + } + } + get aspectRatio() { + const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this; + if (!isNullOrUndef(aspectRatio)) { + return aspectRatio; + } + if (maintainAspectRatio && _aspectRatio) { + return _aspectRatio; + } + return height ? width / height : null; + } + get data() { + return this.config.data; + } + set data(data) { + this.config.data = data; + } + get options() { + return this._options; + } + set options(options) { + this.config.options = options; + } + _initialize() { + this.notifyPlugins('beforeInit'); + if (this.options.responsive) { + this.resize(); + } else { + retinaScale(this, this.options.devicePixelRatio); + } + this.bindEvents(); + this.notifyPlugins('afterInit'); + return this; + } + clear() { + clearCanvas(this.canvas, this.ctx); + return this; + } + stop() { + animator.stop(this); + return this; + } + resize(width, height) { + if (!animator.running(this)) { + this._resize(width, height); + } else { + this._resizeBeforeDraw = {width, height}; + } + } + _resize(width, height) { + const options = this.options; + const canvas = this.canvas; + const aspectRatio = options.maintainAspectRatio && this.aspectRatio; + const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); + const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); + const mode = this.width ? 'resize' : 'attach'; + this.width = newSize.width; + this.height = newSize.height; + this._aspectRatio = this.aspectRatio; + if (!retinaScale(this, newRatio, true)) { + return; + } + this.notifyPlugins('resize', {size: newSize}); + callback(options.onResize, [this, newSize], this); + if (this.attached) { + if (this._doResize(mode)) { + this.render(); + } + } + } + ensureScalesHaveIDs() { + const options = this.options; + const scalesOptions = options.scales || {}; + each(scalesOptions, (axisOptions, axisID) => { + axisOptions.id = axisID; + }); + } + buildOrUpdateScales() { + const options = this.options; + const scaleOpts = options.scales; + const scales = this.scales; + const updated = Object.keys(scales).reduce((obj, id) => { + obj[id] = false; + return obj; + }, {}); + let items = []; + if (scaleOpts) { + items = items.concat( + Object.keys(scaleOpts).map((id) => { + const scaleOptions = scaleOpts[id]; + const axis = determineAxis(id, scaleOptions); + const isRadial = axis === 'r'; + const isHorizontal = axis === 'x'; + return { + options: scaleOptions, + dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', + dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' + }; + }) + ); + } + each(items, (item) => { + const scaleOptions = item.options; + const id = scaleOptions.id; + const axis = determineAxis(id, scaleOptions); + const scaleType = valueOrDefault(scaleOptions.type, item.dtype); + if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + updated[id] = true; + let scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + } else { + const scaleClass = registry.getScale(scaleType); + scale = new scaleClass({ + id, + type: scaleType, + ctx: this.ctx, + chart: this + }); + scales[scale.id] = scale; + } + scale.init(scaleOptions, options); + }); + each(updated, (hasUpdated, id) => { + if (!hasUpdated) { + delete scales[id]; + } + }); + each(scales, (scale) => { + layouts.configure(this, scale, scale.options); + layouts.addBox(this, scale); + }); + } + _updateMetasets() { + const metasets = this._metasets; + const numData = this.data.datasets.length; + const numMeta = metasets.length; + metasets.sort((a, b) => a.index - b.index); + if (numMeta > numData) { + for (let i = numData; i < numMeta; ++i) { + this._destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + } + _removeUnreferencedMetasets() { + const {_metasets: metasets, data: {datasets}} = this; + if (metasets.length > datasets.length) { + delete this._stacks; + } + metasets.forEach((meta, index) => { + if (datasets.filter(x => x === meta._dataset).length === 0) { + this._destroyDatasetMeta(index); + } + }); + } + buildOrUpdateControllers() { + const newControllers = []; + const datasets = this.data.datasets; + let i, ilen; + this._removeUnreferencedMetasets(); + for (i = 0, ilen = datasets.length; i < ilen; i++) { + const dataset = datasets[i]; + let meta = this.getDatasetMeta(i); + const type = dataset.type || this.config.type; + if (meta.type && meta.type !== type) { + this._destroyDatasetMeta(i); + meta = this.getDatasetMeta(i); + } + meta.type = type; + meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); + meta.order = dataset.order || 0; + meta.index = i; + meta.label = '' + dataset.label; + meta.visible = this.isDatasetVisible(i); + if (meta.controller) { + meta.controller.updateIndex(i); + meta.controller.linkScales(); + } else { + const ControllerClass = registry.getController(type); + const {datasetElementType, dataElementType} = defaults.datasets[type]; + Object.assign(ControllerClass.prototype, { + dataElementType: registry.getElement(dataElementType), + datasetElementType: datasetElementType && registry.getElement(datasetElementType) + }); + meta.controller = new ControllerClass(this, i); + newControllers.push(meta.controller); + } + } + this._updateMetasets(); + return newControllers; + } + _resetElements() { + each(this.data.datasets, (dataset, datasetIndex) => { + this.getDatasetMeta(datasetIndex).controller.reset(); + }, this); + } + reset() { + this._resetElements(); + this.notifyPlugins('reset'); + } + update(mode) { + const config = this.config; + config.update(); + const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); + const animsDisabled = this._animationsDisabled = !options.animation; + this._updateScales(); + this._checkEventBindings(); + this._updateHiddenIndices(); + this._plugins.invalidate(); + if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) { + return; + } + const newControllers = this.buildOrUpdateControllers(); + this.notifyPlugins('beforeElementsUpdate'); + let minPadding = 0; + for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) { + const {controller} = this.getDatasetMeta(i); + const reset = !animsDisabled && newControllers.indexOf(controller) === -1; + controller.buildOrUpdateElements(reset); + minPadding = Math.max(+controller.getMaxOverflow(), minPadding); + } + minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; + this._updateLayout(minPadding); + if (!animsDisabled) { + each(newControllers, (controller) => { + controller.reset(); + }); + } + this._updateDatasets(mode); + this.notifyPlugins('afterUpdate', {mode}); + this._layers.sort(compare2Level('z', '_idx')); + const {_active, _lastEvent} = this; + if (_lastEvent) { + this._eventHandler(_lastEvent, true); + } else if (_active.length) { + this._updateHoverStyles(_active, _active, true); + } + this.render(); + } + _updateScales() { + each(this.scales, (scale) => { + layouts.removeBox(this, scale); + }); + this.ensureScalesHaveIDs(); + this.buildOrUpdateScales(); + } + _checkEventBindings() { + const options = this.options; + const existingEvents = new Set(Object.keys(this._listeners)); + const newEvents = new Set(options.events); + if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { + this.unbindEvents(); + this.bindEvents(); + } + } + _updateHiddenIndices() { + const {_hiddenIndices} = this; + const changes = this._getUniformDataChanges() || []; + for (const {method, start, count} of changes) { + const move = method === '_removeElements' ? -count : count; + moveNumericKeys(_hiddenIndices, start, move); + } + } + _getUniformDataChanges() { + const _dataChanges = this._dataChanges; + if (!_dataChanges || !_dataChanges.length) { + return; + } + this._dataChanges = []; + const datasetCount = this.data.datasets.length; + const makeSet = (idx) => new Set( + _dataChanges + .filter(c => c[0] === idx) + .map((c, i) => i + ',' + c.splice(1).join(',')) + ); + const changeSet = makeSet(0); + for (let i = 1; i < datasetCount; i++) { + if (!setsEqual(changeSet, makeSet(i))) { + return; + } + } + return Array.from(changeSet) + .map(c => c.split(',')) + .map(a => ({method: a[1], start: +a[2], count: +a[3]})); + } + _updateLayout(minPadding) { + if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) { + return; + } + layouts.update(this, this.width, this.height, minPadding); + const area = this.chartArea; + const noArea = area.width <= 0 || area.height <= 0; + this._layers = []; + each(this.boxes, (box) => { + if (noArea && box.position === 'chartArea') { + return; + } + if (box.configure) { + box.configure(); + } + this._layers.push(...box._layers()); + }, this); + this._layers.forEach((item, index) => { + item._idx = index; + }); + this.notifyPlugins('afterLayout'); + } + _updateDatasets(mode) { + if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { + return; + } + for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this.getDatasetMeta(i).controller.configure(); + } + for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); + } + this.notifyPlugins('afterDatasetsUpdate', {mode}); + } + _updateDataset(index, mode) { + const meta = this.getDatasetMeta(index); + const args = {meta, index, mode, cancelable: true}; + if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { + return; + } + meta.controller._update(mode); + args.cancelable = false; + this.notifyPlugins('afterDatasetUpdate', args); + } + render() { + if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) { + return; + } + if (animator.has(this)) { + if (this.attached && !animator.running(this)) { + animator.start(this); + } + } else { + this.draw(); + onAnimationsComplete({chart: this}); + } + } + draw() { + let i; + if (this._resizeBeforeDraw) { + const {width, height} = this._resizeBeforeDraw; + this._resize(width, height); + this._resizeBeforeDraw = null; + } + this.clear(); + if (this.width <= 0 || this.height <= 0) { + return; + } + if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) { + return; + } + const layers = this._layers; + for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { + layers[i].draw(this.chartArea); + } + this._drawDatasets(); + for (; i < layers.length; ++i) { + layers[i].draw(this.chartArea); + } + this.notifyPlugins('afterDraw'); + } + _getSortedDatasetMetas(filterVisible) { + const metasets = this._sortedMetasets; + const result = []; + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + const meta = metasets[i]; + if (!filterVisible || meta.visible) { + result.push(meta); + } + } + return result; + } + getSortedVisibleDatasetMetas() { + return this._getSortedDatasetMetas(true); + } + _drawDatasets() { + if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) { + return; + } + const metasets = this.getSortedVisibleDatasetMetas(); + for (let i = metasets.length - 1; i >= 0; --i) { + this._drawDataset(metasets[i]); + } + this.notifyPlugins('afterDatasetsDraw'); + } + _drawDataset(meta) { + const ctx = this.ctx; + const clip = meta._clip; + const useClip = !clip.disabled; + const area = this.chartArea; + const args = { + meta, + index: meta.index, + cancelable: true + }; + if (this.notifyPlugins('beforeDatasetDraw', args) === false) { + return; + } + if (useClip) { + clipArea(ctx, { + left: clip.left === false ? 0 : area.left - clip.left, + right: clip.right === false ? this.width : area.right + clip.right, + top: clip.top === false ? 0 : area.top - clip.top, + bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom + }); + } + meta.controller.draw(); + if (useClip) { + unclipArea(ctx); + } + args.cancelable = false; + this.notifyPlugins('afterDatasetDraw', args); + } + getElementsAtEventForMode(e, mode, options, useFinalPosition) { + const method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options, useFinalPosition); + } + return []; + } + getDatasetMeta(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + const metasets = this._metasets; + let meta = metasets.filter(x => x && x._dataset === dataset).pop(); + if (!meta) { + meta = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, + xAxisID: null, + yAxisID: null, + order: dataset && dataset.order || 0, + index: datasetIndex, + _dataset: dataset, + _parsed: [], + _sorted: false + }; + metasets.push(meta); + } + return meta; + } + getContext() { + return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'})); + } + getVisibleDatasetCount() { + return this.getSortedVisibleDatasetMetas().length; + } + isDatasetVisible(datasetIndex) { + const dataset = this.data.datasets[datasetIndex]; + if (!dataset) { + return false; + } + const meta = this.getDatasetMeta(datasetIndex); + return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; + } + setDatasetVisibility(datasetIndex, visible) { + const meta = this.getDatasetMeta(datasetIndex); + meta.hidden = !visible; + } + toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + } + getDataVisibility(index) { + return !this._hiddenIndices[index]; + } + _updateVisibility(datasetIndex, dataIndex, visible) { + const mode = visible ? 'show' : 'hide'; + const meta = this.getDatasetMeta(datasetIndex); + const anims = meta.controller._resolveAnimations(undefined, mode); + if (defined(dataIndex)) { + meta.data[dataIndex].hidden = !visible; + this.update(); + } else { + this.setDatasetVisibility(datasetIndex, visible); + anims.update(meta, {visible}); + this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); + } + } + hide(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, false); + } + show(datasetIndex, dataIndex) { + this._updateVisibility(datasetIndex, dataIndex, true); + } + _destroyDatasetMeta(datasetIndex) { + const meta = this._metasets[datasetIndex]; + if (meta && meta.controller) { + meta.controller._destroy(); + } + delete this._metasets[datasetIndex]; + } + _stop() { + let i, ilen; + this.stop(); + animator.remove(this); + for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + this._destroyDatasetMeta(i); + } + } + destroy() { + this.notifyPlugins('beforeDestroy'); + const {canvas, ctx} = this; + this._stop(); + this.config.clearCache(); + if (canvas) { + this.unbindEvents(); + clearCanvas(canvas, ctx); + this.platform.releaseContext(ctx); + this.canvas = null; + this.ctx = null; + } + this.notifyPlugins('destroy'); + delete instances[this.id]; + this.notifyPlugins('afterDestroy'); + } + toBase64Image(...args) { + return this.canvas.toDataURL(...args); + } + bindEvents() { + this.bindUserEvents(); + if (this.options.responsive) { + this.bindResponsiveEvents(); + } else { + this.attached = true; + } + } + bindUserEvents() { + const listeners = this._listeners; + const platform = this.platform; + const _add = (type, listener) => { + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const listener = (e, x, y) => { + e.offsetX = x; + e.offsetY = y; + this._eventHandler(e); + }; + each(this.options.events, (type) => _add(type, listener)); + } + bindResponsiveEvents() { + if (!this._responsiveListeners) { + this._responsiveListeners = {}; + } + const listeners = this._responsiveListeners; + const platform = this.platform; + const _add = (type, listener) => { + platform.addEventListener(this, type, listener); + listeners[type] = listener; + }; + const _remove = (type, listener) => { + if (listeners[type]) { + platform.removeEventListener(this, type, listener); + delete listeners[type]; + } + }; + const listener = (width, height) => { + if (this.canvas) { + this.resize(width, height); + } + }; + let detached; + const attached = () => { + _remove('attach', attached); + this.attached = true; + this.resize(); + _add('resize', listener); + _add('detach', detached); + }; + detached = () => { + this.attached = false; + _remove('resize', listener); + this._stop(); + this._resize(0, 0); + _add('attach', attached); + }; + if (platform.isAttached(this.canvas)) { + attached(); + } else { + detached(); + } + } + unbindEvents() { + each(this._listeners, (listener, type) => { + this.platform.removeEventListener(this, type, listener); + }); + this._listeners = {}; + each(this._responsiveListeners, (listener, type) => { + this.platform.removeEventListener(this, type, listener); + }); + this._responsiveListeners = undefined; + } + updateHoverStyle(items, mode, enabled) { + const prefix = enabled ? 'set' : 'remove'; + let meta, item, i, ilen; + if (mode === 'dataset') { + meta = this.getDatasetMeta(items[0].datasetIndex); + meta.controller['_' + prefix + 'DatasetHoverStyle'](); + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + item = items[i]; + const controller = item && this.getDatasetMeta(item.datasetIndex).controller; + if (controller) { + controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); + } + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements) { + const lastActive = this._active || []; + const active = activeElements.map(({datasetIndex, index}) => { + const meta = this.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('No dataset found at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index, + }; + }); + const changed = !_elementsEqual(active, lastActive); + if (changed) { + this._active = active; + this._lastEvent = null; + this._updateHoverStyles(active, lastActive); + } + } + notifyPlugins(hook, args, filter) { + return this._plugins.notify(this, hook, args, filter); + } + _updateHoverStyles(active, lastActive, replay) { + const hoverOptions = this.options.hover; + const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index)); + const deactivated = diff(lastActive, active); + const activated = replay ? active : diff(active, lastActive); + if (deactivated.length) { + this.updateHoverStyle(deactivated, hoverOptions.mode, false); + } + if (activated.length && hoverOptions.mode) { + this.updateHoverStyle(activated, hoverOptions.mode, true); + } + } + _eventHandler(e, replay) { + const args = { + event: e, + replay, + cancelable: true, + inChartArea: _isPointInArea(e, this.chartArea, this._minPadding) + }; + const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type); + if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { + return; + } + const changed = this._handleEvent(e, replay, args.inChartArea); + args.cancelable = false; + this.notifyPlugins('afterEvent', args, eventFilter); + if (changed || args.changed) { + this.render(); + } + return this; + } + _handleEvent(e, replay, inChartArea) { + const {_active: lastActive = [], options} = this; + const useFinalPosition = replay; + const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); + const isClick = _isClickEvent(e); + const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); + if (inChartArea) { + this._lastEvent = null; + callback(options.onHover, [e, active, this], this); + if (isClick) { + callback(options.onClick, [e, active, this], this); + } + } + const changed = !_elementsEqual(active, lastActive); + if (changed || replay) { + this._active = active; + this._updateHoverStyles(active, lastActive, replay); + } + this._lastEvent = lastEvent; + return changed; + } + _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const hoverOptions = this.options.hover; + return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); + } +} +const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); +const enumerable = true; +Object.defineProperties(Chart, { + defaults: { + enumerable, + value: defaults + }, + instances: { + enumerable, + value: instances + }, + overrides: { + enumerable, + value: overrides + }, + registry: { + enumerable, + value: registry + }, + version: { + enumerable, + value: version + }, + getChart: { + enumerable, + value: getChart + }, + register: { + enumerable, + value: (...items) => { + registry.add(...items); + invalidatePlugins(); + } + }, + unregister: { + enumerable, + value: (...items) => { + registry.remove(...items); + invalidatePlugins(); + } + } +}); + +function abstract() { + throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); +} +class DateAdapter { + constructor(options) { + this.options = options || {}; + } + formats() { + return abstract(); + } + parse(value, format) { + return abstract(); + } + format(timestamp, format) { + return abstract(); + } + add(timestamp, amount, unit) { + return abstract(); + } + diff(a, b, unit) { + return abstract(); + } + startOf(timestamp, unit, weekday) { + return abstract(); + } + endOf(timestamp, unit) { + return abstract(); + } +} +DateAdapter.override = function(members) { + Object.assign(DateAdapter.prototype, members); +}; +var _adapters = { + _date: DateAdapter +}; + +function getAllScaleValues(scale, type) { + if (!scale._cache.$bar) { + const visibleMetas = scale.getMatchingVisibleMetas(type); + let values = []; + for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) { + values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); + } + scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b)); + } + return scale._cache.$bar; +} +function computeMinSampleSize(meta) { + const scale = meta.iScale; + const values = getAllScaleValues(scale, meta.type); + let min = scale._length; + let i, ilen, curr, prev; + const updateMinAndPrev = () => { + if (curr === 32767 || curr === -32768) { + return; + } + if (defined(prev)) { + min = Math.min(min, Math.abs(curr - prev) || min); + } + prev = curr; + }; + for (i = 0, ilen = values.length; i < ilen; ++i) { + curr = scale.getPixelForValue(values[i]); + updateMinAndPrev(); + } + prev = undefined; + for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { + curr = scale.getPixelForTick(i); + updateMinAndPrev(); + } + return min; +} +function computeFitCategoryTraits(index, ruler, options, stackCount) { + const thickness = options.barThickness; + let size, ratio; + if (isNullOrUndef(thickness)) { + size = ruler.min * options.categoryPercentage; + ratio = options.barPercentage; + } else { + size = thickness * stackCount; + ratio = 1; + } + return { + chunk: size / stackCount, + ratio, + start: ruler.pixels[index] - (size / 2) + }; +} +function computeFlexCategoryTraits(index, ruler, options, stackCount) { + const pixels = ruler.pixels; + const curr = pixels[index]; + let prev = index > 0 ? pixels[index - 1] : null; + let next = index < pixels.length - 1 ? pixels[index + 1] : null; + const percent = options.categoryPercentage; + if (prev === null) { + prev = curr - (next === null ? ruler.end - ruler.start : next - curr); + } + if (next === null) { + next = curr + curr - prev; + } + const start = curr - (curr - Math.min(prev, next)) / 2 * percent; + const size = Math.abs(next - prev) / 2 * percent; + return { + chunk: size / stackCount, + ratio: options.barPercentage, + start + }; +} +function parseFloatBar(entry, item, vScale, i) { + const startValue = vScale.parse(entry[0], i); + const endValue = vScale.parse(entry[1], i); + const min = Math.min(startValue, endValue); + const max = Math.max(startValue, endValue); + let barStart = min; + let barEnd = max; + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + item[vScale.axis] = barEnd; + item._custom = { + barStart, + barEnd, + start: startValue, + end: endValue, + min, + max + }; +} +function parseValue(entry, item, vScale, i) { + if (isArray(entry)) { + parseFloatBar(entry, item, vScale, i); + } else { + item[vScale.axis] = vScale.parse(entry, i); + } + return item; +} +function parseArrayOrPrimitive(meta, data, start, count) { + const iScale = meta.iScale; + const vScale = meta.vScale; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = []; + let i, ilen, item, entry; + for (i = start, ilen = start + count; i < ilen; ++i) { + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; +} +function isFloatBar(custom) { + return custom && custom.barStart !== undefined && custom.barEnd !== undefined; +} +function barSign(size, vScale, actualBase) { + if (size !== 0) { + return sign(size); + } + return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); +} +function borderProps(properties) { + let reverse, start, end, top, bottom; + if (properties.horizontal) { + reverse = properties.base > properties.x; + start = 'left'; + end = 'right'; + } else { + reverse = properties.base < properties.y; + start = 'bottom'; + end = 'top'; + } + if (reverse) { + top = 'end'; + bottom = 'start'; + } else { + top = 'start'; + bottom = 'end'; + } + return {start, end, reverse, top, bottom}; +} +function setBorderSkipped(properties, options, stack, index) { + let edge = options.borderSkipped; + const res = {}; + if (!edge) { + properties.borderSkipped = res; + return; + } + const {start, end, reverse, top, bottom} = borderProps(properties); + if (edge === 'middle' && stack) { + properties.enableBorderRadius = true; + if ((stack._top || 0) === index) { + edge = top; + } else if ((stack._bottom || 0) === index) { + edge = bottom; + } else { + res[parseEdge(bottom, start, end, reverse)] = true; + edge = top; + } + } + res[parseEdge(edge, start, end, reverse)] = true; + properties.borderSkipped = res; +} +function parseEdge(edge, a, b, reverse) { + if (reverse) { + edge = swap(edge, a, b); + edge = startEnd(edge, b, a); + } else { + edge = startEnd(edge, a, b); + } + return edge; +} +function swap(orig, v1, v2) { + return orig === v1 ? v2 : orig === v2 ? v1 : orig; +} +function startEnd(v, start, end) { + return v === 'start' ? start : v === 'end' ? end : v; +} +function setInflateAmount(properties, {inflateAmount}, ratio) { + properties.inflateAmount = inflateAmount === 'auto' + ? ratio === 1 ? 0.33 : 0 + : inflateAmount; +} +class BarController extends DatasetController { + parsePrimitiveData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseArrayData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseObjectData(meta, data, start, count) { + const {iScale, vScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; + const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; + const parsed = []; + let i, ilen, item, obj; + for (i = start, ilen = start + count; i < ilen; ++i) { + obj = data[i]; + item = {}; + item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); + parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); + } + return parsed; + } + updateRangeFromParsed(range, scale, parsed, stack) { + super.updateRangeFromParsed(range, scale, parsed, stack); + const custom = parsed._custom; + if (custom && scale === this._cachedMeta.vScale) { + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + getMaxOverflow() { + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const {iScale, vScale} = meta; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const value = isFloatBar(custom) + ? '[' + custom.start + ', ' + custom.end + ']' + : '' + vScale.getLabelForValue(parsed[vScale.axis]); + return { + label: '' + iScale.getLabelForValue(parsed[iScale.axis]), + value + }; + } + initialize() { + this.enableOptionSharing = true; + super.initialize(); + const meta = this._cachedMeta; + meta.stack = this.getDataset().stack; + } + update(mode) { + const meta = this._cachedMeta; + this.updateElements(meta.data, 0, meta.data.length, mode); + } + updateElements(bars, start, count, mode) { + const reset = mode === 'reset'; + const {index, _cachedMeta: {vScale}} = this; + const base = vScale.getBasePixel(); + const horizontal = vScale.isHorizontal(); + const ruler = this._getRuler(); + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + this.updateSharedOptions(sharedOptions, mode, firstOpts); + for (let i = start; i < start + count; i++) { + const parsed = this.getParsed(i); + const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i); + const ipixels = this._calculateBarIndexPixels(i, ruler); + const stack = (parsed._stacks || {})[vScale.axis]; + const properties = { + horizontal, + base: vpixels.base, + enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom), + x: horizontal ? vpixels.head : ipixels.center, + y: horizontal ? ipixels.center : vpixels.head, + height: horizontal ? ipixels.size : Math.abs(vpixels.size), + width: horizontal ? Math.abs(vpixels.size) : ipixels.size + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); + } + const options = properties.options || bars[i].options; + setBorderSkipped(properties, options, stack, index); + setInflateAmount(properties, options, ruler.ratio); + this.updateElement(bars[i], i, properties, mode); + } + } + _getStacks(last, dataIndex) { + const meta = this._cachedMeta; + const iScale = meta.iScale; + const metasets = iScale.getMatchingVisibleMetas(this._type); + const stacked = iScale.options.stacked; + const ilen = metasets.length; + const stacks = []; + let i, item; + for (i = 0; i < ilen; ++i) { + item = metasets[i]; + if (!item.controller.options.grouped) { + continue; + } + if (typeof dataIndex !== 'undefined') { + const val = item.controller.getParsed(dataIndex)[ + item.controller._cachedMeta.vScale.axis + ]; + if (isNullOrUndef(val) || isNaN(val)) { + continue; + } + } + if (stacked === false || stacks.indexOf(item.stack) === -1 || + (stacked === undefined && item.stack === undefined)) { + stacks.push(item.stack); + } + if (item.index === last) { + break; + } + } + if (!stacks.length) { + stacks.push(undefined); + } + return stacks; + } + _getStackCount(index) { + return this._getStacks(undefined, index).length; + } + _getStackIndex(datasetIndex, name, dataIndex) { + const stacks = this._getStacks(datasetIndex, dataIndex); + const index = (name !== undefined) + ? stacks.indexOf(name) + : -1; + return (index === -1) + ? stacks.length - 1 + : index; + } + _getRuler() { + const opts = this.options; + const meta = this._cachedMeta; + const iScale = meta.iScale; + const pixels = []; + let i, ilen; + for (i = 0, ilen = meta.data.length; i < ilen; ++i) { + pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); + } + const barThickness = opts.barThickness; + const min = barThickness || computeMinSampleSize(meta); + return { + min, + pixels, + start: iScale._startPixel, + end: iScale._endPixel, + stackCount: this._getStackCount(), + scale: iScale, + grouped: opts.grouped, + ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage + }; + } + _calculateBarValuePixels(index) { + const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; + const actualBase = baseValue || 0; + const parsed = this.getParsed(index); + const custom = parsed._custom; + const floating = isFloatBar(custom); + let value = parsed[vScale.axis]; + let start = 0; + let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; + let head, size; + if (length !== value) { + start = length - value; + length = value; + } + if (floating) { + value = custom.barStart; + length = custom.barEnd - custom.barStart; + if (value !== 0 && sign(value) !== sign(custom.barEnd)) { + start = 0; + } + start += value; + } + const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; + let base = vScale.getPixelForValue(startValue); + if (this.chart.getDataVisibility(index)) { + head = vScale.getPixelForValue(start + length); + } else { + head = base; + } + size = head - base; + if (Math.abs(size) < minBarLength) { + size = barSign(size, vScale, actualBase) * minBarLength; + if (value === actualBase) { + base -= size / 2; + } + head = base + size; + } + if (base === vScale.getPixelForValue(actualBase)) { + const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; + base += halfGrid; + size -= halfGrid; + } + return { + size, + base, + head, + center: head + size / 2 + }; + } + _calculateBarIndexPixels(index, ruler) { + const scale = ruler.scale; + const options = this.options; + const skipNull = options.skipNull; + const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); + let center, size; + if (ruler.grouped) { + const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; + const range = options.barThickness === 'flex' + ? computeFlexCategoryTraits(index, ruler, options, stackCount) + : computeFitCategoryTraits(index, ruler, options, stackCount); + const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); + center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); + size = Math.min(maxBarThickness, range.chunk * range.ratio); + } else { + center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); + size = Math.min(maxBarThickness, ruler.min * ruler.ratio); + } + return { + base: center - size / 2, + head: center + size / 2, + center, + size + }; + } + draw() { + const meta = this._cachedMeta; + const vScale = meta.vScale; + const rects = meta.data; + const ilen = rects.length; + let i = 0; + for (; i < ilen; ++i) { + if (this.getParsed(i)[vScale.axis] !== null) { + rects[i].draw(this._ctx); + } + } + } +} +BarController.id = 'bar'; +BarController.defaults = { + datasetElementType: false, + dataElementType: 'bar', + categoryPercentage: 0.8, + barPercentage: 0.9, + grouped: true, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'base', 'width', 'height'] + } + } +}; +BarController.overrides = { + scales: { + _index_: { + type: 'category', + offset: true, + grid: { + offset: true + } + }, + _value_: { + type: 'linear', + beginAtZero: true, + } + } +}; + +class BubbleController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + parsePrimitiveData(meta, data, start, count) { + const parsed = super.parsePrimitiveData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; + } + return parsed; + } + parseArrayData(meta, data, start, count) { + const parsed = super.parseArrayData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const parsed = super.parseObjectData(meta, data, start, count); + for (let i = 0; i < parsed.length; i++) { + const item = data[start + i]; + parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); + } + return parsed; + } + getMaxOverflow() { + const data = this._cachedMeta.data; + let max = 0; + for (let i = data.length - 1; i >= 0; --i) { + max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); + } + return max > 0 && max; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const {xScale, yScale} = meta; + const parsed = this.getParsed(index); + const x = xScale.getLabelForValue(parsed.x); + const y = yScale.getLabelForValue(parsed.y); + const r = parsed._custom; + return { + label: meta.label, + value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + }; + } + update(mode) { + const points = this._cachedMeta.data; + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const {iScale, vScale} = this._cachedMeta; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + for (let i = start; i < start + count; i++) { + const point = points[i]; + const parsed = !reset && this.getParsed(i); + const properties = {}; + const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); + const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); + properties.skip = isNaN(iPixel) || isNaN(vPixel); + if (includeOptions) { + properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); + if (reset) { + properties.options.radius = 0; + } + } + this.updateElement(point, i, properties, mode); + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + resolveDataElementOptions(index, mode) { + const parsed = this.getParsed(index); + let values = super.resolveDataElementOptions(index, mode); + if (values.$shared) { + values = Object.assign({}, values, {$shared: false}); + } + const radius = values.radius; + if (mode !== 'active') { + values.radius = 0; + } + values.radius += valueOrDefault(parsed && parsed._custom, radius); + return values; + } +} +BubbleController.id = 'bubble'; +BubbleController.defaults = { + datasetElementType: false, + dataElementType: 'point', + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'borderWidth', 'radius'] + } + } +}; +BubbleController.overrides = { + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + plugins: { + tooltip: { + callbacks: { + title() { + return ''; + } + } + } + } +}; + +function getRatioAndOffset(rotation, circumference, cutout) { + let ratioX = 1; + let ratioY = 1; + let offsetX = 0; + let offsetY = 0; + if (circumference < TAU) { + const startAngle = rotation; + const endAngle = startAngle + circumference; + const startX = Math.cos(startAngle); + const startY = Math.sin(startAngle); + const endX = Math.cos(endAngle); + const endY = Math.sin(endAngle); + const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); + const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); + const maxX = calcMax(0, startX, endX); + const maxY = calcMax(HALF_PI, startY, endY); + const minX = calcMin(PI, startX, endX); + const minY = calcMin(PI + HALF_PI, startY, endY); + ratioX = (maxX - minX) / 2; + ratioY = (maxY - minY) / 2; + offsetX = -(maxX + minX) / 2; + offsetY = -(maxY + minY) / 2; + } + return {ratioX, ratioY, offsetX, offsetY}; +} +class DoughnutController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.enableOptionSharing = true; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.offsetX = undefined; + this.offsetY = undefined; + } + linkScales() {} + parse(start, count) { + const data = this.getDataset().data; + const meta = this._cachedMeta; + if (this._parsing === false) { + meta._parsed = data; + } else { + let getter = (i) => +data[i]; + if (isObject(data[start])) { + const {key = 'value'} = this._parsing; + getter = (i) => +resolveObjectKey(data[i], key); + } + let i, ilen; + for (i = start, ilen = start + count; i < ilen; ++i) { + meta._parsed[i] = getter(i); + } + } + } + _getRotation() { + return toRadians(this.options.rotation - 90); + } + _getCircumference() { + return toRadians(this.options.circumference); + } + _getRotationExtents() { + let min = TAU; + let max = -TAU; + for (let i = 0; i < this.chart.data.datasets.length; ++i) { + if (this.chart.isDatasetVisible(i)) { + const controller = this.chart.getDatasetMeta(i).controller; + const rotation = controller._getRotation(); + const circumference = controller._getCircumference(); + min = Math.min(min, rotation); + max = Math.max(max, rotation + circumference); + } + } + return { + rotation: min, + circumference: max - min, + }; + } + update(mode) { + const chart = this.chart; + const {chartArea} = chart; + const meta = this._cachedMeta; + const arcs = meta.data; + const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; + const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); + const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); + const chartWeight = this._getRingWeight(this.index); + const {circumference, rotation} = this._getRotationExtents(); + const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout); + const maxWidth = (chartArea.width - spacing) / ratioX; + const maxHeight = (chartArea.height - spacing) / ratioY; + const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); + const outerRadius = toDimension(this.options.radius, maxRadius); + const innerRadius = Math.max(outerRadius * cutout, 0); + const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); + this.offsetX = offsetX * outerRadius; + this.offsetY = offsetY * outerRadius; + meta.total = this.calculateTotal(); + this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); + this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); + this.updateElements(arcs, 0, arcs.length, mode); + } + _circumference(i, reset) { + const opts = this.options; + const meta = this._cachedMeta; + const circumference = this._getCircumference(); + if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { + return 0; + } + return this.calculateCircumference(meta._parsed[i] * circumference / TAU); + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const animationOpts = opts.animation; + const centerX = (chartArea.left + chartArea.right) / 2; + const centerY = (chartArea.top + chartArea.bottom) / 2; + const animateScale = reset && animationOpts.animateScale; + const innerRadius = animateScale ? 0 : this.innerRadius; + const outerRadius = animateScale ? 0 : this.outerRadius; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + let startAngle = this._getRotation(); + let i; + for (i = 0; i < start; ++i) { + startAngle += this._circumference(i, reset); + } + for (i = start; i < start + count; ++i) { + const circumference = this._circumference(i, reset); + const arc = arcs[i]; + const properties = { + x: centerX + this.offsetX, + y: centerY + this.offsetY, + startAngle, + endAngle: startAngle + circumference, + circumference, + outerRadius, + innerRadius + }; + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); + } + startAngle += circumference; + this.updateElement(arc, i, properties, mode); + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + calculateTotal() { + const meta = this._cachedMeta; + const metaData = meta.data; + let total = 0; + let i; + for (i = 0; i < metaData.length; i++) { + const value = meta._parsed[i]; + if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { + total += Math.abs(value); + } + } + return total; + } + calculateCircumference(value) { + const total = this._cachedMeta.total; + if (total > 0 && !isNaN(value)) { + return TAU * (Math.abs(value) / total); + } + return 0; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index], chart.options.locale); + return { + label: labels[index] || '', + value, + }; + } + getMaxBorderWidth(arcs) { + let max = 0; + const chart = this.chart; + let i, ilen, meta, controller, options; + if (!arcs) { + for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + if (chart.isDatasetVisible(i)) { + meta = chart.getDatasetMeta(i); + arcs = meta.data; + controller = meta.controller; + break; + } + } + } + if (!arcs) { + return 0; + } + for (i = 0, ilen = arcs.length; i < ilen; ++i) { + options = controller.resolveDataElementOptions(i); + if (options.borderAlign !== 'inner') { + max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); + } + } + return max; + } + getMaxOffset(arcs) { + let max = 0; + for (let i = 0, ilen = arcs.length; i < ilen; ++i) { + const options = this.resolveDataElementOptions(i); + max = Math.max(max, options.offset || 0, options.hoverOffset || 0); + } + return max; + } + _getRingWeightOffset(datasetIndex) { + let ringWeightOffset = 0; + for (let i = 0; i < datasetIndex; ++i) { + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + return ringWeightOffset; + } + _getRingWeight(datasetIndex) { + return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); + } + _getVisibleDatasetWeightTotal() { + return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; + } +} +DoughnutController.id = 'doughnut'; +DoughnutController.defaults = { + datasetElementType: false, + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: false + }, + animations: { + numbers: { + type: 'number', + properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing'] + }, + }, + cutout: '50%', + rotation: 0, + circumference: 360, + radius: '100%', + spacing: 0, + indexAxis: 'r', +}; +DoughnutController.descriptors = { + _scriptable: (name) => name !== 'spacing', + _indexable: (name) => name !== 'spacing', +}; +DoughnutController.overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const {labels: {pointStyle}} = chart.legend.options; + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltip: { + callbacks: { + title() { + return ''; + }, + label(tooltipItem) { + let dataLabel = tooltipItem.label; + const value = ': ' + tooltipItem.formattedValue; + if (isArray(dataLabel)) { + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; + } + return dataLabel; + } + } + } + } +}; + +class LineController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + update(mode) { + const meta = this._cachedMeta; + const {dataset: line, data: points = [], _dataset} = meta; + const animationsDisabled = this.chart._animationsDisabled; + let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); + this._drawStart = start; + this._drawCount = count; + if (scaleRangesChanged(meta)) { + start = 0; + count = points.length; + } + line._chart = this.chart; + line._datasetIndex = this.index; + line._decimated = !!_dataset._decimated; + line.points = points; + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + options.segment = this.options.segment; + this.updateElement(line, undefined, { + animated: !animationsDisabled, + options + }, mode); + this.updateElements(points, start, count, mode); + } + updateElements(points, start, count, mode) { + const reset = mode === 'reset'; + const {iScale, vScale, _stacked, _dataset} = this._cachedMeta; + const firstOpts = this.resolveDataElementOptions(start, mode); + const sharedOptions = this.getSharedOptions(firstOpts); + const includeOptions = this.includeOptions(mode, sharedOptions); + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const {spanGaps, segment} = this.options; + const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; + let prevParsed = start > 0 && this.getParsed(start - 1); + for (let i = start; i < start + count; ++i) { + const point = points[i]; + const parsed = this.getParsed(i); + const properties = directUpdate ? point : {}; + const nullData = isNullOrUndef(parsed[vAxis]); + const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); + const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); + properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; + properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; + if (segment) { + properties.parsed = parsed; + properties.raw = _dataset.data[i]; + } + if (includeOptions) { + properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); + } + if (!directUpdate) { + this.updateElement(point, i, properties, mode); + } + prevParsed = parsed; + } + this.updateSharedOptions(sharedOptions, mode, firstOpts); + } + getMaxOverflow() { + const meta = this._cachedMeta; + const dataset = meta.dataset; + const border = dataset.options && dataset.options.borderWidth || 0; + const data = meta.data || []; + if (!data.length) { + return border; + } + const firstPoint = data[0].size(this.resolveDataElementOptions(0)); + const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); + return Math.max(border, firstPoint, lastPoint) / 2; + } + draw() { + const meta = this._cachedMeta; + meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); + super.draw(); + } +} +LineController.id = 'line'; +LineController.defaults = { + datasetElementType: 'line', + dataElementType: 'point', + showLine: true, + spanGaps: false, +}; +LineController.overrides = { + scales: { + _index_: { + type: 'category', + }, + _value_: { + type: 'linear', + }, + } +}; +function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { + const pointCount = points.length; + let start = 0; + let count = pointCount; + if (meta._sorted) { + const {iScale, _parsed} = meta; + const axis = iScale.axis; + const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(Math.min( + _lookupByKey(_parsed, iScale.axis, min).lo, + animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), + 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(Math.max( + _lookupByKey(_parsed, iScale.axis, max).hi + 1, + animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), + start, pointCount) - start; + } else { + count = pointCount - start; + } + } + return {start, count}; +} +function scaleRangesChanged(meta) { + const {xScale, yScale, _scaleRanges} = meta; + const newRanges = { + xmin: xScale.min, + xmax: xScale.max, + ymin: yScale.min, + ymax: yScale.max + }; + if (!_scaleRanges) { + meta._scaleRanges = newRanges; + return true; + } + const changed = _scaleRanges.xmin !== xScale.min + || _scaleRanges.xmax !== xScale.max + || _scaleRanges.ymin !== yScale.min + || _scaleRanges.ymax !== yScale.max; + Object.assign(_scaleRanges, newRanges); + return changed; +} + +class PolarAreaController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.innerRadius = undefined; + this.outerRadius = undefined; + } + getLabelAndValue(index) { + const meta = this._cachedMeta; + const chart = this.chart; + const labels = chart.data.labels || []; + const value = formatNumber(meta._parsed[index].r, chart.options.locale); + return { + label: labels[index] || '', + value, + }; + } + update(mode) { + const arcs = this._cachedMeta.data; + this._updateRadius(); + this.updateElements(arcs, 0, arcs.length, mode); + } + _updateRadius() { + const chart = this.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + const outerRadius = Math.max(minSize / 2, 0); + const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); + this.outerRadius = outerRadius - (radiusLength * this.index); + this.innerRadius = this.outerRadius - radiusLength; + } + updateElements(arcs, start, count, mode) { + const reset = mode === 'reset'; + const chart = this.chart; + const dataset = this.getDataset(); + const opts = chart.options; + const animationOpts = opts.animation; + const scale = this._cachedMeta.rScale; + const centerX = scale.xCenter; + const centerY = scale.yCenter; + const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; + let angle = datasetStartAngle; + let i; + const defaultAngle = 360 / this.countVisibleElements(); + for (i = 0; i < start; ++i) { + angle += this._computeAngle(i, mode, defaultAngle); + } + for (i = start; i < start + count; i++) { + const arc = arcs[i]; + let startAngle = angle; + let endAngle = angle + this._computeAngle(i, mode, defaultAngle); + let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; + angle = endAngle; + if (reset) { + if (animationOpts.animateScale) { + outerRadius = 0; + } + if (animationOpts.animateRotate) { + startAngle = endAngle = datasetStartAngle; + } + } + const properties = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius, + startAngle, + endAngle, + options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) + }; + this.updateElement(arc, i, properties, mode); + } + } + countVisibleElements() { + const dataset = this.getDataset(); + const meta = this._cachedMeta; + let count = 0; + meta.data.forEach((element, index) => { + if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { + count++; + } + }); + return count; + } + _computeAngle(index, mode, defaultAngle) { + return this.chart.getDataVisibility(index) + ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) + : 0; + } +} +PolarAreaController.id = 'polarArea'; +PolarAreaController.defaults = { + dataElementType: 'arc', + animation: { + animateRotate: true, + animateScale: true + }, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] + }, + }, + indexAxis: 'r', + startAngle: 0, +}; +PolarAreaController.overrides = { + aspectRatio: 1, + plugins: { + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + const {labels: {pointStyle}} = chart.legend.options; + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + pointStyle: pointStyle, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltip: { + callbacks: { + title() { + return ''; + }, + label(context) { + return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; + } + } + } + }, + scales: { + r: { + type: 'radialLinear', + angleLines: { + display: false + }, + beginAtZero: true, + grid: { + circular: true + }, + pointLabels: { + display: false + }, + startAngle: 0 + } + } +}; + +class PieController extends DoughnutController { +} +PieController.id = 'pie'; +PieController.defaults = { + cutout: 0, + rotation: 0, + circumference: 360, + radius: '100%' +}; + +class RadarController extends DatasetController { + getLabelAndValue(index) { + const vScale = this._cachedMeta.vScale; + const parsed = this.getParsed(index); + return { + label: vScale.getLabels()[index], + value: '' + vScale.getLabelForValue(parsed[vScale.axis]) + }; + } + update(mode) { + const meta = this._cachedMeta; + const line = meta.dataset; + const points = meta.data || []; + const labels = meta.iScale.getLabels(); + line.points = points; + if (mode !== 'resize') { + const options = this.resolveDatasetElementOptions(mode); + if (!this.options.showLine) { + options.borderWidth = 0; + } + const properties = { + _loop: true, + _fullLoop: labels.length === points.length, + options + }; + this.updateElement(line, undefined, properties, mode); + } + this.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const dataset = this.getDataset(); + const scale = this._cachedMeta.rScale; + const reset = mode === 'reset'; + for (let i = start; i < start + count; i++) { + const point = points[i]; + const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); + const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); + const x = reset ? scale.xCenter : pointPosition.x; + const y = reset ? scale.yCenter : pointPosition.y; + const properties = { + x, + y, + angle: pointPosition.angle, + skip: isNaN(x) || isNaN(y), + options + }; + this.updateElement(point, i, properties, mode); + } + } +} +RadarController.id = 'radar'; +RadarController.defaults = { + datasetElementType: 'line', + dataElementType: 'point', + indexAxis: 'r', + showLine: true, + elements: { + line: { + fill: 'start' + } + }, +}; +RadarController.overrides = { + aspectRatio: 1, + scales: { + r: { + type: 'radialLinear', + } + } +}; + +class ScatterController extends LineController { +} +ScatterController.id = 'scatter'; +ScatterController.defaults = { + showLine: false, + fill: false +}; +ScatterController.overrides = { + interaction: { + mode: 'point' + }, + plugins: { + tooltip: { + callbacks: { + title() { + return ''; + }, + label(item) { + return '(' + item.label + ', ' + item.formattedValue + ')'; + } + } + } + }, + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + } +}; + +var controllers = /*#__PURE__*/Object.freeze({ +__proto__: null, +BarController: BarController, +BubbleController: BubbleController, +DoughnutController: DoughnutController, +LineController: LineController, +PolarAreaController: PolarAreaController, +PieController: PieController, +RadarController: RadarController, +ScatterController: ScatterController +}); + +function clipArc(ctx, element, endAngle) { + const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; + let angleMargin = pixelMargin / outerRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (innerRadius > pixelMargin) { + angleMargin = pixelMargin / innerRadius; + ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); + } + ctx.closePath(); + ctx.clip(); +} +function toRadiusCorners(value) { + return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']); +} +function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { + const o = toRadiusCorners(arc.options.borderRadius); + const halfThickness = (outerRadius - innerRadius) / 2; + const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); + const computeOuterLimit = (val) => { + const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; + return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); + }; + return { + outerStart: computeOuterLimit(o.outerStart), + outerEnd: computeOuterLimit(o.outerEnd), + innerStart: _limitValue(o.innerStart, 0, innerLimit), + innerEnd: _limitValue(o.innerEnd, 0, innerLimit), + }; +} +function rThetaToXY(r, theta, x, y) { + return { + x: x + r * Math.cos(theta), + y: y + r * Math.sin(theta), + }; +} +function pathArc(ctx, element, offset, spacing, end) { + const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element; + const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); + const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; + let spacingOffset = 0; + const alpha = end - start; + if (spacing) { + const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; + const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; + const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; + const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha; + spacingOffset = (alpha - adjustedAngle) / 2; + } + const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; + const angleOffset = (alpha - beta) / 2; + const startAngle = start + angleOffset + spacingOffset; + const endAngle = end - angleOffset - spacingOffset; + const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); + const outerStartAdjustedRadius = outerRadius - outerStart; + const outerEndAdjustedRadius = outerRadius - outerEnd; + const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; + const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; + const innerStartAdjustedRadius = innerRadius + innerStart; + const innerEndAdjustedRadius = innerRadius + innerEnd; + const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; + const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle); + if (outerEnd > 0) { + const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); + } + const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); + ctx.lineTo(p4.x, p4.y); + if (innerEnd > 0) { + const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); + } + ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true); + if (innerStart > 0) { + const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); + } + const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); + ctx.lineTo(p8.x, p8.y); + if (outerStart > 0) { + const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); + ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); + } + ctx.closePath(); +} +function drawArc(ctx, element, offset, spacing) { + const {fullCircles, startAngle, circumference} = element; + let endAngle = element.endAngle; + if (fullCircles) { + pathArc(ctx, element, offset, spacing, startAngle + TAU); + for (let i = 0; i < fullCircles; ++i) { + ctx.fill(); + } + if (!isNaN(circumference)) { + endAngle = startAngle + circumference % TAU; + if (circumference % TAU === 0) { + endAngle += TAU; + } + } + } + pathArc(ctx, element, offset, spacing, endAngle); + ctx.fill(); + return endAngle; +} +function drawFullCircleBorders(ctx, element, inner) { + const {x, y, startAngle, pixelMargin, fullCircles} = element; + const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + const innerRadius = element.innerRadius + pixelMargin; + let i; + if (inner) { + clipArc(ctx, element, startAngle + TAU); + } + ctx.beginPath(); + ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); + for (i = 0; i < fullCircles; ++i) { + ctx.stroke(); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); + for (i = 0; i < fullCircles; ++i) { + ctx.stroke(); + } +} +function drawBorder(ctx, element, offset, spacing, endAngle) { + const {options} = element; + const {borderWidth, borderJoinStyle} = options; + const inner = options.borderAlign === 'inner'; + if (!borderWidth) { + return; + } + if (inner) { + ctx.lineWidth = borderWidth * 2; + ctx.lineJoin = borderJoinStyle || 'round'; + } else { + ctx.lineWidth = borderWidth; + ctx.lineJoin = borderJoinStyle || 'bevel'; + } + if (element.fullCircles) { + drawFullCircleBorders(ctx, element, inner); + } + if (inner) { + clipArc(ctx, element, endAngle); + } + pathArc(ctx, element, offset, spacing, endAngle); + ctx.stroke(); +} +class ArcElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.circumference = undefined; + this.startAngle = undefined; + this.endAngle = undefined; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.pixelMargin = 0; + this.fullCircles = 0; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(chartX, chartY, useFinalPosition) { + const point = this.getProps(['x', 'y'], useFinalPosition); + const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); + const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference' + ], useFinalPosition); + const rAdjust = this.options.spacing / 2; + const _circumference = valueOrDefault(circumference, endAngle - startAngle); + const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); + const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); + return (betweenAngles && withinRadius); + } + getCenterPoint(useFinalPosition) { + const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference', + ], useFinalPosition); + const {offset, spacing} = this.options; + const halfAngle = (startAngle + endAngle) / 2; + const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + } + draw(ctx) { + const {options, circumference} = this; + const offset = (options.offset || 0) / 2; + const spacing = (options.spacing || 0) / 2; + this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; + this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; + if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { + return; + } + ctx.save(); + let radiusOffset = 0; + if (offset) { + radiusOffset = offset / 2; + const halfAngle = (this.startAngle + this.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset); + if (this.circumference >= PI) { + radiusOffset = offset; + } + } + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + const endAngle = drawArc(ctx, this, radiusOffset, spacing); + drawBorder(ctx, this, radiusOffset, spacing, endAngle); + ctx.restore(); + } +} +ArcElement.id = 'arc'; +ArcElement.defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderJoinStyle: undefined, + borderRadius: 0, + borderWidth: 2, + offset: 0, + spacing: 0, + angle: undefined, +}; +ArcElement.defaultRoutes = { + backgroundColor: 'backgroundColor' +}; + +function setStyle(ctx, options, style = options) { + ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); + ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); + ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); + ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); + ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); + ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); +} +function lineTo(ctx, previous, target) { + ctx.lineTo(target.x, target.y); +} +function getLineMethod(options) { + if (options.stepped) { + return _steppedLineTo; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierCurveTo; + } + return lineTo; +} +function pathVars(points, segment, params = {}) { + const count = points.length; + const {start: paramsStart = 0, end: paramsEnd = count - 1} = params; + const {start: segmentStart, end: segmentEnd} = segment; + const start = Math.max(paramsStart, segmentStart); + const end = Math.min(paramsEnd, segmentEnd); + const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; + return { + count, + start, + loop: segment.loop, + ilen: end < start && !outside ? count + end - start : end - start + }; +} +function pathSegment(ctx, line, segment, params) { + const {points, options} = line; + const {count, start, loop, ilen} = pathVars(points, segment, params); + const lineMethod = getLineMethod(options); + let {move = true, reverse} = params || {}; + let i, point, prev; + for (i = 0; i <= ilen; ++i) { + point = points[(start + (reverse ? ilen - i : i)) % count]; + if (point.skip) { + continue; + } else if (move) { + ctx.moveTo(point.x, point.y); + move = false; + } else { + lineMethod(ctx, prev, point, reverse, options.stepped); + } + prev = point; + } + if (loop) { + point = points[(start + (reverse ? ilen : 0)) % count]; + lineMethod(ctx, prev, point, reverse, options.stepped); + } + return !!loop; +} +function fastPathSegment(ctx, line, segment, params) { + const points = line.points; + const {count, start, ilen} = pathVars(points, segment, params); + const {move = true, reverse} = params || {}; + let avgX = 0; + let countX = 0; + let i, point, prevX, minY, maxY, lastY; + const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; + const drawX = () => { + if (minY !== maxY) { + ctx.lineTo(avgX, maxY); + ctx.lineTo(avgX, minY); + ctx.lineTo(avgX, lastY); + } + }; + if (move) { + point = points[pointIndex(0)]; + ctx.moveTo(point.x, point.y); + } + for (i = 0; i <= ilen; ++i) { + point = points[pointIndex(i)]; + if (point.skip) { + continue; + } + const x = point.x; + const y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + avgX = (countX * avgX + x) / ++countX; + } else { + drawX(); + ctx.lineTo(x, y); + prevX = truncX; + countX = 0; + minY = maxY = y; + } + lastY = y; + } + drawX(); +} +function _getSegmentMethod(line) { + const opts = line.options; + const borderDash = opts.borderDash && opts.borderDash.length; + const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; + return useFastPath ? fastPathSegment : pathSegment; +} +function _getInterpolationMethod(options) { + if (options.stepped) { + return _steppedInterpolation; + } + if (options.tension || options.cubicInterpolationMode === 'monotone') { + return _bezierInterpolation; + } + return _pointInLine; +} +function strokePathWithCache(ctx, line, start, count) { + let path = line._path; + if (!path) { + path = line._path = new Path2D(); + if (line.path(path, start, count)) { + path.closePath(); + } + } + setStyle(ctx, line.options); + ctx.stroke(path); +} +function strokePathDirect(ctx, line, start, count) { + const {segments, options} = line; + const segmentMethod = _getSegmentMethod(line); + for (const segment of segments) { + setStyle(ctx, options, segment.style); + ctx.beginPath(); + if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) { + ctx.closePath(); + } + ctx.stroke(); + } +} +const usePath2D = typeof Path2D === 'function'; +function draw(ctx, line, start, count) { + if (usePath2D && !line.options.segment) { + strokePathWithCache(ctx, line, start, count); + } else { + strokePathDirect(ctx, line, start, count); + } +} +class LineElement extends Element { + constructor(cfg) { + super(); + this.animated = true; + this.options = undefined; + this._chart = undefined; + this._loop = undefined; + this._fullLoop = undefined; + this._path = undefined; + this._points = undefined; + this._segments = undefined; + this._decimated = false; + this._pointsUpdated = false; + this._datasetIndex = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + updateControlPoints(chartArea, indexAxis) { + const options = this.options; + if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { + const loop = options.spanGaps ? this._loop : this._fullLoop; + _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); + this._pointsUpdated = true; + } + } + set points(points) { + this._points = points; + delete this._segments; + delete this._path; + this._pointsUpdated = false; + } + get points() { + return this._points; + } + get segments() { + return this._segments || (this._segments = _computeSegments(this, this.options.segment)); + } + first() { + const segments = this.segments; + const points = this.points; + return segments.length && points[segments[0].start]; + } + last() { + const segments = this.segments; + const points = this.points; + const count = segments.length; + return count && points[segments[count - 1].end]; + } + interpolate(point, property) { + const options = this.options; + const value = point[property]; + const points = this.points; + const segments = _boundSegments(this, {property, start: value, end: value}); + if (!segments.length) { + return; + } + const result = []; + const _interpolate = _getInterpolationMethod(options); + let i, ilen; + for (i = 0, ilen = segments.length; i < ilen; ++i) { + const {start, end} = segments[i]; + const p1 = points[start]; + const p2 = points[end]; + if (p1 === p2) { + result.push(p1); + continue; + } + const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); + const interpolated = _interpolate(p1, p2, t, options.stepped); + interpolated[property] = point[property]; + result.push(interpolated); + } + return result.length === 1 ? result[0] : result; + } + pathSegment(ctx, segment, params) { + const segmentMethod = _getSegmentMethod(this); + return segmentMethod(ctx, this, segment, params); + } + path(ctx, start, count) { + const segments = this.segments; + const segmentMethod = _getSegmentMethod(this); + let loop = this._loop; + start = start || 0; + count = count || (this.points.length - start); + for (const segment of segments) { + loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1}); + } + return !!loop; + } + draw(ctx, chartArea, start, count) { + const options = this.options || {}; + const points = this.points || []; + if (points.length && options.borderWidth) { + ctx.save(); + draw(ctx, this, start, count); + ctx.restore(); + } + if (this.animated) { + this._pointsUpdated = false; + this._path = undefined; + } + } +} +LineElement.id = 'line'; +LineElement.defaults = { + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: 'miter', + borderWidth: 3, + capBezierPoints: true, + cubicInterpolationMode: 'default', + fill: false, + spanGaps: false, + stepped: false, + tension: 0, +}; +LineElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; +LineElement.descriptors = { + _scriptable: true, + _indexable: (name) => name !== 'borderDash' && name !== 'fill', +}; + +function inRange$1(el, pos, axis, useFinalPosition) { + const options = el.options; + const {[axis]: value} = el.getProps([axis], useFinalPosition); + return (Math.abs(pos - value) < options.radius + options.hitRadius); +} +class PointElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.parsed = undefined; + this.skip = undefined; + this.stop = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(mouseX, mouseY, useFinalPosition) { + const options = this.options; + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); + } + inXRange(mouseX, useFinalPosition) { + return inRange$1(this, mouseX, 'x', useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange$1(this, mouseY, 'y', useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + size(options) { + options = options || this.options || {}; + let radius = options.radius || 0; + radius = Math.max(radius, radius && options.hoverRadius || 0); + const borderWidth = radius && options.borderWidth || 0; + return (radius + borderWidth) * 2; + } + draw(ctx, area) { + const options = this.options; + if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { + return; + } + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.fillStyle = options.backgroundColor; + drawPoint(ctx, options, this.x, this.y); + } + getRange() { + const options = this.options || {}; + return options.radius + options.hitRadius; + } +} +PointElement.id = 'point'; +PointElement.defaults = { + borderWidth: 1, + hitRadius: 1, + hoverBorderWidth: 1, + hoverRadius: 4, + pointStyle: 'circle', + radius: 3, + rotation: 0 +}; +PointElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; + +function getBarBounds(bar, useFinalPosition) { + const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); + let left, right, top, bottom, half; + if (bar.horizontal) { + half = height / 2; + left = Math.min(x, base); + right = Math.max(x, base); + top = y - half; + bottom = y + half; + } else { + half = width / 2; + left = x - half; + right = x + half; + top = Math.min(y, base); + bottom = Math.max(y, base); + } + return {left, top, right, bottom}; +} +function skipOrLimit(skip, value, min, max) { + return skip ? 0 : _limitValue(value, min, max); +} +function parseBorderWidth(bar, maxW, maxH) { + const value = bar.options.borderWidth; + const skip = bar.borderSkipped; + const o = toTRBL(value); + return { + t: skipOrLimit(skip.top, o.top, 0, maxH), + r: skipOrLimit(skip.right, o.right, 0, maxW), + b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), + l: skipOrLimit(skip.left, o.left, 0, maxW) + }; +} +function parseBorderRadius(bar, maxW, maxH) { + const {enableBorderRadius} = bar.getProps(['enableBorderRadius']); + const value = bar.options.borderRadius; + const o = toTRBLCorners(value); + const maxR = Math.min(maxW, maxH); + const skip = bar.borderSkipped; + const enableBorder = enableBorderRadius || isObject(value); + return { + topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), + topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), + bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), + bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) + }; +} +function boundingRects(bar) { + const bounds = getBarBounds(bar); + const width = bounds.right - bounds.left; + const height = bounds.bottom - bounds.top; + const border = parseBorderWidth(bar, width / 2, height / 2); + const radius = parseBorderRadius(bar, width / 2, height / 2); + return { + outer: { + x: bounds.left, + y: bounds.top, + w: width, + h: height, + radius + }, + inner: { + x: bounds.left + border.l, + y: bounds.top + border.t, + w: width - border.l - border.r, + h: height - border.t - border.b, + radius: { + topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), + topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), + bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), + bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)), + } + } + }; +} +function inRange(bar, x, y, useFinalPosition) { + const skipX = x === null; + const skipY = y === null; + const skipBoth = skipX && skipY; + const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); + return bounds + && (skipX || _isBetween(x, bounds.left, bounds.right)) + && (skipY || _isBetween(y, bounds.top, bounds.bottom)); +} +function hasRadius(radius) { + return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; +} +function addNormalRectPath(ctx, rect) { + ctx.rect(rect.x, rect.y, rect.w, rect.h); +} +function inflateRect(rect, amount, refRect = {}) { + const x = rect.x !== refRect.x ? -amount : 0; + const y = rect.y !== refRect.y ? -amount : 0; + const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; + const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; + return { + x: rect.x + x, + y: rect.y + y, + w: rect.w + w, + h: rect.h + h, + radius: rect.radius + }; +} +class BarElement extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.horizontal = undefined; + this.base = undefined; + this.width = undefined; + this.height = undefined; + this.inflateAmount = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + draw(ctx) { + const {inflateAmount, options: {borderColor, backgroundColor}} = this; + const {inner, outer} = boundingRects(this); + const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; + ctx.save(); + if (outer.w !== inner.w || outer.h !== inner.h) { + ctx.beginPath(); + addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); + ctx.clip(); + addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); + ctx.fillStyle = borderColor; + ctx.fill('evenodd'); + } + ctx.beginPath(); + addRectPath(ctx, inflateRect(inner, inflateAmount)); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + inRange(mouseX, mouseY, useFinalPosition) { + return inRange(this, mouseX, mouseY, useFinalPosition); + } + inXRange(mouseX, useFinalPosition) { + return inRange(this, mouseX, null, useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange(this, null, mouseY, useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); + return { + x: horizontal ? (x + base) / 2 : x, + y: horizontal ? y : (y + base) / 2 + }; + } + getRange(axis) { + return axis === 'x' ? this.width / 2 : this.height / 2; + } +} +BarElement.id = 'bar'; +BarElement.defaults = { + borderSkipped: 'start', + borderWidth: 0, + borderRadius: 0, + inflateAmount: 'auto', + pointStyle: undefined +}; +BarElement.defaultRoutes = { + backgroundColor: 'backgroundColor', + borderColor: 'borderColor' +}; + +var elements = /*#__PURE__*/Object.freeze({ +__proto__: null, +ArcElement: ArcElement, +LineElement: LineElement, +PointElement: PointElement, +BarElement: BarElement +}); + +function lttbDecimation(data, start, count, availableWidth, options) { + const samples = options.samples || availableWidth; + if (samples >= count) { + return data.slice(start, start + count); + } + const decimated = []; + const bucketWidth = (count - 2) / (samples - 2); + let sampledIndex = 0; + const endIndex = start + count - 1; + let a = start; + let i, maxAreaPoint, maxArea, area, nextA; + decimated[sampledIndex++] = data[a]; + for (i = 0; i < samples - 2; i++) { + let avgX = 0; + let avgY = 0; + let j; + const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; + const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; + const avgRangeLength = avgRangeEnd - avgRangeStart; + for (j = avgRangeStart; j < avgRangeEnd; j++) { + avgX += data[j].x; + avgY += data[j].y; + } + avgX /= avgRangeLength; + avgY /= avgRangeLength; + const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; + const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; + const {x: pointAx, y: pointAy} = data[a]; + maxArea = area = -1; + for (j = rangeOffs; j < rangeTo; j++) { + area = 0.5 * Math.abs( + (pointAx - avgX) * (data[j].y - pointAy) - + (pointAx - data[j].x) * (avgY - pointAy) + ); + if (area > maxArea) { + maxArea = area; + maxAreaPoint = data[j]; + nextA = j; + } + } + decimated[sampledIndex++] = maxAreaPoint; + a = nextA; + } + decimated[sampledIndex++] = data[endIndex]; + return decimated; +} +function minMaxDecimation(data, start, count, availableWidth) { + let avgX = 0; + let countX = 0; + let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; + const decimated = []; + const endIndex = start + count - 1; + const xMin = data[start].x; + const xMax = data[endIndex].x; + const dx = xMax - xMin; + for (i = start; i < start + count; ++i) { + point = data[i]; + x = (point.x - xMin) / dx * availableWidth; + y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + minIndex = i; + } else if (y > maxY) { + maxY = y; + maxIndex = i; + } + avgX = (countX * avgX + point.x) / ++countX; + } else { + const lastIndex = i - 1; + if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { + const intermediateIndex1 = Math.min(minIndex, maxIndex); + const intermediateIndex2 = Math.max(minIndex, maxIndex); + if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex1], + x: avgX, + }); + } + if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { + decimated.push({ + ...data[intermediateIndex2], + x: avgX + }); + } + } + if (i > 0 && lastIndex !== startIndex) { + decimated.push(data[lastIndex]); + } + decimated.push(point); + prevX = truncX; + countX = 0; + minY = maxY = y; + minIndex = maxIndex = startIndex = i; + } + } + return decimated; +} +function cleanDecimatedDataset(dataset) { + if (dataset._decimated) { + const data = dataset._data; + delete dataset._decimated; + delete dataset._data; + Object.defineProperty(dataset, 'data', {value: data}); + } +} +function cleanDecimatedData(chart) { + chart.data.datasets.forEach((dataset) => { + cleanDecimatedDataset(dataset); + }); +} +function getStartAndCountOfVisiblePointsSimplified(meta, points) { + const pointCount = points.length; + let start = 0; + let count; + const {iScale} = meta; + const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; + } else { + count = pointCount - start; + } + return {start, count}; +} +var plugin_decimation = { + id: 'decimation', + defaults: { + algorithm: 'min-max', + enabled: false, + }, + beforeElementsUpdate: (chart, args, options) => { + if (!options.enabled) { + cleanDecimatedData(chart); + return; + } + const availableWidth = chart.width; + chart.data.datasets.forEach((dataset, datasetIndex) => { + const {_data, indexAxis} = dataset; + const meta = chart.getDatasetMeta(datasetIndex); + const data = _data || dataset.data; + if (resolve([indexAxis, chart.options.indexAxis]) === 'y') { + return; + } + if (meta.type !== 'line') { + return; + } + const xAxis = chart.scales[meta.xAxisID]; + if (xAxis.type !== 'linear' && xAxis.type !== 'time') { + return; + } + if (chart.options.parsing) { + return; + } + let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data); + const threshold = options.threshold || 4 * availableWidth; + if (count <= threshold) { + cleanDecimatedDataset(dataset); + return; + } + if (isNullOrUndef(_data)) { + dataset._data = data; + delete dataset.data; + Object.defineProperty(dataset, 'data', { + configurable: true, + enumerable: true, + get: function() { + return this._decimated; + }, + set: function(d) { + this._data = d; + } + }); + } + let decimated; + switch (options.algorithm) { + case 'lttb': + decimated = lttbDecimation(data, start, count, availableWidth, options); + break; + case 'min-max': + decimated = minMaxDecimation(data, start, count, availableWidth); + break; + default: + throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); + } + dataset._decimated = decimated; + }); + }, + destroy(chart) { + cleanDecimatedData(chart); + } +}; + +function getLineByIndex(chart, index) { + const meta = chart.getDatasetMeta(index); + const visible = meta && chart.isDatasetVisible(index); + return visible ? meta.dataset : null; +} +function parseFillOption(line) { + const options = line.options; + const fillOption = options.fill; + let fill = valueOrDefault(fillOption && fillOption.target, fillOption); + if (fill === undefined) { + fill = !!options.backgroundColor; + } + if (fill === false || fill === null) { + return false; + } + if (fill === true) { + return 'origin'; + } + return fill; +} +function decodeFill(line, index, count) { + const fill = parseFillOption(line); + if (isObject(fill)) { + return isNaN(fill.value) ? false : fill; + } + let target = parseFloat(fill); + if (isNumberFinite(target) && Math.floor(target) === target) { + if (fill[0] === '-' || fill[0] === '+') { + target = index + target; + } + if (target === index || target < 0 || target >= count) { + return false; + } + return target; + } + return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill; +} +function computeLinearBoundary(source) { + const {scale = {}, fill} = source; + let target = null; + let horizontal; + if (fill === 'start') { + target = scale.bottom; + } else if (fill === 'end') { + target = scale.top; + } else if (isObject(fill)) { + target = scale.getPixelForValue(fill.value); + } else if (scale.getBasePixel) { + target = scale.getBasePixel(); + } + if (isNumberFinite(target)) { + horizontal = scale.isHorizontal(); + return { + x: horizontal ? target : null, + y: horizontal ? null : target + }; + } + return null; +} +class simpleArc { + constructor(opts) { + this.x = opts.x; + this.y = opts.y; + this.radius = opts.radius; + } + pathSegment(ctx, bounds, opts) { + const {x, y, radius} = this; + bounds = bounds || {start: 0, end: TAU}; + ctx.arc(x, y, radius, bounds.end, bounds.start, true); + return !opts.bounds; + } + interpolate(point) { + const {x, y, radius} = this; + const angle = point.angle; + return { + x: x + Math.cos(angle) * radius, + y: y + Math.sin(angle) * radius, + angle + }; + } +} +function computeCircularBoundary(source) { + const {scale, fill} = source; + const options = scale.options; + const length = scale.getLabels().length; + const target = []; + const start = options.reverse ? scale.max : scale.min; + const end = options.reverse ? scale.min : scale.max; + let i, center, value; + if (fill === 'start') { + value = start; + } else if (fill === 'end') { + value = end; + } else if (isObject(fill)) { + value = fill.value; + } else { + value = scale.getBaseValue(); + } + if (options.grid.circular) { + center = scale.getPointPositionForValue(0, start); + return new simpleArc({ + x: center.x, + y: center.y, + radius: scale.getDistanceFromCenterForValue(value) + }); + } + for (i = 0; i < length; ++i) { + target.push(scale.getPointPositionForValue(i, value)); + } + return target; +} +function computeBoundary(source) { + const scale = source.scale || {}; + if (scale.getPointPositionForValue) { + return computeCircularBoundary(source); + } + return computeLinearBoundary(source); +} +function findSegmentEnd(start, end, points) { + for (;end > start; end--) { + const point = points[end]; + if (!isNaN(point.x) && !isNaN(point.y)) { + break; + } + } + return end; +} +function pointsFromSegments(boundary, line) { + const {x = null, y = null} = boundary || {}; + const linePoints = line.points; + const points = []; + line.segments.forEach(({start, end}) => { + end = findSegmentEnd(start, end, linePoints); + const first = linePoints[start]; + const last = linePoints[end]; + if (y !== null) { + points.push({x: first.x, y}); + points.push({x: last.x, y}); + } else if (x !== null) { + points.push({x, y: first.y}); + points.push({x, y: last.y}); + } + }); + return points; +} +function buildStackLine(source) { + const {scale, index, line} = source; + const points = []; + const segments = line.segments; + const sourcePoints = line.points; + const linesBelow = getLinesBelow(scale, index); + linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + for (let j = segment.start; j <= segment.end; j++) { + addPointsBelow(points, sourcePoints[j], linesBelow); + } + } + return new LineElement({points, options: {}}); +} +function getLinesBelow(scale, index) { + const below = []; + const metas = scale.getMatchingVisibleMetas('line'); + for (let i = 0; i < metas.length; i++) { + const meta = metas[i]; + if (meta.index === index) { + break; + } + if (!meta.hidden) { + below.unshift(meta.dataset); + } + } + return below; +} +function addPointsBelow(points, sourcePoint, linesBelow) { + const postponed = []; + for (let j = 0; j < linesBelow.length; j++) { + const line = linesBelow[j]; + const {first, last, point} = findPoint(line, sourcePoint, 'x'); + if (!point || (first && last)) { + continue; + } + if (first) { + postponed.unshift(point); + } else { + points.push(point); + if (!last) { + break; + } + } + } + points.push(...postponed); +} +function findPoint(line, sourcePoint, property) { + const point = line.interpolate(sourcePoint, property); + if (!point) { + return {}; + } + const pointValue = point[property]; + const segments = line.segments; + const linePoints = line.points; + let first = false; + let last = false; + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + const firstValue = linePoints[segment.start][property]; + const lastValue = linePoints[segment.end][property]; + if (_isBetween(pointValue, firstValue, lastValue)) { + first = pointValue === firstValue; + last = pointValue === lastValue; + break; + } + } + return {first, last, point}; +} +function getTarget(source) { + const {chart, fill, line} = source; + if (isNumberFinite(fill)) { + return getLineByIndex(chart, fill); + } + if (fill === 'stack') { + return buildStackLine(source); + } + if (fill === 'shape') { + return true; + } + const boundary = computeBoundary(source); + if (boundary instanceof simpleArc) { + return boundary; + } + return createBoundaryLine(boundary, line); +} +function createBoundaryLine(boundary, line) { + let points = []; + let _loop = false; + if (isArray(boundary)) { + _loop = true; + points = boundary; + } else { + points = pointsFromSegments(boundary, line); + } + return points.length ? new LineElement({ + points, + options: {tension: 0}, + _loop, + _fullLoop: _loop + }) : null; +} +function resolveTarget(sources, index, propagate) { + const source = sources[index]; + let fill = source.fill; + const visited = [index]; + let target; + if (!propagate) { + return fill; + } + while (fill !== false && visited.indexOf(fill) === -1) { + if (!isNumberFinite(fill)) { + return fill; + } + target = sources[fill]; + if (!target) { + return false; + } + if (target.visible) { + return fill; + } + visited.push(fill); + fill = target.fill; + } + return false; +} +function _clip(ctx, target, clipY) { + const {segments, points} = target; + let first = true; + let lineLoop = false; + ctx.beginPath(); + for (const segment of segments) { + const {start, end} = segment; + const firstPoint = points[start]; + const lastPoint = points[findSegmentEnd(start, end, points)]; + if (first) { + ctx.moveTo(firstPoint.x, firstPoint.y); + first = false; + } else { + ctx.lineTo(firstPoint.x, clipY); + ctx.lineTo(firstPoint.x, firstPoint.y); + } + lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop}); + if (lineLoop) { + ctx.closePath(); + } else { + ctx.lineTo(lastPoint.x, clipY); + } + } + ctx.lineTo(target.first().x, clipY); + ctx.closePath(); + ctx.clip(); +} +function getBounds(property, first, last, loop) { + if (loop) { + return; + } + let start = first[property]; + let end = last[property]; + if (property === 'angle') { + start = _normalizeAngle(start); + end = _normalizeAngle(end); + } + return {property, start, end}; +} +function _getEdge(a, b, prop, fn) { + if (a && b) { + return fn(a[prop], b[prop]); + } + return a ? a[prop] : b ? b[prop] : 0; +} +function _segments(line, target, property) { + const segments = line.segments; + const points = line.points; + const tpoints = target.points; + const parts = []; + for (const segment of segments) { + let {start, end} = segment; + end = findSegmentEnd(start, end, points); + const bounds = getBounds(property, points[start], points[end], segment.loop); + if (!target.segments) { + parts.push({ + source: segment, + target: bounds, + start: points[start], + end: points[end] + }); + continue; + } + const targetSegments = _boundSegments(target, bounds); + for (const tgt of targetSegments) { + const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); + const fillSources = _boundSegment(segment, points, subBounds); + for (const fillSource of fillSources) { + parts.push({ + source: fillSource, + target: tgt, + start: { + [property]: _getEdge(bounds, subBounds, 'start', Math.max) + }, + end: { + [property]: _getEdge(bounds, subBounds, 'end', Math.min) + } + }); + } + } + } + return parts; +} +function clipBounds(ctx, scale, bounds) { + const {top, bottom} = scale.chart.chartArea; + const {property, start, end} = bounds || {}; + if (property === 'x') { + ctx.beginPath(); + ctx.rect(start, top, end - start, bottom - top); + ctx.clip(); + } +} +function interpolatedLineTo(ctx, target, point, property) { + const interpolatedPoint = target.interpolate(point, property); + if (interpolatedPoint) { + ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); + } +} +function _fill(ctx, cfg) { + const {line, target, property, color, scale} = cfg; + const segments = _segments(line, target, property); + for (const {source: src, target: tgt, start, end} of segments) { + const {style: {backgroundColor = color} = {}} = src; + const notShape = target !== true; + ctx.save(); + ctx.fillStyle = backgroundColor; + clipBounds(ctx, scale, notShape && getBounds(property, start, end)); + ctx.beginPath(); + const lineLoop = !!line.pathSegment(ctx, src); + let loop; + if (notShape) { + if (lineLoop) { + ctx.closePath(); + } else { + interpolatedLineTo(ctx, target, end, property); + } + const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); + loop = lineLoop && targetLoop; + if (!loop) { + interpolatedLineTo(ctx, target, start, property); + } + } + ctx.closePath(); + ctx.fill(loop ? 'evenodd' : 'nonzero'); + ctx.restore(); + } +} +function doFill(ctx, cfg) { + const {line, target, above, below, area, scale} = cfg; + const property = line._loop ? 'angle' : cfg.axis; + ctx.save(); + if (property === 'x' && below !== above) { + _clip(ctx, target, area.top); + _fill(ctx, {line, target, color: above, scale, property}); + ctx.restore(); + ctx.save(); + _clip(ctx, target, area.bottom); + } + _fill(ctx, {line, target, color: below, scale, property}); + ctx.restore(); +} +function drawfill(ctx, source, area) { + const target = getTarget(source); + const {line, scale, axis} = source; + const lineOpts = line.options; + const fillOption = lineOpts.fill; + const color = lineOpts.backgroundColor; + const {above = color, below = color} = fillOption || {}; + if (target && line.points.length) { + clipArea(ctx, area); + doFill(ctx, {line, target, above, below, area, scale, axis}); + unclipArea(ctx); + } +} +var plugin_filler = { + id: 'filler', + afterDatasetsUpdate(chart, _args, options) { + const count = (chart.data.datasets || []).length; + const sources = []; + let meta, i, line, source; + for (i = 0; i < count; ++i) { + meta = chart.getDatasetMeta(i); + line = meta.dataset; + source = null; + if (line && line.options && line instanceof LineElement) { + source = { + visible: chart.isDatasetVisible(i), + index: i, + fill: decodeFill(line, i, count), + chart, + axis: meta.controller.options.indexAxis, + scale: meta.vScale, + line, + }; + } + meta.$filler = source; + sources.push(source); + } + for (i = 0; i < count; ++i) { + source = sources[i]; + if (!source || source.fill === false) { + continue; + } + source.fill = resolveTarget(sources, i, options.propagate); + } + }, + beforeDraw(chart, _args, options) { + const draw = options.drawTime === 'beforeDraw'; + const metasets = chart.getSortedVisibleDatasetMetas(); + const area = chart.chartArea; + for (let i = metasets.length - 1; i >= 0; --i) { + const source = metasets[i].$filler; + if (!source) { + continue; + } + source.line.updateControlPoints(area, source.axis); + if (draw) { + drawfill(chart.ctx, source, area); + } + } + }, + beforeDatasetsDraw(chart, _args, options) { + if (options.drawTime !== 'beforeDatasetsDraw') { + return; + } + const metasets = chart.getSortedVisibleDatasetMetas(); + for (let i = metasets.length - 1; i >= 0; --i) { + const source = metasets[i].$filler; + if (source) { + drawfill(chart.ctx, source, chart.chartArea); + } + } + }, + beforeDatasetDraw(chart, args, options) { + const source = args.meta.$filler; + if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') { + return; + } + drawfill(chart.ctx, source, chart.chartArea); + }, + defaults: { + propagate: true, + drawTime: 'beforeDatasetDraw' + } +}; + +const getBoxSize = (labelOpts, fontSize) => { + let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts; + if (labelOpts.usePointStyle) { + boxHeight = Math.min(boxHeight, fontSize); + boxWidth = Math.min(boxWidth, fontSize); + } + return { + boxWidth, + boxHeight, + itemHeight: Math.max(fontSize, boxHeight) + }; +}; +const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; +class Legend extends Element { + constructor(config) { + super(); + this._added = false; + this.legendHitBoxes = []; + this._hoveredItem = null; + this.doughnutMode = false; + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this.legendItems = undefined; + this.columnSizes = undefined; + this.lineWidths = undefined; + this.maxHeight = undefined; + this.maxWidth = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.height = undefined; + this.width = undefined; + this._margins = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; + } + update(maxWidth, maxHeight, margins) { + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this._margins = margins; + this.setDimensions(); + this.buildLabels(); + this.fit(); + } + setDimensions() { + if (this.isHorizontal()) { + this.width = this.maxWidth; + this.left = this._margins.left; + this.right = this.width; + } else { + this.height = this.maxHeight; + this.top = this._margins.top; + this.bottom = this.height; + } + } + buildLabels() { + const labelOpts = this.options.labels || {}; + let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || []; + if (labelOpts.filter) { + legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data)); + } + if (labelOpts.sort) { + legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data)); + } + if (this.options.reverse) { + legendItems.reverse(); + } + this.legendItems = legendItems; + } + fit() { + const {options, ctx} = this; + if (!options.display) { + this.width = this.height = 0; + return; + } + const labelOpts = options.labels; + const labelFont = toFont(labelOpts.font); + const fontSize = labelFont.size; + const titleHeight = this._computeTitleHeight(); + const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize); + let width, height; + ctx.font = labelFont.string; + if (this.isHorizontal()) { + width = this.maxWidth; + height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; + } else { + height = this.maxHeight; + width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10; + } + this.width = Math.min(width, options.maxWidth || this.maxWidth); + this.height = Math.min(height, options.maxHeight || this.maxHeight); + } + _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { + const {ctx, maxWidth, options: {labels: {padding}}} = this; + const hitboxes = this.legendHitBoxes = []; + const lineWidths = this.lineWidths = [0]; + const lineHeight = itemHeight + padding; + let totalHeight = titleHeight; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + let row = -1; + let top = -lineHeight; + this.legendItems.forEach((legendItem, i) => { + const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { + totalHeight += lineHeight; + lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; + top += lineHeight; + row++; + } + hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight}; + lineWidths[lineWidths.length - 1] += itemWidth + padding; + }); + return totalHeight; + } + _fitCols(titleHeight, fontSize, boxWidth, itemHeight) { + const {ctx, maxHeight, options: {labels: {padding}}} = this; + const hitboxes = this.legendHitBoxes = []; + const columnSizes = this.columnSizes = []; + const heightLimit = maxHeight - titleHeight; + let totalWidth = padding; + let currentColWidth = 0; + let currentColHeight = 0; + let left = 0; + let col = 0; + this.legendItems.forEach((legendItem, i) => { + const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { + totalWidth += currentColWidth + padding; + columnSizes.push({width: currentColWidth, height: currentColHeight}); + left += currentColWidth + padding; + col++; + currentColWidth = currentColHeight = 0; + } + hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight}; + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += itemHeight + padding; + }); + totalWidth += currentColWidth; + columnSizes.push({width: currentColWidth, height: currentColHeight}); + return totalWidth; + } + adjustHitBoxes() { + if (!this.options.display) { + return; + } + const titleHeight = this._computeTitleHeight(); + const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this; + const rtlHelper = getRtlAdapter(rtl, this.left, this.width); + if (this.isHorizontal()) { + let row = 0; + let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + for (const hitbox of hitboxes) { + if (row !== hitbox.row) { + row = hitbox.row; + left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); + } + hitbox.top += this.top + titleHeight + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); + left += hitbox.width + padding; + } + } else { + let col = 0; + let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + for (const hitbox of hitboxes) { + if (hitbox.col !== col) { + col = hitbox.col; + top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); + } + hitbox.top = top; + hitbox.left += this.left + padding; + hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); + top += hitbox.height + padding; + } + } + } + isHorizontal() { + return this.options.position === 'top' || this.options.position === 'bottom'; + } + draw() { + if (this.options.display) { + const ctx = this.ctx; + clipArea(ctx, this); + this._draw(); + unclipArea(ctx); + } + } + _draw() { + const {options: opts, columnSizes, lineWidths, ctx} = this; + const {align, labels: labelOpts} = opts; + const defaultColor = defaults.color; + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const labelFont = toFont(labelOpts.font); + const {color: fontColor, padding} = labelOpts; + const fontSize = labelFont.size; + const halfFontSize = fontSize / 2; + let cursor; + this.drawTitle(); + ctx.textAlign = rtlHelper.textAlign('left'); + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.font = labelFont.string; + const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize); + const drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { + return; + } + ctx.save(); + const lineWidth = valueOrDefault(legendItem.lineWidth, 1); + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); + ctx.lineWidth = lineWidth; + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); + ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); + if (labelOpts.usePointStyle) { + const drawOptions = { + radius: boxWidth * Math.SQRT2 / 2, + pointStyle: legendItem.pointStyle, + rotation: legendItem.rotation, + borderWidth: lineWidth + }; + const centerX = rtlHelper.xPlus(x, boxWidth / 2); + const centerY = y + halfFontSize; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); + const borderRadius = toTRBLCorners(legendItem.borderRadius); + ctx.beginPath(); + if (Object.values(borderRadius).some(v => v !== 0)) { + addRoundedRectPath(ctx, { + x: xBoxLeft, + y: yBoxTop, + w: boxWidth, + h: boxHeight, + radius: borderRadius, + }); + } else { + ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); + } + ctx.fill(); + if (lineWidth !== 0) { + ctx.stroke(); + } + } + ctx.restore(); + }; + const fillText = function(x, y, legendItem) { + renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, { + strikethrough: legendItem.hidden, + textAlign: rtlHelper.textAlign(legendItem.textAlign) + }); + }; + const isHorizontal = this.isHorizontal(); + const titleHeight = this._computeTitleHeight(); + if (isHorizontal) { + cursor = { + x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), + y: this.top + padding + titleHeight, + line: 0 + }; + } else { + cursor = { + x: this.left + padding, + y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), + line: 0 + }; + } + overrideTextDirection(this.ctx, opts.textDirection); + const lineHeight = itemHeight + padding; + this.legendItems.forEach((legendItem, i) => { + ctx.strokeStyle = legendItem.fontColor || fontColor; + ctx.fillStyle = legendItem.fontColor || fontColor; + const textWidth = ctx.measureText(legendItem.text).width; + const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); + const width = boxWidth + halfFontSize + textWidth; + let x = cursor.x; + let y = cursor.y; + rtlHelper.setWidth(this.width); + if (isHorizontal) { + if (i > 0 && x + width + padding > this.right) { + y = cursor.y += lineHeight; + cursor.line++; + x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); + } + } else if (i > 0 && y + lineHeight > this.bottom) { + x = cursor.x = x + columnSizes[cursor.line].width + padding; + cursor.line++; + y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); + } + const realX = rtlHelper.x(x); + drawLegendBox(realX, y, legendItem); + x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); + fillText(rtlHelper.x(x), y, legendItem); + if (isHorizontal) { + cursor.x += width + padding; + } else { + cursor.y += lineHeight; + } + }); + restoreTextDirection(this.ctx, opts.textDirection); + } + drawTitle() { + const opts = this.options; + const titleOpts = opts.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + if (!titleOpts.display) { + return; + } + const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); + const ctx = this.ctx; + const position = titleOpts.position; + const halfFontSize = titleFont.size / 2; + const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; + let y; + let left = this.left; + let maxWidth = this.width; + if (this.isHorizontal()) { + maxWidth = Math.max(...this.lineWidths); + y = this.top + topPaddingPlusHalfFontSize; + left = _alignStartEnd(opts.align, left, this.right - maxWidth); + } else { + const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0); + y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); + } + const x = _alignStartEnd(position, left, left + maxWidth); + ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); + ctx.textBaseline = 'middle'; + ctx.strokeStyle = titleOpts.color; + ctx.fillStyle = titleOpts.color; + ctx.font = titleFont.string; + renderText(ctx, titleOpts.text, x, y, titleFont); + } + _computeTitleHeight() { + const titleOpts = this.options.title; + const titleFont = toFont(titleOpts.font); + const titlePadding = toPadding(titleOpts.padding); + return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; + } + _getLegendItemAt(x, y) { + let i, hitBox, lh; + if (_isBetween(x, this.left, this.right) + && _isBetween(y, this.top, this.bottom)) { + lh = this.legendHitBoxes; + for (i = 0; i < lh.length; ++i) { + hitBox = lh[i]; + if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) + && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { + return this.legendItems[i]; + } + } + } + return null; + } + handleEvent(e) { + const opts = this.options; + if (!isListened(e.type, opts)) { + return; + } + const hoveredItem = this._getLegendItemAt(e.x, e.y); + if (e.type === 'mousemove') { + const previous = this._hoveredItem; + const sameItem = itemsEqual(previous, hoveredItem); + if (previous && !sameItem) { + callback(opts.onLeave, [e, previous, this], this); + } + this._hoveredItem = hoveredItem; + if (hoveredItem && !sameItem) { + callback(opts.onHover, [e, hoveredItem, this], this); + } + } else if (hoveredItem) { + callback(opts.onClick, [e, hoveredItem, this], this); + } + } +} +function isListened(type, opts) { + if (type === 'mousemove' && (opts.onHover || opts.onLeave)) { + return true; + } + if (opts.onClick && (type === 'click' || type === 'mouseup')) { + return true; + } + return false; +} +var plugin_legend = { + id: 'legend', + _element: Legend, + start(chart, _args, options) { + const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart}); + layouts.configure(chart, legend, options); + layouts.addBox(chart, legend); + }, + stop(chart) { + layouts.removeBox(chart, chart.legend); + delete chart.legend; + }, + beforeUpdate(chart, _args, options) { + const legend = chart.legend; + layouts.configure(chart, legend, options); + legend.options = options; + }, + afterUpdate(chart) { + const legend = chart.legend; + legend.buildLabels(); + legend.adjustHitBoxes(); + }, + afterEvent(chart, args) { + if (!args.replay) { + chart.legend.handleEvent(args.event); + } + }, + defaults: { + display: true, + position: 'top', + align: 'center', + fullSize: true, + reverse: false, + weight: 1000, + onClick(e, legendItem, legend) { + const index = legendItem.datasetIndex; + const ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } + }, + onHover: null, + onLeave: null, + labels: { + color: (ctx) => ctx.chart.options.color, + boxWidth: 40, + padding: 10, + generateLabels(chart) { + const datasets = chart.data.datasets; + const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options; + return chart._getSortedDatasetMetas().map((meta) => { + const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); + const borderWidth = toPadding(style.borderWidth); + return { + text: datasets[meta.index].label, + fillStyle: style.backgroundColor, + fontColor: color, + hidden: !meta.visible, + lineCap: style.borderCapStyle, + lineDash: style.borderDash, + lineDashOffset: style.borderDashOffset, + lineJoin: style.borderJoinStyle, + lineWidth: (borderWidth.width + borderWidth.height) / 4, + strokeStyle: style.borderColor, + pointStyle: pointStyle || style.pointStyle, + rotation: style.rotation, + textAlign: textAlign || style.textAlign, + borderRadius: 0, + datasetIndex: meta.index + }; + }, this); + } + }, + title: { + color: (ctx) => ctx.chart.options.color, + display: false, + position: 'center', + text: '', + } + }, + descriptors: { + _scriptable: (name) => !name.startsWith('on'), + labels: { + _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name), + } + }, +}; + +class Title extends Element { + constructor(config) { + super(); + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this._padding = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this.position = undefined; + this.weight = undefined; + this.fullSize = undefined; + } + update(maxWidth, maxHeight) { + const opts = this.options; + this.left = 0; + this.top = 0; + if (!opts.display) { + this.width = this.height = this.right = this.bottom = 0; + return; + } + this.width = this.right = maxWidth; + this.height = this.bottom = maxHeight; + const lineCount = isArray(opts.text) ? opts.text.length : 1; + this._padding = toPadding(opts.padding); + const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; + if (this.isHorizontal()) { + this.height = textSize; + } else { + this.width = textSize; + } + } + isHorizontal() { + const pos = this.options.position; + return pos === 'top' || pos === 'bottom'; + } + _drawArgs(offset) { + const {top, left, bottom, right, options} = this; + const align = options.align; + let rotation = 0; + let maxWidth, titleX, titleY; + if (this.isHorizontal()) { + titleX = _alignStartEnd(align, left, right); + titleY = top + offset; + maxWidth = right - left; + } else { + if (options.position === 'left') { + titleX = left + offset; + titleY = _alignStartEnd(align, bottom, top); + rotation = PI * -0.5; + } else { + titleX = right - offset; + titleY = _alignStartEnd(align, top, bottom); + rotation = PI * 0.5; + } + maxWidth = bottom - top; + } + return {titleX, titleY, maxWidth, rotation}; + } + draw() { + const ctx = this.ctx; + const opts = this.options; + if (!opts.display) { + return; + } + const fontOpts = toFont(opts.font); + const lineHeight = fontOpts.lineHeight; + const offset = lineHeight / 2 + this._padding.top; + const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset); + renderText(ctx, opts.text, 0, 0, fontOpts, { + color: opts.color, + maxWidth, + rotation, + textAlign: _toLeftRightCenter(opts.align), + textBaseline: 'middle', + translation: [titleX, titleY], + }); + } +} +function createTitle(chart, titleOpts) { + const title = new Title({ + ctx: chart.ctx, + options: titleOpts, + chart + }); + layouts.configure(chart, title, titleOpts); + layouts.addBox(chart, title); + chart.titleBlock = title; +} +var plugin_title = { + id: 'title', + _element: Title, + start(chart, _args, options) { + createTitle(chart, options); + }, + stop(chart) { + const titleBlock = chart.titleBlock; + layouts.removeBox(chart, titleBlock); + delete chart.titleBlock; + }, + beforeUpdate(chart, _args, options) { + const title = chart.titleBlock; + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'bold', + }, + fullSize: true, + padding: 10, + position: 'top', + text: '', + weight: 2000 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false, + }, +}; + +const map = new WeakMap(); +var plugin_subtitle = { + id: 'subtitle', + start(chart, _args, options) { + const title = new Title({ + ctx: chart.ctx, + options, + chart + }); + layouts.configure(chart, title, options); + layouts.addBox(chart, title); + map.set(chart, title); + }, + stop(chart) { + layouts.removeBox(chart, map.get(chart)); + map.delete(chart); + }, + beforeUpdate(chart, _args, options) { + const title = map.get(chart); + layouts.configure(chart, title, options); + title.options = options; + }, + defaults: { + align: 'center', + display: false, + font: { + weight: 'normal', + }, + fullSize: true, + padding: 0, + position: 'top', + text: '', + weight: 1500 + }, + defaultRoutes: { + color: 'color' + }, + descriptors: { + _scriptable: true, + _indexable: false, + }, +}; + +const positioners = { + average(items) { + if (!items.length) { + return false; + } + let i, len; + let x = 0; + let y = 0; + let count = 0; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest(items, eventPosition) { + if (!items.length) { + return false; + } + let x = eventPosition.x; + let y = eventPosition.y; + let minDistance = Number.POSITIVE_INFINITY; + let i, len, nearestElement; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const center = el.getCenterPoint(); + const d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + const tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x, + y + }; + } +}; +function pushOrConcat(base, toPush) { + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + return base; +} +function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} +function createTooltipItem(chart, item) { + const {element, datasetIndex, index} = item; + const controller = chart.getDatasetMeta(datasetIndex).controller; + const {label, value} = controller.getLabelAndValue(index); + return { + chart, + label, + parsed: controller.getParsed(index), + raw: chart.data.datasets[datasetIndex].data[index], + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex, + element + }; +} +function getTooltipSize(tooltip, options) { + const ctx = tooltip.chart.ctx; + const {body, footer, title} = tooltip; + const {boxWidth, boxHeight} = options; + const bodyFont = toFont(options.bodyFont); + const titleFont = toFont(options.titleFont); + const footerFont = toFont(options.footerFont); + const titleLineCount = title.length; + const footerLineCount = footer.length; + const bodyLineItemCount = body.length; + const padding = toPadding(options.padding); + let height = padding.height; + let width = 0; + let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.lineHeight + + (titleLineCount - 1) * options.titleSpacing + + options.titleMarginBottom; + } + if (combinedBodyLength) { + const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; + height += bodyLineItemCount * bodyLineHeight + + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + + footerLineCount * footerFont.lineHeight + + (footerLineCount - 1) * options.footerSpacing; + } + let widthPadding = 0; + const maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0; + each(body, (bodyItem) => { + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += padding.width; + return {width, height}; +} +function determineYAlign(chart, size) { + const {y, height} = size; + if (y < height / 2) { + return 'top'; + } else if (y > (chart.height - height / 2)) { + return 'bottom'; + } + return 'center'; +} +function doesNotFitWithAlign(xAlign, chart, options, size) { + const {x, width} = size; + const caret = options.caretSize + options.caretPadding; + if (xAlign === 'left' && x + width + caret > chart.width) { + return true; + } + if (xAlign === 'right' && x - width - caret < 0) { + return true; + } +} +function determineXAlign(chart, options, size, yAlign) { + const {x, width} = size; + const {width: chartWidth, chartArea: {left, right}} = chart; + let xAlign = 'center'; + if (yAlign === 'center') { + xAlign = x <= (left + right) / 2 ? 'left' : 'right'; + } else if (x <= width / 2) { + xAlign = 'left'; + } else if (x >= chartWidth - width / 2) { + xAlign = 'right'; + } + if (doesNotFitWithAlign(xAlign, chart, options, size)) { + xAlign = 'center'; + } + return xAlign; +} +function determineAlignment(chart, options, size) { + const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); + return { + xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), + yAlign + }; +} +function alignX(size, xAlign) { + let {x, width} = size; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= (width / 2); + } + return x; +} +function alignY(size, yAlign, paddingAndSize) { + let {y, height} = size; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= (height / 2); + } + return y; +} +function getBackgroundPoint(options, size, alignment, chart) { + const {caretSize, caretPadding, cornerRadius} = options; + const {xAlign, yAlign} = alignment; + const paddingAndSize = caretSize + caretPadding; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); + let x = alignX(size, xAlign); + const y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= Math.max(topLeft, bottomLeft) + caretSize; + } else if (xAlign === 'right') { + x += Math.max(topRight, bottomRight) + caretSize; + } + return { + x: _limitValue(x, 0, chart.width - size.width), + y: _limitValue(y, 0, chart.height - size.height) + }; +} +function getAlignedX(tooltip, align, options) { + const padding = toPadding(options.padding); + return align === 'center' + ? tooltip.x + tooltip.width / 2 + : align === 'right' + ? tooltip.x + tooltip.width - padding.right + : tooltip.x + padding.left; +} +function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} +function createTooltipContext(parent, tooltip, tooltipItems) { + return createContext(parent, { + tooltip, + tooltipItems, + type: 'tooltip' + }); +} +function overrideCallbacks(callbacks, context) { + const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; + return override ? callbacks.override(override) : callbacks; +} +class Tooltip extends Element { + constructor(config) { + super(); + this.opacity = 0; + this._active = []; + this._eventPosition = undefined; + this._size = undefined; + this._cachedAnimations = undefined; + this._tooltipItems = []; + this.$animations = undefined; + this.$context = undefined; + this.chart = config.chart || config._chart; + this._chart = this.chart; + this.options = config.options; + this.dataPoints = undefined; + this.title = undefined; + this.beforeBody = undefined; + this.body = undefined; + this.afterBody = undefined; + this.footer = undefined; + this.xAlign = undefined; + this.yAlign = undefined; + this.x = undefined; + this.y = undefined; + this.height = undefined; + this.width = undefined; + this.caretX = undefined; + this.caretY = undefined; + this.labelColors = undefined; + this.labelPointStyles = undefined; + this.labelTextColors = undefined; + } + initialize(options) { + this.options = options; + this._cachedAnimations = undefined; + this.$context = undefined; + } + _resolveAnimations() { + const cached = this._cachedAnimations; + if (cached) { + return cached; + } + const chart = this.chart; + const options = this.options.setContext(this.getContext()); + const opts = options.enabled && chart.options.animation && options.animations; + const animations = new Animations(this.chart, opts); + if (opts._cacheable) { + this._cachedAnimations = Object.freeze(animations); + } + return animations; + } + getContext() { + return this.$context || + (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); + } + getTitle(context, options) { + const {callbacks} = options; + const beforeTitle = callbacks.beforeTitle.apply(this, [context]); + const title = callbacks.title.apply(this, [context]); + const afterTitle = callbacks.afterTitle.apply(this, [context]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + } + getBeforeBody(tooltipItems, options) { + return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems])); + } + getBody(tooltipItems, options) { + const {callbacks} = options; + const bodyItems = []; + each(tooltipItems, (context) => { + const bodyItem = { + before: [], + lines: [], + after: [] + }; + const scoped = overrideCallbacks(callbacks, context); + pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context))); + pushOrConcat(bodyItem.lines, scoped.label.call(this, context)); + pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + } + getAfterBody(tooltipItems, options) { + return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems])); + } + getFooter(tooltipItems, options) { + const {callbacks} = options; + const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]); + const footer = callbacks.footer.apply(this, [tooltipItems]); + const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + _createItems(options) { + const active = this._active; + const data = this.chart.data; + const labelColors = []; + const labelPointStyles = []; + const labelTextColors = []; + let tooltipItems = []; + let i, len; + for (i = 0, len = active.length; i < len; ++i) { + tooltipItems.push(createTooltipItem(this.chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); + } + each(tooltipItems, (context) => { + const scoped = overrideCallbacks(options.callbacks, context); + labelColors.push(scoped.labelColor.call(this, context)); + labelPointStyles.push(scoped.labelPointStyle.call(this, context)); + labelTextColors.push(scoped.labelTextColor.call(this, context)); + }); + this.labelColors = labelColors; + this.labelPointStyles = labelPointStyles; + this.labelTextColors = labelTextColors; + this.dataPoints = tooltipItems; + return tooltipItems; + } + update(changed, replay) { + const options = this.options.setContext(this.getContext()); + const active = this._active; + let properties; + let tooltipItems = []; + if (!active.length) { + if (this.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + const position = positioners[options.position].call(this, active, this._eventPosition); + tooltipItems = this._createItems(options); + this.title = this.getTitle(tooltipItems, options); + this.beforeBody = this.getBeforeBody(tooltipItems, options); + this.body = this.getBody(tooltipItems, options); + this.afterBody = this.getAfterBody(tooltipItems, options); + this.footer = this.getFooter(tooltipItems, options); + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, size); + const alignment = determineAlignment(this.chart, options, positionAndSize); + const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + this._tooltipItems = tooltipItems; + this.$context = undefined; + if (properties) { + this._resolveAnimations().update(this, properties); + } + if (changed && options.external) { + options.external.call(this, {chart: this.chart, tooltip: this, replay}); + } + } + drawCaret(tooltipPoint, ctx, size, options) { + const caretPosition = this.getCaretPosition(tooltipPoint, size, options); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + } + getCaretPosition(tooltipPoint, size, options) { + const {xAlign, yAlign} = this; + const {caretSize, cornerRadius} = options; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); + const {x: ptX, y: ptY} = tooltipPoint; + const {width, height} = size; + let x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + (height / 2); + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize); + } else if (xAlign === 'right') { + x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return {x1, x2, x3, y1, y2, y3}; + } + drawTitle(pt, ctx, options) { + const title = this.title; + const length = title.length; + let titleFont, titleSpacing, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.titleAlign, options); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = toFont(options.titleFont); + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleColor; + ctx.font = titleFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); + pt.y += titleFont.lineHeight + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + _drawColorBox(ctx, pt, i, rtlHelper, options) { + const labelColors = this.labelColors[i]; + const labelPointStyle = this.labelPointStyles[i]; + const {boxHeight, boxWidth, boxPadding} = options; + const bodyFont = toFont(options.bodyFont); + const colorX = getAlignedX(this, 'left', options); + const rtlColorX = rtlHelper.x(colorX); + const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; + const colorY = pt.y + yOffSet; + if (options.usePointStyle) { + const drawOptions = { + radius: Math.min(boxWidth, boxHeight) / 2, + pointStyle: labelPointStyle.pointStyle, + rotation: labelPointStyle.rotation, + borderWidth: 1 + }; + const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; + const centerY = colorY + boxHeight / 2; + ctx.strokeStyle = options.multiKeyBackground; + ctx.fillStyle = options.multiKeyBackground; + drawPoint(ctx, drawOptions, centerX, centerY); + ctx.strokeStyle = labelColors.borderColor; + ctx.fillStyle = labelColors.backgroundColor; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + ctx.lineWidth = labelColors.borderWidth || 1; + ctx.strokeStyle = labelColors.borderColor; + ctx.setLineDash(labelColors.borderDash || []); + ctx.lineDashOffset = labelColors.borderDashOffset || 0; + const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding); + const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2); + const borderRadius = toTRBLCorners(labelColors.borderRadius); + if (Object.values(borderRadius).some(v => v !== 0)) { + ctx.beginPath(); + ctx.fillStyle = options.multiKeyBackground; + addRoundedRectPath(ctx, { + x: outerX, + y: colorY, + w: boxWidth, + h: boxHeight, + radius: borderRadius, + }); + ctx.fill(); + ctx.stroke(); + ctx.fillStyle = labelColors.backgroundColor; + ctx.beginPath(); + addRoundedRectPath(ctx, { + x: innerX, + y: colorY + 1, + w: boxWidth - 2, + h: boxHeight - 2, + radius: borderRadius, + }); + ctx.fill(); + } else { + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(outerX, colorY, boxWidth, boxHeight); + ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColors.backgroundColor; + ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); + } + } + ctx.fillStyle = this.labelTextColors[i]; + } + drawBody(pt, ctx, options) { + const {body} = this; + const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options; + const bodyFont = toFont(options.bodyFont); + let bodyLineHeight = bodyFont.lineHeight; + let xLinePadding = 0; + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + const fillLineOfText = function(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + let bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(this, bodyAlignForCalculation, options); + ctx.fillStyle = options.bodyColor; + each(this.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' + ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding) + : 0; + for (i = 0, ilen = body.length; i < ilen; ++i) { + bodyItem = body[i]; + textColor = this.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + this._drawColorBox(ctx, pt, i, rtlHelper, options); + bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); + } + for (j = 0, jlen = lines.length; j < jlen; ++j) { + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.lineHeight; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.lineHeight; + each(this.afterBody, fillLineOfText); + pt.y -= bodySpacing; + } + drawFooter(pt, ctx, options) { + const footer = this.footer; + const length = footer.length; + let footerFont, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); + pt.x = getAlignedX(this, options.footerAlign, options); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = toFont(options.footerFont); + ctx.fillStyle = options.footerColor; + ctx.font = footerFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); + pt.y += footerFont.lineHeight + options.footerSpacing; + } + } + } + drawBackground(pt, ctx, tooltipSize, options) { + const {xAlign, yAlign} = this; + const {x, y} = pt; + const {width, height} = tooltipSize; + const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius); + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + topLeft, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width - topRight, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + width, y + height - bottomRight); + ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x + bottomLeft, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize, options); + } + ctx.lineTo(x, y + topLeft); + ctx.quadraticCurveTo(x, y, x + topLeft, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + _updateAnimationTarget(options) { + const chart = this.chart; + const anims = this.$animations; + const animX = anims && anims.x; + const animY = anims && anims.y; + if (animX || animY) { + const position = positioners[options.position].call(this, this._active, this._eventPosition); + if (!position) { + return; + } + const size = this._size = getTooltipSize(this, options); + const positionAndSize = Object.assign({}, position, this._size); + const alignment = determineAlignment(chart, options, positionAndSize); + const point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + this.xAlign = alignment.xAlign; + this.yAlign = alignment.yAlign; + this.width = size.width; + this.height = size.height; + this.caretX = position.x; + this.caretY = position.y; + this._resolveAnimations().update(this, point); + } + } + } + draw(ctx) { + const options = this.options.setContext(this.getContext()); + let opacity = this.opacity; + if (!opacity) { + return; + } + this._updateAnimationTarget(options); + const tooltipSize = { + width: this.width, + height: this.height + }; + const pt = { + x: this.x, + y: this.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + const padding = toPadding(options.padding); + const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + this.drawBackground(pt, ctx, tooltipSize, options); + overrideTextDirection(ctx, options.textDirection); + pt.y += padding.top; + this.drawTitle(pt, ctx, options); + this.drawBody(pt, ctx, options); + this.drawFooter(pt, ctx, options); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + getActiveElements() { + return this._active || []; + } + setActiveElements(activeElements, eventPosition) { + const lastActive = this._active; + const active = activeElements.map(({datasetIndex, index}) => { + const meta = this.chart.getDatasetMeta(datasetIndex); + if (!meta) { + throw new Error('Cannot find a dataset at index ' + datasetIndex); + } + return { + datasetIndex, + element: meta.data[index], + index, + }; + }); + const changed = !_elementsEqual(lastActive, active); + const positionChanged = this._positionChanged(active, eventPosition); + if (changed || positionChanged) { + this._active = active; + this._eventPosition = eventPosition; + this._ignoreReplayEvents = true; + this.update(true); + } + } + handleEvent(e, replay, inChartArea = true) { + if (replay && this._ignoreReplayEvents) { + return false; + } + this._ignoreReplayEvents = false; + const options = this.options; + const lastActive = this._active || []; + const active = this._getActiveElements(e, lastActive, replay, inChartArea); + const positionChanged = this._positionChanged(active, e); + const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + this._active = active; + if (options.enabled || options.external) { + this._eventPosition = { + x: e.x, + y: e.y + }; + this.update(true, replay); + } + } + return changed; + } + _getActiveElements(e, lastActive, replay, inChartArea) { + const options = this.options; + if (e.type === 'mouseout') { + return []; + } + if (!inChartArea) { + return lastActive; + } + const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + return active; + } + _positionChanged(active, e) { + const {caretX, caretY, options} = this; + const position = positioners[options.position].call(this, active, e); + return position !== false && (caretX !== position.x || caretY !== position.y); + } +} +Tooltip.positioners = positioners; +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners, + afterInit(chart, _args, options) { + if (options) { + chart.tooltip = new Tooltip({chart, options}); + } + }, + beforeUpdate(chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + reset(chart, _args, options) { + if (chart.tooltip) { + chart.tooltip.initialize(options); + } + }, + afterDraw(chart) { + const tooltip = chart.tooltip; + const args = { + tooltip + }; + if (chart.notifyPlugins('beforeTooltipDraw', args) === false) { + return; + } + if (tooltip) { + tooltip.draw(chart.ctx); + } + chart.notifyPlugins('afterTooltipDraw', args); + }, + afterEvent(chart, args) { + if (chart.tooltip) { + const useFinalPosition = args.replay; + if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { + args.changed = true; + } + } + }, + defaults: { + enabled: true, + external: null, + position: 'average', + backgroundColor: 'rgba(0,0,0,0.8)', + titleColor: '#fff', + titleFont: { + weight: 'bold', + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodyColor: '#fff', + bodySpacing: 2, + bodyFont: { + }, + bodyAlign: 'left', + footerColor: '#fff', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + weight: 'bold', + }, + footerAlign: 'left', + padding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + boxHeight: (ctx, opts) => opts.bodyFont.size, + boxWidth: (ctx, opts) => opts.bodyFont.size, + multiKeyBackground: '#fff', + displayColors: true, + boxPadding: 0, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart', + }, + animations: { + numbers: { + type: 'number', + properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: { + beforeTitle: noop, + title(tooltipItems) { + if (tooltipItems.length > 0) { + const item = tooltipItems[0]; + const labels = item.chart.data.labels; + const labelCount = labels ? labels.length : 0; + if (this && this.options && this.options.mode === 'dataset') { + return item.dataset.label || ''; + } else if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } + } + return ''; + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label(tooltipItem) { + if (this && this.options && this.options.mode === 'dataset') { + return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; + } + let label = tooltipItem.dataset.label || ''; + if (label) { + label += ': '; + } + const value = tooltipItem.formattedValue; + if (!isNullOrUndef(value)) { + label += value; + } + return label; + }, + labelColor(tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + borderColor: options.borderColor, + backgroundColor: options.backgroundColor, + borderWidth: options.borderWidth, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderRadius: 0, + }; + }, + labelTextColor() { + return this.options.bodyColor; + }, + labelPointStyle(tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + pointStyle: options.pointStyle, + rotation: options.rotation, + }; + }, + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop + } + }, + defaultRoutes: { + bodyFont: 'font', + footerFont: 'font', + titleFont: 'font' + }, + descriptors: { + _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external', + _indexable: false, + callbacks: { + _scriptable: false, + _indexable: false, + }, + animation: { + _fallback: false + }, + animations: { + _fallback: 'animation' + } + }, + additionalOptionScopes: ['interaction'] +}; + +var plugins = /*#__PURE__*/Object.freeze({ +__proto__: null, +Decimation: plugin_decimation, +Filler: plugin_filler, +Legend: plugin_legend, +SubTitle: plugin_subtitle, +Title: plugin_title, +Tooltip: plugin_tooltip +}); + +const addIfString = (labels, raw, index, addedLabels) => { + if (typeof raw === 'string') { + index = labels.push(raw) - 1; + addedLabels.unshift({index, label: raw}); + } else if (isNaN(raw)) { + index = null; + } + return index; +}; +function findOrAddLabel(labels, raw, index, addedLabels) { + const first = labels.indexOf(raw); + if (first === -1) { + return addIfString(labels, raw, index, addedLabels); + } + const last = labels.lastIndexOf(raw); + return first !== last ? index : first; +} +const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max); +class CategoryScale extends Scale { + constructor(cfg) { + super(cfg); + this._startValue = undefined; + this._valueRange = 0; + this._addedLabels = []; + } + init(scaleOptions) { + const added = this._addedLabels; + if (added.length) { + const labels = this.getLabels(); + for (const {index, label} of added) { + if (labels[index] === label) { + labels.splice(index, 1); + } + } + this._addedLabels = []; + } + super.init(scaleOptions); + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + const labels = this.getLabels(); + index = isFinite(index) && labels[index] === raw ? index + : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); + return validIndex(index, labels.length - 1); + } + determineDataLimits() { + const {minDefined, maxDefined} = this.getUserBounds(); + let {min, max} = this.getMinMax(true); + if (this.options.bounds === 'ticks') { + if (!minDefined) { + min = 0; + } + if (!maxDefined) { + max = this.getLabels().length - 1; + } + } + this.min = min; + this.max = max; + } + buildTicks() { + const min = this.min; + const max = this.max; + const offset = this.options.offset; + const ticks = []; + let labels = this.getLabels(); + labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); + this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); + this._startValue = this.min - (offset ? 0.5 : 0); + for (let value = min; value <= max; value++) { + ticks.push({value}); + } + return ticks; + } + getLabelForValue(value) { + const labels = this.getLabels(); + if (value >= 0 && value < labels.length) { + return labels[value]; + } + return value; + } + configure() { + super.configure(); + if (!this.isHorizontal()) { + this._reversePixels = !this._reversePixels; + } + } + getPixelForValue(value) { + if (typeof value !== 'number') { + value = this.parse(value); + } + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getValueForPixel(pixel) { + return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); + } + getBasePixel() { + return this.bottom; + } +} +CategoryScale.id = 'category'; +CategoryScale.defaults = { + ticks: { + callback: CategoryScale.prototype.getLabelForValue + } +}; + +function generateTicks$1(generationOptions, dataRange) { + const ticks = []; + const MIN_SPACING = 1e-14; + const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions; + const unit = step || 1; + const maxSpaces = maxTicks - 1; + const {min: rmin, max: rmax} = dataRange; + const minDefined = !isNullOrUndef(min); + const maxDefined = !isNullOrUndef(max); + const countDefined = !isNullOrUndef(count); + const minSpacing = (rmax - rmin) / (maxDigits + 1); + let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; + let factor, niceMin, niceMax, numSpaces; + if (spacing < MIN_SPACING && !minDefined && !maxDefined) { + return [{value: rmin}, {value: rmax}]; + } + numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); + if (numSpaces > maxSpaces) { + spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; + } + if (!isNullOrUndef(precision)) { + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } + if (bounds === 'ticks') { + niceMin = Math.floor(rmin / spacing) * spacing; + niceMax = Math.ceil(rmax / spacing) * spacing; + } else { + niceMin = rmin; + niceMax = rmax; + } + if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { + numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); + spacing = (max - min) / numSpaces; + niceMin = min; + niceMax = max; + } else if (countDefined) { + niceMin = minDefined ? min : niceMin; + niceMax = maxDefined ? max : niceMax; + numSpaces = count - 1; + spacing = (niceMax - niceMin) / numSpaces; + } else { + numSpaces = (niceMax - niceMin) / spacing; + if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + } + const decimalPlaces = Math.max( + _decimalPlaces(spacing), + _decimalPlaces(niceMin) + ); + factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); + niceMin = Math.round(niceMin * factor) / factor; + niceMax = Math.round(niceMax * factor) / factor; + let j = 0; + if (minDefined) { + if (includeBounds && niceMin !== min) { + ticks.push({value: min}); + if (niceMin < min) { + j++; + } + if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { + j++; + } + } else if (niceMin < min) { + j++; + } + } + for (; j < numSpaces; ++j) { + ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); + } + if (maxDefined && includeBounds && niceMax !== max) { + if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { + ticks[ticks.length - 1].value = max; + } else { + ticks.push({value: max}); + } + } else if (!maxDefined || niceMax === max) { + ticks.push({value: niceMax}); + } + return ticks; +} +function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) { + const rad = toRadians(minRotation); + const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; + const length = 0.75 * minSpacing * ('' + value).length; + return Math.min(minSpacing / ratio, length); +} +class LinearScaleBase extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._endValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return null; + } + if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { + return null; + } + return +raw; + } + handleTickRangeOptions() { + const {beginAtZero} = this.options; + const {minDefined, maxDefined} = this.getUserBounds(); + let {min, max} = this; + const setMin = v => (min = minDefined ? min : v); + const setMax = v => (max = maxDefined ? max : v); + if (beginAtZero) { + const minSign = sign(min); + const maxSign = sign(max); + if (minSign < 0 && maxSign < 0) { + setMax(0); + } else if (minSign > 0 && maxSign > 0) { + setMin(0); + } + } + if (min === max) { + let offset = 1; + if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) { + offset = Math.abs(max * 0.05); + } + setMax(max + offset); + if (!beginAtZero) { + setMin(min - offset); + } + } + this.min = min; + this.max = max; + } + getTickLimit() { + const tickOpts = this.options.ticks; + let {maxTicksLimit, stepSize} = tickOpts; + let maxTicks; + if (stepSize) { + maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; + if (maxTicks > 1000) { + console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); + maxTicks = 1000; + } + } else { + maxTicks = this.computeTickLimit(); + maxTicksLimit = maxTicksLimit || 11; + } + if (maxTicksLimit) { + maxTicks = Math.min(maxTicksLimit, maxTicks); + } + return maxTicks; + } + computeTickLimit() { + return Number.POSITIVE_INFINITY; + } + buildTicks() { + const opts = this.options; + const tickOpts = opts.ticks; + let maxTicks = this.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + const numericGeneratorOptions = { + maxTicks, + bounds: opts.bounds, + min: opts.min, + max: opts.max, + precision: tickOpts.precision, + step: tickOpts.stepSize, + count: tickOpts.count, + maxDigits: this._maxDigits(), + horizontal: this.isHorizontal(), + minRotation: tickOpts.minRotation || 0, + includeBounds: tickOpts.includeBounds !== false + }; + const dataRange = this._range || this; + const ticks = generateTicks$1(numericGeneratorOptions, dataRange); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + configure() { + const ticks = this.ticks; + let start = this.min; + let end = this.max; + super.configure(); + if (this.options.offset && ticks.length) { + const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; + start -= offset; + end += offset; + } + this._startValue = start; + this._endValue = end; + this._valueRange = end - start; + } + getLabelForValue(value) { + return formatNumber(value, this.chart.options.locale, this.options.ticks.format); + } +} + +class LinearScale extends LinearScaleBase { + determineDataLimits() { + const {min, max} = this.getMinMax(true); + this.min = isNumberFinite(min) ? min : 0; + this.max = isNumberFinite(max) ? max : 1; + this.handleTickRangeOptions(); + } + computeTickLimit() { + const horizontal = this.isHorizontal(); + const length = horizontal ? this.width : this.height; + const minRotation = toRadians(this.options.ticks.minRotation); + const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; + const tickFont = this._resolveTickFontOptions(0); + return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); + } + getPixelForValue(value) { + return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; + } +} +LinearScale.id = 'linear'; +LinearScale.defaults = { + ticks: { + callback: Ticks.formatters.numeric + } +}; + +function isMajor(tickVal) { + const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); + return remain === 1; +} +function generateTicks(generationOptions, dataRange) { + const endExp = Math.floor(log10(dataRange.max)); + const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + const ticks = []; + let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); + let exp = Math.floor(log10(tickVal)); + let significand = Math.floor(tickVal / Math.pow(10, exp)); + let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; + do { + ticks.push({value: tickVal, major: isMajor(tickVal)}); + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + precision = exp >= 0 ? 1 : precision; + } + tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; + } while (exp < endExp || (exp === endExp && significand < endSignificand)); + const lastTick = finiteOrDefault(generationOptions.max, tickVal); + ticks.push({value: lastTick, major: isMajor(tickVal)}); + return ticks; +} +class LogarithmicScale extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); + if (value === 0) { + this._zero = true; + return undefined; + } + return isNumberFinite(value) && value > 0 ? value : null; + } + determineDataLimits() { + const {min, max} = this.getMinMax(true); + this.min = isNumberFinite(min) ? Math.max(0, min) : null; + this.max = isNumberFinite(max) ? Math.max(0, max) : null; + if (this.options.beginAtZero) { + this._zero = true; + } + this.handleTickRangeOptions(); + } + handleTickRangeOptions() { + const {minDefined, maxDefined} = this.getUserBounds(); + let min = this.min; + let max = this.max; + const setMin = v => (min = minDefined ? min : v); + const setMax = v => (max = maxDefined ? max : v); + const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m); + if (min === max) { + if (min <= 0) { + setMin(1); + setMax(10); + } else { + setMin(exp(min, -1)); + setMax(exp(max, +1)); + } + } + if (min <= 0) { + setMin(exp(max, -1)); + } + if (max <= 0) { + setMax(exp(min, +1)); + } + if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) { + setMin(exp(min, -1)); + } + this.min = min; + this.max = max; + } + buildTicks() { + const opts = this.options; + const generationOptions = { + min: this._userMin, + max: this._userMax + }; + const ticks = generateTicks(generationOptions, this); + if (opts.bounds === 'ticks') { + _setMinAndMaxByKey(ticks, this, 'value'); + } + if (opts.reverse) { + ticks.reverse(); + this.start = this.max; + this.end = this.min; + } else { + this.start = this.min; + this.end = this.max; + } + return ticks; + } + getLabelForValue(value) { + return value === undefined + ? '0' + : formatNumber(value, this.chart.options.locale, this.options.ticks.format); + } + configure() { + const start = this.min; + super.configure(); + this._startValue = log10(start); + this._valueRange = log10(this.max) - log10(start); + } + getPixelForValue(value) { + if (value === undefined || value === 0) { + value = this.min; + } + if (value === null || isNaN(value)) { + return NaN; + } + return this.getPixelForDecimal(value === this.min + ? 0 + : (log10(value) - this._startValue) / this._valueRange); + } + getValueForPixel(pixel) { + const decimal = this.getDecimalForPixel(pixel); + return Math.pow(10, this._startValue + decimal * this._valueRange); + } +} +LogarithmicScale.id = 'logarithmic'; +LogarithmicScale.defaults = { + ticks: { + callback: Ticks.formatters.logarithmic, + major: { + enabled: true + } + } +}; + +function getTickBackdropHeight(opts) { + const tickOpts = opts.ticks; + if (tickOpts.display && opts.display) { + const padding = toPadding(tickOpts.backdropPadding); + return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; + } + return 0; +} +function measureLabelSize(ctx, font, label) { + label = isArray(label) ? label : [label]; + return { + w: _longestText(ctx, font.string, label), + h: label.length * font.lineHeight + }; +} +function determineLimits(angle, pos, size, min, max) { + if (angle === min || angle === max) { + return { + start: pos - (size / 2), + end: pos + (size / 2) + }; + } else if (angle < min || angle > max) { + return { + start: pos - size, + end: pos + }; + } + return { + start: pos, + end: pos + size + }; +} +function fitWithPointLabels(scale) { + const orig = { + l: scale.left + scale._padding.left, + r: scale.right - scale._padding.right, + t: scale.top + scale._padding.top, + b: scale.bottom - scale._padding.bottom + }; + const limits = Object.assign({}, orig); + const labelSizes = []; + const padding = []; + const valueCount = scale._pointLabels.length; + const pointLabelOpts = scale.options.pointLabels; + const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; + for (let i = 0; i < valueCount; i++) { + const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); + padding[i] = opts.padding; + const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); + const plFont = toFont(opts.font); + const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); + labelSizes[i] = textSize; + const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); + const angle = Math.round(toDegrees(angleRadians)); + const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + updateLimits(limits, orig, angleRadians, hLimits, vLimits); + } + scale.setCenterPoint( + orig.l - limits.l, + limits.r - orig.r, + orig.t - limits.t, + limits.b - orig.b + ); + scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); +} +function updateLimits(limits, orig, angle, hLimits, vLimits) { + const sin = Math.abs(Math.sin(angle)); + const cos = Math.abs(Math.cos(angle)); + let x = 0; + let y = 0; + if (hLimits.start < orig.l) { + x = (orig.l - hLimits.start) / sin; + limits.l = Math.min(limits.l, orig.l - x); + } else if (hLimits.end > orig.r) { + x = (hLimits.end - orig.r) / sin; + limits.r = Math.max(limits.r, orig.r + x); + } + if (vLimits.start < orig.t) { + y = (orig.t - vLimits.start) / cos; + limits.t = Math.min(limits.t, orig.t - y); + } else if (vLimits.end > orig.b) { + y = (vLimits.end - orig.b) / cos; + limits.b = Math.max(limits.b, orig.b + y); + } +} +function buildPointLabelItems(scale, labelSizes, padding) { + const items = []; + const valueCount = scale._pointLabels.length; + const opts = scale.options; + const extra = getTickBackdropHeight(opts) / 2; + const outerDistance = scale.drawingArea; + const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0; + for (let i = 0; i < valueCount; i++) { + const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle); + const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); + const size = labelSizes[i]; + const y = yForAngle(pointLabelPosition.y, size.h, angle); + const textAlign = getTextAlignForAngle(angle); + const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); + items.push({ + x: pointLabelPosition.x, + y, + textAlign, + left, + top: y, + right: left + size.w, + bottom: y + size.h + }); + } + return items; +} +function getTextAlignForAngle(angle) { + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + return 'right'; +} +function leftForTextAlign(x, w, align) { + if (align === 'right') { + x -= w; + } else if (align === 'center') { + x -= (w / 2); + } + return x; +} +function yForAngle(y, h, angle) { + if (angle === 90 || angle === 270) { + y -= (h / 2); + } else if (angle > 270 || angle < 90) { + y -= h; + } + return y; +} +function drawPointLabels(scale, labelCount) { + const {ctx, options: {pointLabels}} = scale; + for (let i = labelCount - 1; i >= 0; i--) { + const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); + const plFont = toFont(optsAtIndex.font); + const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i]; + const {backdropColor} = optsAtIndex; + if (!isNullOrUndef(backdropColor)) { + const padding = toPadding(optsAtIndex.backdropPadding); + ctx.fillStyle = backdropColor; + ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height); + } + renderText( + ctx, + scale._pointLabels[i], + x, + y + (plFont.lineHeight / 2), + plFont, + { + color: optsAtIndex.color, + textAlign: textAlign, + textBaseline: 'middle' + } + ); + } +} +function pathRadiusLine(scale, radius, circular, labelCount) { + const {ctx} = scale; + if (circular) { + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); + } else { + let pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + for (let i = 1; i < labelCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } +} +function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { + const ctx = scale.ctx; + const circular = gridLineOpts.circular; + const {color, lineWidth} = gridLineOpts; + if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { + return; + } + ctx.save(); + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.setLineDash(gridLineOpts.borderDash); + ctx.lineDashOffset = gridLineOpts.borderDashOffset; + ctx.beginPath(); + pathRadiusLine(scale, radius, circular, labelCount); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); +} +function createPointLabelContext(parent, index, label) { + return createContext(parent, { + label, + index, + type: 'pointLabel' + }); +} +class RadialLinearScale extends LinearScaleBase { + constructor(cfg) { + super(cfg); + this.xCenter = undefined; + this.yCenter = undefined; + this.drawingArea = undefined; + this._pointLabels = []; + this._pointLabelItems = []; + } + setDimensions() { + const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); + const w = this.width = this.maxWidth - padding.width; + const h = this.height = this.maxHeight - padding.height; + this.xCenter = Math.floor(this.left + w / 2 + padding.left); + this.yCenter = Math.floor(this.top + h / 2 + padding.top); + this.drawingArea = Math.floor(Math.min(w, h) / 2); + } + determineDataLimits() { + const {min, max} = this.getMinMax(false); + this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; + this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; + this.handleTickRangeOptions(); + } + computeTickLimit() { + return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); + } + generateTickLabels(ticks) { + LinearScaleBase.prototype.generateTickLabels.call(this, ticks); + this._pointLabels = this.getLabels() + .map((value, index) => { + const label = callback(this.options.pointLabels.callback, [value, index], this); + return label || label === 0 ? label : ''; + }) + .filter((v, i) => this.chart.getDataVisibility(i)); + } + fit() { + const opts = this.options; + if (opts.display && opts.pointLabels.display) { + fitWithPointLabels(this); + } else { + this.setCenterPoint(0, 0, 0, 0); + } + } + setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { + this.xCenter += Math.floor((leftMovement - rightMovement) / 2); + this.yCenter += Math.floor((topMovement - bottomMovement) / 2); + this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); + } + getIndexAngle(index) { + const angleMultiplier = TAU / (this._pointLabels.length || 1); + const startAngle = this.options.startAngle || 0; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); + } + getDistanceFromCenterForValue(value) { + if (isNullOrUndef(value)) { + return NaN; + } + const scalingFactor = this.drawingArea / (this.max - this.min); + if (this.options.reverse) { + return (this.max - value) * scalingFactor; + } + return (value - this.min) * scalingFactor; + } + getValueForDistanceFromCenter(distance) { + if (isNullOrUndef(distance)) { + return NaN; + } + const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); + return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; + } + getPointLabelContext(index) { + const pointLabels = this._pointLabels || []; + if (index >= 0 && index < pointLabels.length) { + const pointLabel = pointLabels[index]; + return createPointLabelContext(this.getContext(), index, pointLabel); + } + } + getPointPosition(index, distanceFromCenter, additionalAngle = 0) { + const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; + return { + x: Math.cos(angle) * distanceFromCenter + this.xCenter, + y: Math.sin(angle) * distanceFromCenter + this.yCenter, + angle + }; + } + getPointPositionForValue(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + } + getBasePosition(index) { + return this.getPointPositionForValue(index || 0, this.getBaseValue()); + } + getPointLabelPosition(index) { + const {left, top, right, bottom} = this._pointLabelItems[index]; + return { + left, + top, + right, + bottom, + }; + } + drawBackground() { + const {backgroundColor, grid: {circular}} = this.options; + if (backgroundColor) { + const ctx = this.ctx; + ctx.save(); + ctx.beginPath(); + pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); + ctx.closePath(); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + } + drawGrid() { + const ctx = this.ctx; + const opts = this.options; + const {angleLines, grid} = opts; + const labelCount = this._pointLabels.length; + let i, offset, position; + if (opts.pointLabels.display) { + drawPointLabels(this, labelCount); + } + if (grid.display) { + this.ticks.forEach((tick, index) => { + if (index !== 0) { + offset = this.getDistanceFromCenterForValue(tick.value); + const optsAtIndex = grid.setContext(this.getContext(index - 1)); + drawRadiusLine(this, optsAtIndex, offset, labelCount); + } + }); + } + if (angleLines.display) { + ctx.save(); + for (i = labelCount - 1; i >= 0; i--) { + const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); + const {color, lineWidth} = optsAtIndex; + if (!lineWidth || !color) { + continue; + } + ctx.lineWidth = lineWidth; + ctx.strokeStyle = color; + ctx.setLineDash(optsAtIndex.borderDash); + ctx.lineDashOffset = optsAtIndex.borderDashOffset; + offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); + position = this.getPointPosition(i, offset); + ctx.beginPath(); + ctx.moveTo(this.xCenter, this.yCenter); + ctx.lineTo(position.x, position.y); + ctx.stroke(); + } + ctx.restore(); + } + } + drawBorder() {} + drawLabels() { + const ctx = this.ctx; + const opts = this.options; + const tickOpts = opts.ticks; + if (!tickOpts.display) { + return; + } + const startAngle = this.getIndexAngle(0); + let offset, width; + ctx.save(); + ctx.translate(this.xCenter, this.yCenter); + ctx.rotate(startAngle); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + this.ticks.forEach((tick, index) => { + if (index === 0 && !opts.reverse) { + return; + } + const optsAtIndex = tickOpts.setContext(this.getContext(index)); + const tickFont = toFont(optsAtIndex.font); + offset = this.getDistanceFromCenterForValue(this.ticks[index].value); + if (optsAtIndex.showLabelBackdrop) { + ctx.font = tickFont.string; + width = ctx.measureText(tick.label).width; + ctx.fillStyle = optsAtIndex.backdropColor; + const padding = toPadding(optsAtIndex.backdropPadding); + ctx.fillRect( + -width / 2 - padding.left, + -offset - tickFont.size / 2 - padding.top, + width + padding.width, + tickFont.size + padding.height + ); + } + renderText(ctx, tick.label, 0, -offset, tickFont, { + color: optsAtIndex.color, + }); + }); + ctx.restore(); + } + drawTitle() {} +} +RadialLinearScale.id = 'radialLinear'; +RadialLinearScale.defaults = { + display: true, + animate: true, + position: 'chartArea', + angleLines: { + display: true, + lineWidth: 1, + borderDash: [], + borderDashOffset: 0.0 + }, + grid: { + circular: false + }, + startAngle: 0, + ticks: { + showLabelBackdrop: true, + callback: Ticks.formatters.numeric + }, + pointLabels: { + backdropColor: undefined, + backdropPadding: 2, + display: true, + font: { + size: 10 + }, + callback(label) { + return label; + }, + padding: 5, + centerPointLabels: false + } +}; +RadialLinearScale.defaultRoutes = { + 'angleLines.color': 'borderColor', + 'pointLabels.color': 'color', + 'ticks.color': 'color' +}; +RadialLinearScale.descriptors = { + angleLines: { + _fallback: 'grid' + } +}; + +const INTERVALS = { + millisecond: {common: true, size: 1, steps: 1000}, + second: {common: true, size: 1000, steps: 60}, + minute: {common: true, size: 60000, steps: 60}, + hour: {common: true, size: 3600000, steps: 24}, + day: {common: true, size: 86400000, steps: 30}, + week: {common: false, size: 604800000, steps: 4}, + month: {common: true, size: 2.628e9, steps: 12}, + quarter: {common: false, size: 7.884e9, steps: 4}, + year: {common: true, size: 3.154e10} +}; +const UNITS = (Object.keys(INTERVALS)); +function sorter(a, b) { + return a - b; +} +function parse(scale, input) { + if (isNullOrUndef(input)) { + return null; + } + const adapter = scale._adapter; + const {parser, round, isoWeekday} = scale._parseOpts; + let value = input; + if (typeof parser === 'function') { + value = parser(value); + } + if (!isNumberFinite(value)) { + value = typeof parser === 'string' + ? adapter.parse(value, parser) + : adapter.parse(value); + } + if (value === null) { + return null; + } + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) + ? adapter.startOf(value, 'isoWeek', isoWeekday) + : adapter.startOf(value, round); + } + return +value; +} +function determineUnitForAutoTicks(minUnit, min, max, capacity) { + const ilen = UNITS.length; + for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { + const interval = INTERVALS[UNITS[i]]; + const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} +function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { + const unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} +function determineMajorUnit(unit) { + for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} +function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + const {lo, hi} = _lookup(timestamps, time); + const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} +function setMajorTicks(scale, ticks, map, majorUnit) { + const adapter = scale._adapter; + const first = +adapter.startOf(ticks[0].value, majorUnit); + const last = ticks[ticks.length - 1].value; + let major, index; + for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} +function ticksFromTimestamps(scale, values, majorUnit) { + const ticks = []; + const map = {}; + const ilen = values.length; + let i, value; + for (i = 0; i < ilen; ++i) { + value = values[i]; + map[value] = i; + ticks.push({ + value, + major: false + }); + } + return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); +} +class TimeScale extends Scale { + constructor(props) { + super(props); + this._cache = { + data: [], + labels: [], + all: [] + }; + this._unit = 'day'; + this._majorUnit = undefined; + this._offsets = {}; + this._normalized = false; + this._parseOpts = undefined; + } + init(scaleOpts, opts) { + const time = scaleOpts.time || (scaleOpts.time = {}); + const adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date); + mergeIf(time.displayFormats, adapter.formats()); + this._parseOpts = { + parser: time.parser, + round: time.round, + isoWeekday: time.isoWeekday + }; + super.init(scaleOpts); + this._normalized = opts.normalized; + } + parse(raw, index) { + if (raw === undefined) { + return null; + } + return parse(this, raw); + } + beforeLayout() { + super.beforeLayout(); + this._cache = { + data: [], + labels: [], + all: [] + }; + } + determineDataLimits() { + const options = this.options; + const adapter = this._adapter; + const unit = options.time.unit || 'day'; + let {min, max, minDefined, maxDefined} = this.getUserBounds(); + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(this._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(this.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + this.min = Math.min(min, max - 1); + this.max = Math.max(min + 1, max); + } + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return {min, max}; + } + buildTicks() { + const options = this.options; + const timeOpts = options.time; + const tickOpts = options.ticks; + const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + this.min = this._userMin || timestamps[0]; + this.max = this._userMax || timestamps[timestamps.length - 1]; + } + const min = this.min; + const max = this.max; + const ticks = _filterBetween(timestamps, min, max); + this._unit = timeOpts.unit || (tickOpts.autoSkip + ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) + : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); + this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined + : determineMajorUnit(this._unit); + this.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(this, ticks, this._majorUnit); + } + initOffsets(timestamps) { + let start = 0; + let end = 0; + let first, last; + if (this.options.offset && timestamps.length) { + first = this.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (this.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = this.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + const limit = timestamps.length < 3 ? 0.5 : 0.25; + start = _limitValue(start, 0, limit); + end = _limitValue(end, 0, limit); + this._offsets = {start, end, factor: 1 / (start + 1 + end)}; + } + _generate() { + const adapter = this._adapter; + const min = this.min; + const max = this.max; + const options = this.options; + const timeOpts = options.time; + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); + const stepSize = valueOrDefault(timeOpts.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const hasWeekday = isNumber(weekday) || weekday === true; + const ticks = {}; + let first = min; + let time, count; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); + for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) { + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks' || count === 1) { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); + } + getLabelForValue(value) { + const adapter = this._adapter; + const timeOpts = this.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); + } + _tickFormatFunction(time, index, ticks, format) { + const options = this.options; + const formats = options.time.displayFormats; + const unit = this._unit; + const majorUnit = this._majorUnit; + const minorFormat = unit && formats[unit]; + const majorFormat = majorUnit && formats[majorUnit]; + const tick = ticks[index]; + const major = majorUnit && majorFormat && tick && tick.major; + const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat)); + const formatter = options.ticks.callback; + return formatter ? callback(formatter, [label, index, ticks], this) : label; + } + generateTickLabels(ticks) { + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } + } + getDecimalForValue(value) { + return value === null ? NaN : (value - this.min) / (this.max - this.min); + } + getPixelForValue(value) { + const offsets = this._offsets; + const pos = this.getDecimalForValue(value); + return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return this.min + pos * (this.max - this.min); + } + _getLabelSize(label) { + const ticksOpts = this.options.ticks; + const tickLabelWidth = this.ctx.measureText(label).width; + const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + const cosRotation = Math.cos(angle); + const sinRotation = Math.sin(angle); + const tickFontSize = this._resolveTickFontOptions(0).size; + return { + w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), + h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) + }; + } + _getLabelCapacity(exampleTime) { + const timeOpts = this.options.time; + const displayFormats = timeOpts.displayFormats; + const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format); + const size = this._getLabelSize(exampleLabel); + const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + getDataTimestamps() { + let timestamps = this._cache.data || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const metas = this.getMatchingVisibleMetas(); + if (this._normalized && metas.length) { + return (this._cache.data = metas[0].controller.getAllParsedValues(this)); + } + for (i = 0, ilen = metas.length; i < ilen; ++i) { + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); + } + return (this._cache.data = this.normalize(timestamps)); + } + getLabelTimestamps() { + const timestamps = this._cache.labels || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const labels = this.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(parse(this, labels[i])); + } + return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps)); + } + normalize(values) { + return _arrayUnique(values.sort(sorter)); + } +} +TimeScale.id = 'time'; +TimeScale.defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + major: { + enabled: false + } + } +}; + +function interpolate(table, val, reverse) { + let lo = 0; + let hi = table.length - 1; + let prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + if (val >= table[lo].pos && val <= table[hi].pos) { + ({lo, hi} = _lookupByKey(table, 'pos', val)); + } + ({pos: prevSource, time: prevTarget} = table[lo]); + ({pos: nextSource, time: nextTarget} = table[hi]); + } else { + if (val >= table[lo].time && val <= table[hi].time) { + ({lo, hi} = _lookupByKey(table, 'time', val)); + } + ({time: prevSource, pos: prevTarget} = table[lo]); + ({time: nextSource, pos: nextTarget} = table[hi]); + } + const span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; +} +class TimeSeriesScale extends TimeScale { + constructor(props) { + super(props); + this._table = []; + this._minPos = undefined; + this._tableRange = undefined; + } + initOffsets() { + const timestamps = this._getTimestampsForTable(); + const table = this._table = this.buildLookupTable(timestamps); + this._minPos = interpolate(table, this.min); + this._tableRange = interpolate(table, this.max) - this._minPos; + super.initOffsets(timestamps); + } + buildLookupTable(timestamps) { + const {min, max} = this; + const items = []; + const table = []; + let i, ilen, prev, curr, next; + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr >= min && curr <= max) { + items.push(curr); + } + } + if (items.length < 2) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + if (Math.round((next + prev) / 2) !== curr) { + table.push({time: curr, pos: i / (ilen - 1)}); + } + } + return table; + } + _getTimestampsForTable() { + let timestamps = this._cache.all || []; + if (timestamps.length) { + return timestamps; + } + const data = this.getDataTimestamps(); + const label = this.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = this.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = this._cache.all = timestamps; + return timestamps; + } + getDecimalForValue(value) { + return (interpolate(this._table, value) - this._minPos) / this._tableRange; + } + getValueForPixel(pixel) { + const offsets = this._offsets; + const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(this._table, decimal * this._tableRange + this._minPos, true); + } +} +TimeSeriesScale.id = 'timeseries'; +TimeSeriesScale.defaults = TimeScale.defaults; + +var scales = /*#__PURE__*/Object.freeze({ +__proto__: null, +CategoryScale: CategoryScale, +LinearScale: LinearScale, +LogarithmicScale: LogarithmicScale, +RadialLinearScale: RadialLinearScale, +TimeScale: TimeScale, +TimeSeriesScale: TimeSeriesScale +}); + +Chart.register(controllers, scales, elements, plugins); +Chart.helpers = {...helpers}; +Chart._adapters = _adapters; +Chart.Animation = Animation; +Chart.Animations = Animations; +Chart.animator = animator; +Chart.controllers = registry.controllers.items; +Chart.DatasetController = DatasetController; +Chart.Element = Element; +Chart.elements = elements; +Chart.Interaction = Interaction; +Chart.layouts = layouts; +Chart.platforms = platforms; +Chart.Scale = Scale; +Chart.Ticks = Ticks; +Object.assign(Chart, controllers, scales, elements, plugins, platforms); +Chart.Chart = Chart; +if (typeof window !== 'undefined') { + window.Chart = Chart; +} + +return Chart; + +})); diff --git a/node_modules/chart.js/dist/chart.min.js b/node_modules/chart.js/dist/chart.min.js new file mode 100644 index 00000000..2b3e9984 --- /dev/null +++ b/node_modules/chart.js/dist/chart.min.js @@ -0,0 +1,13 @@ +/*! + * Chart.js v3.7.1 + * https://www.chartjs.org + * (c) 2022 Chart.js Contributors + * Released under the MIT License + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";const t="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function e(e,i,s){const n=s||(t=>Array.prototype.slice.call(t));let o=!1,a=[];return function(...s){a=n(s),o||(o=!0,t.call(window,(()=>{o=!1,e.apply(i,a)})))}}function i(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const s=t=>"start"===t?"left":"end"===t?"right":"center",n=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,o=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;var a=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=t.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}; +/*! + * @kurkle/color v0.1.9 + * https://github.com/kurkle/color#readme + * (c) 2020 Jukka Kurkela + * Released under the MIT License + */const r={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},l="0123456789ABCDEF",h=t=>l[15&t],c=t=>l[(240&t)>>4]+l[15&t],d=t=>(240&t)>>4==(15&t);function u(t){var e=function(t){return d(t.r)&&d(t.g)&&d(t.b)&&d(t.a)}(t)?h:c;return t?"#"+e(t.r)+e(t.g)+e(t.b)+(t.a<255?e(t.a):""):t}function f(t){return t+.5|0}const g=(t,e,i)=>Math.max(Math.min(t,i),e);function p(t){return g(f(2.55*t),0,255)}function m(t){return g(f(255*t),0,255)}function x(t){return g(f(t/2.55)/100,0,1)}function b(t){return g(f(100*t),0,100)}const _=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const y=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function v(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function w(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function M(t,e,i){const s=v(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function k(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=n===e?(i-s)/h+(i>16&255,o>>8&255,255&o]}return t}(),T.transparent=[0,0,0,0]);const e=T[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}function R(t,e,i){if(t){let s=k(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=P(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function E(t,e){return t?Object.assign(e||{},t):t}function I(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=m(t[3]))):(e=E(t,{r:0,g:0,b:0,a:1})).a=m(e.a),e}function z(t){return"r"===t.charAt(0)?function(t){const e=_.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=255&(e[8]?p(t):255*t)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?p(i):i),s=255&(e[4]?p(s):s),n=255&(e[6]?p(n):n),{r:i,g:s,b:n,a:o}}}(t):C(t)}class F{constructor(t){if(t instanceof F)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=I(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*r[s[1]],g:255&17*r[s[2]],b:255&17*r[s[3]],a:5===o?17*r[s[4]]:255}:7!==o&&9!==o||(n={r:r[s[1]]<<4|r[s[2]],g:r[s[3]]<<4|r[s[4]],b:r[s[5]]<<4|r[s[6]],a:9===o?r[s[7]]<<4|r[s[8]]:255})),i=n||L(t)||z(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=E(this._rgb);return t&&(t.a=x(t.a)),t}set rgb(t){this._rgb=I(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${x(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):this._rgb;var t}hexString(){return this._valid?u(this._rgb):this._rgb}hslString(){return this._valid?function(t){if(!t)return;const e=k(t),i=e[0],s=b(e[1]),n=b(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${x(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):this._rgb}mix(t,e){const i=this;if(t){const s=i.rgb,n=t.rgb;let o;const a=e===o?.5:e,r=2*a-1,l=s.a-n.a,h=((r*l==-1?r:(r+l)/(1+r*l))+1)/2;o=1-h,s.r=255&h*s.r+o*n.r+.5,s.g=255&h*s.g+o*n.g+.5,s.b=255&h*s.b+o*n.b+.5,s.a=a*s.a+(1-a)*n.a,i.rgb=s}return i}clone(){return new F(this.rgb)}alpha(t){return this._rgb.a=m(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=f(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return R(this._rgb,2,t),this}darken(t){return R(this._rgb,2,-t),this}saturate(t){return R(this._rgb,1,t),this}desaturate(t){return R(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=k(t);i[0]=D(i[0]+e),i=P(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function B(t){return new F(t)}const V=t=>t instanceof CanvasGradient||t instanceof CanvasPattern;function W(t){return V(t)?t:B(t)}function N(t){return V(t)?t:B(t).saturate(.5).darken(.1).hexString()}function H(){}const j=function(){let t=0;return function(){return t++}}();function $(t){return null==t}function Y(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)}function U(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}const X=t=>("number"==typeof t||t instanceof Number)&&isFinite(+t);function q(t,e){return X(t)?t:e}function K(t,e){return void 0===t?e:t}const G=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:t/e,Z=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function J(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function Q(t,e,i,s){let n,o,a;if(Y(t))if(o=t.length,s)for(n=o-1;n>=0;n--)e.call(i,t[n],n);else for(n=0;ni;)t=t[e.substr(i,s-i)],i=s+1,s=rt(e,i);return t}function ht(t){return t.charAt(0).toUpperCase()+t.slice(1)}const ct=t=>void 0!==t,dt=t=>"function"==typeof t,ut=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function ft(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const gt=Object.create(null),pt=Object.create(null);function mt(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>N(e.backgroundColor),this.hoverBorderColor=(t,e)=>N(e.borderColor),this.hoverColor=(t,e)=>N(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t)}set(t,e){return xt(this,t,e)}get(t){return mt(this,t)}describe(t,e){return xt(pt,t,e)}override(t,e){return xt(gt,t,e)}route(t,e,i,s){const n=mt(this,t),o=mt(this,i),a="_"+e;Object.defineProperties(n,{[a]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[a],e=o[s];return U(t)?Object.assign({},e,t):K(t,e)},set(t){this[a]=t}}})}}({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}});const _t=Math.PI,yt=2*_t,vt=yt+_t,wt=Number.POSITIVE_INFINITY,Mt=_t/180,kt=_t/2,St=_t/4,Pt=2*_t/3,Dt=Math.log10,Ct=Math.sign;function Ot(t){const e=Math.round(t);t=Lt(t,e,t/1e3)?e:t;const i=Math.pow(10,Math.floor(Dt(t))),s=t/i;return(s<=1?1:s<=2?2:s<=5?5:10)*i}function At(t){const e=[],i=Math.sqrt(t);let s;for(s=1;st-e)).pop(),e}function Tt(t){return!isNaN(parseFloat(t))&&isFinite(t)}function Lt(t,e,i){return Math.abs(t-e)=t}function Et(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function Ut(t){return!t||$(t.size)||$(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Xt(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function qt(t,e,i,s){let n=(s=s||{}).data=s.data||{},o=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(n=s.data={},o=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let a=0;const r=i.length;let l,h,c,d,u;for(l=0;li.length){for(l=0;l0&&t.stroke()}}function Jt(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==o.strokeColor;let l,h;for(t.save(),t.font=n.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]);$(e.rotation)||t.rotate(e.rotation);e.color&&(t.fillStyle=e.color);e.textAlign&&(t.textAlign=e.textAlign);e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,o),l=0;lt[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const re=(t,e,i)=>ae(t,i,(s=>t[s][e]ae(t,i,(s=>t[s][e]>=i));function he(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+ht(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function ue(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ce.forEach((e=>{delete t[e]})),delete t._chartjs)}function fe(t){const e=new Set;let i,s;for(i=0,s=t.length;iwindow.getComputedStyle(t,null);function be(t,e){return xe(t).getPropertyValue(e)}const _e=["top","right","bottom","left"];function ye(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=_e[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}function ve(t,e){const{canvas:i,currentDevicePixelRatio:s}=e,n=xe(i),o="border-box"===n.boxSizing,a=ye(n,"padding"),r=ye(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.native||t,s=i.touches,n=s&&s.length?s[0]:i,{offsetX:o,offsetY:a}=n;let r,l,h=!1;if(((t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot))(o,a,i.target))r=o,l=a;else{const t=e.getBoundingClientRect();r=n.clientX-t.left,l=n.clientY-t.top,h=!0}return{x:r,y:l,box:h}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const we=t=>Math.round(10*t)/10;function Me(t,e,i,s){const n=xe(t),o=ye(n,"margin"),a=me(n.maxWidth,t,"clientWidth")||wt,r=me(n.maxHeight,t,"clientHeight")||wt,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=pe(t);if(o){const t=o.getBoundingClientRect(),a=xe(o),r=ye(a,"border","width"),l=ye(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=me(a.maxWidth,o,"clientWidth"),n=me(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||wt,maxHeight:n||wt}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=ye(n,"border","width"),e=ye(n,"padding");h-=e.width+t.width,c-=e.height+t.height}return h=Math.max(0,h-o.width),c=Math.max(0,s?Math.floor(h/s):c-o.height),h=we(Math.min(h,a,l.maxWidth)),c=we(Math.min(c,r,l.maxHeight)),h&&!c&&(c=we(h/2)),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=n/s,t.width=o/s;const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function Pe(t,e){const i=be(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t,e){return"native"in t?{x:t.x,y:t.y}:ve(t,e)}function Ce(t,e,i,s){const{controller:n,data:o,_sorted:a}=t,r=n._cachedMeta.iScale;if(r&&e===r.axis&&"r"!==e&&a&&o.length){const t=r._reversePixels?le:re;if(!s)return t(o,e,i);if(n._sharedOptions){const s=o[0],n="function"==typeof s.getRange&&s.getRange(e);if(n){const s=t(o,e,i-n),a=t(o,e,i+n);return{lo:s.lo,hi:a.hi}}}}return{lo:0,hi:o.length-1}}function Oe(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t{t[r](n[a],s)&&o.push({element:t,datasetIndex:e,index:i}),t.inRange(n.x,n.y,s)&&(l=!0)})),i.intersect&&!l?[]:o}var Ee={modes:{index(t,e,i,s){const n=De(e,t),o=i.axis||"x",a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s),r=[];return a.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=a[0].index,i=t.data[e];i&&!i.skip&&r.push({element:i,datasetIndex:t.index,index:e})})),r):[]},dataset(t,e,i,s){const n=De(e,t),o=i.axis||"xy";let a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s);if(a.length>0){const e=a[0].datasetIndex,i=t.getDatasetMeta(e).data;a=[];for(let t=0;tAe(t,De(e,t),i.axis||"xy",s),nearest:(t,e,i,s)=>Le(t,De(e,t),i.axis||"xy",i.intersect,s),x:(t,e,i,s)=>Re(t,e,{axis:"x",intersect:i.intersect},s),y:(t,e,i,s)=>Re(t,e,{axis:"y",intersect:i.intersect},s)}};const Ie=new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/),ze=new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/);function Fe(t,e){const i=(""+t).match(Ie);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}function Be(t,e){const i={},s=U(e),n=s?Object.keys(e):e,o=U(t)?s?i=>K(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=+o(t)||0;return i}function Ve(t){return Be(t,{top:"y",right:"x",bottom:"y",left:"x"})}function We(t){return Be(t,["topLeft","topRight","bottomLeft","bottomRight"])}function Ne(t){const e=Ve(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function He(t,e){t=t||{},e=e||bt.font;let i=K(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=K(t.style,e.style);s&&!(""+s).match(ze)&&(console.warn('Invalid font style specified: "'+s+'"'),s="");const n={family:K(t.family,e.family),lineHeight:Fe(K(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:K(t.weight,e.weight),string:""};return n.string=Ut(n),n}function je(t,e,i,s){let n,o,a,r=!0;for(n=0,o=t.length;ni&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ye(t,e){return Object.assign(Object.create(t),e)}const Ue=["left","top","right","bottom"];function Xe(t,e){return t.filter((t=>t.pos===e))}function qe(t,e){return t.filter((t=>-1===Ue.indexOf(t.pos)&&t.box.axis===e))}function Ke(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function Ge(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Ue.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function ei(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Ke(Xe(e,"left"),!0),n=Ke(Xe(e,"right")),o=Ke(Xe(e,"top"),!0),a=Ke(Xe(e,"bottom")),r=qe(e,"x"),l=qe(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Xe(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;Q(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),u=Object.assign({},n);Je(u,Ne(s));const f=Object.assign({maxPadding:u,w:o,h:a,x:n.left,y:n.top},n),g=Ge(l.concat(h),d);ei(r.fullSize,f,d,g),ei(l,f,d,g),ei(h,f,d,g)&&ei(l,f,d,g),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(f),si(r.leftAndTop,f,d,g),f.x+=f.w,f.y+=f.h,si(r.rightAndBottom,f,d,g),t.chartArea={left:f.left,top:f.top,right:f.left+f.w,bottom:f.top+f.h,height:f.h,width:f.w},Q(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})}))}};function oi(t,e=[""],i=t,s,n=(()=>t[0])){ct(s)||(s=mi("_fallback",t));const o={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:i,_fallback:s,_getTarget:n,override:n=>oi([n,...t],e,i,s)};return new Proxy(o,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>ci(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=mi(li(o,t),i),ct(n))return hi(t,n)?gi(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>xi(t).includes(e),ownKeys:t=>xi(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function ai(t,e,i,s){const n={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:ri(t,s),setContext:e=>ai(t,e,i,s),override:n=>ai(t.override(n),e,i,s)};return new Proxy(n,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>ci(t,e,(()=>function(t,e,i){const{_proxy:s,_context:n,_subProxy:o,_descriptors:a}=t;let r=s[e];dt(r)&&a.isScriptable(e)&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t),e=e(o,a||s),r.delete(t),hi(t,e)&&(e=gi(n._scopes,n,t,e));return e}(e,r,t,i));Y(r)&&r.length&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_descriptors:r}=i;if(ct(o.index)&&s(t))e=e[o.index%e.length];else if(U(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const l of i){const i=gi(s,n,t,l);e.push(ai(i,o,a&&a[t],r))}}return e}(e,r,t,a.isIndexable));hi(e,r)&&(r=ai(r,n,o&&o[e],a));return r}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function ri(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:dt(i)?i:()=>i,isIndexable:dt(s)?s:()=>s}}const li=(t,e)=>t?t+ht(e):e,hi=(t,e)=>U(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function ci(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const s=i();return t[e]=s,s}function di(t,e,i){return dt(t)?t(e,i):t}const ui=(t,e)=>!0===t?e:"string"==typeof t?lt(e,t):void 0;function fi(t,e,i,s,n){for(const o of e){const e=ui(i,o);if(e){t.add(e);const o=di(e._fallback,i,n);if(ct(o)&&o!==i&&o!==s)return o}else if(!1===e&&ct(s)&&i!==s)return null}return!1}function gi(t,e,i,s){const n=e._rootScopes,o=di(e._fallback,i,s),a=[...t,...n],r=new Set;r.add(s);let l=pi(r,a,i,o||i,s);return null!==l&&((!ct(o)||o===i||(l=pi(r,a,o,l,s),null!==l))&&oi(Array.from(r),[""],n,o,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const n=s[e];if(Y(n)&&U(i))return i;return n}(e,i,s))))}function pi(t,e,i,s,n){for(;i;)i=fi(t,e,i,s,n);return i}function mi(t,e){for(const i of e){if(!i)continue;const e=i[t];if(ct(e))return e}}function xi(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}const bi=Number.EPSILON||1e-14,_i=(t,e)=>e"x"===t?"y":"x";function vi(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=Vt(o,n),l=Vt(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function wi(t,e="x"){const i=yi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=_i(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)wi(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,Pi=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*yt/i),Di=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*yt/i)+1,Ci={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*kt),easeOutSine:t=>Math.sin(t*kt),easeInOutSine:t=>-.5*(Math.cos(_t*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>Si(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>Si(t)?t:Pi(t,.075,.3),easeOutElastic:t=>Si(t)?t:Di(t,.075,.3),easeInOutElastic(t){const e=.1125;return Si(t)?t:t<.5?.5*Pi(2*t,e,.45):.5+.5*Di(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-Ci.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*Ci.easeInBounce(2*t):.5*Ci.easeOutBounce(2*t-1)+.5};function Oi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function Ai(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function Ti(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=Oi(t,n,i),r=Oi(n,o,i),l=Oi(o,e,i),h=Oi(a,r,i),c=Oi(r,l,i);return Oi(h,c,i)}const Li=new Map;function Ri(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=Li.get(i);return s||(s=new Intl.NumberFormat(t,e),Li.set(i,s)),s}(e,i).format(t)}function Ei(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ii(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function zi(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Fi(t){return"angle"===t?{between:Ht,compare:Wt,normalize:Nt}:{between:Yt,compare:(t,e)=>t-e,normalize:t=>t}}function Bi({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Vi(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Fi(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Fi(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hb||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Bi({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Bi({start:_,end:d,loop:u,count:a,style:f})),g}function Wi(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Hi(t,[{start:a,end:r,loop:o}],i,e);return Hi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,rnull===t||""===t;const Gi=!!Se&&{passive:!0};function Zi(t,e,i){t.canvas.removeEventListener(e,i,Gi)}function Ji(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function Qi(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.addedNodes,s),e=e&&!Ji(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function ts(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.removedNodes,s),e=e&&!Ji(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const es=new Map;let is=0;function ss(){const t=window.devicePixelRatio;t!==is&&(is=t,es.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function ns(t,i,s){const n=t.canvas,o=n&&pe(n);if(!o)return;const a=e(((t,e)=>{const i=o.clientWidth;s(t,e),i{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||a(i,s)}));return r.observe(o),function(t,e){es.size||window.addEventListener("resize",ss),es.set(t,e)}(t,a),r}function os(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){es.delete(t),es.size||window.removeEventListener("resize",ss)}(t)}function as(t,i,s){const n=t.canvas,o=e((e=>{null!==t.ctx&&s(function(t,e){const i=qi[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t,(t=>{const e=t[0];return[e,e.offsetX,e.offsetY]}));return function(t,e,i){t.addEventListener(e,i,Gi)}(n,i,o),o}class rs extends Ui{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t.$chartjs={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",Ki(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(Ki(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e.$chartjs)return!1;const i=e.$chartjs.initial;["height","width"].forEach((t=>{const s=i[t];$(s)?e.removeAttribute(t):e.setAttribute(t,s)}));const s=i.style||{};return Object.keys(s).forEach((t=>{e.style[t]=s[t]})),e.width=e.width,delete e.$chartjs,!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:Qi,detach:ts,resize:ns}[e]||as;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:os,detach:os,resize:os}[e]||Zi)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return Me(t,e,i,s)}isAttached(t){const e=pe(t);return!(!e||!e.isConnected)}}function ls(t){return!ge()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?Xi:rs}var hs=Object.freeze({__proto__:null,_detectPlatform:ls,BasePlatform:Ui,BasicPlatform:Xi,DomPlatform:rs});const cs="transparent",ds={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=W(t||cs),n=s.valid&&W(e||cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class us{constructor(t,e,i,s){const n=e[i];s=je([t.to,s,n,t.from]);const o=je([t.from,n,s]);this._active=!0,this._fn=t.fn||ds[t.type||typeof o],this._easing=Ci[t.easing]||Ci.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=je([t.to,e,s,t.from]),this._from=je([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),bt.set("animations",{colors:{type:"color",properties:["color","borderColor","backgroundColor"]},numbers:{type:"number",properties:["x","y","borderWidth","radius","tension"]}}),bt.describe("animations",{_fallback:"animation"}),bt.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}});class gs{constructor(t,e){this._chart=t,this._properties=new Map,this.configure(e)}configure(t){if(!U(t))return;const e=this._properties;Object.getOwnPropertyNames(t).forEach((i=>{const s=t[i];if(!U(s))return;const n={};for(const t of fs)n[t]=s[t];(Y(s.properties)&&s.properties||[i]).forEach((t=>{t!==i&&e.has(t)||e.set(t,n)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new us(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(a.add(this._chart,i),!0):void 0}}function ps(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function ms(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Ms(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i]}}}const ks=t=>"reset"===t||"none"===t,Ss=(t,e)=>e?t:Object.assign({},t);class Ps{constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.$context=void 0,this._syncList=[],this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=bs(t.vScale,t),this.addElements()}updateIndex(t){this.index!==t&&Ms(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=K(i.xAxisID,ws(t,"x")),o=e.yAxisID=K(i.yAxisID,ws(t,"y")),a=e.rAxisID=K(i.rAxisID,ws(t,"r")),r=e.indexAxis,l=e.iAxisID=s(r,n,o,a),h=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(l),e.vScale=this.getScaleForId(h)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&ue(this._data,this),t._stacked&&Ms(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(U(e))this._data=function(t){const e=Object.keys(t),i=new Array(e.length);let s,n,o;for(s=0,n=e.length;s0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,h=s;else{h=Y(s[t])?this.parseArrayData(i,s,t,e):U(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const n=()=>null===l[a]||d&&l[a]t&&!e.hidden&&e._stacked&&{keys:ms(i,!0),values:null})(e,i,this.chart),l={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:h,max:c}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(a);let d,u;function f(){u=s[d];const e=u[a.axis];return!X(u[t.axis])||h>e||c=0;--d)if(!f()){this.updateRangeFromParsed(l,t,u,r);break}return l}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Ss(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new gs(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||ks(t)||this.chart._animationsDisabled}updateElement(t,e,i,s){ks(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!ks(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}Ds.defaults={},Ds.defaultRoutes=void 0;const Cs={values:t=>Y(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=Dt(Math.abs(o)),r=Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),Ri(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=t/Math.pow(10,Math.floor(Dt(t)));return 1===s||2===s||5===s?Cs.numeric.call(this,t,e,i):""}};var Os={formatters:Cs};function As(t,e){const i=t.options.ticks,s=i.maxTicksLimit||function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),n=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;is)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(n,e,s);if(o>0){let t,i;const s=o>1?Math.round((r-a)/(o-1)):null;for(Ts(e,l,h,$(s)?0:a-s,a),t=0,i=o-1;te.lineWidth,tickColor:(t,e)=>e.color,offset:!1,borderDash:[],borderDashOffset:0,borderWidth:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:Os.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),bt.route("scale.ticks","color","","color"),bt.route("scale.grid","color","","borderColor"),bt.route("scale.grid","borderColor","","borderColor"),bt.route("scale.title","color","","color"),bt.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t}),bt.describe("scales",{_fallback:"scale"}),bt.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t});const Ls=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i;function Rs(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Is(t){return t.drawTicks?t.tickLength:0}function zs(t,e){if(!t.display)return 0;const i=He(t.font,e),s=Ne(t.padding);return(Y(t.text)?t.text.length:1)*i.lineHeight+s.height}function Fs(t,e,i){let n=s(t);return(i&&"right"!==e||!i&&"right"===e)&&(n=(t=>"left"===t?"right":"right"===t?"left":t)(n)),n}class Bs extends Ds{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=q(t,Number.POSITIVE_INFINITY),e=q(e,Number.NEGATIVE_INFINITY),i=q(i,Number.POSITIVE_INFINITY),s=q(s,Number.NEGATIVE_INFINITY),{min:q(t,i),max:q(e,s),minDefined:X(t),maxDefined:X(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:q(i,q(s,i)),max:q(s,q(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){J(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=$e(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=jt(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Is(t.grid)-e.padding-zs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=zt(Math.min(Math.asin(jt((h.highest.height+6)/o,-1,1)),Math.asin(jt(a/r,-1,1))-Math.asin(jt(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){J(this.options.afterCalculateLabelRotation,[this])}beforeFit(){J(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=zs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Is(n)+o):(t.height=this.maxHeight,t.width=Is(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=It(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){J(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:n[t]||0,height:o[t]||0});return{first:v(0),last:v(e-1),widest:v(_),highest:v(y),widths:n,heights:o}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return $t(this._alignToPixels?Kt(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:o}=s,a=n.offset,r=this.isHorizontal(),l=this.ticks.length+(a?1:0),h=Is(n),c=[],d=n.setContext(this.getContext()),u=d.drawBorder?d.borderWidth:0,f=u/2,g=function(t){return Kt(i,t,u)};let p,m,x,b,_,y,v,w,M,k,S,P;if("top"===o)p=g(this.bottom),y=this.bottom-h,w=p-f,k=g(t.top)+f,P=t.bottom;else if("bottom"===o)p=g(this.top),k=t.top,P=g(t.bottom)-f,y=p+f,w=this.top+h;else if("left"===o)p=g(this.right),_=this.right-h,v=p-f,M=g(t.left)+f,S=t.right;else if("right"===o)p=g(this.left),M=t.left,S=g(t.right)-f,_=p+f,v=this.left+h;else if("x"===e){if("center"===o)p=g((t.top+t.bottom)/2+.5);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}k=t.top,P=t.bottom,y=p+f,w=y+h}else if("y"===e){if("center"===o)p=g((t.left+t.right)/2);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}_=p-f,v=_-h,M=t.left,S=t.right}const D=K(s.ticks.maxTicksLimit,l),C=Math.max(1,Math.ceil(l/D));for(m=0;me.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:i+1,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");bt.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&bt.describe(e,t.descriptors)}(t,o,i),this.override&&bt.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in bt[s]&&(delete bt[s][i],this.override&&delete gt[i])}}var Ws=new class{constructor(){this.controllers=new Vs(Ps,"datasets",!0),this.elements=new Vs(Ds,"elements"),this.plugins=new Vs(Object,"plugins"),this.scales=new Vs(Bs,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):Q(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=ht(t);J(i["before"+s],[],i),e[t](i),J(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function Hs(t,e){return e||!1!==t?!0===t?{}:t:null}function js(t,e,i,s){const n=t.pluginScopeKeys(e),o=t.getOptionScopes(i,n);return t.createResolver(o,s,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function $s(t,e){const i=bt.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function Ys(t,e){return"x"===t||"y"===t?t:e.axis||("top"===(i=e.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.charAt(0).toLowerCase();var i}function Us(t){const e=t.options||(t.options={});e.plugins=K(e.plugins,{}),e.scales=function(t,e){const i=gt[t.type]||{scales:{}},s=e.scales||{},n=$s(t.type,e),o=Object.create(null),a=Object.create(null);return Object.keys(s).forEach((t=>{const e=s[t];if(!U(e))return console.error(`Invalid scale configuration for scale: ${t}`);if(e._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);const r=Ys(t,e),l=function(t,e){return t===e?"_index_":"_value_"}(r,n),h=i.scales||{};o[r]=o[r]||t,a[t]=ot(Object.create(null),[{axis:r},e,h[r],h[l]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,r=i.indexAxis||$s(n,e),l=(gt[n]||{}).scales||{};Object.keys(l).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,r),n=i[e+"AxisID"]||o[e]||e;a[n]=a[n]||Object.create(null),ot(a[n],[{axis:e},s[n],l[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];ot(e,[bt.scales[e.type],bt.scale])})),a}(t,e)}function Xs(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const qs=new Map,Ks=new Set;function Gs(t,e){let i=qs.get(t);return i||(i=e(),qs.set(t,i),Ks.add(i)),i}const Zs=(t,e,i)=>{const s=lt(e,i);void 0!==s&&t.add(s)};class Js{constructor(t){this._config=function(t){return(t=t||{}).data=Xs(t.data),Us(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=Xs(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),Us(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return Gs(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return Gs(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return Gs(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return Gs(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>Zs(r,t,e)))),e.forEach((t=>Zs(r,s,t))),e.forEach((t=>Zs(r,gt[n]||{},t))),e.forEach((t=>Zs(r,bt,t))),e.forEach((t=>Zs(r,pt,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),Ks.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,gt[e]||{},bt.datasets[e]||{},{type:e},bt,pt]}resolveNamedOptions(t,e,i,s=[""]){const n={$shared:!0},{resolver:o,subPrefixes:a}=Qs(this._resolverCache,t,s);let r=o;if(function(t,e){const{isScriptable:i,isIndexable:s}=ri(t);for(const n of e){const e=i(n),o=s(n),a=(o||e)&&t[n];if(e&&(dt(a)||tn(a))||o&&Y(a))return!0}return!1}(o,e)){n.$shared=!1;r=ai(o,i=dt(i)?i():i,this.createResolver(t,i,a))}for(const t of e)n[t]=r[t];return n}createResolver(t,e,i=[""],s){const{resolver:n}=Qs(this._resolverCache,t,i);return U(e)?ai(n,e,void 0,s):n}}function Qs(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:oi(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const tn=t=>U(t)&&Object.getOwnPropertyNames(t).reduce(((e,i)=>e||dt(t[i])),!1);const en=["top","bottom","left","right","chartArea"];function sn(t,e){return"top"===t||"bottom"===t||-1===en.indexOf(t)&&"x"===e}function nn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function on(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),J(i&&i.onComplete,[t],e)}function an(t){const e=t.chart,i=e.options.animation;J(i&&i.onProgress,[t],e)}function rn(t){return ge()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const ln={},hn=t=>{const e=rn(t);return Object.values(ln).filter((t=>t.canvas===e)).pop()};function cn(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class dn{constructor(t,e){const s=this.config=new Js(e),n=rn(t),o=hn(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas can be reused.");const r=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||ls(n)),this.platform.updateConfig(s);const l=this.platform.acquireContext(n,r.aspectRatio),h=l&&l.canvas,c=h&&h.height,d=h&&h.width;this.id=j(),this.ctx=l,this.canvas=h,this.width=d,this.height=c,this._options=r,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Ns,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=i((t=>this.update(t)),r.resizeDelay||0),this._dataChanges=[],ln[this.id]=this,l&&h?(a.listen(this,"complete",on),a.listen(this,"progress",an),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:s,_aspectRatio:n}=this;return $(t)?e&&n?n:s?i/s:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Gt(this.canvas,this.ctx),this}stop(){return a.stop(this),this}resize(t,e){a.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),J(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){Q(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=Ys(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),Q(n,(e=>{const n=e.options,o=n.id,a=Ys(o,n),r=K(n.type,e.dtype);void 0!==n.position&&sn(n.position,a)===sn(e.dposition)||(n.position=e.dposition),s[o]=!0;let l=null;if(o in i&&i[o].type===r)l=i[o];else{l=new(Ws.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[l.id]=l}l.init(n,t)})),Q(s,((t,e)=>{t||delete i[e]})),Q(i,(t=>{ni.configure(this,t,t.options),ni.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(nn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){Q(this.scales,(t=>{ni.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);ut(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){cn(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ni.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],Q(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i=t._clip,s=!i.disabled,n=this.chartArea,o={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",o)&&(s&&Qt(e,{left:!1===i.left?0:n.left-i.left,right:!1===i.right?this.width:n.right+i.right,top:!1===i.top?0:n.top-i.top,bottom:!1===i.bottom?this.height:n.bottom+i.bottom}),t.controller.draw(),s&&te(e),o.cancelable=!1,this.notifyPlugins("afterDatasetDraw",o))}getElementsAtEventForMode(t,e,i,s){const n=Ee.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ye(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);ct(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),a.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};Q(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){Q(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},Q(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!tt(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:Jt(t,this.chartArea,this._minPadding)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=ft(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,J(n.onHover,[t,a,this],this),r&&J(n.onClick,[t,a,this],this));const h=!tt(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}const un=()=>Q(dn.instances,(t=>t._plugins.invalidate())),fn=!0;function gn(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}Object.defineProperties(dn,{defaults:{enumerable:fn,value:bt},instances:{enumerable:fn,value:ln},overrides:{enumerable:fn,value:gt},registry:{enumerable:fn,value:Ws},version:{enumerable:fn,value:"3.7.1"},getChart:{enumerable:fn,value:hn},register:{enumerable:fn,value:(...t)=>{Ws.add(...t),un()}},unregister:{enumerable:fn,value:(...t)=>{Ws.remove(...t),un()}}});class pn{constructor(t){this.options=t||{}}formats(){return gn()}parse(t,e){return gn()}format(t,e){return gn()}add(t,e,i){return gn()}diff(t,e,i){return gn()}startOf(t,e,i){return gn()}endOf(t,e){return gn()}}pn.override=function(t){Object.assign(pn.prototype,t)};var mn={_date:pn};function xn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(ct(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function _n(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base=i?1:-1)}(c,e,o)*n,d===o&&(p-=c/2),h=p+c),p===e.getPixelForValue(o)){const t=Ct(c)*e.getLineWidthForValue(o)/2;p+=t,c-=t}return{size:c,base:p,head:h,center:h+c/2}}_calculateBarIndexPixels(t,e){const i=e.scale,s=this.options,n=s.skipNull,o=K(s.maxBarThickness,1/0);let a,r;if(e.grouped){const i=n?this._getStackCount(t):e.stackCount,l="flex"===s.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,{xScale:i,yScale:s}=e,n=this.getParsed(t),o=i.getLabelForValue(n.x),a=s.getLabelForValue(n.y),r=n._custom;return{label:e.label,value:"("+o+", "+a+(r?", "+r:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,r=this.resolveDataElementOptions(e,s),l=this.getSharedOptions(r),h=this.includeOptions(s,l),c=o.axis,d=a.axis;for(let r=e;r""}}}};class Dn extends Ps{constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,o,a=t=>+i[t];if(U(i[t])){const{key:t="value"}=this._parsing;a=e=>+lt(i[e],t)}for(n=t,o=t+e;nHt(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Ht(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(kt,c,u),x=g(_t,h,d),b=g(_t+kt,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(c,h,r),p=(i.width-o)/d,m=(i.height-o)/u,x=Math.max(Math.min(p,m)/2,0),b=Z(this.options.radius,x),_=(b-Math.max(b*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=f*b,this.offsetY=g*b,s.total=this.calculateTotal(),this.outerRadius=b-_*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-_*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/yt)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,f=this.resolveDataElementOptions(e,s),g=this.getSharedOptions(f),p=this.includeOptions(s,g);let m,x=this._getRotation();for(m=0;m0&&!isNaN(t)?yt*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s"spacing"!==t,_indexable:t=>"spacing"!==t},Dn.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label(t){let e=t.label;const i=": "+t.formattedValue;return Y(e)?(e=e.slice(),e[0]+=i):e+=i,e}}}}};class Cn extends Ps{initialize(){this.enableOptionSharing=!0,super.initialize()}update(t){const e=this._cachedMeta,{dataset:i,data:s=[],_dataset:n}=e,o=this.chart._animationsDisabled;let{start:a,count:r}=function(t,e,i){const s=e.length;let n=0,o=s;if(t._sorted){const{iScale:a,_parsed:r}=t,l=a.axis,{min:h,max:c,minDefined:d,maxDefined:u}=a.getUserBounds();d&&(n=jt(Math.min(re(r,a.axis,h).lo,i?s:re(e,l,a.getPixelForValue(h)).lo),0,s-1)),o=u?jt(Math.max(re(r,a.axis,c).hi+1,i?0:re(e,l,a.getPixelForValue(c)).hi+1),n,s)-n:s-n}return{start:n,count:o}}(e,s,o);this._drawStart=a,this._drawCount=r,function(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}(e)&&(a=0,r=s.length),i._chart=this.chart,i._datasetIndex=this.index,i._decimated=!!n._decimated,i.points=s;const l=this.resolveDatasetElementOptions(t);this.options.showLine||(l.borderWidth=0),l.segment=this.options.segment,this.updateElement(i,void 0,{animated:!o,options:l},t),this.updateElements(s,a,r,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a,_stacked:r,_dataset:l}=this._cachedMeta,h=this.resolveDataElementOptions(e,s),c=this.getSharedOptions(h),d=this.includeOptions(s,c),u=o.axis,f=a.axis,{spanGaps:g,segment:p}=this.options,m=Tt(g)?g:Number.POSITIVE_INFINITY,x=this.chart._animationsDisabled||n||"none"===s;let b=e>0&&this.getParsed(e-1);for(let h=e;h0&&i[u]-b[u]>m,p&&(g.parsed=i,g.raw=l.data[h]),d&&(g.options=c||this.resolveDataElementOptions(h,e.active?"active":s)),x||this.updateElement(e,h,g,s),b=i}this.updateSharedOptions(c,s,h)}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}}Cn.id="line",Cn.defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1},Cn.overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};class On extends Ps{constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=this.getDataset(),r=o.options.animation,l=this._cachedMeta.rScale,h=l.xCenter,c=l.yCenter,d=l.getIndexAngle(0)-.5*_t;let u,f=d;const g=360/this.countVisibleElements();for(u=0;u{!isNaN(t.data[s])&&this.chart.getDataVisibility(s)&&i++})),i}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?It(this.resolveDataElementOptions(t,e).angle||i):0}}On.id="polarArea",On.defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0},On.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label:t=>t.chart.data.labels[t.dataIndex]+": "+t.formattedValue}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};class An extends Dn{}An.id="pie",An.defaults={cutout:0,rotation:0,circumference:360,radius:"100%"};class Tn extends Ps{getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this.getDataset(),o=this._cachedMeta.rScale,a="reset"===s;for(let r=e;r"",label:t=>"("+t.label+", "+t.formattedValue+")"}}},scales:{x:{type:"linear"},y:{type:"linear"}}};var Rn=Object.freeze({__proto__:null,BarController:Sn,BubbleController:Pn,DoughnutController:Dn,LineController:Cn,PolarAreaController:On,PieController:An,RadarController:Tn,ScatterController:Ln});function En(t,e,i){const{startAngle:s,pixelMargin:n,x:o,y:a,outerRadius:r,innerRadius:l}=e;let h=n/r;t.beginPath(),t.arc(o,a,r,s-h,i+h),l>n?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+kt,s-kt),t.closePath(),t.clip()}function In(t,e,i,s){const n=Be(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return jt(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:jt(n.innerStart,0,a),innerEnd:jt(n.innerEnd,0,a)}}function zn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Fn(t,e,i,s,n){const{x:o,y:a,startAngle:r,pixelMargin:l,innerRadius:h}=e,c=Math.max(e.outerRadius+s+i-l,0),d=h>0?h+s+i+l:0;let u=0;const f=n-r;if(s){const t=((h>0?h-s:0)+(c>0?c-s:0))/2;u=(f-(0!==t?f*t/(t+s):f))/2}const g=(f-Math.max(.001,f*c-i/_t)/c)/2,p=r+g+u,m=n-g-u,{outerStart:x,outerEnd:b,innerStart:_,innerEnd:y}=In(e,d,c,m-p),v=c-x,w=c-b,M=p+x/v,k=m-b/w,S=d+_,P=d+y,D=p+_/S,C=m-y/P;if(t.beginPath(),t.arc(o,a,c,M,k),b>0){const e=zn(w,k,o,a);t.arc(e.x,e.y,b,k,m+kt)}const O=zn(P,m,o,a);if(t.lineTo(O.x,O.y),y>0){const e=zn(P,C,o,a);t.arc(e.x,e.y,y,m+kt,C+Math.PI)}if(t.arc(o,a,d,m-y/d,p+_/d,!0),_>0){const e=zn(S,D,o,a);t.arc(e.x,e.y,_,D+Math.PI,p-kt)}const A=zn(v,p,o,a);if(t.lineTo(A.x,A.y),x>0){const e=zn(v,M,o,a);t.arc(e.x,e.y,x,p-kt,M)}t.closePath()}function Bn(t,e,i,s,n){const{options:o}=e,{borderWidth:a,borderJoinStyle:r}=o,l="inner"===o.borderAlign;a&&(l?(t.lineWidth=2*a,t.lineJoin=r||"round"):(t.lineWidth=a,t.lineJoin=r||"bevel"),e.fullCircles&&function(t,e,i){const{x:s,y:n,startAngle:o,pixelMargin:a,fullCircles:r}=e,l=Math.max(e.outerRadius-a,0),h=e.innerRadius+a;let c;for(i&&En(t,e,o+yt),t.beginPath(),t.arc(s,n,h,o+yt,o,!0),c=0;c=yt||Ht(n,a,r),f=Yt(o,l+d,h+d);return u&&f}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius","circumference"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/2,n=(e.spacing||0)/2;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>yt?Math.floor(i/yt):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();let o=0;if(s){o=s/2;const e=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(e)*o,Math.sin(e)*o),this.circumference>=_t&&(o=s)}t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor;const a=function(t,e,i,s){const{fullCircles:n,startAngle:o,circumference:a}=e;let r=e.endAngle;if(n){Fn(t,e,i,s,o+yt);for(let e=0;er&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function Yn(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?$n:jn}Vn.id="arc",Vn.defaults={borderAlign:"center",borderColor:"#fff",borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0},Vn.defaultRoutes={backgroundColor:"backgroundColor"};const Un="function"==typeof Path2D;function Xn(t,e,i,s){Un&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Wn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=Yn(e);for(const r of n)Wn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class qn extends Ds{constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;ki(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Ni(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Wi(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?Ai:t.tension||"monotone"===t.cubicInterpolationMode?Ti:Oi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t&&"fill"!==t};class Gn extends Ds{constructor(t){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.options,{x:n,y:o}=this.getProps(["x","y"],i);return Math.pow(t-n,2)+Math.pow(e-o,2){oo(t)}))}var ro={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void ao(t);const s=t.width;t.data.datasets.forEach(((e,n)=>{const{_data:o,indexAxis:a}=e,r=t.getDatasetMeta(n),l=o||e.data;if("y"===je([a,t.options.indexAxis]))return;if("line"!==r.type)return;const h=t.scales[r.xAxisID];if("linear"!==h.type&&"time"!==h.type)return;if(t.options.parsing)return;let{start:c,count:d}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=jt(re(e,o.axis,a).lo,0,i-1)),s=h?jt(re(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(r,l);if(d<=(i.threshold||4*s))return void oo(e);let u;switch($(o)&&(e._data=l,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":u=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(l,c,d,s,i);break;case"min-max":u=function(t,e,i,s){let n,o,a,r,l,h,c,d,u,f,g=0,p=0;const m=[],x=e+i-1,b=t[e].x,_=t[x].x-b;for(n=e;nf&&(f=r,c=n),g=(p*g+o.x)/++p;else{const i=n-1;if(!$(h)&&!$(c)){const e=Math.min(h,c),s=Math.max(h,c);e!==d&&e!==i&&m.push({...t[e],x:g}),s!==d&&s!==i&&m.push({...t[s],x:g})}n>0&&i!==d&&m.push(t[i]),m.push(o),l=e,p=0,u=f=r,h=c=d=n}}return m}(l,c,d,s);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=u}))},destroy(t){ao(t)}};function lo(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=K(i&&i.target,i);return void 0===s&&(s=!!e.backgroundColor),!1!==s&&null!==s&&(!0===s?"origin":s)}(t);if(U(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return X(n)&&Math.floor(n)===n?("-"!==s[0]&&"+"!==s[0]||(n=e+n),!(n===e||n<0||n>=i)&&n):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}class ho{constructor(t){this.x=t.x,this.y=t.y,this.radius=t.radius}pathSegment(t,e,i){const{x:s,y:n,radius:o}=this;return e=e||{start:0,end:yt},t.arc(s,n,o,e.end,e.start,!0),!i.bounds}interpolate(t){const{x:e,y:i,radius:s}=this,n=t.angle;return{x:e+Math.cos(n)*s,y:i+Math.sin(n)*s,angle:n}}}function co(t){return(t.scale||{}).getPointPositionForValue?function(t){const{scale:e,fill:i}=t,s=e.options,n=e.getLabels().length,o=[],a=s.reverse?e.max:e.min,r=s.reverse?e.min:e.max;let l,h,c;if(c="start"===i?a:"end"===i?r:U(i)?i.value:e.getBaseValue(),s.grid.circular)return h=e.getPointPositionForValue(0,a),new ho({x:h.x,y:h.y,radius:e.getDistanceFromCenterForValue(c)});for(l=0;lt;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function fo(t,e,i){const s=[];for(let n=0;n{e=uo(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new qn({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function xo(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!X(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function bo(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[uo(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(h.x,i),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(c.x,i)}t.lineTo(e.first().x,i),t.closePath(),t.clip()}function _o(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=Nt(n),o=Nt(o)),{property:t,start:n,end:o}}function yo(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function vo(t,e,i){const{top:s,bottom:n}=e.chart.chartArea,{property:o,start:a,end:r}=i||{};"x"===o&&(t.beginPath(),t.rect(a,s,r-a,n-s),t.clip())}function wo(t,e,i,s){const n=e.interpolate(i,s);n&&t.lineTo(n.x,n.y)}function Mo(t,e){const{line:i,target:s,property:n,color:o,scale:a}=e,r=function(t,e,i){const s=t.segments,n=t.points,o=e.points,a=[];for(const t of s){let{start:s,end:r}=t;r=uo(s,r,n);const l=_o(i,n[s],n[r],t.loop);if(!e.segments){a.push({source:t,target:l,start:n[s],end:n[r]});continue}const h=Wi(e,l);for(const e of h){const s=_o(i,o[e.start],o[e.end],e.loop),r=Vi(t,n,s);for(const t of r)a.push({source:t,target:e,start:{[i]:yo(l,s,"start",Math.max)},end:{[i]:yo(l,s,"end",Math.min)}})}}return a}(i,s,n);for(const{source:e,target:l,start:h,end:c}of r){const{style:{backgroundColor:r=o}={}}=e,d=!0!==s;t.save(),t.fillStyle=r,vo(t,a,d&&_o(n,h,c)),t.beginPath();const u=!!i.pathSegment(t,e);let f;if(d){u?t.closePath():wo(t,s,c,n);const e=!!s.pathSegment(t,l,{move:u,reverse:!0});f=u&&e,f||wo(t,s,h,n)}t.closePath(),t.fill(f?"evenodd":"nonzero"),t.restore()}}function ko(t,e,i){const s=po(e),{line:n,scale:o,axis:a}=e,r=n.options,l=r.fill,h=r.backgroundColor,{above:c=h,below:d=h}=l||{};s&&n.points.length&&(Qt(t,i),function(t,e){const{line:i,target:s,above:n,below:o,area:a,scale:r}=e,l=i._loop?"angle":e.axis;t.save(),"x"===l&&o!==n&&(bo(t,s,a.top),Mo(t,{line:i,target:s,color:n,scale:r,property:l}),t.restore(),t.save(),bo(t,s,a.bottom)),Mo(t,{line:i,target:s,color:o,scale:r,property:l}),t.restore()}(t,{line:n,target:s,above:c,below:d,area:i,scale:o,axis:a}),te(t))}var So={id:"filler",afterDatasetsUpdate(t,e,i){const s=(t.data.datasets||[]).length,n=[];let o,a,r,l;for(a=0;a=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&ko(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;i&&ko(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;s&&!1!==s.fill&&"beforeDatasetDraw"===i.drawTime&&ko(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const Po=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class Do extends Ds{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=J(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=He(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=Po(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,n,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const p=i+e/2+n.measureText(t.text).width;o>0&&u+s+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:s},d=Math.max(d,p),u+=s+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:o}}=this,a=Ei(o,this.left,this.width);if(this.isHorizontal()){let o=0,r=n(i,this.left+s,this.right-this.lineWidths[o]);for(const l of e)o!==l.row&&(o=l.row,r=n(i,this.left+s,this.right-this.lineWidths[o])),l.top+=this.top+t+s,l.left=a.leftForLtr(a.x(r),l.width),r+=l.width+s}else{let o=0,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height);for(const l of e)l.col!==o&&(o=l.col,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height)),l.top=r,l.left+=this.left+s,l.left=a.leftForLtr(a.x(l.left),l.width),r+=l.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Qt(t,this),this._draw(),te(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:a,labels:r}=t,l=bt.color,h=Ei(t.rtl,this.left,this.width),c=He(r.font),{color:d,padding:u}=r,f=c.size,g=f/2;let p;this.drawTitle(),s.textAlign=h.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=c.string;const{boxWidth:m,boxHeight:x,itemHeight:b}=Po(r,f),_=this.isHorizontal(),y=this._computeTitleHeight();p=_?{x:n(a,this.left+u,this.right-i[0]),y:this.top+u+y,line:0}:{x:this.left+u,y:n(a,this.top+y+u,this.bottom-e[0].height),line:0},Ii(this.ctx,t.textDirection);const v=b+u;this.legendItems.forEach(((w,M)=>{s.strokeStyle=w.fontColor||d,s.fillStyle=w.fontColor||d;const k=s.measureText(w.text).width,S=h.textAlign(w.textAlign||(w.textAlign=r.textAlign)),P=m+g+k;let D=p.x,C=p.y;h.setWidth(this.width),_?M>0&&D+P+u>this.right&&(C=p.y+=v,p.line++,D=p.x=n(a,this.left+u,this.right-i[p.line])):M>0&&C+v>this.bottom&&(D=p.x=D+e[p.line].width+u,p.line++,C=p.y=n(a,this.top+y+u,this.bottom-e[p.line].height));!function(t,e,i){if(isNaN(m)||m<=0||isNaN(x)||x<0)return;s.save();const n=K(i.lineWidth,1);if(s.fillStyle=K(i.fillStyle,l),s.lineCap=K(i.lineCap,"butt"),s.lineDashOffset=K(i.lineDashOffset,0),s.lineJoin=K(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=K(i.strokeStyle,l),s.setLineDash(K(i.lineDash,[])),r.usePointStyle){const o={radius:m*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},a=h.xPlus(t,m/2);Zt(s,o,a,e+g)}else{const o=e+Math.max((f-x)/2,0),a=h.leftForLtr(t,m),r=We(i.borderRadius);s.beginPath(),Object.values(r).some((t=>0!==t))?oe(s,{x:a,y:o,w:m,h:x,radius:r}):s.rect(a,o,m,x),s.fill(),0!==n&&s.stroke()}s.restore()}(h.x(D),C,w),D=o(S,D+m+g,_?D+P:this.right,t.rtl),function(t,e,i){se(s,i.text,t,e+b/2,c,{strikethrough:i.hidden,textAlign:h.textAlign(i.textAlign)})}(h.x(D),C,w),_?p.x+=P+u:p.y+=v})),zi(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=He(e.font),o=Ne(e.padding);if(!e.display)return;const a=Ei(t.rtl,this.left,this.width),r=this.ctx,l=e.position,h=i.size/2,c=o.top+h;let d,u=this.left,f=this.width;if(this.isHorizontal())f=Math.max(...this.lineWidths),d=this.top+c,u=n(t.align,u,this.right-f);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);d=c+n(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const g=n(l,u,u+f);r.textAlign=a.textAlign(s(l)),r.textBaseline="middle",r.strokeStyle=e.color,r.fillStyle=e.color,r.font=i.string,se(r,e.text,g,d,i)}_computeTitleHeight(){const t=this.options.title,e=He(t.font),i=Ne(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(Yt(t,this.left,this.right)&&Yt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const a=t.controller.getStyle(i?0:void 0),r=Ne(a.borderWidth);return{text:e[t.index].label,fillStyle:a.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:a.borderCapStyle,lineDash:a.borderDash,lineDashOffset:a.borderDashOffset,lineJoin:a.borderJoinStyle,lineWidth:(r.width+r.height)/4,strokeStyle:a.borderColor,pointStyle:s||a.pointStyle,rotation:a.rotation,textAlign:n||a.textAlign,borderRadius:0,datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Oo extends Ds{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=Y(i.text)?i.text.length:1;this._padding=Ne(i.padding);const n=s*He(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=n:this.width=n}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:o,options:a}=this,r=a.align;let l,h,c,d=0;return this.isHorizontal()?(h=n(r,i,o),c=e+t,l=o-i):("left"===a.position?(h=i+t,c=n(r,s,e),d=-.5*_t):(h=o-t,c=n(r,e,s),d=.5*_t),l=s-e),{titleX:h,titleY:c,maxWidth:l,rotation:d}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=He(e.font),n=i.lineHeight/2+this._padding.top,{titleX:o,titleY:a,maxWidth:r,rotation:l}=this._drawArgs(n);se(t,e.text,0,0,i,{color:e.color,maxWidth:r,rotation:l,textAlign:s(e.align),textBaseline:"middle",translation:[o,a]})}}var Ao={id:"title",_element:Oo,start(t,e,i){!function(t,e){const i=new Oo({ctx:t.ctx,options:e,chart:t});ni.configure(t,i,e),ni.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ni.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const To=new WeakMap;var Lo={id:"subtitle",start(t,e,i){const s=new Oo({ctx:t.ctx,options:i,chart:t});ni.configure(t,s,i),ni.addBox(t,s),To.set(t,s)},stop(t){ni.removeBox(t,To.get(t)),To.delete(t)},beforeUpdate(t,e,i){const s=To.get(t);ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Ro={average(t){if(!t.length)return!1;let e,i,s=0,n=0,o=0;for(e=0,i=t.length;e-1?t.split("\n"):t}function zo(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Fo(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=He(e.bodyFont),h=He(e.titleFont),c=He(e.footerFont),d=o.length,u=n.length,f=s.length,g=Ne(e.padding);let p=g.height,m=0,x=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(x+=t.beforeBody.length+t.afterBody.length,d&&(p+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),x){p+=f*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(x-f)*l.lineHeight+(x-1)*e.bodySpacing}u&&(p+=e.footerMarginTop+u*c.lineHeight+(u-1)*e.footerSpacing);let b=0;const _=function(t){m=Math.max(m,i.measureText(t).width+b)};return i.save(),i.font=h.string,Q(t.title,_),i.font=l.string,Q(t.beforeBody.concat(t.afterBody),_),b=e.displayColors?a+2+e.boxPadding:0,Q(s,(t=>{Q(t.before,_),Q(t.lines,_),Q(t.after,_)})),b=0,i.font=c.string,Q(t.footer,_),i.restore(),m+=g.width,{width:m,height:p}}function Bo(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Vo(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Bo(t,e,i,s),yAlign:s}}function Wo(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=We(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:jt(g,0,s.width-e.width),y:jt(p,0,s.height-e.height)}}function No(t,e,i){const s=Ne(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ho(t){return Eo([],Io(t))}function jo(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}class $o extends Ds{constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart||t._chart,this._chart=this.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const e=this.chart,i=this.options.setContext(this.getContext()),s=i.enabled&&e.options.animation&&i.animations,n=new gs(this.chart,s);return s._cacheable&&(this._cachedAnimations=Object.freeze(n)),n}getContext(){return this.$context||(this.$context=(t=this.chart.getContext(),e=this,i=this._tooltipItems,Ye(t,{tooltip:e,tooltipItems:i,type:"tooltip"})));var t,e,i}getTitle(t,e){const{callbacks:i}=e,s=i.beforeTitle.apply(this,[t]),n=i.title.apply(this,[t]),o=i.afterTitle.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}getBeforeBody(t,e){return Ho(e.callbacks.beforeBody.apply(this,[t]))}getBody(t,e){const{callbacks:i}=e,s=[];return Q(t,(t=>{const e={before:[],lines:[],after:[]},n=jo(i,t);Eo(e.before,Io(n.beforeLabel.call(this,t))),Eo(e.lines,n.label.call(this,t)),Eo(e.after,Io(n.afterLabel.call(this,t))),s.push(e)})),s}getAfterBody(t,e){return Ho(e.callbacks.afterBody.apply(this,[t]))}getFooter(t,e){const{callbacks:i}=e,s=i.beforeFooter.apply(this,[t]),n=i.footer.apply(this,[t]),o=i.afterFooter.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),Q(l,(e=>{const i=jo(t.callbacks,e);s.push(i.labelColor.call(this,e)),n.push(i.labelPointStyle.call(this,e)),o.push(i.labelTextColor.call(this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Ro[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Fo(this,i),a=Object.assign({},t,e),r=Vo(this.chart,i,a),l=Wo(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=We(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Ei(i.rtl,this.x,this.width);for(t.x=No(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=He(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,oe(t,{x:e,y:g,w:l,h:r,radius:a}),t.fill(),t.stroke(),t.fillStyle=o.backgroundColor,t.beginPath(),oe(t,{x:i,y:g+1,w:l-2,h:r-2,radius:a}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,l,r),t.strokeRect(e,g,l,r),t.fillStyle=o.backgroundColor,t.fillRect(i,g+1,l-2,r-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=He(i.bodyFont);let d=c.lineHeight,u=0;const f=Ei(i.rtl,this.x,this.width),g=function(i){e.fillText(i,f.x(t.x+u),t.y+d/2),t.y+=d+n},p=f.textAlign(o);let m,x,b,_,y,v,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=No(this,p,i),e.fillStyle=i.bodyColor,Q(this.beforeBody,g),u=a&&"right"!==p?"center"===o?l/2+h:l+2+h:0,_=0,v=s.length;_0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Ro[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Fo(this,t),a=Object.assign({},i,this._size),r=Vo(e,t,a),l=Wo(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=Ne(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ii(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),zi(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!tt(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!tt(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e;const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Ro[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}$o.positioners=Ro;var Yo={id:"tooltip",_element:$o,positioners:Ro,afterInit(t,e,i){i&&(t.tooltip=new $o({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip,i={tooltip:e};!1!==t.notifyPlugins("beforeTooltipDraw",i)&&(e&&e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i))},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:{beforeTitle:H,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]},Uo=Object.freeze({__proto__:null,Decimation:ro,Filler:So,Legend:Co,SubTitle:Lo,Title:Ao,Tooltip:Yo});function Xo(t,e,i,s){const n=t.indexOf(e);if(-1===n)return((t,e,i,s)=>("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}class qo extends Bs{constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if($(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:jt(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:Xo(i,t,K(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){const e=this.getLabels();return t>=0&&te.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}}function Ko(t,e,{horizontal:i,minRotation:s}){const n=It(s),o=(i?Math.sin(n):Math.cos(n))||.001,a=.75*e*(""+t).length;return Math.min(e/o,a)}qo.id="category",qo.defaults={ticks:{callback:qo.prototype.getLabelForValue}};class Go extends Bs{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,e){return $(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:e,maxDefined:i}=this.getUserBounds();let{min:s,max:n}=this;const o=t=>s=e?s:t,a=t=>n=i?n:t;if(t){const t=Ct(s),e=Ct(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=1;(n>=Number.MAX_SAFE_INTEGER||s<=Number.MIN_SAFE_INTEGER)&&(e=Math.abs(.05*n)),a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const s=function(t,e){const i=[],{bounds:s,step:n,min:o,max:a,precision:r,count:l,maxTicks:h,maxDigits:c,includeBounds:d}=t,u=n||1,f=h-1,{min:g,max:p}=e,m=!$(o),x=!$(a),b=!$(l),_=(p-g)/(c+1);let y,v,w,M,k=Ot((p-g)/f/u)*u;if(k<1e-14&&!m&&!x)return[{value:g},{value:p}];M=Math.ceil(p/k)-Math.floor(g/k),M>f&&(k=Ot(M*k/f/u)*u),$(r)||(y=Math.pow(10,r),k=Math.ceil(k*y)/y),"ticks"===s?(v=Math.floor(g/k)*k,w=Math.ceil(p/k)*k):(v=g,w=p),m&&x&&n&&Rt((a-o)/n,k/1e3)?(M=Math.round(Math.min((a-o)/k,h)),k=(a-o)/M,v=o,w=a):b?(v=m?o:v,w=x?a:w,M=l-1,k=(w-v)/M):(M=(w-v)/k,M=Lt(M,Math.round(M),k/1e3)?Math.round(M):Math.ceil(M));const S=Math.max(Ft(k),Ft(v));y=Math.pow(10,$(r)?S:r),v=Math.round(v*y)/y,w=Math.round(w*y)/y;let P=0;for(m&&(d&&v!==o?(i.push({value:o}),v0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=X(t)?Math.max(0,t):null,this.max=X(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t,a=(t,e)=>Math.pow(10,Math.floor(Dt(t))+e);i===s&&(i<=0?(n(1),o(10)):(n(a(i,-1)),o(a(s,1)))),i<=0&&n(a(s,-1)),s<=0&&o(a(i,1)),this._zero&&this.min!==this._suggestedMin&&i===a(this.min,0)&&n(a(i,-1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=function(t,e){const i=Math.floor(Dt(e.max)),s=Math.ceil(e.max/Math.pow(10,i)),n=[];let o=q(t.min,Math.pow(10,Math.floor(Dt(e.min)))),a=Math.floor(Dt(o)),r=Math.floor(o/Math.pow(10,a)),l=a<0?Math.pow(10,Math.abs(a)):1;do{n.push({value:o,major:Jo(o)}),++r,10===r&&(r=1,++a,l=a>=0?1:l),o=Math.round(r*Math.pow(10,a)*l)/l}while(an?{start:e-i,end:e}:{start:e,end:e+i}}function ia(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],n=[],o=t._pointLabels.length,a=t.options.pointLabels,r=a.centerPointLabels?_t/o:0;for(let d=0;de.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function na(t){return 0===t||180===t?"center":t<180?"left":"right"}function oa(t,e,i){return"right"===i?t-=e:"center"===i&&(t-=e/2),t}function aa(t,e,i){return 90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e),t}function ra(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,yt);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;o{const i=J(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?ia(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return Nt(t*(yt/(this._pointLabels.length||1))+It(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if($(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if($(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=s.setContext(t.getPointLabelContext(n)),o=He(e.font),{x:a,y:r,textAlign:l,left:h,top:c,right:d,bottom:u}=t._pointLabelItems[n],{backdropColor:f}=e;if(!$(f)){const t=Ne(e.backdropPadding);i.fillStyle=f,i.fillRect(h-t.left,c-t.top,d-h+t.width,u-c+t.height)}se(i,t._pointLabels[n],a,r+o.lineHeight/2,o,{color:e.color,textAlign:l,textBaseline:"middle"})}}(this,n),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e){a=this.getDistanceFromCenterForValue(t.value);!function(t,e,i,s){const n=t.ctx,o=e.circular,{color:a,lineWidth:r}=e;!o&&!s||!a||!r||i<0||(n.save(),n.strokeStyle=a,n.lineWidth=r,n.setLineDash(e.borderDash),n.lineDashOffset=e.borderDashOffset,n.beginPath(),ra(t,i,o,s),n.closePath(),n.stroke(),n.restore())}(this,s.setContext(this.getContext(e-1)),a,n)}})),i.display){for(t.save(),o=n-1;o>=0;o--){const s=i.setContext(this.getPointLabelContext(o)),{color:n,lineWidth:l}=s;l&&n&&(t.lineWidth=l,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,a=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),r=this.getPointPosition(o,a),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(r.x,r.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=He(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=Ne(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}se(t,s.label,0,-n,l,{color:r.color})})),t.restore()}drawTitle(){}}la.id="radialLinear",la.defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Os.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:t=>t,padding:5,centerPointLabels:!1}},la.defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"},la.descriptors={angleLines:{_fallback:"grid"}};const ha={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ca=Object.keys(ha);function da(t,e){return t-e}function ua(t,e){if($(e))return null;const i=t._adapter,{parser:s,round:n,isoWeekday:o}=t._parseOpts;let a=e;return"function"==typeof s&&(a=s(a)),X(a)||(a="string"==typeof s?i.parse(a,s):i.parse(a)),null===a?null:(n&&(a="week"!==n||!Tt(o)&&!0!==o?i.startOf(a,n):i.startOf(a,"isoWeek",o)),+a)}function fa(t,e,i,s){const n=ca.length;for(let o=ca.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function pa(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class ma extends Bs{constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e){const i=t.time||(t.time={}),s=this._adapter=new mn._date(t.adapters.date);ot(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:ua(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:a}=this.getUserBounds();function r(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),a||isNaN(t.max)||(n=Math.max(n,t.max))}o&&a||(r(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||r(this.getMinMax(!1))),s=X(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=X(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=he(s,n,this.max);return this._unit=e.unit||(i.autoSkip?fa(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=ca.length-1;o>=ca.indexOf(i);o--){const i=ca[o];if(ha[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return ca[i?ca.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=ca.indexOf(t)+1,i=ca.length;e1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const f="data"===s.ticks.source&&this.getDataTimestamps();for(c=u,d=0;ct-e)).map((t=>+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.time.displayFormats,a=this._unit,r=this._majorUnit,l=a&&o[a],h=r&&o[r],c=i[e],d=r&&h&&c&&c.major,u=this._adapter.format(t,s||(d?h:l)),f=n.ticks.callback;return f?J(f,[u,e,i],this):u}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=re(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=re(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}ma.id="time",ma.defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",major:{enabled:!1}}};class ba extends ma{constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=xa(e,this.min),this._tableRange=xa(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;o Array.prototype.slice.call(args)); + let ticking = false; + let args = []; + return function(...rest) { + args = updateArgs(rest); + if (!ticking) { + ticking = true; + requestAnimFrame.call(window, () => { + ticking = false; + fn.apply(thisArg, args); + }); + } + }; +} +function debounce(fn, delay) { + let timeout; + return function(...args) { + if (delay) { + clearTimeout(timeout); + timeout = setTimeout(fn, delay, args); + } else { + fn.apply(this, args); + } + return delay; + }; +} +const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; +const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; +const _textX = (align, left, right, rtl) => { + const check = rtl ? 'left' : 'right'; + return align === check ? right : align === 'center' ? (left + right) / 2 : left; +}; + +function noop() {} +const uid = (function() { + let id = 0; + return function() { + return id++; + }; +}()); +function isNullOrUndef(value) { + return value === null || typeof value === 'undefined'; +} +function isArray(value) { + if (Array.isArray && Array.isArray(value)) { + return true; + } + const type = Object.prototype.toString.call(value); + if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { + return true; + } + return false; +} +function isObject(value) { + return value !== null && Object.prototype.toString.call(value) === '[object Object]'; +} +const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value); +function finiteOrDefault(value, defaultValue) { + return isNumberFinite(value) ? value : defaultValue; +} +function valueOrDefault(value, defaultValue) { + return typeof value === 'undefined' ? defaultValue : value; +} +const toPercentage = (value, dimension) => + typeof value === 'string' && value.endsWith('%') ? + parseFloat(value) / 100 + : value / dimension; +const toDimension = (value, dimension) => + typeof value === 'string' && value.endsWith('%') ? + parseFloat(value) / 100 * dimension + : +value; +function callback(fn, args, thisArg) { + if (fn && typeof fn.call === 'function') { + return fn.apply(thisArg, args); + } +} +function each(loopable, fn, thisArg, reverse) { + let i, len, keys; + if (isArray(loopable)) { + len = loopable.length; + if (reverse) { + for (i = len - 1; i >= 0; i--) { + fn.call(thisArg, loopable[i], i); + } + } else { + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[i], i); + } + } + } else if (isObject(loopable)) { + keys = Object.keys(loopable); + len = keys.length; + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[keys[i]], keys[i]); + } + } +} +function _elementsEqual(a0, a1) { + let i, ilen, v0, v1; + if (!a0 || !a1 || a0.length !== a1.length) { + return false; + } + for (i = 0, ilen = a0.length; i < ilen; ++i) { + v0 = a0[i]; + v1 = a1[i]; + if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { + return false; + } + } + return true; +} +function clone$1(source) { + if (isArray(source)) { + return source.map(clone$1); + } + if (isObject(source)) { + const target = Object.create(null); + const keys = Object.keys(source); + const klen = keys.length; + let k = 0; + for (; k < klen; ++k) { + target[keys[k]] = clone$1(source[keys[k]]); + } + return target; + } + return source; +} +function isValidKey(key) { + return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; +} +function _merger(key, target, source, options) { + if (!isValidKey(key)) { + return; + } + const tval = target[key]; + const sval = source[key]; + if (isObject(tval) && isObject(sval)) { + merge(tval, sval, options); + } else { + target[key] = clone$1(sval); + } +} +function merge(target, source, options) { + const sources = isArray(source) ? source : [source]; + const ilen = sources.length; + if (!isObject(target)) { + return target; + } + options = options || {}; + const merger = options.merger || _merger; + for (let i = 0; i < ilen; ++i) { + source = sources[i]; + if (!isObject(source)) { + continue; + } + const keys = Object.keys(source); + for (let k = 0, klen = keys.length; k < klen; ++k) { + merger(keys[k], target, source, options); + } + } + return target; +} +function mergeIf(target, source) { + return merge(target, source, {merger: _mergerIf}); +} +function _mergerIf(key, target, source) { + if (!isValidKey(key)) { + return; + } + const tval = target[key]; + const sval = source[key]; + if (isObject(tval) && isObject(sval)) { + mergeIf(tval, sval); + } else if (!Object.prototype.hasOwnProperty.call(target, key)) { + target[key] = clone$1(sval); + } +} +function _deprecated(scope, value, previous, current) { + if (value !== undefined) { + console.warn(scope + ': "' + previous + + '" is deprecated. Please use "' + current + '" instead'); + } +} +const emptyString = ''; +const dot = '.'; +function indexOfDotOrLength(key, start) { + const idx = key.indexOf(dot, start); + return idx === -1 ? key.length : idx; +} +function resolveObjectKey(obj, key) { + if (key === emptyString) { + return obj; + } + let pos = 0; + let idx = indexOfDotOrLength(key, pos); + while (obj && idx > pos) { + obj = obj[key.substr(pos, idx - pos)]; + pos = idx + 1; + idx = indexOfDotOrLength(key, pos); + } + return obj; +} +function _capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); +} +const defined = (value) => typeof value !== 'undefined'; +const isFunction = (value) => typeof value === 'function'; +const setsEqual = (a, b) => { + if (a.size !== b.size) { + return false; + } + for (const item of a) { + if (!b.has(item)) { + return false; + } + } + return true; +}; +function _isClickEvent(e) { + return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; +} + +const PI = Math.PI; +const TAU = 2 * PI; +const PITAU = TAU + PI; +const INFINITY = Number.POSITIVE_INFINITY; +const RAD_PER_DEG = PI / 180; +const HALF_PI = PI / 2; +const QUARTER_PI = PI / 4; +const TWO_THIRDS_PI = PI * 2 / 3; +const log10 = Math.log10; +const sign = Math.sign; +function niceNum(range) { + const roundedRange = Math.round(range); + range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; + const niceRange = Math.pow(10, Math.floor(log10(range))); + const fraction = range / niceRange; + const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; + return niceFraction * niceRange; +} +function _factorize(value) { + const result = []; + const sqrt = Math.sqrt(value); + let i; + for (i = 1; i < sqrt; i++) { + if (value % i === 0) { + result.push(i); + result.push(value / i); + } + } + if (sqrt === (sqrt | 0)) { + result.push(sqrt); + } + result.sort((a, b) => a - b).pop(); + return result; +} +function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} +function almostEquals(x, y, epsilon) { + return Math.abs(x - y) < epsilon; +} +function almostWhole(x, epsilon) { + const rounded = Math.round(x); + return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x); +} +function _setMinAndMaxByKey(array, target, property) { + let i, ilen, value; + for (i = 0, ilen = array.length; i < ilen; i++) { + value = array[i][property]; + if (!isNaN(value)) { + target.min = Math.min(target.min, value); + target.max = Math.max(target.max, value); + } + } +} +function toRadians(degrees) { + return degrees * (PI / 180); +} +function toDegrees(radians) { + return radians * (180 / PI); +} +function _decimalPlaces(x) { + if (!isNumberFinite(x)) { + return; + } + let e = 1; + let p = 0; + while (Math.round(x * e) / e !== x) { + e *= 10; + p++; + } + return p; +} +function getAngleFromPoint(centrePoint, anglePoint) { + const distanceFromXCenter = anglePoint.x - centrePoint.x; + const distanceFromYCenter = anglePoint.y - centrePoint.y; + const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); + if (angle < (-0.5 * PI)) { + angle += TAU; + } + return { + angle, + distance: radialDistanceFromCenter + }; +} +function distanceBetweenPoints(pt1, pt2) { + return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); +} +function _angleDiff(a, b) { + return (a - b + PITAU) % TAU - PI; +} +function _normalizeAngle(a) { + return (a % TAU + TAU) % TAU; +} +function _angleBetween(angle, start, end, sameAngleIsFullCircle) { + const a = _normalizeAngle(angle); + const s = _normalizeAngle(start); + const e = _normalizeAngle(end); + const angleToStart = _normalizeAngle(s - a); + const angleToEnd = _normalizeAngle(e - a); + const startToAngle = _normalizeAngle(a - s); + const endToAngle = _normalizeAngle(a - e); + return a === s || a === e || (sameAngleIsFullCircle && s === e) + || (angleToStart > angleToEnd && startToAngle < endToAngle); +} +function _limitValue(value, min, max) { + return Math.max(min, Math.min(max, value)); +} +function _int16Range(value) { + return _limitValue(value, -32768, 32767); +} +function _isBetween(value, start, end, epsilon = 1e-6) { + return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; +} + +const atEdge = (t) => t === 0 || t === 1; +const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); +const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; +const effects = { + linear: t => t, + easeInQuad: t => t * t, + easeOutQuad: t => -t * (t - 2), + easeInOutQuad: t => ((t /= 0.5) < 1) + ? 0.5 * t * t + : -0.5 * ((--t) * (t - 2) - 1), + easeInCubic: t => t * t * t, + easeOutCubic: t => (t -= 1) * t * t + 1, + easeInOutCubic: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t + : 0.5 * ((t -= 2) * t * t + 2), + easeInQuart: t => t * t * t * t, + easeOutQuart: t => -((t -= 1) * t * t * t - 1), + easeInOutQuart: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t * t + : -0.5 * ((t -= 2) * t * t * t - 2), + easeInQuint: t => t * t * t * t * t, + easeOutQuint: t => (t -= 1) * t * t * t * t + 1, + easeInOutQuint: t => ((t /= 0.5) < 1) + ? 0.5 * t * t * t * t * t + : 0.5 * ((t -= 2) * t * t * t * t + 2), + easeInSine: t => -Math.cos(t * HALF_PI) + 1, + easeOutSine: t => Math.sin(t * HALF_PI), + easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1), + easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)), + easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1, + easeInOutExpo: t => atEdge(t) ? t : t < 0.5 + ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) + : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), + easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1), + easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t), + easeInOutCirc: t => ((t /= 0.5) < 1) + ? -0.5 * (Math.sqrt(1 - t * t) - 1) + : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), + easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3), + easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3), + easeInOutElastic(t) { + const s = 0.1125; + const p = 0.45; + return atEdge(t) ? t : + t < 0.5 + ? 0.5 * elasticIn(t * 2, s, p) + : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); + }, + easeInBack(t) { + const s = 1.70158; + return t * t * ((s + 1) * t - s); + }, + easeOutBack(t) { + const s = 1.70158; + return (t -= 1) * t * ((s + 1) * t + s) + 1; + }, + easeInOutBack(t) { + let s = 1.70158; + if ((t /= 0.5) < 1) { + return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); + } + return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); + }, + easeInBounce: t => 1 - effects.easeOutBounce(1 - t), + easeOutBounce(t) { + const m = 7.5625; + const d = 2.75; + if (t < (1 / d)) { + return m * t * t; + } + if (t < (2 / d)) { + return m * (t -= (1.5 / d)) * t + 0.75; + } + if (t < (2.5 / d)) { + return m * (t -= (2.25 / d)) * t + 0.9375; + } + return m * (t -= (2.625 / d)) * t + 0.984375; + }, + easeInOutBounce: t => (t < 0.5) + ? effects.easeInBounce(t * 2) * 0.5 + : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5, +}; + +/*! + * @kurkle/color v0.1.9 + * https://github.com/kurkle/color#readme + * (c) 2020 Jukka Kurkela + * Released under the MIT License + */ +const map = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; +const hex = '0123456789ABCDEF'; +const h1 = (b) => hex[b & 0xF]; +const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; +const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF)); +function isShort(v) { + return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); +} +function hexParse(str) { + var len = str.length; + var ret; + if (str[0] === '#') { + if (len === 4 || len === 5) { + ret = { + r: 255 & map[str[1]] * 17, + g: 255 & map[str[2]] * 17, + b: 255 & map[str[3]] * 17, + a: len === 5 ? map[str[4]] * 17 : 255 + }; + } else if (len === 7 || len === 9) { + ret = { + r: map[str[1]] << 4 | map[str[2]], + g: map[str[3]] << 4 | map[str[4]], + b: map[str[5]] << 4 | map[str[6]], + a: len === 9 ? (map[str[7]] << 4 | map[str[8]]) : 255 + }; + } + } + return ret; +} +function hexString(v) { + var f = isShort(v) ? h1 : h2; + return v + ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') + : v; +} +function round(v) { + return v + 0.5 | 0; +} +const lim = (v, l, h) => Math.max(Math.min(v, h), l); +function p2b(v) { + return lim(round(v * 2.55), 0, 255); +} +function n2b(v) { + return lim(round(v * 255), 0, 255); +} +function b2n(v) { + return lim(round(v / 2.55) / 100, 0, 1); +} +function n2p(v) { + return lim(round(v * 100), 0, 100); +} +const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; +function rgbParse(str) { + const m = RGB_RE.exec(str); + let a = 255; + let r, g, b; + if (!m) { + return; + } + if (m[7] !== r) { + const v = +m[7]; + a = 255 & (m[8] ? p2b(v) : v * 255); + } + r = +m[1]; + g = +m[3]; + b = +m[5]; + r = 255 & (m[2] ? p2b(r) : r); + g = 255 & (m[4] ? p2b(g) : g); + b = 255 & (m[6] ? p2b(b) : b); + return { + r: r, + g: g, + b: b, + a: a + }; +} +function rgbString(v) { + return v && ( + v.a < 255 + ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` + : `rgb(${v.r}, ${v.g}, ${v.b})` + ); +} +const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; +function hsl2rgbn(h, s, l) { + const a = s * Math.min(l, 1 - l); + const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return [f(0), f(8), f(4)]; +} +function hsv2rgbn(h, s, v) { + const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); + return [f(5), f(3), f(1)]; +} +function hwb2rgbn(h, w, b) { + const rgb = hsl2rgbn(h, 1, 0.5); + let i; + if (w + b > 1) { + i = 1 / (w + b); + w *= i; + b *= i; + } + for (i = 0; i < 3; i++) { + rgb[i] *= 1 - w - b; + rgb[i] += w; + } + return rgb; +} +function rgb2hsl(v) { + const range = 255; + const r = v.r / range; + const g = v.g / range; + const b = v.b / range; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + const l = (max + min) / 2; + let h, s, d; + if (max !== min) { + d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + h = max === r + ? ((g - b) / d) + (g < b ? 6 : 0) + : max === g + ? (b - r) / d + 2 + : (r - g) / d + 4; + h = h * 60 + 0.5; + } + return [h | 0, s || 0, l]; +} +function calln(f, a, b, c) { + return ( + Array.isArray(a) + ? f(a[0], a[1], a[2]) + : f(a, b, c) + ).map(n2b); +} +function hsl2rgb(h, s, l) { + return calln(hsl2rgbn, h, s, l); +} +function hwb2rgb(h, w, b) { + return calln(hwb2rgbn, h, w, b); +} +function hsv2rgb(h, s, v) { + return calln(hsv2rgbn, h, s, v); +} +function hue(h) { + return (h % 360 + 360) % 360; +} +function hueParse(str) { + const m = HUE_RE.exec(str); + let a = 255; + let v; + if (!m) { + return; + } + if (m[5] !== v) { + a = m[6] ? p2b(+m[5]) : n2b(+m[5]); + } + const h = hue(+m[2]); + const p1 = +m[3] / 100; + const p2 = +m[4] / 100; + if (m[1] === 'hwb') { + v = hwb2rgb(h, p1, p2); + } else if (m[1] === 'hsv') { + v = hsv2rgb(h, p1, p2); + } else { + v = hsl2rgb(h, p1, p2); + } + return { + r: v[0], + g: v[1], + b: v[2], + a: a + }; +} +function rotate(v, deg) { + var h = rgb2hsl(v); + h[0] = hue(h[0] + deg); + h = hsl2rgb(h); + v.r = h[0]; + v.g = h[1]; + v.b = h[2]; +} +function hslString(v) { + if (!v) { + return; + } + const a = rgb2hsl(v); + const h = a[0]; + const s = n2p(a[1]); + const l = n2p(a[2]); + return v.a < 255 + ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` + : `hsl(${h}, ${s}%, ${l}%)`; +} +const map$1 = { + x: 'dark', + Z: 'light', + Y: 're', + X: 'blu', + W: 'gr', + V: 'medium', + U: 'slate', + A: 'ee', + T: 'ol', + S: 'or', + B: 'ra', + C: 'lateg', + D: 'ights', + R: 'in', + Q: 'turquois', + E: 'hi', + P: 'ro', + O: 'al', + N: 'le', + M: 'de', + L: 'yello', + F: 'en', + K: 'ch', + G: 'arks', + H: 'ea', + I: 'ightg', + J: 'wh' +}; +const names = { + OiceXe: 'f0f8ff', + antiquewEte: 'faebd7', + aqua: 'ffff', + aquamarRe: '7fffd4', + azuY: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '0', + blanKedOmond: 'ffebcd', + Xe: 'ff', + XeviTet: '8a2be2', + bPwn: 'a52a2a', + burlywood: 'deb887', + caMtXe: '5f9ea0', + KartYuse: '7fff00', + KocTate: 'd2691e', + cSO: 'ff7f50', + cSnflowerXe: '6495ed', + cSnsilk: 'fff8dc', + crimson: 'dc143c', + cyan: 'ffff', + xXe: '8b', + xcyan: '8b8b', + xgTMnPd: 'b8860b', + xWay: 'a9a9a9', + xgYF: '6400', + xgYy: 'a9a9a9', + xkhaki: 'bdb76b', + xmagFta: '8b008b', + xTivegYF: '556b2f', + xSange: 'ff8c00', + xScEd: '9932cc', + xYd: '8b0000', + xsOmon: 'e9967a', + xsHgYF: '8fbc8f', + xUXe: '483d8b', + xUWay: '2f4f4f', + xUgYy: '2f4f4f', + xQe: 'ced1', + xviTet: '9400d3', + dAppRk: 'ff1493', + dApskyXe: 'bfff', + dimWay: '696969', + dimgYy: '696969', + dodgerXe: '1e90ff', + fiYbrick: 'b22222', + flSOwEte: 'fffaf0', + foYstWAn: '228b22', + fuKsia: 'ff00ff', + gaRsbSo: 'dcdcdc', + ghostwEte: 'f8f8ff', + gTd: 'ffd700', + gTMnPd: 'daa520', + Way: '808080', + gYF: '8000', + gYFLw: 'adff2f', + gYy: '808080', + honeyMw: 'f0fff0', + hotpRk: 'ff69b4', + RdianYd: 'cd5c5c', + Rdigo: '4b0082', + ivSy: 'fffff0', + khaki: 'f0e68c', + lavFMr: 'e6e6fa', + lavFMrXsh: 'fff0f5', + lawngYF: '7cfc00', + NmoncEffon: 'fffacd', + ZXe: 'add8e6', + ZcSO: 'f08080', + Zcyan: 'e0ffff', + ZgTMnPdLw: 'fafad2', + ZWay: 'd3d3d3', + ZgYF: '90ee90', + ZgYy: 'd3d3d3', + ZpRk: 'ffb6c1', + ZsOmon: 'ffa07a', + ZsHgYF: '20b2aa', + ZskyXe: '87cefa', + ZUWay: '778899', + ZUgYy: '778899', + ZstAlXe: 'b0c4de', + ZLw: 'ffffe0', + lime: 'ff00', + limegYF: '32cd32', + lRF: 'faf0e6', + magFta: 'ff00ff', + maPon: '800000', + VaquamarRe: '66cdaa', + VXe: 'cd', + VScEd: 'ba55d3', + VpurpN: '9370db', + VsHgYF: '3cb371', + VUXe: '7b68ee', + VsprRggYF: 'fa9a', + VQe: '48d1cc', + VviTetYd: 'c71585', + midnightXe: '191970', + mRtcYam: 'f5fffa', + mistyPse: 'ffe4e1', + moccasR: 'ffe4b5', + navajowEte: 'ffdead', + navy: '80', + Tdlace: 'fdf5e6', + Tive: '808000', + TivedBb: '6b8e23', + Sange: 'ffa500', + SangeYd: 'ff4500', + ScEd: 'da70d6', + pOegTMnPd: 'eee8aa', + pOegYF: '98fb98', + pOeQe: 'afeeee', + pOeviTetYd: 'db7093', + papayawEp: 'ffefd5', + pHKpuff: 'ffdab9', + peru: 'cd853f', + pRk: 'ffc0cb', + plum: 'dda0dd', + powMrXe: 'b0e0e6', + purpN: '800080', + YbeccapurpN: '663399', + Yd: 'ff0000', + Psybrown: 'bc8f8f', + PyOXe: '4169e1', + saddNbPwn: '8b4513', + sOmon: 'fa8072', + sandybPwn: 'f4a460', + sHgYF: '2e8b57', + sHshell: 'fff5ee', + siFna: 'a0522d', + silver: 'c0c0c0', + skyXe: '87ceeb', + UXe: '6a5acd', + UWay: '708090', + UgYy: '708090', + snow: 'fffafa', + sprRggYF: 'ff7f', + stAlXe: '4682b4', + tan: 'd2b48c', + teO: '8080', + tEstN: 'd8bfd8', + tomato: 'ff6347', + Qe: '40e0d0', + viTet: 'ee82ee', + JHt: 'f5deb3', + wEte: 'ffffff', + wEtesmoke: 'f5f5f5', + Lw: 'ffff00', + LwgYF: '9acd32' +}; +function unpack() { + const unpacked = {}; + const keys = Object.keys(names); + const tkeys = Object.keys(map$1); + let i, j, k, ok, nk; + for (i = 0; i < keys.length; i++) { + ok = nk = keys[i]; + for (j = 0; j < tkeys.length; j++) { + k = tkeys[j]; + nk = nk.replace(k, map$1[k]); + } + k = parseInt(names[ok], 16); + unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; + } + return unpacked; +} +let names$1; +function nameParse(str) { + if (!names$1) { + names$1 = unpack(); + names$1.transparent = [0, 0, 0, 0]; + } + const a = names$1[str.toLowerCase()]; + return a && { + r: a[0], + g: a[1], + b: a[2], + a: a.length === 4 ? a[3] : 255 + }; +} +function modHSL(v, i, ratio) { + if (v) { + let tmp = rgb2hsl(v); + tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); + tmp = hsl2rgb(tmp); + v.r = tmp[0]; + v.g = tmp[1]; + v.b = tmp[2]; + } +} +function clone(v, proto) { + return v ? Object.assign(proto || {}, v) : v; +} +function fromObject(input) { + var v = {r: 0, g: 0, b: 0, a: 255}; + if (Array.isArray(input)) { + if (input.length >= 3) { + v = {r: input[0], g: input[1], b: input[2], a: 255}; + if (input.length > 3) { + v.a = n2b(input[3]); + } + } + } else { + v = clone(input, {r: 0, g: 0, b: 0, a: 1}); + v.a = n2b(v.a); + } + return v; +} +function functionParse(str) { + if (str.charAt(0) === 'r') { + return rgbParse(str); + } + return hueParse(str); +} +class Color { + constructor(input) { + if (input instanceof Color) { + return input; + } + const type = typeof input; + let v; + if (type === 'object') { + v = fromObject(input); + } else if (type === 'string') { + v = hexParse(input) || nameParse(input) || functionParse(input); + } + this._rgb = v; + this._valid = !!v; + } + get valid() { + return this._valid; + } + get rgb() { + var v = clone(this._rgb); + if (v) { + v.a = b2n(v.a); + } + return v; + } + set rgb(obj) { + this._rgb = fromObject(obj); + } + rgbString() { + return this._valid ? rgbString(this._rgb) : this._rgb; + } + hexString() { + return this._valid ? hexString(this._rgb) : this._rgb; + } + hslString() { + return this._valid ? hslString(this._rgb) : this._rgb; + } + mix(color, weight) { + const me = this; + if (color) { + const c1 = me.rgb; + const c2 = color.rgb; + let w2; + const p = weight === w2 ? 0.5 : weight; + const w = 2 * p - 1; + const a = c1.a - c2.a; + const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + w2 = 1 - w1; + c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; + c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; + c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; + c1.a = p * c1.a + (1 - p) * c2.a; + me.rgb = c1; + } + return me; + } + clone() { + return new Color(this.rgb); + } + alpha(a) { + this._rgb.a = n2b(a); + return this; + } + clearer(ratio) { + const rgb = this._rgb; + rgb.a *= 1 - ratio; + return this; + } + greyscale() { + const rgb = this._rgb; + const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); + rgb.r = rgb.g = rgb.b = val; + return this; + } + opaquer(ratio) { + const rgb = this._rgb; + rgb.a *= 1 + ratio; + return this; + } + negate() { + const v = this._rgb; + v.r = 255 - v.r; + v.g = 255 - v.g; + v.b = 255 - v.b; + return this; + } + lighten(ratio) { + modHSL(this._rgb, 2, ratio); + return this; + } + darken(ratio) { + modHSL(this._rgb, 2, -ratio); + return this; + } + saturate(ratio) { + modHSL(this._rgb, 1, ratio); + return this; + } + desaturate(ratio) { + modHSL(this._rgb, 1, -ratio); + return this; + } + rotate(deg) { + rotate(this._rgb, deg); + return this; + } +} +function index_esm(input) { + return new Color(input); +} + +const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern; +function color(value) { + return isPatternOrGradient(value) ? value : index_esm(value); +} +function getHoverColor(value) { + return isPatternOrGradient(value) + ? value + : index_esm(value).saturate(0.5).darken(0.1).hexString(); +} + +const overrides = Object.create(null); +const descriptors = Object.create(null); +function getScope$1(node, key) { + if (!key) { + return node; + } + const keys = key.split('.'); + for (let i = 0, n = keys.length; i < n; ++i) { + const k = keys[i]; + node = node[k] || (node[k] = Object.create(null)); + } + return node; +} +function set(root, scope, values) { + if (typeof scope === 'string') { + return merge(getScope$1(root, scope), values); + } + return merge(getScope$1(root, ''), scope); +} +class Defaults { + constructor(_descriptors) { + this.animation = undefined; + this.backgroundColor = 'rgba(0,0,0,0.1)'; + this.borderColor = 'rgba(0,0,0,0.1)'; + this.color = '#666'; + this.datasets = {}; + this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); + this.elements = {}; + this.events = [ + 'mousemove', + 'mouseout', + 'click', + 'touchstart', + 'touchmove' + ]; + this.font = { + family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + size: 12, + style: 'normal', + lineHeight: 1.2, + weight: null + }; + this.hover = {}; + this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); + this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); + this.hoverColor = (ctx, options) => getHoverColor(options.color); + this.indexAxis = 'x'; + this.interaction = { + mode: 'nearest', + intersect: true + }; + this.maintainAspectRatio = true; + this.onHover = null; + this.onClick = null; + this.parsing = true; + this.plugins = {}; + this.responsive = true; + this.scale = undefined; + this.scales = {}; + this.showLine = true; + this.drawActiveElementsOnTop = true; + this.describe(_descriptors); + } + set(scope, values) { + return set(this, scope, values); + } + get(scope) { + return getScope$1(this, scope); + } + describe(scope, values) { + return set(descriptors, scope, values); + } + override(scope, values) { + return set(overrides, scope, values); + } + route(scope, name, targetScope, targetName) { + const scopeObject = getScope$1(this, scope); + const targetScopeObject = getScope$1(this, targetScope); + const privateName = '_' + name; + Object.defineProperties(scopeObject, { + [privateName]: { + value: scopeObject[name], + writable: true + }, + [name]: { + enumerable: true, + get() { + const local = this[privateName]; + const target = targetScopeObject[targetName]; + if (isObject(local)) { + return Object.assign({}, target, local); + } + return valueOrDefault(local, target); + }, + set(value) { + this[privateName] = value; + } + } + }); + } +} +var defaults = new Defaults({ + _scriptable: (name) => !name.startsWith('on'), + _indexable: (name) => name !== 'events', + hover: { + _fallback: 'interaction' + }, + interaction: { + _scriptable: false, + _indexable: false, + } +}); + +function toFontString(font) { + if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { + return null; + } + return (font.style ? font.style + ' ' : '') + + (font.weight ? font.weight + ' ' : '') + + font.size + 'px ' + + font.family; +} +function _measureText(ctx, data, gc, longest, string) { + let textWidth = data[string]; + if (!textWidth) { + textWidth = data[string] = ctx.measureText(string).width; + gc.push(string); + } + if (textWidth > longest) { + longest = textWidth; + } + return longest; +} +function _longestText(ctx, font, arrayOfThings, cache) { + cache = cache || {}; + let data = cache.data = cache.data || {}; + let gc = cache.garbageCollect = cache.garbageCollect || []; + if (cache.font !== font) { + data = cache.data = {}; + gc = cache.garbageCollect = []; + cache.font = font; + } + ctx.save(); + ctx.font = font; + let longest = 0; + const ilen = arrayOfThings.length; + let i, j, jlen, thing, nestedThing; + for (i = 0; i < ilen; i++) { + thing = arrayOfThings[i]; + if (thing !== undefined && thing !== null && isArray(thing) !== true) { + longest = _measureText(ctx, data, gc, longest, thing); + } else if (isArray(thing)) { + for (j = 0, jlen = thing.length; j < jlen; j++) { + nestedThing = thing[j]; + if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { + longest = _measureText(ctx, data, gc, longest, nestedThing); + } + } + } + } + ctx.restore(); + const gcLen = gc.length / 2; + if (gcLen > arrayOfThings.length) { + for (i = 0; i < gcLen; i++) { + delete data[gc[i]]; + } + gc.splice(0, gcLen); + } + return longest; +} +function _alignPixel(chart, pixel, width) { + const devicePixelRatio = chart.currentDevicePixelRatio; + const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; + return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; +} +function clearCanvas(canvas, ctx) { + ctx = ctx || canvas.getContext('2d'); + ctx.save(); + ctx.resetTransform(); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.restore(); +} +function drawPoint(ctx, options, x, y) { + let type, xOffset, yOffset, size, cornerRadius; + const style = options.pointStyle; + const rotation = options.rotation; + const radius = options.radius; + let rad = (rotation || 0) * RAD_PER_DEG; + if (style && typeof style === 'object') { + type = style.toString(); + if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { + ctx.save(); + ctx.translate(x, y); + ctx.rotate(rad); + ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); + ctx.restore(); + return; + } + } + if (isNaN(radius) || radius <= 0) { + return; + } + ctx.beginPath(); + switch (style) { + default: + ctx.arc(x, y, radius, 0, TAU); + ctx.closePath(); + break; + case 'triangle': + ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + ctx.closePath(); + break; + case 'rectRounded': + cornerRadius = radius * 0.516; + size = radius - cornerRadius; + xOffset = Math.cos(rad + QUARTER_PI) * size; + yOffset = Math.sin(rad + QUARTER_PI) * size; + ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); + ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); + ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); + ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); + ctx.closePath(); + break; + case 'rect': + if (!rotation) { + size = Math.SQRT1_2 * radius; + ctx.rect(x - size, y - size, 2 * size, 2 * size); + break; + } + rad += QUARTER_PI; + case 'rectRot': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + yOffset, y - xOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.lineTo(x - yOffset, y + xOffset); + ctx.closePath(); + break; + case 'crossRot': + rad += QUARTER_PI; + case 'cross': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'star': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + rad += QUARTER_PI; + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'line': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + break; + case 'dash': + ctx.moveTo(x, y); + ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); + break; + } + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } +} +function _isPointInArea(point, area, margin) { + margin = margin || 0.5; + return !area || (point && point.x > area.left - margin && point.x < area.right + margin && + point.y > area.top - margin && point.y < area.bottom + margin); +} +function clipArea(ctx, area) { + ctx.save(); + ctx.beginPath(); + ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); + ctx.clip(); +} +function unclipArea(ctx) { + ctx.restore(); +} +function _steppedLineTo(ctx, previous, target, flip, mode) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + if (mode === 'middle') { + const midpoint = (previous.x + target.x) / 2.0; + ctx.lineTo(midpoint, previous.y); + ctx.lineTo(midpoint, target.y); + } else if (mode === 'after' !== !!flip) { + ctx.lineTo(previous.x, target.y); + } else { + ctx.lineTo(target.x, previous.y); + } + ctx.lineTo(target.x, target.y); +} +function _bezierCurveTo(ctx, previous, target, flip) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + ctx.bezierCurveTo( + flip ? previous.cp1x : previous.cp2x, + flip ? previous.cp1y : previous.cp2y, + flip ? target.cp2x : target.cp1x, + flip ? target.cp2y : target.cp1y, + target.x, + target.y); +} +function renderText(ctx, text, x, y, font, opts = {}) { + const lines = isArray(text) ? text : [text]; + const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; + let i, line; + ctx.save(); + ctx.font = font.string; + setRenderOpts(ctx, opts); + for (i = 0; i < lines.length; ++i) { + line = lines[i]; + if (stroke) { + if (opts.strokeColor) { + ctx.strokeStyle = opts.strokeColor; + } + if (!isNullOrUndef(opts.strokeWidth)) { + ctx.lineWidth = opts.strokeWidth; + } + ctx.strokeText(line, x, y, opts.maxWidth); + } + ctx.fillText(line, x, y, opts.maxWidth); + decorateText(ctx, x, y, line, opts); + y += font.lineHeight; + } + ctx.restore(); +} +function setRenderOpts(ctx, opts) { + if (opts.translation) { + ctx.translate(opts.translation[0], opts.translation[1]); + } + if (!isNullOrUndef(opts.rotation)) { + ctx.rotate(opts.rotation); + } + if (opts.color) { + ctx.fillStyle = opts.color; + } + if (opts.textAlign) { + ctx.textAlign = opts.textAlign; + } + if (opts.textBaseline) { + ctx.textBaseline = opts.textBaseline; + } +} +function decorateText(ctx, x, y, line, opts) { + if (opts.strikethrough || opts.underline) { + const metrics = ctx.measureText(line); + const left = x - metrics.actualBoundingBoxLeft; + const right = x + metrics.actualBoundingBoxRight; + const top = y - metrics.actualBoundingBoxAscent; + const bottom = y + metrics.actualBoundingBoxDescent; + const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; + ctx.strokeStyle = ctx.fillStyle; + ctx.beginPath(); + ctx.lineWidth = opts.decorationWidth || 2; + ctx.moveTo(left, yDecoration); + ctx.lineTo(right, yDecoration); + ctx.stroke(); + } +} +function addRoundedRectPath(ctx, rect) { + const {x, y, w, h, radius} = rect; + ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true); + ctx.lineTo(x, y + h - radius.bottomLeft); + ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); + ctx.lineTo(x + w - radius.bottomRight, y + h); + ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); + ctx.lineTo(x + w, y + radius.topRight); + ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); + ctx.lineTo(x + radius.topLeft, y); +} + +const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); +const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/); +function toLineHeight(value, size) { + const matches = ('' + value).match(LINE_HEIGHT); + if (!matches || matches[1] === 'normal') { + return size * 1.2; + } + value = +matches[2]; + switch (matches[3]) { + case 'px': + return value; + case '%': + value /= 100; + break; + } + return size * value; +} +const numberOrZero = v => +v || 0; +function _readValueToProps(value, props) { + const ret = {}; + const objProps = isObject(props); + const keys = objProps ? Object.keys(props) : props; + const read = isObject(value) + ? objProps + ? prop => valueOrDefault(value[prop], value[props[prop]]) + : prop => value[prop] + : () => value; + for (const prop of keys) { + ret[prop] = numberOrZero(read(prop)); + } + return ret; +} +function toTRBL(value) { + return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'}); +} +function toTRBLCorners(value) { + return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']); +} +function toPadding(value) { + const obj = toTRBL(value); + obj.width = obj.left + obj.right; + obj.height = obj.top + obj.bottom; + return obj; +} +function toFont(options, fallback) { + options = options || {}; + fallback = fallback || defaults.font; + let size = valueOrDefault(options.size, fallback.size); + if (typeof size === 'string') { + size = parseInt(size, 10); + } + let style = valueOrDefault(options.style, fallback.style); + if (style && !('' + style).match(FONT_STYLE)) { + console.warn('Invalid font style specified: "' + style + '"'); + style = ''; + } + const font = { + family: valueOrDefault(options.family, fallback.family), + lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), + size, + style, + weight: valueOrDefault(options.weight, fallback.weight), + string: '' + }; + font.string = toFontString(font); + return font; +} +function resolve(inputs, context, index, info) { + let cacheable = true; + let i, ilen, value; + for (i = 0, ilen = inputs.length; i < ilen; ++i) { + value = inputs[i]; + if (value === undefined) { + continue; + } + if (context !== undefined && typeof value === 'function') { + value = value(context); + cacheable = false; + } + if (index !== undefined && isArray(value)) { + value = value[index % value.length]; + cacheable = false; + } + if (value !== undefined) { + if (info && !cacheable) { + info.cacheable = false; + } + return value; + } + } +} +function _addGrace(minmax, grace, beginAtZero) { + const {min, max} = minmax; + const change = toDimension(grace, (max - min) / 2); + const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; + return { + min: keepZero(min, -Math.abs(change)), + max: keepZero(max, change) + }; +} +function createContext(parentContext, context) { + return Object.assign(Object.create(parentContext), context); +} + +function _lookup(table, value, cmp) { + cmp = cmp || ((index) => table[index] < value); + let hi = table.length - 1; + let lo = 0; + let mid; + while (hi - lo > 1) { + mid = (lo + hi) >> 1; + if (cmp(mid)) { + lo = mid; + } else { + hi = mid; + } + } + return {lo, hi}; +} +const _lookupByKey = (table, key, value) => + _lookup(table, value, index => table[index][key] < value); +const _rlookupByKey = (table, key, value) => + _lookup(table, value, index => table[index][key] >= value); +function _filterBetween(values, min, max) { + let start = 0; + let end = values.length; + while (start < end && values[start] < min) { + start++; + } + while (end > start && values[end - 1] > max) { + end--; + } + return start > 0 || end < values.length + ? values.slice(start, end) + : values; +} +const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; +function listenArrayEvents(array, listener) { + if (array._chartjs) { + array._chartjs.listeners.push(listener); + return; + } + Object.defineProperty(array, '_chartjs', { + configurable: true, + enumerable: false, + value: { + listeners: [listener] + } + }); + arrayEvents.forEach((key) => { + const method = '_onData' + _capitalize(key); + const base = array[key]; + Object.defineProperty(array, key, { + configurable: true, + enumerable: false, + value(...args) { + const res = base.apply(this, args); + array._chartjs.listeners.forEach((object) => { + if (typeof object[method] === 'function') { + object[method](...args); + } + }); + return res; + } + }); + }); +} +function unlistenArrayEvents(array, listener) { + const stub = array._chartjs; + if (!stub) { + return; + } + const listeners = stub.listeners; + const index = listeners.indexOf(listener); + if (index !== -1) { + listeners.splice(index, 1); + } + if (listeners.length > 0) { + return; + } + arrayEvents.forEach((key) => { + delete array[key]; + }); + delete array._chartjs; +} +function _arrayUnique(items) { + const set = new Set(); + let i, ilen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + set.add(items[i]); + } + if (set.size === ilen) { + return items; + } + return Array.from(set); +} + +function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) { + if (!defined(fallback)) { + fallback = _resolve('_fallback', scopes); + } + const cache = { + [Symbol.toStringTag]: 'Object', + _cacheable: true, + _scopes: scopes, + _rootScopes: rootScopes, + _fallback: fallback, + _getTarget: getTarget, + override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback), + }; + return new Proxy(cache, { + deleteProperty(target, prop) { + delete target[prop]; + delete target._keys; + delete scopes[0][prop]; + return true; + }, + get(target, prop) { + return _cached(target, prop, + () => _resolveWithPrefixes(prop, prefixes, scopes, target)); + }, + getOwnPropertyDescriptor(target, prop) { + return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); + }, + getPrototypeOf() { + return Reflect.getPrototypeOf(scopes[0]); + }, + has(target, prop) { + return getKeysFromAllScopes(target).includes(prop); + }, + ownKeys(target) { + return getKeysFromAllScopes(target); + }, + set(target, prop, value) { + const storage = target._storage || (target._storage = getTarget()); + target[prop] = storage[prop] = value; + delete target._keys; + return true; + } + }); +} +function _attachContext(proxy, context, subProxy, descriptorDefaults) { + const cache = { + _cacheable: false, + _proxy: proxy, + _context: context, + _subProxy: subProxy, + _stack: new Set(), + _descriptors: _descriptors(proxy, descriptorDefaults), + setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults), + override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) + }; + return new Proxy(cache, { + deleteProperty(target, prop) { + delete target[prop]; + delete proxy[prop]; + return true; + }, + get(target, prop, receiver) { + return _cached(target, prop, + () => _resolveWithContext(target, prop, receiver)); + }, + getOwnPropertyDescriptor(target, prop) { + return target._descriptors.allKeys + ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined + : Reflect.getOwnPropertyDescriptor(proxy, prop); + }, + getPrototypeOf() { + return Reflect.getPrototypeOf(proxy); + }, + has(target, prop) { + return Reflect.has(proxy, prop); + }, + ownKeys() { + return Reflect.ownKeys(proxy); + }, + set(target, prop, value) { + proxy[prop] = value; + delete target[prop]; + return true; + } + }); +} +function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) { + const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy; + return { + allKeys: _allKeys, + scriptable: _scriptable, + indexable: _indexable, + isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable, + isIndexable: isFunction(_indexable) ? _indexable : () => _indexable + }; +} +const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name; +const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' && + (Object.getPrototypeOf(value) === null || value.constructor === Object); +function _cached(target, prop, resolve) { + if (Object.prototype.hasOwnProperty.call(target, prop)) { + return target[prop]; + } + const value = resolve(); + target[prop] = value; + return value; +} +function _resolveWithContext(target, prop, receiver) { + const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; + let value = _proxy[prop]; + if (isFunction(value) && descriptors.isScriptable(prop)) { + value = _resolveScriptable(prop, value, target, receiver); + } + if (isArray(value) && value.length) { + value = _resolveArray(prop, value, target, descriptors.isIndexable); + } + if (needsSubResolver(prop, value)) { + value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); + } + return value; +} +function _resolveScriptable(prop, value, target, receiver) { + const {_proxy, _context, _subProxy, _stack} = target; + if (_stack.has(prop)) { + throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); + } + _stack.add(prop); + value = value(_context, _subProxy || receiver); + _stack.delete(prop); + if (needsSubResolver(prop, value)) { + value = createSubResolver(_proxy._scopes, _proxy, prop, value); + } + return value; +} +function _resolveArray(prop, value, target, isIndexable) { + const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; + if (defined(_context.index) && isIndexable(prop)) { + value = value[_context.index % value.length]; + } else if (isObject(value[0])) { + const arr = value; + const scopes = _proxy._scopes.filter(s => s !== arr); + value = []; + for (const item of arr) { + const resolver = createSubResolver(scopes, _proxy, prop, item); + value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); + } + } + return value; +} +function resolveFallback(fallback, prop, value) { + return isFunction(fallback) ? fallback(prop, value) : fallback; +} +const getScope = (key, parent) => key === true ? parent + : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; +function addScopes(set, parentScopes, key, parentFallback, value) { + for (const parent of parentScopes) { + const scope = getScope(key, parent); + if (scope) { + set.add(scope); + const fallback = resolveFallback(scope._fallback, key, value); + if (defined(fallback) && fallback !== key && fallback !== parentFallback) { + return fallback; + } + } else if (scope === false && defined(parentFallback) && key !== parentFallback) { + return null; + } + } + return false; +} +function createSubResolver(parentScopes, resolver, prop, value) { + const rootScopes = resolver._rootScopes; + const fallback = resolveFallback(resolver._fallback, prop, value); + const allScopes = [...parentScopes, ...rootScopes]; + const set = new Set(); + set.add(value); + let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); + if (key === null) { + return false; + } + if (defined(fallback) && fallback !== prop) { + key = addScopesFromKey(set, allScopes, fallback, key, value); + if (key === null) { + return false; + } + } + return _createResolver(Array.from(set), [''], rootScopes, fallback, + () => subGetTarget(resolver, prop, value)); +} +function addScopesFromKey(set, allScopes, key, fallback, item) { + while (key) { + key = addScopes(set, allScopes, key, fallback, item); + } + return key; +} +function subGetTarget(resolver, prop, value) { + const parent = resolver._getTarget(); + if (!(prop in parent)) { + parent[prop] = {}; + } + const target = parent[prop]; + if (isArray(target) && isObject(value)) { + return value; + } + return target; +} +function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { + let value; + for (const prefix of prefixes) { + value = _resolve(readKey(prefix, prop), scopes); + if (defined(value)) { + return needsSubResolver(prop, value) + ? createSubResolver(scopes, proxy, prop, value) + : value; + } + } +} +function _resolve(key, scopes) { + for (const scope of scopes) { + if (!scope) { + continue; + } + const value = scope[key]; + if (defined(value)) { + return value; + } + } +} +function getKeysFromAllScopes(target) { + let keys = target._keys; + if (!keys) { + keys = target._keys = resolveKeysFromAllScopes(target._scopes); + } + return keys; +} +function resolveKeysFromAllScopes(scopes) { + const set = new Set(); + for (const scope of scopes) { + for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) { + set.add(key); + } + } + return Array.from(set); +} + +const EPSILON = Number.EPSILON || 1e-14; +const getPoint = (points, i) => i < points.length && !points[i].skip && points[i]; +const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x'; +function splineCurve(firstPoint, middlePoint, afterPoint, t) { + const previous = firstPoint.skip ? middlePoint : firstPoint; + const current = middlePoint; + const next = afterPoint.skip ? middlePoint : afterPoint; + const d01 = distanceBetweenPoints(current, previous); + const d12 = distanceBetweenPoints(next, current); + let s01 = d01 / (d01 + d12); + let s12 = d12 / (d01 + d12); + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + const fa = t * s01; + const fb = t * s12; + return { + previous: { + x: current.x - fa * (next.x - previous.x), + y: current.y - fa * (next.y - previous.y) + }, + next: { + x: current.x + fb * (next.x - previous.x), + y: current.y + fb * (next.y - previous.y) + } + }; +} +function monotoneAdjust(points, deltaK, mK) { + const pointsLen = points.length; + let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; + let pointAfter = getPoint(points, 0); + for (let i = 0; i < pointsLen - 1; ++i) { + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent || !pointAfter) { + continue; + } + if (almostEquals(deltaK[i], 0, EPSILON)) { + mK[i] = mK[i + 1] = 0; + continue; + } + alphaK = mK[i] / deltaK[i]; + betaK = mK[i + 1] / deltaK[i]; + squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); + if (squaredMagnitude <= 9) { + continue; + } + tauK = 3 / Math.sqrt(squaredMagnitude); + mK[i] = alphaK * tauK * deltaK[i]; + mK[i + 1] = betaK * tauK * deltaK[i]; + } +} +function monotoneCompute(points, mK, indexAxis = 'x') { + const valueAxis = getValueAxis(indexAxis); + const pointsLen = points.length; + let delta, pointBefore, pointCurrent; + let pointAfter = getPoint(points, 0); + for (let i = 0; i < pointsLen; ++i) { + pointBefore = pointCurrent; + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent) { + continue; + } + const iPixel = pointCurrent[indexAxis]; + const vPixel = pointCurrent[valueAxis]; + if (pointBefore) { + delta = (iPixel - pointBefore[indexAxis]) / 3; + pointCurrent[`cp1${indexAxis}`] = iPixel - delta; + pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; + } + if (pointAfter) { + delta = (pointAfter[indexAxis] - iPixel) / 3; + pointCurrent[`cp2${indexAxis}`] = iPixel + delta; + pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; + } + } +} +function splineCurveMonotone(points, indexAxis = 'x') { + const valueAxis = getValueAxis(indexAxis); + const pointsLen = points.length; + const deltaK = Array(pointsLen).fill(0); + const mK = Array(pointsLen); + let i, pointBefore, pointCurrent; + let pointAfter = getPoint(points, 0); + for (i = 0; i < pointsLen; ++i) { + pointBefore = pointCurrent; + pointCurrent = pointAfter; + pointAfter = getPoint(points, i + 1); + if (!pointCurrent) { + continue; + } + if (pointAfter) { + const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; + deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; + } + mK[i] = !pointBefore ? deltaK[i] + : !pointAfter ? deltaK[i - 1] + : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0 + : (deltaK[i - 1] + deltaK[i]) / 2; + } + monotoneAdjust(points, deltaK, mK); + monotoneCompute(points, mK, indexAxis); +} +function capControlPoint(pt, min, max) { + return Math.max(Math.min(pt, max), min); +} +function capBezierPoints(points, area) { + let i, ilen, point, inArea, inAreaPrev; + let inAreaNext = _isPointInArea(points[0], area); + for (i = 0, ilen = points.length; i < ilen; ++i) { + inAreaPrev = inArea; + inArea = inAreaNext; + inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); + if (!inArea) { + continue; + } + point = points[i]; + if (inAreaPrev) { + point.cp1x = capControlPoint(point.cp1x, area.left, area.right); + point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); + } + if (inAreaNext) { + point.cp2x = capControlPoint(point.cp2x, area.left, area.right); + point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); + } + } +} +function _updateBezierControlPoints(points, options, area, loop, indexAxis) { + let i, ilen, point, controlPoints; + if (options.spanGaps) { + points = points.filter((pt) => !pt.skip); + } + if (options.cubicInterpolationMode === 'monotone') { + splineCurveMonotone(points, indexAxis); + } else { + let prev = loop ? points[points.length - 1] : points[0]; + for (i = 0, ilen = points.length; i < ilen; ++i) { + point = points[i]; + controlPoints = splineCurve( + prev, + point, + points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], + options.tension + ); + point.cp1x = controlPoints.previous.x; + point.cp1y = controlPoints.previous.y; + point.cp2x = controlPoints.next.x; + point.cp2y = controlPoints.next.y; + prev = point; + } + } + if (options.capBezierPoints) { + capBezierPoints(points, area); + } +} + +function _isDomSupported() { + return typeof window !== 'undefined' && typeof document !== 'undefined'; +} +function _getParentNode(domNode) { + let parent = domNode.parentNode; + if (parent && parent.toString() === '[object ShadowRoot]') { + parent = parent.host; + } + return parent; +} +function parseMaxStyle(styleValue, node, parentProperty) { + let valueInPixels; + if (typeof styleValue === 'string') { + valueInPixels = parseInt(styleValue, 10); + if (styleValue.indexOf('%') !== -1) { + valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; + } + } else { + valueInPixels = styleValue; + } + return valueInPixels; +} +const getComputedStyle = (element) => window.getComputedStyle(element, null); +function getStyle(el, property) { + return getComputedStyle(el).getPropertyValue(property); +} +const positions = ['top', 'right', 'bottom', 'left']; +function getPositionedStyle(styles, style, suffix) { + const result = {}; + suffix = suffix ? '-' + suffix : ''; + for (let i = 0; i < 4; i++) { + const pos = positions[i]; + result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; + } + result.width = result.left + result.right; + result.height = result.top + result.bottom; + return result; +} +const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot); +function getCanvasPosition(evt, canvas) { + const e = evt.native || evt; + const touches = e.touches; + const source = touches && touches.length ? touches[0] : e; + const {offsetX, offsetY} = source; + let box = false; + let x, y; + if (useOffsetPos(offsetX, offsetY, e.target)) { + x = offsetX; + y = offsetY; + } else { + const rect = canvas.getBoundingClientRect(); + x = source.clientX - rect.left; + y = source.clientY - rect.top; + box = true; + } + return {x, y, box}; +} +function getRelativePosition(evt, chart) { + const {canvas, currentDevicePixelRatio} = chart; + const style = getComputedStyle(canvas); + const borderBox = style.boxSizing === 'border-box'; + const paddings = getPositionedStyle(style, 'padding'); + const borders = getPositionedStyle(style, 'border', 'width'); + const {x, y, box} = getCanvasPosition(evt, canvas); + const xOffset = paddings.left + (box && borders.left); + const yOffset = paddings.top + (box && borders.top); + let {width, height} = chart; + if (borderBox) { + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + return { + x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), + y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) + }; +} +function getContainerSize(canvas, width, height) { + let maxWidth, maxHeight; + if (width === undefined || height === undefined) { + const container = _getParentNode(canvas); + if (!container) { + width = canvas.clientWidth; + height = canvas.clientHeight; + } else { + const rect = container.getBoundingClientRect(); + const containerStyle = getComputedStyle(container); + const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); + const containerPadding = getPositionedStyle(containerStyle, 'padding'); + width = rect.width - containerPadding.width - containerBorder.width; + height = rect.height - containerPadding.height - containerBorder.height; + maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); + maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); + } + } + return { + width, + height, + maxWidth: maxWidth || INFINITY, + maxHeight: maxHeight || INFINITY + }; +} +const round1 = v => Math.round(v * 10) / 10; +function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { + const style = getComputedStyle(canvas); + const margins = getPositionedStyle(style, 'margin'); + const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; + const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; + const containerSize = getContainerSize(canvas, bbWidth, bbHeight); + let {width, height} = containerSize; + if (style.boxSizing === 'content-box') { + const borders = getPositionedStyle(style, 'border', 'width'); + const paddings = getPositionedStyle(style, 'padding'); + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + width = Math.max(0, width - margins.width); + height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); + width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); + height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); + if (width && !height) { + height = round1(width / 2); + } + return { + width, + height + }; +} +function retinaScale(chart, forceRatio, forceStyle) { + const pixelRatio = forceRatio || 1; + const deviceHeight = Math.floor(chart.height * pixelRatio); + const deviceWidth = Math.floor(chart.width * pixelRatio); + chart.height = deviceHeight / pixelRatio; + chart.width = deviceWidth / pixelRatio; + const canvas = chart.canvas; + if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) { + canvas.style.height = `${chart.height}px`; + canvas.style.width = `${chart.width}px`; + } + if (chart.currentDevicePixelRatio !== pixelRatio + || canvas.height !== deviceHeight + || canvas.width !== deviceWidth) { + chart.currentDevicePixelRatio = pixelRatio; + canvas.height = deviceHeight; + canvas.width = deviceWidth; + chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + return true; + } + return false; +} +const supportsEventListenerOptions = (function() { + let passiveSupported = false; + try { + const options = { + get passive() { + passiveSupported = true; + return false; + } + }; + window.addEventListener('test', null, options); + window.removeEventListener('test', null, options); + } catch (e) { + } + return passiveSupported; +}()); +function readUsedSize(element, property) { + const value = getStyle(element, property); + const matches = value && value.match(/^(\d+)(\.\d+)?px$/); + return matches ? +matches[1] : undefined; +} + +function _pointInLine(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: p1.y + t * (p2.y - p1.y) + }; +} +function _steppedInterpolation(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y + : mode === 'after' ? t < 1 ? p1.y : p2.y + : t > 0 ? p2.y : p1.y + }; +} +function _bezierInterpolation(p1, p2, t, mode) { + const cp1 = {x: p1.cp2x, y: p1.cp2y}; + const cp2 = {x: p2.cp1x, y: p2.cp1y}; + const a = _pointInLine(p1, cp1, t); + const b = _pointInLine(cp1, cp2, t); + const c = _pointInLine(cp2, p2, t); + const d = _pointInLine(a, b, t); + const e = _pointInLine(b, c, t); + return _pointInLine(d, e, t); +} + +const intlCache = new Map(); +function getNumberFormat(locale, options) { + options = options || {}; + const cacheKey = locale + JSON.stringify(options); + let formatter = intlCache.get(cacheKey); + if (!formatter) { + formatter = new Intl.NumberFormat(locale, options); + intlCache.set(cacheKey, formatter); + } + return formatter; +} +function formatNumber(num, locale, options) { + return getNumberFormat(locale, options).format(num); +} + +const getRightToLeftAdapter = function(rectX, width) { + return { + x(x) { + return rectX + rectX + width - x; + }, + setWidth(w) { + width = w; + }, + textAlign(align) { + if (align === 'center') { + return align; + } + return align === 'right' ? 'left' : 'right'; + }, + xPlus(x, value) { + return x - value; + }, + leftForLtr(x, itemWidth) { + return x - itemWidth; + }, + }; +}; +const getLeftToRightAdapter = function() { + return { + x(x) { + return x; + }, + setWidth(w) { + }, + textAlign(align) { + return align; + }, + xPlus(x, value) { + return x + value; + }, + leftForLtr(x, _itemWidth) { + return x; + }, + }; +}; +function getRtlAdapter(rtl, rectX, width) { + return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); +} +function overrideTextDirection(ctx, direction) { + let style, original; + if (direction === 'ltr' || direction === 'rtl') { + style = ctx.canvas.style; + original = [ + style.getPropertyValue('direction'), + style.getPropertyPriority('direction'), + ]; + style.setProperty('direction', direction, 'important'); + ctx.prevTextDirection = original; + } +} +function restoreTextDirection(ctx, original) { + if (original !== undefined) { + delete ctx.prevTextDirection; + ctx.canvas.style.setProperty('direction', original[0], original[1]); + } +} + +function propertyFn(property) { + if (property === 'angle') { + return { + between: _angleBetween, + compare: _angleDiff, + normalize: _normalizeAngle, + }; + } + return { + between: _isBetween, + compare: (a, b) => a - b, + normalize: x => x + }; +} +function normalizeSegment({start, end, count, loop, style}) { + return { + start: start % count, + end: end % count, + loop: loop && (end - start + 1) % count === 0, + style + }; +} +function getSegment(segment, points, bounds) { + const {property, start: startBound, end: endBound} = bounds; + const {between, normalize} = propertyFn(property); + const count = points.length; + let {start, end, loop} = segment; + let i, ilen; + if (loop) { + start += count; + end += count; + for (i = 0, ilen = count; i < ilen; ++i) { + if (!between(normalize(points[start % count][property]), startBound, endBound)) { + break; + } + start--; + end--; + } + start %= count; + end %= count; + } + if (end < start) { + end += count; + } + return {start, end, loop, style: segment.style}; +} +function _boundSegment(segment, points, bounds) { + if (!bounds) { + return [segment]; + } + const {property, start: startBound, end: endBound} = bounds; + const count = points.length; + const {compare, between, normalize} = propertyFn(property); + const {start, end, loop, style} = getSegment(segment, points, bounds); + const result = []; + let inside = false; + let subStart = null; + let value, point, prevValue; + const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; + const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value); + const shouldStart = () => inside || startIsBefore(); + const shouldStop = () => !inside || endIsBefore(); + for (let i = start, prev = start; i <= end; ++i) { + point = points[i % count]; + if (point.skip) { + continue; + } + value = normalize(point[property]); + if (value === prevValue) { + continue; + } + inside = between(value, startBound, endBound); + if (subStart === null && shouldStart()) { + subStart = compare(value, startBound) === 0 ? i : prev; + } + if (subStart !== null && shouldStop()) { + result.push(normalizeSegment({start: subStart, end: i, loop, count, style})); + subStart = null; + } + prev = i; + prevValue = value; + } + if (subStart !== null) { + result.push(normalizeSegment({start: subStart, end, loop, count, style})); + } + return result; +} +function _boundSegments(line, bounds) { + const result = []; + const segments = line.segments; + for (let i = 0; i < segments.length; i++) { + const sub = _boundSegment(segments[i], line.points, bounds); + if (sub.length) { + result.push(...sub); + } + } + return result; +} +function findStartAndEnd(points, count, loop, spanGaps) { + let start = 0; + let end = count - 1; + if (loop && !spanGaps) { + while (start < count && !points[start].skip) { + start++; + } + } + while (start < count && points[start].skip) { + start++; + } + start %= count; + if (loop) { + end += start; + } + while (end > start && points[end % count].skip) { + end--; + } + end %= count; + return {start, end}; +} +function solidSegments(points, start, max, loop) { + const count = points.length; + const result = []; + let last = start; + let prev = points[start]; + let end; + for (end = start + 1; end <= max; ++end) { + const cur = points[end % count]; + if (cur.skip || cur.stop) { + if (!prev.skip) { + loop = false; + result.push({start: start % count, end: (end - 1) % count, loop}); + start = last = cur.stop ? end : null; + } + } else { + last = end; + if (prev.skip) { + start = end; + } + } + prev = cur; + } + if (last !== null) { + result.push({start: start % count, end: last % count, loop}); + } + return result; +} +function _computeSegments(line, segmentOptions) { + const points = line.points; + const spanGaps = line.options.spanGaps; + const count = points.length; + if (!count) { + return []; + } + const loop = !!line._loop; + const {start, end} = findStartAndEnd(points, count, loop, spanGaps); + if (spanGaps === true) { + return splitByStyles(line, [{start, end, loop}], points, segmentOptions); + } + const max = end < start ? end + count : end; + const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; + return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); +} +function splitByStyles(line, segments, points, segmentOptions) { + if (!segmentOptions || !segmentOptions.setContext || !points) { + return segments; + } + return doSplitByStyles(line, segments, points, segmentOptions); +} +function doSplitByStyles(line, segments, points, segmentOptions) { + const chartContext = line._chart.getContext(); + const baseStyle = readStyle(line.options); + const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; + const count = points.length; + const result = []; + let prevStyle = baseStyle; + let start = segments[0].start; + let i = start; + function addStyle(s, e, l, st) { + const dir = spanGaps ? -1 : 1; + if (s === e) { + return; + } + s += count; + while (points[s % count].skip) { + s -= dir; + } + while (points[e % count].skip) { + e += dir; + } + if (s % count !== e % count) { + result.push({start: s % count, end: e % count, loop: l, style: st}); + prevStyle = st; + start = e % count; + } + } + for (const segment of segments) { + start = spanGaps ? start : segment.start; + let prev = points[start % count]; + let style; + for (i = start + 1; i <= segment.end; i++) { + const pt = points[i % count]; + style = readStyle(segmentOptions.setContext(createContext(chartContext, { + type: 'segment', + p0: prev, + p1: pt, + p0DataIndex: (i - 1) % count, + p1DataIndex: i % count, + datasetIndex + }))); + if (styleChanged(style, prevStyle)) { + addStyle(start, i - 1, segment.loop, prevStyle); + } + prev = pt; + prevStyle = style; + } + if (start < i - 1) { + addStyle(start, i - 1, segment.loop, prevStyle); + } + } + return result; +} +function readStyle(options) { + return { + backgroundColor: options.backgroundColor, + borderCapStyle: options.borderCapStyle, + borderDash: options.borderDash, + borderDashOffset: options.borderDashOffset, + borderJoinStyle: options.borderJoinStyle, + borderWidth: options.borderWidth, + borderColor: options.borderColor + }; +} +function styleChanged(style, prevStyle) { + return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle); +} + +export { _toLeftRightCenter as $, _rlookupByKey as A, getAngleFromPoint as B, toPadding as C, each as D, getMaximumSize as E, _getParentNode as F, readUsedSize as G, HALF_PI as H, throttled as I, supportsEventListenerOptions as J, _isDomSupported as K, log10 as L, _factorize as M, finiteOrDefault as N, callback as O, PI as P, _addGrace as Q, toDegrees as R, _measureText as S, TAU as T, _int16Range as U, _alignPixel as V, clipArea as W, renderText as X, unclipArea as Y, toFont as Z, _arrayUnique as _, resolve as a, _angleDiff as a$, _alignStartEnd as a0, overrides as a1, merge as a2, _capitalize as a3, descriptors as a4, isFunction as a5, _attachContext as a6, _createResolver as a7, _descriptors as a8, mergeIf as a9, restoreTextDirection as aA, noop as aB, distanceBetweenPoints as aC, _setMinAndMaxByKey as aD, niceNum as aE, almostWhole as aF, almostEquals as aG, _decimalPlaces as aH, _longestText as aI, _filterBetween as aJ, _lookup as aK, getHoverColor as aL, clone$1 as aM, _merger as aN, _mergerIf as aO, _deprecated as aP, toFontString as aQ, splineCurve as aR, splineCurveMonotone as aS, getStyle as aT, fontString as aU, toLineHeight as aV, PITAU as aW, INFINITY as aX, RAD_PER_DEG as aY, QUARTER_PI as aZ, TWO_THIRDS_PI as a_, uid as aa, debounce as ab, retinaScale as ac, clearCanvas as ad, setsEqual as ae, _elementsEqual as af, _isClickEvent as ag, _isBetween as ah, _readValueToProps as ai, _updateBezierControlPoints as aj, _computeSegments as ak, _boundSegments as al, _steppedInterpolation as am, _bezierInterpolation as an, _pointInLine as ao, _steppedLineTo as ap, _bezierCurveTo as aq, drawPoint as ar, addRoundedRectPath as as, toTRBL as at, toTRBLCorners as au, _boundSegment as av, _normalizeAngle as aw, getRtlAdapter as ax, overrideTextDirection as ay, _textX as az, isArray as b, color as c, defaults as d, effects as e, resolveObjectKey as f, isNumberFinite as g, createContext as h, isObject as i, defined as j, isNullOrUndef as k, listenArrayEvents as l, toPercentage as m, toDimension as n, formatNumber as o, _angleBetween as p, isNumber as q, requestAnimFrame as r, sign as s, toRadians as t, unlistenArrayEvents as u, valueOrDefault as v, _limitValue as w, _lookupByKey as x, getRelativePosition as y, _isPointInArea as z }; diff --git a/node_modules/chart.js/dist/helpers.esm.js b/node_modules/chart.js/dist/helpers.esm.js new file mode 100644 index 00000000..399496db --- /dev/null +++ b/node_modules/chart.js/dist/helpers.esm.js @@ -0,0 +1,7 @@ +/*! + * Chart.js v3.7.1 + * https://www.chartjs.org + * (c) 2022 Chart.js Contributors + * Released under the MIT License + */ +export { H as HALF_PI, aX as INFINITY, P as PI, aW as PITAU, aZ as QUARTER_PI, aY as RAD_PER_DEG, T as TAU, a_ as TWO_THIRDS_PI, Q as _addGrace, V as _alignPixel, a0 as _alignStartEnd, p as _angleBetween, a$ as _angleDiff, _ as _arrayUnique, a6 as _attachContext, aq as _bezierCurveTo, an as _bezierInterpolation, av as _boundSegment, al as _boundSegments, a3 as _capitalize, ak as _computeSegments, a7 as _createResolver, aH as _decimalPlaces, aP as _deprecated, a8 as _descriptors, af as _elementsEqual, M as _factorize, aJ as _filterBetween, F as _getParentNode, U as _int16Range, ah as _isBetween, ag as _isClickEvent, K as _isDomSupported, z as _isPointInArea, w as _limitValue, aI as _longestText, aK as _lookup, x as _lookupByKey, S as _measureText, aN as _merger, aO as _mergerIf, aw as _normalizeAngle, ao as _pointInLine, ai as _readValueToProps, A as _rlookupByKey, aD as _setMinAndMaxByKey, am as _steppedInterpolation, ap as _steppedLineTo, az as _textX, $ as _toLeftRightCenter, aj as _updateBezierControlPoints, as as addRoundedRectPath, aG as almostEquals, aF as almostWhole, O as callback, ad as clearCanvas, W as clipArea, aM as clone, c as color, h as createContext, ab as debounce, j as defined, aC as distanceBetweenPoints, ar as drawPoint, D as each, e as easingEffects, N as finiteOrDefault, aU as fontString, o as formatNumber, B as getAngleFromPoint, aL as getHoverColor, E as getMaximumSize, y as getRelativePosition, ax as getRtlAdapter, aT as getStyle, b as isArray, g as isFinite, a5 as isFunction, k as isNullOrUndef, q as isNumber, i as isObject, l as listenArrayEvents, L as log10, a2 as merge, a9 as mergeIf, aE as niceNum, aB as noop, ay as overrideTextDirection, G as readUsedSize, X as renderText, r as requestAnimFrame, a as resolve, f as resolveObjectKey, aA as restoreTextDirection, ac as retinaScale, ae as setsEqual, s as sign, aR as splineCurve, aS as splineCurveMonotone, J as supportsEventListenerOptions, I as throttled, R as toDegrees, n as toDimension, Z as toFont, aQ as toFontString, aV as toLineHeight, C as toPadding, m as toPercentage, t as toRadians, at as toTRBL, au as toTRBLCorners, aa as uid, Y as unclipArea, u as unlistenArrayEvents, v as valueOrDefault } from './chunks/helpers.segment.js'; diff --git a/node_modules/chart.js/helpers/helpers.esm.d.ts b/node_modules/chart.js/helpers/helpers.esm.d.ts new file mode 100644 index 00000000..2c3468e7 --- /dev/null +++ b/node_modules/chart.js/helpers/helpers.esm.d.ts @@ -0,0 +1 @@ +export * from '../types/helpers'; diff --git a/node_modules/chart.js/helpers/helpers.esm.js b/node_modules/chart.js/helpers/helpers.esm.js new file mode 100644 index 00000000..ca4eee52 --- /dev/null +++ b/node_modules/chart.js/helpers/helpers.esm.js @@ -0,0 +1 @@ +export * from '../dist/helpers.esm'; diff --git a/node_modules/chart.js/helpers/helpers.js b/node_modules/chart.js/helpers/helpers.js new file mode 100644 index 00000000..a762f589 --- /dev/null +++ b/node_modules/chart.js/helpers/helpers.js @@ -0,0 +1 @@ +module.exports = require('..').helpers; diff --git a/node_modules/chart.js/helpers/package.json b/node_modules/chart.js/helpers/package.json new file mode 100644 index 00000000..d97b75cb --- /dev/null +++ b/node_modules/chart.js/helpers/package.json @@ -0,0 +1,8 @@ +{ + "name": "chart.js-helpers", + "private": true, + "description": "helper package", + "main": "helpers.js", + "module": "helpers.esm.js", + "types": "helpers.esm.d.ts" +} \ No newline at end of file diff --git a/node_modules/chart.js/package.json b/node_modules/chart.js/package.json new file mode 100644 index 00000000..24c99596 --- /dev/null +++ b/node_modules/chart.js/package.json @@ -0,0 +1,111 @@ +{ + "name": "chart.js", + "homepage": "https://www.chartjs.org", + "description": "Simple HTML5 charts using the canvas element.", + "version": "3.7.1", + "license": "MIT", + "jsdelivr": "dist/chart.min.js", + "unpkg": "dist/chart.min.js", + "main": "dist/chart.js", + "module": "dist/chart.esm.js", + "types": "types/index.esm.d.ts", + "keywords": [ + "canvas", + "charts", + "data", + "graphs", + "html5", + "responsive" + ], + "repository": { + "type": "git", + "url": "https://github.com/chartjs/Chart.js.git" + }, + "bugs": { + "url": "https://github.com/chartjs/Chart.js/issues" + }, + "files": [ + "auto/**/*.js", + "auto/**/*.d.ts", + "dist/*.js", + "dist/chunks/*.js", + "types/*.d.ts", + "types/helpers/*.d.ts", + "helpers/**/*.js", + "helpers/**/*.d.ts" + ], + "scripts": { + "autobuild": "rollup -c -w", + "build": "rollup -c", + "dev": "karma start --auto-watch --no-single-run --browsers chrome --grep", + "dev:ff": "karma start --auto-watch --no-single-run --browsers firefox --grep", + "docs": "npm run build && vuepress build docs --no-cache", + "docs:dev": "npm run build && vuepress dev docs --no-cache", + "lint-js": "eslint \"src/**/*.js\" \"test/**/*.js\" \"docs/**/*.js\"", + "lint-md": "eslint \"**/*.md\"", + "lint-tsc": "tsc", + "lint-types": "eslint \"types/**/*.ts\" && node -r esm types/tests/autogen.js && tsc -p types/tests/", + "lint": "concurrently \"npm:lint-*\"", + "test": "npm run lint && cross-env NODE_ENV=test karma start --auto-watch --single-run --coverage --grep" + }, + "devDependencies": { + "@kurkle/color": "^0.1.9", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-inject": "^4.0.2", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.0", + "@simonbrunel/vuepress-plugin-versions": "^0.2.0", + "@types/offscreencanvas": "^2019.6.4", + "@typescript-eslint/eslint-plugin": "^5.8.0", + "@typescript-eslint/parser": "^5.8.0", + "@vuepress/plugin-google-analytics": "^1.8.3", + "@vuepress/plugin-html-redirect": "^0.1.2", + "chartjs-adapter-luxon": "^1.0.0", + "chartjs-adapter-moment": "^1.0.0", + "chartjs-test-utils": "^0.3.1", + "concurrently": "^6.0.1", + "coveralls": "^3.1.0", + "cross-env": "^7.0.3", + "eslint": "^8.5.0", + "eslint-config-chartjs": "^0.3.0", + "eslint-plugin-es": "^4.1.0", + "eslint-plugin-html": "^6.1.2", + "eslint-plugin-markdown": "^2.2.1", + "esm": "^3.2.25", + "glob": "^7.1.6", + "jasmine": "^3.7.0", + "jasmine-core": "^3.7.1", + "karma": "^6.3.2", + "karma-chrome-launcher": "^3.1.0", + "karma-coverage": "^2.0.3", + "karma-edge-launcher": "^0.4.2", + "karma-firefox-launcher": "^2.1.0", + "karma-jasmine": "^4.0.1", + "karma-jasmine-html-reporter": "^1.5.4", + "karma-rollup-preprocessor": "^7.0.7", + "karma-safari-private-launcher": "^1.0.0", + "karma-spec-reporter": "0.0.32", + "luxon": "^2.2.0", + "markdown-it-include": "^2.0.0", + "moment": "^2.29.1", + "moment-timezone": "^0.5.34", + "pixelmatch": "^5.2.1", + "rollup": "^2.44.0", + "rollup-plugin-analyzer": "^4.0.0", + "rollup-plugin-cleanup": "^3.2.1", + "rollup-plugin-istanbul": "^3.0.0", + "rollup-plugin-terser": "^7.0.2", + "typedoc": "^0.22.10", + "typedoc-plugin-markdown": "^3.6.1", + "typescript": "^4.3.5", + "vue-tabs-component": "^1.5.0", + "vuepress": "^1.8.2", + "vuepress-plugin-code-copy": "^1.0.6", + "vuepress-plugin-flexsearch": "^0.3.0", + "vuepress-plugin-redirect": "^1.2.5", + "vuepress-plugin-tabs": "^0.3.0", + "vuepress-plugin-typedoc": "^0.10.0", + "vuepress-theme-chartjs": "^0.2.0", + "yargs": "^17.0.1" + } +} diff --git a/node_modules/chart.js/types/adapters.d.ts b/node_modules/chart.js/types/adapters.d.ts new file mode 100644 index 00000000..f06c41b6 --- /dev/null +++ b/node_modules/chart.js/types/adapters.d.ts @@ -0,0 +1,63 @@ +export type TimeUnit = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'; + +export interface DateAdapter { + // Override one or multiple of the methods to adjust to the logic of the current date library. + override(members: Partial): void; + readonly options: unknown; + + /** + * Returns a map of time formats for the supported formatting units defined + * in Unit as well as 'datetime' representing a detailed date/time string. + * @returns {{string: string}} + */ + formats(): { [key: string]: string }; + /** + * Parses the given `value` and return the associated timestamp. + * @param {unknown} value - the value to parse (usually comes from the data) + * @param {string} [format] - the expected data format + */ + parse(value: unknown, format?: TimeUnit): number | null; + /** + * Returns the formatted date in the specified `format` for a given `timestamp`. + * @param {number} timestamp - the timestamp to format + * @param {string} format - the date/time token + * @return {string} + */ + format(timestamp: number, format: TimeUnit): string; + /** + * Adds the specified `amount` of `unit` to the given `timestamp`. + * @param {number} timestamp - the input timestamp + * @param {number} amount - the amount to add + * @param {Unit} unit - the unit as string + * @return {number} + */ + add(timestamp: number, amount: number, unit: TimeUnit): number; + /** + * Returns the number of `unit` between the given timestamps. + * @param {number} a - the input timestamp (reference) + * @param {number} b - the timestamp to subtract + * @param {Unit} unit - the unit as string + * @return {number} + */ + diff(a: number, b: number, unit: TimeUnit): number; + /** + * Returns start of `unit` for the given `timestamp`. + * @param {number} timestamp - the input timestamp + * @param {Unit|'isoWeek'} unit - the unit as string + * @param {number} [weekday] - the ISO day of the week with 1 being Monday + * and 7 being Sunday (only needed if param *unit* is `isoWeek`). + * @return {number} + */ + startOf(timestamp: number, unit: TimeUnit | 'isoWeek', weekday?: number): number; + /** + * Returns end of `unit` for the given `timestamp`. + * @param {number} timestamp - the input timestamp + * @param {Unit|'isoWeek'} unit - the unit as string + * @return {number} + */ + endOf(timestamp: number, unit: TimeUnit | 'isoWeek'): number; +} + +export const _adapters: { + _date: DateAdapter; +}; diff --git a/node_modules/chart.js/types/animation.d.ts b/node_modules/chart.js/types/animation.d.ts new file mode 100644 index 00000000..b8320412 --- /dev/null +++ b/node_modules/chart.js/types/animation.d.ts @@ -0,0 +1,33 @@ +import { Chart } from './index.esm'; +import { AnyObject } from './basic'; + +export class Animation { + constructor(cfg: AnyObject, target: AnyObject, prop: string, to?: unknown); + active(): boolean; + update(cfg: AnyObject, to: unknown, date: number): void; + cancel(): void; + tick(date: number): void; +} + +export interface AnimationEvent { + chart: Chart; + numSteps: number; + initial: boolean; + currentStep: number; +} + +export class Animator { + listen(chart: Chart, event: 'complete' | 'progress', cb: (event: AnimationEvent) => void): void; + add(chart: Chart, items: readonly Animation[]): void; + has(chart: Chart): boolean; + start(chart: Chart): void; + running(chart: Chart): boolean; + stop(chart: Chart): void; + remove(chart: Chart): boolean; +} + +export class Animations { + constructor(chart: Chart, animations: AnyObject); + configure(animations: AnyObject): void; + update(target: AnyObject, values: AnyObject): undefined | boolean; +} diff --git a/node_modules/chart.js/types/basic.d.ts b/node_modules/chart.js/types/basic.d.ts new file mode 100644 index 00000000..1692c9cb --- /dev/null +++ b/node_modules/chart.js/types/basic.d.ts @@ -0,0 +1,3 @@ + +export type AnyObject = Record; +export type EmptyObject = Record; diff --git a/node_modules/chart.js/types/color.d.ts b/node_modules/chart.js/types/color.d.ts new file mode 100644 index 00000000..4a68f98b --- /dev/null +++ b/node_modules/chart.js/types/color.d.ts @@ -0,0 +1 @@ +export type Color = string | CanvasGradient | CanvasPattern; diff --git a/node_modules/chart.js/types/element.d.ts b/node_modules/chart.js/types/element.d.ts new file mode 100644 index 00000000..3b9359b3 --- /dev/null +++ b/node_modules/chart.js/types/element.d.ts @@ -0,0 +1,17 @@ +import { AnyObject } from './basic'; +import { Point } from './geometric'; + +export interface Element { + readonly x: number; + readonly y: number; + readonly active: boolean; + readonly options: O; + + tooltipPosition(useFinalPosition?: boolean): Point; + hasValue(): boolean; + getProps

(props: P, final?: boolean): Pick; +} +export const Element: { + prototype: Element; + new (): Element; +}; diff --git a/node_modules/chart.js/types/geometric.d.ts b/node_modules/chart.js/types/geometric.d.ts new file mode 100644 index 00000000..0e1affda --- /dev/null +++ b/node_modules/chart.js/types/geometric.d.ts @@ -0,0 +1,37 @@ +export interface ChartArea { + top: number; + left: number; + right: number; + bottom: number; + width: number; + height: number; +} + +export interface Point { + x: number; + y: number; +} + +export type TRBL = { + top: number; + right: number; + bottom: number; + left: number; +} + +export type TRBLCorners = { + topLeft: number; + topRight: number; + bottomLeft: number; + bottomRight: number; +}; + +export type CornerRadius = number | Partial; + +export type RoundedRect = { + x: number; + y: number; + w: number; + h: number; + radius?: CornerRadius +} diff --git a/node_modules/chart.js/types/helpers/helpers.canvas.d.ts b/node_modules/chart.js/types/helpers/helpers.canvas.d.ts new file mode 100644 index 00000000..44e570e6 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.canvas.d.ts @@ -0,0 +1,101 @@ +import { PointStyle } from '../index.esm'; +import { Color } from '../color'; +import { ChartArea, RoundedRect } from '../geometric'; +import { CanvasFontSpec } from './helpers.options'; + +export function clearCanvas(canvas: HTMLCanvasElement, ctx?: CanvasRenderingContext2D): void; + +export function clipArea(ctx: CanvasRenderingContext2D, area: ChartArea): void; + +export function unclipArea(ctx: CanvasRenderingContext2D): void; + +export interface DrawPointOptions { + pointStyle: PointStyle; + rotation?: number; + radius: number; + borderWidth: number; +} + +export function drawPoint(ctx: CanvasRenderingContext2D, options: DrawPointOptions, x: number, y: number): void; + +/** + * Converts the given font object into a CSS font string. + * @param font a font object + * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font + */ +export function toFontString(font: { size: number; family: string; style?: string; weight?: string }): string | null; + +export interface RenderTextOpts { + /** + * The fill color of the text. If unset, the existing + * fillStyle property of the canvas is unchanged. + */ + color?: Color; + + /** + * The width of the strikethrough / underline + * @default 2 + */ + decorationWidth?: number; + + /** + * The max width of the text in pixels + */ + maxWidth?: number; + + /** + * A rotation to be applied to the canvas + * This is applied after the translation is applied + */ + rotation?: number; + + /** + * Apply a strikethrough effect to the text + */ + strikethrough?: boolean; + + /** + * The color of the text stroke. If unset, the existing + * strokeStyle property of the context is unchanged + */ + strokeColor?: Color; + + /** + * The text stroke width. If unset, the existing + * lineWidth property of the context is unchanged + */ + strokeWidth?: number; + + /** + * The text alignment to use. If unset, the existing + * textAlign property of the context is unchanged + */ + textAlign: CanvasTextAlign; + + /** + * The text baseline to use. If unset, the existing + * textBaseline property of the context is unchanged + */ + textBaseline: CanvasTextBaseline; + + /** + * If specified, a translation to apply to the context + */ + translation?: [number, number]; + + /** + * Underline the text + */ + underline?: boolean; +} + +export function renderText( + ctx: CanvasRenderingContext2D, + text: string | string[], + x: number, + y: number, + font: CanvasFontSpec, + opts?: RenderTextOpts +): void; + +export function addRoundedRectPath(ctx: CanvasRenderingContext2D, rect: RoundedRect): void; diff --git a/node_modules/chart.js/types/helpers/helpers.collection.d.ts b/node_modules/chart.js/types/helpers/helpers.collection.d.ts new file mode 100644 index 00000000..6a51597c --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.collection.d.ts @@ -0,0 +1,20 @@ +export interface ArrayListener { + _onDataPush?(...item: T[]): void; + _onDataPop?(): void; + _onDataShift?(): void; + _onDataSplice?(index: number, deleteCount: number, ...items: T[]): void; + _onDataUnshift?(...item: T[]): void; +} + +/** + * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', + * 'unshift') and notify the listener AFTER the array has been altered. Listeners are + * called on the '_onData*' callbacks (e.g. _onDataPush, etc.) with same arguments. + */ +export function listenArrayEvents(array: T[], listener: ArrayListener): void; + +/** + * Removes the given array event listener and cleanup extra attached properties (such as + * the _chartjs stub and overridden methods) if array doesn't have any more listeners. + */ +export function unlistenArrayEvents(array: T[], listener: ArrayListener): void; diff --git a/node_modules/chart.js/types/helpers/helpers.color.d.ts b/node_modules/chart.js/types/helpers/helpers.color.d.ts new file mode 100644 index 00000000..3cfc20ea --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.color.d.ts @@ -0,0 +1,33 @@ +export function color(value: CanvasGradient): CanvasGradient; +export function color(value: CanvasPattern): CanvasPattern; +export function color( + value: + | string + | { r: number; g: number; b: number; a: number } + | [number, number, number] + | [number, number, number, number] +): ColorModel; + +export interface ColorModel { + rgbString(): string; + hexString(): string; + hslString(): string; + rgb: { r: number; g: number; b: number; a: number }; + valid: boolean; + mix(color: ColorModel, weight: number): this; + clone(): ColorModel; + alpha(a: number): ColorModel; + clearer(ration: number): ColorModel; + greyscale(): ColorModel; + opaquer(ratio: number): ColorModel; + negate(): ColorModel; + lighten(ratio: number): ColorModel; + darken(ratio: number): ColorModel; + saturate(ratio: number): ColorModel; + desaturate(ratio: number): ColorModel; + rotate(deg: number): this; +} + +export function getHoverColor(value: CanvasGradient): CanvasGradient; +export function getHoverColor(value: CanvasPattern): CanvasPattern; +export function getHoverColor(value: string): string; diff --git a/node_modules/chart.js/types/helpers/helpers.core.d.ts b/node_modules/chart.js/types/helpers/helpers.core.d.ts new file mode 100644 index 00000000..bc376da0 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.core.d.ts @@ -0,0 +1,157 @@ +import { AnyObject } from '../basic'; + +/** + * An empty function that can be used, for example, for optional callback. + */ +export function noop(): void; + +/** + * Returns a unique id, sequentially generated from a global variable. + * @returns {number} + * @function + */ +export function uid(): number; +/** + * Returns true if `value` is neither null nor undefined, else returns false. + * @param {*} value - The value to test. + * @returns {boolean} + * @since 2.7.0 + */ +export function isNullOrUndef(value: unknown): value is null | undefined; +/** + * Returns true if `value` is an array (including typed arrays), else returns false. + * @param {*} value - The value to test. + * @returns {boolean} + * @function + */ +export function isArray(value: unknown): value is ArrayLike; +/** + * Returns true if `value` is an object (excluding null), else returns false. + * @param {*} value - The value to test. + * @returns {boolean} + * @since 2.7.0 + */ +export function isObject(value: unknown): value is AnyObject; +/** + * Returns true if `value` is a finite number, else returns false + * @param {*} value - The value to test. + * @returns {boolean} + */ +export function isFinite(value: unknown): value is number; + +/** + * Returns `value` if finite, else returns `defaultValue`. + * @param {*} value - The value to return if defined. + * @param {*} defaultValue - The value to return if `value` is not finite. + * @returns {*} + */ +export function finiteOrDefault(value: unknown, defaultValue: number): number; + +/** + * Returns `value` if defined, else returns `defaultValue`. + * @param {*} value - The value to return if defined. + * @param {*} defaultValue - The value to return if `value` is undefined. + * @returns {*} + */ +export function valueOrDefault(value: T | undefined, defaultValue: T): T; + +export function toPercentage(value: number | string, dimesion: number): number; +export function toDimension(value: number | string, dimension: number): number; + +/** + * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the + * value returned by `fn`. If `fn` is not a function, this method returns undefined. + * @param fn - The function to call. + * @param args - The arguments with which `fn` should be called. + * @param [thisArg] - The value of `this` provided for the call to `fn`. + * @returns {*} + */ +export function callback R, TA, R>( + fn: T | undefined, + args: unknown[], + thisArg?: TA +): R | undefined; + +/** + * Note(SB) for performance sake, this method should only be used when loopable type + * is unknown or in none intensive code (not called often and small loopable). Else + * it's preferable to use a regular for() loop and save extra function calls. + * @param loopable - The object or array to be iterated. + * @param fn - The function to call for each item. + * @param [thisArg] - The value of `this` provided for the call to `fn`. + * @param [reverse] - If true, iterates backward on the loopable. + */ +export function each( + loopable: T[], + fn: (this: TA, v: T, i: number) => void, + thisArg?: TA, + reverse?: boolean +): void; +/** + * Note(SB) for performance sake, this method should only be used when loopable type + * is unknown or in none intensive code (not called often and small loopable). Else + * it's preferable to use a regular for() loop and save extra function calls. + * @param loopable - The object or array to be iterated. + * @param fn - The function to call for each item. + * @param [thisArg] - The value of `this` provided for the call to `fn`. + * @param [reverse] - If true, iterates backward on the loopable. + */ +export function each( + loopable: { [key: string]: T }, + fn: (this: TA, v: T, k: string) => void, + thisArg?: TA, + reverse?: boolean +): void; + +/** + * Returns a deep copy of `source` without keeping references on objects and arrays. + * @param source - The value to clone. + */ +export function clone(source: T): T; + +export interface MergeOptions { + merger?: (key: string, target: AnyObject, source: AnyObject, options: AnyObject) => AnyObject; +} +/** + * Recursively deep copies `source` properties into `target` with the given `options`. + * IMPORTANT: `target` is not cloned and will be updated with `source` properties. + * @param target - The target object in which all sources are merged into. + * @param source - Object(s) to merge into `target`. + * @param {object} [options] - Merging options: + * @param {function} [options.merger] - The merge method (key, target, source, options) + * @returns {object} The `target` object. + */ +export function merge(target: T, source: [], options?: MergeOptions): T; +export function merge(target: T, source: S1, options?: MergeOptions): T & S1; +export function merge(target: T, source: [S1], options?: MergeOptions): T & S1; +export function merge(target: T, source: [S1, S2], options?: MergeOptions): T & S1 & S2; +export function merge(target: T, source: [S1, S2, S3], options?: MergeOptions): T & S1 & S2 & S3; +export function merge( + target: T, + source: [S1, S2, S3, S4], + options?: MergeOptions +): T & S1 & S2 & S3 & S4; +export function merge(target: T, source: AnyObject[], options?: MergeOptions): AnyObject; + +/** + * Recursively deep copies `source` properties into `target` *only* if not defined in target. + * IMPORTANT: `target` is not cloned and will be updated with `source` properties. + * @param target - The target object in which all sources are merged into. + * @param source - Object(s) to merge into `target`. + * @returns The `target` object. + */ +export function mergeIf(target: T, source: []): T; +export function mergeIf(target: T, source: S1): T & S1; +export function mergeIf(target: T, source: [S1]): T & S1; +export function mergeIf(target: T, source: [S1, S2]): T & S1 & S2; +export function mergeIf(target: T, source: [S1, S2, S3]): T & S1 & S2 & S3; +export function mergeIf(target: T, source: [S1, S2, S3, S4]): T & S1 & S2 & S3 & S4; +export function mergeIf(target: T, source: AnyObject[]): AnyObject; + +export function resolveObjectKey(obj: AnyObject, key: string): AnyObject; + +export function defined(value: unknown): boolean; + +export function isFunction(value: unknown): boolean; + +export function setsEqual(a: Set, b: Set): boolean; diff --git a/node_modules/chart.js/types/helpers/helpers.curve.d.ts b/node_modules/chart.js/types/helpers/helpers.curve.d.ts new file mode 100644 index 00000000..28d9ee4a --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.curve.d.ts @@ -0,0 +1,34 @@ +export interface SplinePoint { + x: number; + y: number; +} + +/** + * Props to Rob Spencer at scaled innovation for his post on splining between points + * http://scaledinnovation.com/analytics/splines/aboutSplines.html + */ +export function splineCurve( + firstPoint: SplinePoint & { skip?: boolean }, + middlePoint: SplinePoint, + afterPoint: SplinePoint, + t: number +): { + previous: SplinePoint; + next: SplinePoint; +}; + +export interface MonotoneSplinePoint extends SplinePoint { + skip: boolean; + cp1x?: number; + cp1y?: number; + cp2x?: number; + cp2y?: number; +} + +/** + * This function calculates BΓ©zier control points in a similar way than |splineCurve|, + * but preserves monotonicity of the provided data and ensures no local extremums are added + * between the dataset discrete points due to the interpolation. + * @see https://en.wikipedia.org/wiki/Monotone_cubic_interpolation + */ +export function splineCurveMonotone(points: readonly MonotoneSplinePoint[], indexAxis?: 'x' | 'y'): void; diff --git a/node_modules/chart.js/types/helpers/helpers.dom.d.ts b/node_modules/chart.js/types/helpers/helpers.dom.d.ts new file mode 100644 index 00000000..73864314 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.dom.d.ts @@ -0,0 +1,20 @@ +import { ChartEvent } from '../index.esm'; + +export function getMaximumSize(node: HTMLElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number }; +export function getRelativePosition( + evt: MouseEvent | ChartEvent, + chart: { readonly canvas: HTMLCanvasElement } +): { x: number; y: number }; +export function getStyle(el: HTMLElement, property: string): string; +export function retinaScale( + chart: { + currentDevicePixelRatio: number; + readonly canvas: HTMLCanvasElement; + readonly width: number; + readonly height: number; + readonly ctx: CanvasRenderingContext2D; + }, + forceRatio: number, + forceStyle?: boolean +): void; +export function readUsedSize(element: HTMLElement, property: 'width' | 'height'): number | undefined; diff --git a/node_modules/chart.js/types/helpers/helpers.easing.d.ts b/node_modules/chart.js/types/helpers/helpers.easing.d.ts new file mode 100644 index 00000000..b86d6532 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.easing.d.ts @@ -0,0 +1,5 @@ +import { EasingFunction } from '../index.esm'; + +export type EasingFunctionSignature = (t: number) => number; + +export const easingEffects: Record; diff --git a/node_modules/chart.js/types/helpers/helpers.extras.d.ts b/node_modules/chart.js/types/helpers/helpers.extras.d.ts new file mode 100644 index 00000000..cb445c32 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.extras.d.ts @@ -0,0 +1,23 @@ +export function fontString(pixelSize: number, fontStyle: string, fontFamily: string): string; + +/** + * Request animation polyfill + */ +export function requestAnimFrame(cb: () => void): void; + +/** + * Throttles calling `fn` once per animation frame + * Latest arguments are used on the actual call + * @param {function} fn + * @param {*} thisArg + * @param {function} [updateFn] + */ +export function throttled(fn: (...args: unknown[]) => void, thisArg: unknown, updateFn?: (...args: unknown[]) => unknown[]): (...args: unknown[]) => void; + +/** + * Debounces calling `fn` for `delay` ms + * @param {function} fn - Function to call. No arguments are passed. + * @param {number} delay - Delay in ms. 0 = immediate invocation. + * @returns {function} + */ +export function debounce(fn: () => void, delay: number): () => number; diff --git a/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts b/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/chart.js/types/helpers/helpers.intl.d.ts b/node_modules/chart.js/types/helpers/helpers.intl.d.ts new file mode 100644 index 00000000..3a896f4a --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.intl.d.ts @@ -0,0 +1,7 @@ +/** + * Format a number using a localized number formatter. + * @param num The number to format + * @param locale The locale to pass to the Intl.NumberFormat constructor + * @param options Number format options + */ +export function formatNumber(num: number, locale: string, options: Intl.NumberFormatOptions): string; diff --git a/node_modules/chart.js/types/helpers/helpers.math.d.ts b/node_modules/chart.js/types/helpers/helpers.math.d.ts new file mode 100644 index 00000000..cc58b30e --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.math.d.ts @@ -0,0 +1,17 @@ +export function log10(x: number): number; +export function isNumber(v: unknown): boolean; +export function almostEquals(x: number, y: number, epsilon: number): boolean; +export function almostWhole(x: number, epsilon: number): number; +export function sign(x: number): number; +export function niceNum(range: number): number; +export function toRadians(degrees: number): number; +export function toDegrees(radians: number): number; +/** + * Gets the angle from vertical upright to the point about a centre. + */ +export function getAngleFromPoint( + centrePoint: { x: number; y: number }, + anglePoint: { x: number; y: number } +): { angle: number; distance: number }; + +export function distanceBetweenPoints(pt1: { x: number; y: number }, pt2: { x: number; y: number }): number; diff --git a/node_modules/chart.js/types/helpers/helpers.options.d.ts b/node_modules/chart.js/types/helpers/helpers.options.d.ts new file mode 100644 index 00000000..0bd783fa --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.options.d.ts @@ -0,0 +1,61 @@ +import { TRBL, TRBLCorners } from '../geometric'; +import { FontSpec } from '../index.esm'; + +export interface CanvasFontSpec extends FontSpec { + string: string; +} +/** + * Parses font options and returns the font object. + * @param {object} options - A object that contains font options to be parsed. + * @return {object} The font object. + */ +export function toFont(options: Partial): CanvasFontSpec; + +/** + * Converts the given line height `value` in pixels for a specific font `size`. + * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). + * @param {number} size - The font size (in pixels) used to resolve relative `value`. + * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid). + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height + * @since 2.7.0 + */ +export function toLineHeight(value: string, size: number): number; + +export function toTRBL(value: number | Partial): TRBL; +export function toTRBLCorners(value: number | Partial): TRBLCorners; + +/** + * Converts the given value into a padding object with pre-computed width/height. + * @param {number|object} value - If a number, set the value to all TRBL component; + * else, if an object, use defined properties and sets undefined ones to 0. + * @returns {object} The padding values (top, right, bottom, left, width, height) + * @since 2.7.0 + */ +export function toPadding( + value?: number | { top?: number; left?: number; right?: number; bottom?: number; x?:number, y?: number } +): { top: number; left: number; right: number; bottom: number; width: number; height: number }; + +/** + * Evaluates the given `inputs` sequentially and returns the first defined value. + * @param inputs - An array of values, falling back to the last value. + * @param [context] - If defined and the current value is a function, the value + * is called with `context` as first argument and the result becomes the new input. + * @param [index] - If defined and the current value is an array, the value + * at `index` become the new input. + * @param [info] - object to return information about resolution in + * @param [info.cacheable] - Will be set to `false` if option is not cacheable. + * @since 2.7.0 + */ +export function resolve( + inputs: undefined | T | ((c: C) => T) | readonly T[], + context?: C, + index?: number, + info?: { cacheable?: boolean } +): T | undefined; + + +/** + * Create a context inheriting parentContext + * @since 3.6.0 + */ +export function createContext(parentContext: P, context: T): P extends null ? T : P & T; diff --git a/node_modules/chart.js/types/helpers/helpers.rtl.d.ts b/node_modules/chart.js/types/helpers/helpers.rtl.d.ts new file mode 100644 index 00000000..ed0b9248 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.rtl.d.ts @@ -0,0 +1,12 @@ +export interface RTLAdapter { + x(x: number): number; + setWidth(w: number): void; + textAlign(align: 'center' | 'left' | 'right'): 'center' | 'left' | 'right'; + xPlus(x: number, value: number): number; + leftForLtr(x: number, itemWidth: number): number; +} +export function getRtlAdapter(rtl: boolean, rectX: number, width: number): RTLAdapter; + +export function overrideTextDirection(ctx: CanvasRenderingContext2D, direction: 'ltr' | 'rtl'): void; + +export function restoreTextDirection(ctx: CanvasRenderingContext2D, original?: [string, string]): void; diff --git a/node_modules/chart.js/types/helpers/helpers.segment.d.ts b/node_modules/chart.js/types/helpers/helpers.segment.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/node_modules/chart.js/types/helpers/helpers.segment.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/chart.js/types/helpers/index.d.ts b/node_modules/chart.js/types/helpers/index.d.ts new file mode 100644 index 00000000..01332692 --- /dev/null +++ b/node_modules/chart.js/types/helpers/index.d.ts @@ -0,0 +1,15 @@ +export * from './helpers.canvas'; +export * from './helpers.collection'; +export * from './helpers.color'; +export * from './helpers.core'; +export * from './helpers.curve'; +export * from './helpers.dom'; +export * from './helpers.easing'; +export * from './helpers.extras'; +export * from './helpers.interpolation'; +export * from './helpers.intl'; +export * from './helpers.math'; +export * from './helpers.options'; +export * from './helpers.canvas'; +export * from './helpers.rtl'; +export * from './helpers.segment'; diff --git a/node_modules/chart.js/types/index.esm.d.ts b/node_modules/chart.js/types/index.esm.d.ts new file mode 100644 index 00000000..ccea4128 --- /dev/null +++ b/node_modules/chart.js/types/index.esm.d.ts @@ -0,0 +1,3601 @@ +import { DeepPartial, DistributiveArray, UnionToIntersection } from './utils'; + +import { TimeUnit } from './adapters'; +import { AnimationEvent } from './animation'; +import { AnyObject, EmptyObject } from './basic'; +import { Color } from './color'; +import { Element } from './element'; +import { ChartArea, Point } from './geometric'; +import { LayoutItem, LayoutPosition } from './layout'; + +export { DateAdapter, TimeUnit, _adapters } from './adapters'; +export { Animation, Animations, Animator, AnimationEvent } from './animation'; +export { Color } from './color'; +export { Element } from './element'; +export { ChartArea, Point } from './geometric'; +export { LayoutItem, LayoutPosition } from './layout'; + +export interface ScriptableContext { + active: boolean; + chart: Chart; + dataIndex: number; + dataset: UnionToIntersection>; + datasetIndex: number; + parsed: UnionToIntersection>; + raw: unknown; +} + +export interface ScriptableLineSegmentContext { + type: 'segment', + p0: PointElement, + p1: PointElement, + p0DataIndex: number, + p1DataIndex: number, + datasetIndex: number +} + +export type Scriptable = T | ((ctx: TContext, options: AnyObject) => T | undefined); +export type ScriptableOptions = { [P in keyof T]: Scriptable }; +export type ScriptableAndArray = readonly T[] | Scriptable; +export type ScriptableAndArrayOptions = { [P in keyof T]: ScriptableAndArray }; + +export interface ParsingOptions { + /** + * How to parse the dataset. The parsing can be disabled by specifying parsing: false at chart options or dataset. If parsing is disabled, data must be sorted and in the formats the associated chart type and scales use internally. + */ + parsing: + { + [key: string]: string; + } + | false; + + /** + * Chart.js is fastest if you provide data with indices that are unique, sorted, and consistent across datasets and provide the normalized: true option to let Chart.js know that you have done so. + */ + normalized: boolean; +} + +export interface ControllerDatasetOptions extends ParsingOptions { + /** + * The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts. + * @default 'x' + */ + indexAxis: 'x' | 'y'; + /** + * How to clip relative to chartArea. Positive value allows overflow, negative value clips that many pixels inside chartArea. 0 = clip at chartArea. Clipping can also be configured per side: clip: {left: 5, top: false, right: -2, bottom: 0} + */ + clip: number | ChartArea; + /** + * The label for the dataset which appears in the legend and tooltips. + */ + label: string; + /** + * The drawing order of dataset. Also affects order for stacking, tooltip and legend. + */ + order: number; + + /** + * The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack). + */ + stack: string; + /** + * Configures the visibility state of the dataset. Set it to true, to hide the dataset from the chart. + * @default false + */ + hidden: boolean; +} + +export interface BarControllerDatasetOptions + extends ControllerDatasetOptions, + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + AnimationOptions<'bar'> { + /** + * The ID of the x axis to plot this dataset on. + */ + xAxisID: string; + /** + * The ID of the y axis to plot this dataset on. + */ + yAxisID: string; + + /** + * Percent (0-1) of the available width each bar should be within the category width. 1.0 will take the whole category width and put the bars right next to each other. + * @default 0.9 + */ + barPercentage: number; + /** + * Percent (0-1) of the available width each category should be within the sample width. + * @default 0.8 + */ + categoryPercentage: number; + + /** + * Manually set width of each bar in pixels. If set to 'flex', it computes "optimal" sample widths that globally arrange bars side by side. If not set (default), bars are equally sized based on the smallest interval. + */ + barThickness: number | 'flex'; + + /** + * Set this to ensure that bars are not sized thicker than this. + */ + maxBarThickness: number; + + /** + * Set this to ensure that bars have a minimum length in pixels. + */ + minBarLength: number; + + /** + * Point style for the legend + * @default 'circle; + */ + pointStyle: PointStyle; +} + +export interface BarControllerChartOptions { + /** + * Should null or undefined values be omitted from drawing + */ + skipNull?: boolean; +} + +export type BarController = DatasetController +export const BarController: ChartComponent & { + prototype: BarController; + new (chart: Chart, datasetIndex: number): BarController; +}; + +export interface BubbleControllerDatasetOptions + extends ControllerDatasetOptions, + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> {} + +export interface BubbleDataPoint { + /** + * X Value + */ + x: number; + + /** + * Y Value + */ + y: number; + + /** + * Bubble radius in pixels (not scaled). + */ + r: number; +} + +export type BubbleController = DatasetController +export const BubbleController: ChartComponent & { + prototype: BubbleController; + new (chart: Chart, datasetIndex: number): BubbleController; +}; + +export interface LineControllerDatasetOptions + extends ControllerDatasetOptions, + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + ScriptableOptions>, + ScriptableOptions>, + AnimationOptions<'line'> { + /** + * The ID of the x axis to plot this dataset on. + */ + xAxisID: string; + /** + * The ID of the y axis to plot this dataset on. + */ + yAxisID: string; + + /** + * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. + * @default false + */ + spanGaps: boolean | number; + + showLine: boolean; +} + +export interface LineControllerChartOptions { + /** + * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. + * @default false + */ + spanGaps: boolean | number; + /** + * If false, the lines between points are not drawn. + * @default true + */ + showLine: boolean; +} + +export type LineController = DatasetController +export const LineController: ChartComponent & { + prototype: LineController; + new (chart: Chart, datasetIndex: number): LineController; +}; + +export type ScatterControllerDatasetOptions = LineControllerDatasetOptions; + +export interface ScatterDataPoint { + x: number; + y: number; +} + +export type ScatterControllerChartOptions = LineControllerChartOptions; + +export type ScatterController = LineController +export const ScatterController: ChartComponent & { + prototype: ScatterController; + new (chart: Chart, datasetIndex: number): ScatterController; +}; + +export interface DoughnutControllerDatasetOptions + extends ControllerDatasetOptions, + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + AnimationOptions<'doughnut'> { + + /** + * Sweep to allow arcs to cover. + * @default 360 + */ + circumference: number; + + /** + * Arc offset (in pixels). + */ + offset: number; + + /** + * Starting angle to draw this dataset from. + * @default 0 + */ + rotation: number; + + /** + * The relative thickness of the dataset. Providing a value for weight will cause the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weight values. + * @default 1 + */ + weight: number; + + /** + * Similar to the `offset` option, but applies to all arcs. This can be used to to add spaces + * between arcs + * @default 0 + */ + spacing: number; +} + +export interface DoughnutAnimationOptions { + /** + * If true, the chart will animate in with a rotation animation. This property is in the options.animation object. + * @default true + */ + animateRotate: boolean; + + /** + * If true, will animate scaling the chart from the center outwards. + * @default false + */ + animateScale: boolean; +} + +export interface DoughnutControllerChartOptions { + /** + * Sweep to allow arcs to cover. + * @default 360 + */ + circumference: number; + + /** + * The portion of the chart that is cut out of the middle. ('50%' - for doughnut, 0 - for pie) + * String ending with '%' means percentage, number means pixels. + * @default 50 + */ + cutout: Scriptable>; + + /** + * Arc offset (in pixels). + */ + offset: number; + + /** + * The outer radius of the chart. String ending with '%' means percentage of maximum radius, number means pixels. + * @default '100%' + */ + radius: Scriptable>; + + /** + * Starting angle to draw arcs from. + * @default 0 + */ + rotation: number; + + /** + * Spacing between the arcs + * @default 0 + */ + spacing: number; + + animation: false | DoughnutAnimationOptions; +} + +export type DoughnutDataPoint = number; + +export interface DoughnutController extends DatasetController { + readonly innerRadius: number; + readonly outerRadius: number; + readonly offsetX: number; + readonly offsetY: number; + + calculateTotal(): number; + calculateCircumference(value: number): number; +} + +export const DoughnutController: ChartComponent & { + prototype: DoughnutController; + new (chart: Chart, datasetIndex: number): DoughnutController; +}; + +export interface DoughnutMetaExtensions { + total: number; +} + +export type PieControllerDatasetOptions = DoughnutControllerDatasetOptions; +export type PieControllerChartOptions = DoughnutControllerChartOptions; +export type PieAnimationOptions = DoughnutAnimationOptions; + +export type PieDataPoint = DoughnutDataPoint; +export type PieMetaExtensions = DoughnutMetaExtensions; + +export type PieController = DoughnutController +export const PieController: ChartComponent & { + prototype: PieController; + new (chart: Chart, datasetIndex: number): PieController; +}; + +export interface PolarAreaControllerDatasetOptions extends DoughnutControllerDatasetOptions { + /** + * Arc angle to cover. - for polar only + * @default circumference / (arc count) + */ + angle: number; +} + +export type PolarAreaAnimationOptions = DoughnutAnimationOptions; + +export interface PolarAreaControllerChartOptions { + /** + * Starting angle to draw arcs for the first item in a dataset. In degrees, 0 is at top. + * @default 0 + */ + startAngle: number; + + animation: false | PolarAreaAnimationOptions; +} + +export interface PolarAreaController extends DoughnutController { + countVisibleElements(): number; +} +export const PolarAreaController: ChartComponent & { + prototype: PolarAreaController; + new (chart: Chart, datasetIndex: number): PolarAreaController; +}; + +export interface RadarControllerDatasetOptions + extends ControllerDatasetOptions, + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + AnimationOptions<'radar'> { + /** + * The ID of the x axis to plot this dataset on. + */ + xAxisID: string; + /** + * The ID of the y axis to plot this dataset on. + */ + yAxisID: string; + + /** + * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. + */ + spanGaps: boolean | number; + + /** + * If false, the line is not drawn for this dataset. + */ + showLine: boolean; +} + +export type RadarControllerChartOptions = LineControllerChartOptions; + +export type RadarController = DatasetController +export const RadarController: ChartComponent & { + prototype: RadarController; + new (chart: Chart, datasetIndex: number): RadarController; +}; +interface ChartMetaCommon { + type: string; + controller: DatasetController; + order: number; + + label: string; + index: number; + visible: boolean; + + stack: number; + + indexAxis: 'x' | 'y'; + + data: TElement[]; + dataset?: TDatasetElement; + + hidden: boolean; + + xAxisID?: string; + yAxisID?: string; + rAxisID?: string; + iAxisID: string; + vAxisID: string; + + xScale?: Scale; + yScale?: Scale; + rScale?: Scale; + iScale?: Scale; + vScale?: Scale; + + _sorted: boolean; + _stacked: boolean | 'single'; + _parsed: unknown[]; +} + +export type ChartMeta< + TElement extends Element = Element, + TDatasetElement extends Element = Element, + // TODO - V4, move this to the first parameter. + // When this was introduced, doing so was a breaking change + TType extends ChartType = ChartType, +> = DeepPartial< +{ [key in ChartType]: ChartTypeRegistry[key]['metaExtensions'] }[TType] +> & ChartMetaCommon; + +export interface ActiveDataPoint { + datasetIndex: number; + index: number; +} + +export interface ActiveElement extends ActiveDataPoint { + element: Element; +} + +export declare class Chart< + TType extends ChartType = ChartType, + TData = DefaultDataPoint, + TLabel = unknown +> { + readonly platform: BasePlatform; + readonly id: string; + readonly canvas: HTMLCanvasElement; + readonly ctx: CanvasRenderingContext2D; + readonly config: ChartConfiguration; + readonly width: number; + readonly height: number; + readonly aspectRatio: number; + readonly boxes: LayoutItem[]; + readonly currentDevicePixelRatio: number; + readonly chartArea: ChartArea; + readonly scales: { [key: string]: Scale }; + readonly attached: boolean; + + readonly legend?: LegendElement; // Only available if legend plugin is registered and enabled + readonly tooltip?: TooltipModel; // Only available if tooltip plugin is registered and enabled + + data: ChartData; + options: ChartOptions; + + constructor(item: ChartItem, config: ChartConfiguration); + + clear(): this; + stop(): this; + + resize(width?: number, height?: number): void; + ensureScalesHaveIDs(): void; + buildOrUpdateScales(): void; + buildOrUpdateControllers(): void; + reset(): void; + update(mode?: UpdateMode): void; + render(): void; + draw(): void; + + getElementsAtEventForMode(e: Event, mode: string, options: InteractionOptions, useFinalPosition: boolean): InteractionItem[]; + + getSortedVisibleDatasetMetas(): ChartMeta[]; + getDatasetMeta(datasetIndex: number): ChartMeta; + getVisibleDatasetCount(): number; + isDatasetVisible(datasetIndex: number): boolean; + setDatasetVisibility(datasetIndex: number, visible: boolean): void; + toggleDataVisibility(index: number): void; + getDataVisibility(index: number): boolean; + hide(datasetIndex: number, dataIndex?: number): void; + show(datasetIndex: number, dataIndex?: number): void; + + getActiveElements(): ActiveElement[]; + setActiveElements(active: ActiveDataPoint[]): void; + + destroy(): void; + toBase64Image(type?: string, quality?: unknown): string; + bindEvents(): void; + unbindEvents(): void; + updateHoverStyle(items: InteractionItem[], mode: 'dataset', enabled: boolean): void; + + notifyPlugins(hook: string, args?: AnyObject): boolean | void; + + static readonly defaults: Defaults; + static readonly overrides: Overrides; + static readonly version: string; + static readonly instances: { [key: string]: Chart }; + static readonly registry: Registry; + static getChart(key: string | CanvasRenderingContext2D | HTMLCanvasElement): Chart | undefined; + static register(...items: ChartComponentLike[]): void; + static unregister(...items: ChartComponentLike[]): void; +} + +export const registerables: readonly ChartComponentLike[]; + +export declare type ChartItem = + | string + | CanvasRenderingContext2D + | HTMLCanvasElement + | { canvas: HTMLCanvasElement } + | ArrayLike; + +export declare enum UpdateModeEnum { + resize = 'resize', + reset = 'reset', + none = 'none', + hide = 'hide', + show = 'show', + normal = 'normal', + active = 'active' +} + +export type UpdateMode = keyof typeof UpdateModeEnum; + +export class DatasetController< + TType extends ChartType = ChartType, + TElement extends Element = Element, + TDatasetElement extends Element = Element, + TParsedData = ParsedDataType, +> { + constructor(chart: Chart, datasetIndex: number); + + readonly chart: Chart; + readonly index: number; + readonly _cachedMeta: ChartMeta; + enableOptionSharing: boolean; + + linkScales(): void; + getAllParsedValues(scale: Scale): number[]; + protected getLabelAndValue(index: number): { label: string; value: string }; + updateElements(elements: TElement[], start: number, count: number, mode: UpdateMode): void; + update(mode: UpdateMode): void; + updateIndex(datasetIndex: number): void; + protected getMaxOverflow(): boolean | number; + draw(): void; + reset(): void; + getDataset(): ChartDataset; + getMeta(): ChartMeta; + getScaleForId(scaleID: string): Scale | undefined; + configure(): void; + initialize(): void; + addElements(): void; + buildOrUpdateElements(resetNewElements?: boolean): void; + + getStyle(index: number, active: boolean): AnyObject; + protected resolveDatasetElementOptions(mode: UpdateMode): AnyObject; + protected resolveDataElementOptions(index: number, mode: UpdateMode): AnyObject; + /** + * Utility for checking if the options are shared and should be animated separately. + * @protected + */ + protected getSharedOptions(options: AnyObject): undefined | AnyObject; + /** + * Utility for determining if `options` should be included in the updated properties + * @protected + */ + protected includeOptions(mode: UpdateMode, sharedOptions: AnyObject): boolean; + /** + * Utility for updating an element with new properties, using animations when appropriate. + * @protected + */ + + protected updateElement(element: TElement | TDatasetElement, index: number | undefined, properties: AnyObject, mode: UpdateMode): void; + /** + * Utility to animate the shared options, that are potentially affecting multiple elements. + * @protected + */ + + protected updateSharedOptions(sharedOptions: AnyObject, mode: UpdateMode, newOptions: AnyObject): void; + removeHoverStyle(element: TElement, datasetIndex: number, index: number): void; + setHoverStyle(element: TElement, datasetIndex: number, index: number): void; + + parse(start: number, count: number): void; + protected parsePrimitiveData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; + protected parseArrayData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; + protected parseObjectData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; + protected getParsed(index: number): TParsedData; + protected applyStack(scale: Scale, parsed: unknown[]): number; + protected updateRangeFromParsed( + range: { min: number; max: number }, + scale: Scale, + parsed: unknown[], + stack: boolean | string + ): void; + protected getMinMax(scale: Scale, canStack?: boolean): { min: number; max: number }; +} + +export interface DatasetControllerChartComponent extends ChartComponent { + defaults: { + datasetElementType?: string | null | false; + dataElementType?: string | null | false; + }; +} + +export interface Defaults extends CoreChartOptions, ElementChartOptions, PluginChartOptions { + + scale: ScaleOptionsByType; + scales: { + [key in ScaleType]: ScaleOptionsByType; + }; + + set(values: AnyObject): AnyObject; + set(scope: string, values: AnyObject): AnyObject; + get(scope: string): AnyObject; + + describe(scope: string, values: AnyObject): AnyObject; + override(scope: string, values: AnyObject): AnyObject; + + /** + * Routes the named defaults to fallback to another scope/name. + * This routing is useful when those target values, like defaults.color, are changed runtime. + * If the values would be copied, the runtime change would not take effect. By routing, the + * fallback is evaluated at each access, so its always up to date. + * + * Example: + * + * defaults.route('elements.arc', 'backgroundColor', '', 'color') + * - reads the backgroundColor from defaults.color when undefined locally + * + * @param scope Scope this route applies to. + * @param name Property name that should be routed to different namespace when not defined here. + * @param targetScope The namespace where those properties should be routed to. + * Empty string ('') is the root of defaults. + * @param targetName The target name in the target scope the property should be routed to. + */ + route(scope: string, name: string, targetScope: string, targetName: string): void; +} + +export type Overrides = { + [key in ChartType]: + CoreChartOptions & + ElementChartOptions & + PluginChartOptions & + DatasetChartOptions & + ScaleChartOptions & + ChartTypeRegistry[key]['chartOptions']; +} + +export const defaults: Defaults; +export interface InteractionOptions { + axis?: string; + intersect?: boolean; +} + +export interface InteractionItem { + element: Element; + datasetIndex: number; + index: number; +} + +export type InteractionModeFunction = ( + chart: Chart, + e: ChartEvent, + options: InteractionOptions, + useFinalPosition?: boolean +) => InteractionItem[]; + +export interface InteractionModeMap { + /** + * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item + */ + index: InteractionModeFunction; + + /** + * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect is false, we find the nearest item and return the items in that dataset + */ + dataset: InteractionModeFunction; + /** + * Point mode returns all elements that hit test based on the event position + * of the event + */ + point: InteractionModeFunction; + /** + * nearest mode returns the element closest to the point + */ + nearest: InteractionModeFunction; + /** + * x mode returns the elements that hit-test at the current x coordinate + */ + x: InteractionModeFunction; + /** + * y mode returns the elements that hit-test at the current y coordinate + */ + y: InteractionModeFunction; +} + +export type InteractionMode = keyof InteractionModeMap; + +export const Interaction: { + modes: InteractionModeMap; +}; + +export const layouts: { + /** + * Register a box to a chart. + * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title. + * @param {Chart} chart - the chart to use + * @param {LayoutItem} item - the item to add to be laid out + */ + addBox(chart: Chart, item: LayoutItem): void; + + /** + * Remove a layoutItem from a chart + * @param {Chart} chart - the chart to remove the box from + * @param {LayoutItem} layoutItem - the item to remove from the layout + */ + removeBox(chart: Chart, layoutItem: LayoutItem): void; + + /** + * Sets (or updates) options on the given `item`. + * @param {Chart} chart - the chart in which the item lives (or will be added to) + * @param {LayoutItem} item - the item to configure with the given options + * @param options - the new item options. + */ + configure( + chart: Chart, + item: LayoutItem, + options: { fullSize?: number; position?: LayoutPosition; weight?: number } + ): void; + + /** + * Fits boxes of the given chart into the given size by having each box measure itself + * then running a fitting algorithm + * @param {Chart} chart - the chart + * @param {number} width - the width to fit into + * @param {number} height - the height to fit into + */ + update(chart: Chart, width: number, height: number): void; +}; + +export interface Plugin extends ExtendedPlugin { + id: string; + + /** + * @desc Called when plugin is installed for this chart instance. This hook is also invoked for disabled plugins (options === false). + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @since 3.0.0 + */ + install?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called when a plugin is starting. This happens when chart is created or plugin is enabled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @since 3.0.0 + */ + start?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called when a plugin stopping. This happens when chart is destroyed or plugin is disabled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @since 3.0.0 + */ + stop?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before initializing `chart`. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + beforeInit?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called after `chart` has been initialized and before the first update. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterInit?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before updating `chart`. If any plugin returns `false`, the update + * is cancelled (and thus subsequent render(s)) until another `update` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {UpdateMode} args.mode - The update mode + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart update. + */ + beforeUpdate?(chart: Chart, args: { mode: UpdateMode, cancelable: true }, options: O): boolean | void; + /** + * @desc Called after `chart` has been updated and before rendering. Note that this + * hook will not be called if the chart update has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {UpdateMode} args.mode - The update mode + * @param {object} options - The plugin options. + */ + afterUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): void; + /** + * @desc Called during the update process, before any chart elements have been created. + * This can be used for data decimation by changing the data array inside a dataset. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + beforeElementsUpdate?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called during chart reset + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @since version 3.0.0 + */ + reset?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before updating the `chart` datasets. If any plugin returns `false`, + * the datasets update is cancelled until another `update` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {UpdateMode} args.mode - The update mode. + * @param {object} options - The plugin options. + * @returns {boolean} false to cancel the datasets update. + * @since version 2.1.5 + */ + beforeDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): boolean | void; + /** + * @desc Called after the `chart` datasets have been updated. Note that this hook + * will not be called if the datasets update has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {UpdateMode} args.mode - The update mode. + * @param {object} options - The plugin options. + * @since version 2.1.5 + */ + afterDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode, cancelable: true }, options: O): void; + /** + * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin + * returns `false`, the datasets update is cancelled until another `update` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {number} args.index - The dataset index. + * @param {object} args.meta - The dataset metadata. + * @param {UpdateMode} args.mode - The update mode. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart datasets drawing. + */ + beforeDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode, cancelable: true }, options: O): boolean | void; + /** + * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note + * that this hook will not be called if the datasets update has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {number} args.index - The dataset index. + * @param {object} args.meta - The dataset metadata. + * @param {UpdateMode} args.mode - The update mode. + * @param {object} options - The plugin options. + */ + afterDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode, cancelable: false }, options: O): void; + /** + * @desc Called before laying out `chart`. If any plugin returns `false`, + * the layout update is cancelled until another `update` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart layout. + */ + beforeLayout?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; + /** + * @desc Called before scale data limits are calculated. This hook is called separately for each scale in the chart. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Scale} args.scale - The scale. + * @param {object} options - The plugin options. + */ + beforeDataLimits?(chart: Chart, args: { scale: Scale }, options: O): void; + /** + * @desc Called after scale data limits are calculated. This hook is called separately for each scale in the chart. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Scale} args.scale - The scale. + * @param {object} options - The plugin options. + */ + afterDataLimits?(chart: Chart, args: { scale: Scale }, options: O): void; + /** + * @desc Called before scale builds its ticks. This hook is called separately for each scale in the chart. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Scale} args.scale - The scale. + * @param {object} options - The plugin options. + */ + beforeBuildTicks?(chart: Chart, args: { scale: Scale }, options: O): void; + /** + * @desc Called after scale has build its ticks. This hook is called separately for each scale in the chart. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Scale} args.scale - The scale. + * @param {object} options - The plugin options. + */ + afterBuildTicks?(chart: Chart, args: { scale: Scale }, options: O): void; + /** + * @desc Called after the `chart` has been laid out. Note that this hook will not + * be called if the layout update has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterLayout?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before rendering `chart`. If any plugin returns `false`, + * the rendering is cancelled until another `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart rendering. + */ + beforeRender?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; + /** + * @desc Called after the `chart` has been fully rendered (and animation completed). Note + * that this hook will not be called if the rendering has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterRender?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before drawing `chart` at every animation frame. If any plugin returns `false`, + * the frame drawing is cancelled untilanother `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart drawing. + */ + beforeDraw?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; + /** + * @desc Called after the `chart` has been drawn. Note that this hook will not be called + * if the drawing has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterDraw?(chart: Chart, args: EmptyObject, options: O): void; + /** + * @desc Called before drawing the `chart` datasets. If any plugin returns `false`, + * the datasets drawing is cancelled until another `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart datasets drawing. + */ + beforeDatasetsDraw?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; + /** + * @desc Called after the `chart` datasets have been drawn. Note that this hook + * will not be called if the datasets drawing has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterDatasetsDraw?(chart: Chart, args: EmptyObject, options: O, cancelable: false): void; + /** + * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets + * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing + * is cancelled until another `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {number} args.index - The dataset index. + * @param {object} args.meta - The dataset metadata. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart datasets drawing. + */ + beforeDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): boolean | void; + /** + * @desc Called after the `chart` datasets at the given `args.index` have been drawn + * (datasets are drawn in the reverse order). Note that this hook will not be called + * if the datasets drawing has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {number} args.index - The dataset index. + * @param {object} args.meta - The dataset metadata. + * @param {object} options - The plugin options. + */ + afterDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): void; + /** + * @desc Called before processing the specified `event`. If any plugin returns `false`, + * the event will be discarded. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {ChartEvent} args.event - The event object. + * @param {boolean} args.replay - True if this event is replayed from `Chart.update` + * @param {boolean} args.inChartArea - The event position is inside chartArea + * @param {object} options - The plugin options. + */ + beforeEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean, cancelable: true, inChartArea: boolean }, options: O): boolean | void; + /** + * @desc Called after the `event` has been consumed. Note that this hook + * will not be called if the `event` has been previously discarded. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {ChartEvent} args.event - The event object. + * @param {boolean} args.replay - True if this event is replayed from `Chart.update` + * @param {boolean} args.inChartArea - The event position is inside chartArea + * @param {boolean} [args.changed] - Set to true if the plugin needs a render. Should only be changed to true, because this args object is passed through all plugins. + * @param {object} options - The plugin options. + */ + afterEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean, changed?: boolean, cancelable: false, inChartArea: boolean }, options: O): void; + /** + * @desc Called after the chart as been resized. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {number} args.size - The new canvas display size (eq. canvas.style width & height). + * @param {object} options - The plugin options. + */ + resize?(chart: Chart, args: { size: { width: number, height: number } }, options: O): void; + /** + * Called before the chart is being destroyed. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + beforeDestroy?(chart: Chart, args: EmptyObject, options: O): void; + /** + * Called after the chart has been destroyed. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @deprecated since version 3.7.0 in favour of afterDestroy + */ + destroy?(chart: Chart, args: EmptyObject, options: O): void; + /** + * Called after the chart has been destroyed. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + */ + afterDestroy?(chart: Chart, args: EmptyObject, options: O): void; + /** + * Called after chart is destroyed on all plugins that were installed for that chart. This hook is also invoked for disabled plugins (options === false). + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {object} options - The plugin options. + * @since 3.0.0 + */ + uninstall?(chart: Chart, args: EmptyObject, options: O): void; +} + +export declare type ChartComponentLike = ChartComponent | ChartComponent[] | { [key: string]: ChartComponent } | Plugin | Plugin[]; + +/** + * Please use the module's default export which provides a singleton instance + * Note: class is exported for typedoc + */ +export interface Registry { + readonly controllers: TypedRegistry; + readonly elements: TypedRegistry; + readonly plugins: TypedRegistry; + readonly scales: TypedRegistry; + + add(...args: ChartComponentLike[]): void; + remove(...args: ChartComponentLike[]): void; + + addControllers(...args: ChartComponentLike[]): void; + addElements(...args: ChartComponentLike[]): void; + addPlugins(...args: ChartComponentLike[]): void; + addScales(...args: ChartComponentLike[]): void; + + getController(id: string): DatasetController | undefined; + getElement(id: string): Element | undefined; + getPlugin(id: string): Plugin | undefined; + getScale(id: string): Scale | undefined; +} + +export const registry: Registry; + +export interface Tick { + value: number; + label?: string | string[]; + major?: boolean; +} + +export interface CoreScaleOptions { + /** + * Controls the axis global visibility (visible when true, hidden when false). When display: 'auto', the axis is visible only if at least one associated dataset is visible. + * @default true + */ + display: boolean | 'auto'; + /** + * Align pixel values to device pixels + */ + alignToPixels: boolean; + /** + * Reverse the scale. + * @default false + */ + reverse: boolean; + /** + * The weight used to sort the axis. Higher weights are further away from the chart area. + * @default true + */ + weight: number; + /** + * Callback called before the update process starts. + */ + beforeUpdate(axis: Scale): void; + /** + * Callback that runs before dimensions are set. + */ + beforeSetDimensions(axis: Scale): void; + /** + * Callback that runs after dimensions are set. + */ + afterSetDimensions(axis: Scale): void; + /** + * Callback that runs before data limits are determined. + */ + beforeDataLimits(axis: Scale): void; + /** + * Callback that runs after data limits are determined. + */ + afterDataLimits(axis: Scale): void; + /** + * Callback that runs before ticks are created. + */ + beforeBuildTicks(axis: Scale): void; + /** + * Callback that runs after ticks are created. Useful for filtering ticks. + */ + afterBuildTicks(axis: Scale): void; + /** + * Callback that runs before ticks are converted into strings. + */ + beforeTickToLabelConversion(axis: Scale): void; + /** + * Callback that runs after ticks are converted into strings. + */ + afterTickToLabelConversion(axis: Scale): void; + /** + * Callback that runs before tick rotation is determined. + */ + beforeCalculateLabelRotation(axis: Scale): void; + /** + * Callback that runs after tick rotation is determined. + */ + afterCalculateLabelRotation(axis: Scale): void; + /** + * Callback that runs before the scale fits to the canvas. + */ + beforeFit(axis: Scale): void; + /** + * Callback that runs after the scale fits to the canvas. + */ + afterFit(axis: Scale): void; + /** + * Callback that runs at the end of the update process. + */ + afterUpdate(axis: Scale): void; +} + +export interface Scale extends Element, LayoutItem { + readonly id: string; + readonly type: string; + readonly ctx: CanvasRenderingContext2D; + readonly chart: Chart; + + maxWidth: number; + maxHeight: number; + + paddingTop: number; + paddingBottom: number; + paddingLeft: number; + paddingRight: number; + + axis: string; + labelRotation: number; + min: number; + max: number; + ticks: Tick[]; + getMatchingVisibleMetas(type?: string): ChartMeta[]; + + drawTitle(chartArea: ChartArea): void; + drawLabels(chartArea: ChartArea): void; + drawGrid(chartArea: ChartArea): void; + + /** + * @param {number} pixel + * @return {number} + */ + getDecimalForPixel(pixel: number): number; + /** + * Utility for getting the pixel location of a percentage of scale + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @param {number} decimal + * @return {number} + */ + getPixelForDecimal(decimal: number): number; + /** + * Returns the location of the tick at the given index + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @param {number} index + * @return {number} + */ + getPixelForTick(index: number): number; + /** + * Used to get the label to display in the tooltip for the given value + * @param {*} value + * @return {string} + */ + getLabelForValue(value: number): string; + + /** + * Returns the grid line width at given value + */ + getLineWidthForValue(value: number): number; + + /** + * Returns the location of the given data point. Value can either be an index or a numerical value + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @param {*} value + * @param {number} [index] + * @return {number} + */ + getPixelForValue(value: number, index?: number): number; + + /** + * Used to get the data value from a given pixel. This is the inverse of getPixelForValue + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @param {number} pixel + * @return {*} + */ + getValueForPixel(pixel: number): number | undefined; + + getBaseValue(): number; + /** + * Returns the pixel for the minimum chart value + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @return {number} + */ + getBasePixel(): number; + + init(options: O): void; + parse(raw: unknown, index: number): unknown; + getUserBounds(): { min: number; max: number; minDefined: boolean; maxDefined: boolean }; + getMinMax(canStack: boolean): { min: number; max: number }; + getTicks(): Tick[]; + getLabels(): string[]; + beforeUpdate(): void; + configure(): void; + afterUpdate(): void; + beforeSetDimensions(): void; + setDimensions(): void; + afterSetDimensions(): void; + beforeDataLimits(): void; + determineDataLimits(): void; + afterDataLimits(): void; + beforeBuildTicks(): void; + buildTicks(): Tick[]; + afterBuildTicks(): void; + beforeTickToLabelConversion(): void; + generateTickLabels(ticks: Tick[]): void; + afterTickToLabelConversion(): void; + beforeCalculateLabelRotation(): void; + calculateLabelRotation(): void; + afterCalculateLabelRotation(): void; + beforeFit(): void; + fit(): void; + afterFit(): void; + + isFullSize(): boolean; +} +export declare class Scale { + constructor(cfg: {id: string, type: string, ctx: CanvasRenderingContext2D, chart: Chart}); +} + +export interface ScriptableScaleContext { + chart: Chart; + scale: Scale; + index: number; + tick: Tick; +} + +export interface ScriptableScalePointLabelContext { + chart: Chart; + scale: Scale; + index: number; + label: string; +} + + +export const Ticks: { + formatters: { + /** + * Formatter for value labels + * @param value the value to display + * @return {string|string[]} the label to display + */ + values(value: unknown): string | string[]; + /** + * Formatter for numeric ticks + * @param tickValue the value to be formatted + * @param index the position of the tickValue parameter in the ticks array + * @param ticks the list of ticks being converted + * @return string representation of the tickValue parameter + */ + numeric(tickValue: number, index: number, ticks: { value: number }[]): string; + /** + * Formatter for logarithmic ticks + * @param tickValue the value to be formatted + * @param index the position of the tickValue parameter in the ticks array + * @param ticks the list of ticks being converted + * @return string representation of the tickValue parameter + */ + logarithmic(tickValue: number, index: number, ticks: { value: number }[]): string; + }; +}; + +export interface TypedRegistry { + /** + * @param {ChartComponent} item + * @returns {string} The scope where items defaults were registered to. + */ + register(item: ChartComponent): string; + get(id: string): T | undefined; + unregister(item: ChartComponent): void; +} + +export interface ChartEvent { + type: + | 'contextmenu' + | 'mouseenter' + | 'mousedown' + | 'mousemove' + | 'mouseup' + | 'mouseout' + | 'click' + | 'dblclick' + | 'keydown' + | 'keypress' + | 'keyup' + | 'resize'; + native: Event | null; + x: number | null; + y: number | null; +} +export interface ChartComponent { + id: string; + defaults?: AnyObject; + defaultRoutes?: { [property: string]: string }; + + beforeRegister?(): void; + afterRegister?(): void; + beforeUnregister?(): void; + afterUnregister?(): void; +} + +export interface CoreInteractionOptions { + /** + * Sets which elements appear in the tooltip. See Interaction Modes for details. + * @default 'nearest' + */ + mode: InteractionMode; + /** + * if true, the hover mode only applies when the mouse position intersects an item on the chart. + * @default true + */ + intersect: boolean; + + /** + * Can be set to 'x', 'y', 'xy' or 'r' to define which directions are used in calculating distances. Defaults to 'x' for 'index' mode and 'xy' in dataset and 'nearest' modes. + */ + axis: 'x' | 'y' | 'xy' | 'r'; +} + +export interface CoreChartOptions extends ParsingOptions, AnimationOptions { + + datasets: { + [key in ChartType]: ChartTypeRegistry[key]['datasetOptions'] + } + + /** + * The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts. + * @default 'x' + */ + indexAxis: 'x' | 'y'; + + /** + * base color + * @see Defaults.color + */ + color: Scriptable>; + /** + * base background color + * @see Defaults.backgroundColor + */ + backgroundColor: Scriptable>; + /** + * base border color + * @see Defaults.borderColor + */ + borderColor: Scriptable>; + /** + * base font + * @see Defaults.font + */ + font: Partial; + /** + * Resizes the chart canvas when its container does (important note...). + * @default true + */ + responsive: boolean; + /** + * Maintain the original canvas aspect ratio (width / height) when resizing. + * @default true + */ + maintainAspectRatio: boolean; + /** + * Delay the resize update by give amount of milliseconds. This can ease the resize process by debouncing update of the elements. + * @default 0 + */ + resizeDelay: number; + + /** + * Canvas aspect ratio (i.e. width / height, a value of 1 representing a square canvas). Note that this option is ignored if the height is explicitly defined either as attribute or via the style. + * @default 2 + */ + aspectRatio: number; + + /** + * Locale used for number formatting (using `Intl.NumberFormat`). + * @default user's browser setting + */ + locale: string; + + /** + * Called when a resize occurs. Gets passed two arguments: the chart instance and the new size. + */ + onResize(chart: Chart, size: { width: number; height: number }): void; + + /** + * Override the window's default devicePixelRatio. + * @default window.devicePixelRatio + */ + devicePixelRatio: number; + + interaction: CoreInteractionOptions; + + hover: CoreInteractionOptions; + + /** + * The events option defines the browser events that the chart should listen to for tooltips and hovering. + * @default ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'] + */ + events: (keyof HTMLElementEventMap)[] + + /** + * Called when any of the events fire. Passed the event, an array of active elements (bars, points, etc), and the chart. + */ + onHover(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; + + /** + * Called if the event is of type 'mouseup' or 'click'. Passed the event, an array of active elements, and the chart. + */ + onClick(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; + + layout: Partial<{ + autoPadding: boolean; + padding: Scriptable, ScriptableContext>; + }>; +} + +export type EasingFunction = + | 'linear' + | 'easeInQuad' + | 'easeOutQuad' + | 'easeInOutQuad' + | 'easeInCubic' + | 'easeOutCubic' + | 'easeInOutCubic' + | 'easeInQuart' + | 'easeOutQuart' + | 'easeInOutQuart' + | 'easeInQuint' + | 'easeOutQuint' + | 'easeInOutQuint' + | 'easeInSine' + | 'easeOutSine' + | 'easeInOutSine' + | 'easeInExpo' + | 'easeOutExpo' + | 'easeInOutExpo' + | 'easeInCirc' + | 'easeOutCirc' + | 'easeInOutCirc' + | 'easeInElastic' + | 'easeOutElastic' + | 'easeInOutElastic' + | 'easeInBack' + | 'easeOutBack' + | 'easeInOutBack' + | 'easeInBounce' + | 'easeOutBounce' + | 'easeInOutBounce'; + +export type AnimationSpec = { + /** + * The number of milliseconds an animation takes. + * @default 1000 + */ + duration?: Scriptable>; + /** + * Easing function to use + * @default 'easeOutQuart' + */ + easing?: Scriptable>; + + /** + * Delay before starting the animations. + * @default 0 + */ + delay?: Scriptable>; + + /** + * If set to true, the animations loop endlessly. + * @default false + */ + loop?: Scriptable>; +} + +export type AnimationsSpec = { + [name: string]: false | AnimationSpec & { + properties: string[]; + + /** + * Type of property, determines the interpolator used. Possible values: 'number', 'color' and 'boolean'. Only really needed for 'color', because typeof does not get that right. + */ + type: 'color' | 'number' | 'boolean'; + + fn: (from: T, to: T, factor: number) => T; + + /** + * Start value for the animation. Current value is used when undefined + */ + from: Scriptable>; + /** + * + */ + to: Scriptable>; + } +} + +export type TransitionSpec = { + animation: AnimationSpec; + animations: AnimationsSpec; +} + +export type TransitionsSpec = { + [mode: string]: TransitionSpec +} + +export type AnimationOptions = { + animation: false | AnimationSpec & { + /** + * Callback called on each step of an animation. + */ + onProgress?: (this: Chart, event: AnimationEvent) => void; + /** + * Callback called when all animations are completed. + */ + onComplete?: (this: Chart, event: AnimationEvent) => void; + }; + animations: AnimationsSpec; + transitions: TransitionsSpec; +}; + +export interface FontSpec { + /** + * Default font family for all text, follows CSS font-family options. + * @default "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" + */ + family: string; + /** + * Default font size (in px) for text. Does not apply to radialLinear scale point labels. + * @default 12 + */ + size: number; + /** + * Default font style. Does not apply to tooltip title or footer. Does not apply to chart title. Follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit) + * @default 'normal' + */ + style: 'normal' | 'italic' | 'oblique' | 'initial' | 'inherit'; + /** + * Default font weight (boldness). (see MDN). + */ + weight: string | null; + /** + * Height of an individual line of text (see MDN). + * @default 1.2 + */ + lineHeight: number | string; +} + +export type TextAlign = 'left' | 'center' | 'right'; +export type Align = 'start' | 'center' | 'end'; + +export interface VisualElement { + draw(ctx: CanvasRenderingContext2D, area?: ChartArea): void; + inRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean; + inXRange(mouseX: number, useFinalPosition?: boolean): boolean; + inYRange(mouseY: number, useFinalPosition?: boolean): boolean; + getCenterPoint(useFinalPosition?: boolean): { x: number; y: number }; + getRange?(axis: 'x' | 'y'): number; +} + +export interface CommonElementOptions { + borderWidth: number; + borderColor: Color; + backgroundColor: Color; +} + +export interface CommonHoverOptions { + hoverBorderWidth: number; + hoverBorderColor: Color; + hoverBackgroundColor: Color; +} + +export interface Segment { + start: number; + end: number; + loop: boolean; +} + +export interface ArcProps { + x: number; + y: number; + startAngle: number; + endAngle: number; + innerRadius: number; + outerRadius: number; + circumference: number; +} + +export interface ArcBorderRadius { + outerStart: number; + outerEnd: number; + innerStart: number; + innerEnd: number; +} + +export interface ArcOptions extends CommonElementOptions { + /** + * Arc stroke alignment. + */ + borderAlign: 'center' | 'inner'; + + /** + * Line join style. See MDN. Default is 'round' when `borderAlign` is 'inner', else 'bevel'. + */ + borderJoinStyle: CanvasLineJoin; + + /** + * Sets the border radius for arcs + * @default 0 + */ + borderRadius: number | ArcBorderRadius; + + /** + * Arc offset (in pixels). + */ + offset: number; +} + +export interface ArcHoverOptions extends CommonHoverOptions { + hoverOffset: number; +} + +export interface ArcElement + extends Element, + VisualElement {} + +export const ArcElement: ChartComponent & { + prototype: ArcElement; + new (cfg: AnyObject): ArcElement; +}; + +export interface LineProps { + points: Point[] +} + +export interface LineOptions extends CommonElementOptions { + /** + * Line cap style. See MDN. + * @default 'butt' + */ + borderCapStyle: CanvasLineCap; + /** + * Line dash. See MDN. + * @default [] + */ + borderDash: number[]; + /** + * Line dash offset. See MDN. + * @default 0.0 + */ + borderDashOffset: number; + /** + * Line join style. See MDN. + * @default 'miter' + */ + borderJoinStyle: CanvasLineJoin; + /** + * true to keep BΓ©zier control inside the chart, false for no restriction. + * @default true + */ + capBezierPoints: boolean; + /** + * Interpolation mode to apply. + * @default 'default' + */ + cubicInterpolationMode: 'default' | 'monotone'; + /** + * BΓ©zier curve tension (0 for no BΓ©zier curves). + * @default 0 + */ + tension: number; + /** + * true to show the line as a stepped line (tension will be ignored). + * @default false + */ + stepped: 'before' | 'after' | 'middle' | boolean; + /** + * Both line and radar charts support a fill option on the dataset object which can be used to create area between two datasets or a dataset and a boundary, i.e. the scale origin, start or end + */ + fill: FillTarget | ComplexFillTarget; + /** + * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. + */ + spanGaps: boolean | number; + + segment: { + backgroundColor: Scriptable, + borderColor: Scriptable, + borderCapStyle: Scriptable; + borderDash: Scriptable; + borderDashOffset: Scriptable; + borderJoinStyle: Scriptable; + borderWidth: Scriptable; + }; +} + +export interface LineHoverOptions extends CommonHoverOptions { + hoverBorderCapStyle: CanvasLineCap; + hoverBorderDash: number[]; + hoverBorderDashOffset: number; + hoverBorderJoinStyle: CanvasLineJoin; +} + +export interface LineElement + extends Element, + VisualElement { + updateControlPoints(chartArea: ChartArea, indexAxis?: 'x' | 'y'): void; + points: Point[]; + readonly segments: Segment[]; + first(): Point | false; + last(): Point | false; + interpolate(point: Point, property: 'x' | 'y'): undefined | Point | Point[]; + pathSegment(ctx: CanvasRenderingContext2D, segment: Segment, params: AnyObject): undefined | boolean; + path(ctx: CanvasRenderingContext2D): boolean; +} + +export const LineElement: ChartComponent & { + prototype: LineElement; + new (cfg: AnyObject): LineElement; +}; + +export interface PointProps { + x: number; + y: number; +} + +export type PointStyle = + | 'circle' + | 'cross' + | 'crossRot' + | 'dash' + | 'line' + | 'rect' + | 'rectRounded' + | 'rectRot' + | 'star' + | 'triangle' + | HTMLImageElement + | HTMLCanvasElement; + +export interface PointOptions extends CommonElementOptions { + /** + * Point radius + * @default 3 + */ + radius: number; + /** + * Extra radius added to point radius for hit detection. + * @default 1 + */ + hitRadius: number; + /** + * Point style + * @default 'circle; + */ + pointStyle: PointStyle; + /** + * Point rotation (in degrees). + * @default 0 + */ + rotation: number; + /** + * Draw the active elements over the other elements of the dataset, + * @default true + */ + drawActiveElementsOnTop: boolean; +} + +export interface PointHoverOptions extends CommonHoverOptions { + /** + * Point radius when hovered. + * @default 4 + */ + hoverRadius: number; +} + +export interface PointPrefixedOptions { + /** + * The fill color for points. + */ + pointBackgroundColor: Color; + /** + * The border color for points. + */ + pointBorderColor: Color; + /** + * The width of the point border in pixels. + */ + pointBorderWidth: number; + /** + * The pixel size of the non-displayed point that reacts to mouse events. + */ + pointHitRadius: number; + /** + * The radius of the point shape. If set to 0, the point is not rendered. + */ + pointRadius: number; + /** + * The rotation of the point in degrees. + */ + pointRotation: number; + /** + * Style of the point. + */ + pointStyle: PointStyle; +} + +export interface PointPrefixedHoverOptions { + /** + * Point background color when hovered. + */ + pointHoverBackgroundColor: Color; + /** + * Point border color when hovered. + */ + pointHoverBorderColor: Color; + /** + * Border width of point when hovered. + */ + pointHoverBorderWidth: number; + /** + * The radius of the point when hovered. + */ + pointHoverRadius: number; +} + +export interface PointElement + extends Element, + VisualElement { + readonly skip: boolean; + readonly parsed: CartesianParsedData; +} + +export const PointElement: ChartComponent & { + prototype: PointElement; + new (cfg: AnyObject): PointElement; +}; + +export interface BarProps { + x: number; + y: number; + base: number; + horizontal: boolean; + width: number; + height: number; +} + +export interface BarOptions extends Omit { + /** + * The base value for the bar in data units along the value axis. + */ + base: number; + + /** + * Skipped (excluded) border: 'start', 'end', 'left', 'right', 'bottom', 'top' or false (none). + * @default 'start' + */ + borderSkipped: 'start' | 'end' | 'left' | 'right' | 'bottom' | 'top' | false; + + /** + * Border radius + * @default 0 + */ + borderRadius: number | BorderRadius; + + /** + * Amount to inflate the rectangle(s). This can be used to hide artifacts between bars. + * Unit is pixels. 'auto' translates to 0.33 pixels when barPercentage * categoryPercentage is 1, else 0. + * @default 'auto' + */ + inflateAmount: number | 'auto'; + + /** + * Width of the border, number for all sides, object to specify width for each side specifically + * @default 0 + */ + borderWidth: number | { top?: number, right?: number, bottom?: number, left?: number }; +} + +export interface BorderRadius { + topLeft: number; + topRight: number; + bottomLeft: number; + bottomRight: number; +} + +export interface BarHoverOptions extends CommonHoverOptions { + hoverBorderRadius: number | BorderRadius; +} + +export interface BarElement< + T extends BarProps = BarProps, + O extends BarOptions = BarOptions +> extends Element, VisualElement {} + +export const BarElement: ChartComponent & { + prototype: BarElement; + new (cfg: AnyObject): BarElement; +}; + +export interface ElementOptionsByType { + arc: ScriptableAndArrayOptions>; + bar: ScriptableAndArrayOptions>; + line: ScriptableAndArrayOptions>; + point: ScriptableAndArrayOptions>; +} + +export type ElementChartOptions = { + elements: ElementOptionsByType +}; + +export class BasePlatform { + /** + * Called at chart construction time, returns a context2d instance implementing + * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}. + * @param {HTMLCanvasElement} canvas - The canvas from which to acquire context (platform specific) + * @param options - The chart options + */ + acquireContext( + canvas: HTMLCanvasElement, + options?: CanvasRenderingContext2DSettings + ): CanvasRenderingContext2D | null; + /** + * Called at chart destruction time, releases any resources associated to the context + * previously returned by the acquireContext() method. + * @param {CanvasRenderingContext2D} context - The context2d instance + * @returns {boolean} true if the method succeeded, else false + */ + releaseContext(context: CanvasRenderingContext2D): boolean; + /** + * Registers the specified listener on the given chart. + * @param {Chart} chart - Chart from which to listen for event + * @param {string} type - The ({@link ChartEvent}) type to listen for + * @param listener - Receives a notification (an object that implements + * the {@link ChartEvent} interface) when an event of the specified type occurs. + */ + addEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void; + /** + * Removes the specified listener previously registered with addEventListener. + * @param {Chart} chart - Chart from which to remove the listener + * @param {string} type - The ({@link ChartEvent}) type to remove + * @param listener - The listener function to remove from the event target. + */ + removeEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void; + /** + * @returns {number} the current devicePixelRatio of the device this platform is connected to. + */ + getDevicePixelRatio(): number; + /** + * @param {HTMLCanvasElement} canvas - The canvas for which to calculate the maximum size + * @param {number} [width] - Parent element's content width + * @param {number} [height] - Parent element's content height + * @param {number} [aspectRatio] - The aspect ratio to maintain + * @returns { width: number, height: number } the maximum size available. + */ + getMaximumSize(canvas: HTMLCanvasElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number }; + /** + * @param {HTMLCanvasElement} canvas + * @returns {boolean} true if the canvas is attached to the platform, false if not. + */ + isAttached(canvas: HTMLCanvasElement): boolean; + /** + * Updates config with platform specific requirements + * @param {ChartConfiguration} config + */ + updateConfig(config: ChartConfiguration): void; +} + +export class BasicPlatform extends BasePlatform {} +export class DomPlatform extends BasePlatform {} + +export const Decimation: Plugin; + +export const enum DecimationAlgorithm { + lttb = 'lttb', + minmax = 'min-max', +} +interface BaseDecimationOptions { + enabled: boolean; + threshold?: number; +} + +interface LttbDecimationOptions extends BaseDecimationOptions { + algorithm: DecimationAlgorithm.lttb | 'lttb'; + samples?: number; +} + +interface MinMaxDecimationOptions extends BaseDecimationOptions { + algorithm: DecimationAlgorithm.minmax | 'min-max'; +} + +export type DecimationOptions = LttbDecimationOptions | MinMaxDecimationOptions; + +export const Filler: Plugin; +export interface FillerOptions { + drawTime: 'beforeDatasetDraw' | 'beforeDatasetsDraw'; + propagate: boolean; +} + +export type FillTarget = number | string | { value: number } | 'start' | 'end' | 'origin' | 'stack' | 'shape' | boolean; + +export interface ComplexFillTarget { + /** + * The accepted values are the same as the filling mode values, so you may use absolute and relative dataset indexes and/or boundaries. + */ + target: FillTarget; + /** + * If no color is set, the default color will be the background color of the chart. + */ + above: Color; + /** + * Same as the above. + */ + below: Color; +} + +export interface FillerControllerDatasetOptions { + /** + * Both line and radar charts support a fill option on the dataset object which can be used to create area between two datasets or a dataset and a boundary, i.e. the scale origin, start or end + */ + fill: FillTarget | ComplexFillTarget; +} + +export const Legend: Plugin; + +export interface LegendItem { + /** + * Label that will be displayed + */ + text: string; + + /** + * Border radius of the legend box + * @since 3.1.0 + */ + borderRadius?: number | BorderRadius; + + /** + * Index of the associated dataset + */ + datasetIndex: number; + + /** + * Fill style of the legend box + */ + fillStyle?: Color; + + /** + * Font color for the text + * Defaults to LegendOptions.labels.color + */ + fontColor?: Color; + + /** + * If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect + */ + hidden?: boolean; + + /** + * For box border. + * @see https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap + */ + lineCap?: CanvasLineCap; + + /** + * For box border. + * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash + */ + lineDash?: number[]; + + /** + * For box border. + * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset + */ + lineDashOffset?: number; + + /** + * For box border. + * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin + */ + lineJoin?: CanvasLineJoin; + + /** + * Width of box border + */ + lineWidth?: number; + + /** + * Stroke style of the legend box + */ + strokeStyle?: Color; + + /** + * Point style of the legend box (only used if usePointStyle is true) + */ + pointStyle?: PointStyle; + + /** + * Rotation of the point in degrees (only used if usePointStyle is true) + */ + rotation?: number; + + /** + * Text alignment + */ + textAlign?: TextAlign; +} + +export interface LegendElement extends Element>, LayoutItem { + chart: Chart; + ctx: CanvasRenderingContext2D; + legendItems?: LegendItem[]; + options: LegendOptions; +} + +export interface LegendOptions { + /** + * Is the legend shown? + * @default true + */ + display: boolean; + /** + * Position of the legend. + * @default 'top' + */ + position: LayoutPosition; + /** + * Alignment of the legend. + * @default 'center' + */ + align: Align; + /** + * Maximum height of the legend, in pixels + */ + maxHeight: number; + /** + * Maximum width of the legend, in pixels + */ + maxWidth: number; + /** + * Marks that this box should take the full width/height of the canvas (moving other boxes). This is unlikely to need to be changed in day-to-day use. + * @default true + */ + fullSize: boolean; + /** + * Legend will show datasets in reverse order. + * @default false + */ + reverse: boolean; + /** + * A callback that is called when a click event is registered on a label item. + */ + onClick(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; + /** + * A callback that is called when a 'mousemove' event is registered on top of a label item + */ + onHover(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; + /** + * A callback that is called when a 'mousemove' event is registered outside of a previously hovered label item. + */ + onLeave(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; + + labels: { + /** + * Width of colored box. + * @default 40 + */ + boxWidth: number; + /** + * Height of the coloured box. + * @default fontSize + */ + boxHeight: number; + /** + * Padding between the color box and the text + * @default 1 + */ + boxPadding: number; + /** + * Color of label + * @see Defaults.color + */ + color: Color; + /** + * Font of label + * @see Defaults.font + */ + font: FontSpec; + /** + * Padding between rows of colored boxes. + * @default 10 + */ + padding: number; + /** + * Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See Legend Item for details. + */ + generateLabels(chart: Chart): LegendItem[]; + + /** + * Filters legend items out of the legend. Receives 2 parameters, a Legend Item and the chart data + */ + filter(item: LegendItem, data: ChartData): boolean; + + /** + * Sorts the legend items + */ + sort(a: LegendItem, b: LegendItem, data: ChartData): number; + + /** + * Override point style for the legend. Only applies if usePointStyle is true + */ + pointStyle: PointStyle; + + /** + * Text alignment + */ + textAlign?: TextAlign; + + /** + * Label style will match corresponding point style (size is based on the minimum value between boxWidth and font.size). + * @default false + */ + usePointStyle: boolean; + }; + /** + * true for rendering the legends from right to left. + */ + rtl: boolean; + /** + * This will force the text direction 'rtl' or 'ltr' on the canvas for rendering the legend, regardless of the css specified on the canvas + * @default canvas' default + */ + textDirection: string; + + title: { + /** + * Is the legend title displayed. + * @default false + */ + display: boolean; + /** + * Color of title + * @see Defaults.color + */ + color: Color; + /** + * see Fonts + */ + font: FontSpec; + position: 'center' | 'start' | 'end'; + padding?: number | ChartArea; + /** + * The string title. + */ + text: string; + }; +} + +export const SubTitle: Plugin; +export const Title: Plugin; + +export interface TitleOptions { + /** + * Alignment of the title. + * @default 'center' + */ + align: Align; + /** + * Is the title shown? + * @default false + */ + display: boolean; + /** + * Position of title + * @default 'top' + */ + position: 'top' | 'left' | 'bottom' | 'right'; + /** + * Color of text + * @see Defaults.color + */ + color: Color; + font: FontSpec; + + /** + * Marks that this box should take the full width/height of the canvas (moving other boxes). If set to `false`, places the box above/beside the + * chart area + * @default true + */ + fullSize: boolean; + /** + * Adds padding above and below the title text if a single number is specified. It is also possible to change top and bottom padding separately. + */ + padding: number | { top: number; bottom: number }; + /** + * Title text to display. If specified as an array, text is rendered on multiple lines. + */ + text: string | string[]; +} + +export type TooltipXAlignment = 'left' | 'center' | 'right'; +export type TooltipYAlignment = 'top' | 'center' | 'bottom'; +export interface TooltipLabelStyle { + borderColor: Color; + backgroundColor: Color; + + /** + * Width of border line + * @since 3.1.0 + */ + borderWidth?: number; + + /** + * Border dash + * @since 3.1.0 + */ + borderDash?: [number, number]; + + /** + * Border dash offset + * @since 3.1.0 + */ + borderDashOffset?: number; + + /** + * borderRadius + * @since 3.1.0 + */ + borderRadius?: number | BorderRadius; +} +export interface TooltipModel extends Element> { + readonly chart: Chart; + + // The items that we are rendering in the tooltip. See Tooltip Item Interface section + dataPoints: TooltipItem[]; + + // Positioning + xAlign: TooltipXAlignment; + yAlign: TooltipYAlignment; + + // X and Y properties are the top left of the tooltip + x: number; + y: number; + width: number; + height: number; + // Where the tooltip points to + caretX: number; + caretY: number; + + // Body + // The body lines that need to be rendered + // Each object contains 3 parameters + // before: string[] // lines of text before the line with the color square + // lines: string[]; // lines of text to render as the main item with color square + // after: string[]; // lines of text to render after the main lines + body: { before: string[]; lines: string[]; after: string[] }[]; + // lines of text that appear after the title but before the body + beforeBody: string[]; + // line of text that appear after the body and before the footer + afterBody: string[]; + + // Title + // lines of text that form the title + title: string[]; + + // Footer + // lines of text that form the footer + footer: string[]; + + // Styles to render for each item in body[]. This is the styling of the squares in the tooltip + labelColors: TooltipLabelStyle[]; + labelTextColors: Color[]; + labelPointStyles: { pointStyle: PointStyle; rotation: number }[]; + + // 0 opacity is a hidden tooltip + opacity: number; + + // tooltip options + options: TooltipOptions; + + getActiveElements(): ActiveElement[]; + setActiveElements(active: ActiveDataPoint[], eventPosition: Point): void; +} + +export interface TooltipPosition { + x: number; + y: number; + xAlign?: TooltipXAlignment; + yAlign?: TooltipYAlignment; +} + +export type TooltipPositionerFunction = ( + this: TooltipModel, + items: readonly ActiveElement[], + eventPosition: Point +) => TooltipPosition | false; + +export interface TooltipPositionerMap { + average: TooltipPositionerFunction; + nearest: TooltipPositionerFunction; +} + +export type TooltipPositioner = keyof TooltipPositionerMap; + +export interface Tooltip extends Plugin { + readonly positioners: TooltipPositionerMap; +} + +export const Tooltip: Tooltip; + +export interface TooltipCallbacks< + TType extends ChartType, + Model = TooltipModel, + Item = TooltipItem> { + + beforeTitle(this: Model, tooltipItems: Item[]): string | string[]; + title(this: Model, tooltipItems: Item[]): string | string[]; + afterTitle(this: Model, tooltipItems: Item[]): string | string[]; + + beforeBody(this: Model, tooltipItems: Item[]): string | string[]; + afterBody(this: Model, tooltipItems: Item[]): string | string[]; + + beforeLabel(this: Model, tooltipItem: Item): string | string[]; + label(this: Model, tooltipItem: Item): string | string[]; + afterLabel(this: Model, tooltipItem: Item): string | string[]; + + labelColor(this: Model, tooltipItem: Item): TooltipLabelStyle; + labelTextColor(this: Model, tooltipItem: Item): Color; + labelPointStyle(this: Model, tooltipItem: Item): { pointStyle: PointStyle; rotation: number }; + + beforeFooter(this: Model, tooltipItems: Item[]): string | string[]; + footer(this: Model, tooltipItems: Item[]): string | string[]; + afterFooter(this: Model, tooltipItems: Item[]): string | string[]; +} + +export interface ExtendedPlugin< + TType extends ChartType, + O = AnyObject, + Model = TooltipModel> { + /** + * @desc Called before drawing the `tooltip`. If any plugin returns `false`, + * the tooltip drawing is cancelled until another `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Tooltip} args.tooltip - The tooltip. + * @param {object} options - The plugin options. + * @returns {boolean} `false` to cancel the chart tooltip drawing. + */ + beforeTooltipDraw?(chart: Chart, args: { tooltip: Model }, options: O): boolean | void; + /** + * @desc Called after drawing the `tooltip`. Note that this hook will not + * be called if the tooltip drawing has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {object} args - The call arguments. + * @param {Tooltip} args.tooltip - The tooltip. + * @param {object} options - The plugin options. + */ + afterTooltipDraw?(chart: Chart, args: { tooltip: Model }, options: O): void; +} + +export interface ScriptableTooltipContext { + chart: UnionToIntersection>; + tooltip: UnionToIntersection>; + tooltipItems: TooltipItem[]; +} + +export interface TooltipOptions extends CoreInteractionOptions { + /** + * Are on-canvas tooltips enabled? + * @default true + */ + enabled: Scriptable>; + /** + * See external tooltip section. + */ + external(this: TooltipModel, args: { chart: Chart; tooltip: TooltipModel }): void; + /** + * The mode for positioning the tooltip + */ + position: Scriptable> + + /** + * Override the tooltip alignment calculations + */ + xAlign: Scriptable>; + yAlign: Scriptable>; + + /** + * Sort tooltip items. + */ + itemSort: (a: TooltipItem, b: TooltipItem, data: ChartData) => number; + + filter: (e: TooltipItem, index: number, array: TooltipItem[], data: ChartData) => boolean; + + /** + * Background color of the tooltip. + * @default 'rgba(0, 0, 0, 0.8)' + */ + backgroundColor: Scriptable>; + /** + * Padding between the color box and the text. + * @default 1 + */ + boxPadding: number; + /** + * Color of title + * @default '#fff' + */ + titleColor: Scriptable>; + /** + * See Fonts + * @default {weight: 'bold'} + */ + titleFont: Scriptable>; + /** + * Spacing to add to top and bottom of each title line. + * @default 2 + */ + titleSpacing: Scriptable>; + /** + * Margin to add on bottom of title section. + * @default 6 + */ + titleMarginBottom: Scriptable>; + /** + * Horizontal alignment of the title text lines. + * @default 'left' + */ + titleAlign: Scriptable>; + /** + * Spacing to add to top and bottom of each tooltip item. + * @default 2 + */ + bodySpacing: Scriptable>; + /** + * Color of body + * @default '#fff' + */ + bodyColor: Scriptable>; + /** + * See Fonts. + * @default {} + */ + bodyFont: Scriptable>; + /** + * Horizontal alignment of the body text lines. + * @default 'left' + */ + bodyAlign: Scriptable>; + /** + * Spacing to add to top and bottom of each footer line. + * @default 2 + */ + footerSpacing: Scriptable>; + /** + * Margin to add before drawing the footer. + * @default 6 + */ + footerMarginTop: Scriptable>; + /** + * Color of footer + * @default '#fff' + */ + footerColor: Scriptable>; + /** + * See Fonts + * @default {weight: 'bold'} + */ + footerFont: Scriptable>; + /** + * Horizontal alignment of the footer text lines. + * @default 'left' + */ + footerAlign: Scriptable>; + /** + * Padding to add to the tooltip + * @default 6 + */ + padding: Scriptable>; + /** + * Extra distance to move the end of the tooltip arrow away from the tooltip point. + * @default 2 + */ + caretPadding: Scriptable>; + /** + * Size, in px, of the tooltip arrow. + * @default 5 + */ + caretSize: Scriptable>; + /** + * Radius of tooltip corner curves. + * @default 6 + */ + cornerRadius: Scriptable>; + /** + * Color to draw behind the colored boxes when multiple items are in the tooltip. + * @default '#fff' + */ + multiKeyBackground: Scriptable>; + /** + * If true, color boxes are shown in the tooltip. + * @default true + */ + displayColors: Scriptable>; + /** + * Width of the color box if displayColors is true. + * @default bodyFont.size + */ + boxWidth: Scriptable>; + /** + * Height of the color box if displayColors is true. + * @default bodyFont.size + */ + boxHeight: Scriptable>; + /** + * Use the corresponding point style (from dataset options) instead of color boxes, ex: star, triangle etc. (size is based on the minimum value between boxWidth and boxHeight) + * @default false + */ + usePointStyle: Scriptable>; + /** + * Color of the border. + * @default 'rgba(0, 0, 0, 0)' + */ + borderColor: Scriptable>; + /** + * Size of the border. + * @default 0 + */ + borderWidth: Scriptable>; + /** + * true for rendering the legends from right to left. + */ + rtl: Scriptable>; + + /** + * This will force the text direction 'rtl' or 'ltr on the canvas for rendering the tooltips, regardless of the css specified on the canvas + * @default canvas's default + */ + textDirection: Scriptable>; + + animation: AnimationSpec; + animations: AnimationsSpec; + callbacks: TooltipCallbacks; +} + +export interface TooltipItem { + /** + * The chart the tooltip is being shown on + */ + chart: Chart; + + /** + * Label for the tooltip + */ + label: string; + + /** + * Parsed data values for the given `dataIndex` and `datasetIndex` + */ + parsed: UnionToIntersection>; + + /** + * Raw data values for the given `dataIndex` and `datasetIndex` + */ + raw: unknown; + + /** + * Formatted value for the tooltip + */ + formattedValue: string; + + /** + * The dataset the item comes from + */ + dataset: UnionToIntersection>; + + /** + * Index of the dataset the item comes from + */ + datasetIndex: number; + + /** + * Index of this data item in the dataset + */ + dataIndex: number; + + /** + * The chart element (point, arc, bar, etc.) for this tooltip item + */ + element: Element; +} + +export interface PluginOptionsByType { + decimation: DecimationOptions; + filler: FillerOptions; + legend: LegendOptions; + subtitle: TitleOptions; + title: TitleOptions; + tooltip: TooltipOptions; +} +export interface PluginChartOptions { + plugins: PluginOptionsByType; +} + +export interface GridLineOptions { + /** + * @default true + */ + display: boolean; + borderColor: Color; + borderWidth: number; + /** + * @default false + */ + circular: boolean; + /** + * @default 'rgba(0, 0, 0, 0.1)' + */ + color: ScriptableAndArray; + /** + * @default [] + */ + borderDash: number[]; + /** + * @default 0 + */ + borderDashOffset: Scriptable; + /** + * @default 1 + */ + lineWidth: ScriptableAndArray; + + /** + * @default true + */ + drawBorder: boolean; + /** + * @default true + */ + drawOnChartArea: boolean; + /** + * @default true + */ + drawTicks: boolean; + /** + * @default [] + */ + tickBorderDash: number[]; + /** + * @default 0 + */ + tickBorderDashOffset: Scriptable; + /** + * @default 'rgba(0, 0, 0, 0.1)' + */ + tickColor: ScriptableAndArray; + /** + * @default 10 + */ + tickLength: number; + /** + * @default 1 + */ + tickWidth: number; + /** + * @default false + */ + offset: boolean; + /** + * @default 0 + */ + z: number; +} + +export interface TickOptions { + /** + * Color of label backdrops. + * @default 'rgba(255, 255, 255, 0.75)' + */ + backdropColor: Scriptable; + /** + * Padding of tick backdrop. + * @default 2 + */ + backdropPadding: number | ChartArea; + + /** + * Returns the string representation of the tick value as it should be displayed on the chart. See callback. + */ + callback: (this: Scale, tickValue: number | string, index: number, ticks: Tick[]) => string | string[] | number | number[] | null | undefined; + /** + * If true, show tick labels. + * @default true + */ + display: boolean; + /** + * Color of tick + * @see Defaults.color + */ + color: ScriptableAndArray; + /** + * see Fonts + */ + font: Scriptable; + /** + * Sets the offset of the tick labels from the axis + */ + padding: number; + /** + * If true, draw a background behind the tick labels. + * @default false + */ + showLabelBackdrop: Scriptable; + /** + * The color of the stroke around the text. + * @default undefined + */ + textStrokeColor: Scriptable; + /** + * Stroke width around the text. + * @default 0 + */ + textStrokeWidth: Scriptable; + /** + * z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top. + * @default 0 + */ + z: number; + + major: { + /** + * If true, major ticks are generated. A major tick will affect autoskipping and major will be defined on ticks in the scriptable options context. + * @default false + */ + enabled: boolean; + }; +} + +export interface CartesianScaleOptions extends CoreScaleOptions { + /** + * Scale boundary strategy (bypassed by min/max time options) + * - `data`: make sure data are fully visible, ticks outside are removed + * - `ticks`: make sure ticks are fully visible, data outside are truncated + * @since 2.7.0 + * @default 'ticks' + */ + bounds: 'ticks' | 'data'; + + /** + * Position of the axis. + */ + position: 'left' | 'top' | 'right' | 'bottom' | 'center' | { [scale: string]: number }; + + /** + * Stack group. Axes at the same `position` with same `stack` are stacked. + */ + stack?: string; + + /** + * Weight of the scale in stack group. Used to determine the amount of allocated space for the scale within the group. + * @default 1 + */ + stackWeight?: number; + + /** + * Which type of axis this is. Possible values are: 'x', 'y'. If not set, this is inferred from the first character of the ID which should be 'x' or 'y'. + */ + axis: 'x' | 'y'; + + /** + * User defined minimum value for the scale, overrides minimum value from data. + */ + min: number; + + /** + * User defined maximum value for the scale, overrides maximum value from data. + */ + max: number; + + /** + * If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to true for a bar chart by default. + * @default false + */ + offset: boolean; + + grid: GridLineOptions; + + /** Options for the scale title. */ + title: { + /** If true, displays the axis title. */ + display: boolean; + /** Alignment of the axis title. */ + align: Align; + /** The text for the title, e.g. "# of People" or "Response Choices". */ + text: string | string[]; + /** Color of the axis label. */ + color: Color; + /** Information about the axis title font. */ + font: FontSpec; + /** Padding to apply around scale labels. */ + padding: number | { + /** Padding on the (relative) top side of this axis label. */ + top: number; + /** Padding on the (relative) bottom side of this axis label. */ + bottom: number; + /** This is a shorthand for defining top/bottom to the same values. */ + y: number; + }; + }; + + /** + * If true, data will be comprised between datasets of data + * @default false + */ + stacked?: boolean | 'single'; + + ticks: TickOptions & { + /** + * The number of ticks to examine when deciding how many labels will fit. Setting a smaller value will be faster, but may be less accurate when there is large variability in label length. + * @default ticks.length + */ + sampleSize: number; + /** + * The label alignment + * @default 'center' + */ + align: Align; + /** + * If true, automatically calculates how many labels can be shown and hides labels accordingly. Labels will be rotated up to maxRotation before skipping any. Turn autoSkip off to show all labels no matter what. + * @default true + */ + autoSkip: boolean; + /** + * Padding between the ticks on the horizontal axis when autoSkip is enabled. + * @default 0 + */ + autoSkipPadding: number; + + /** + * How is the label positioned perpendicular to the axis direction. + * This only applies when the rotation is 0 and the axis position is one of "top", "left", "right", or "bottom" + * @default 'near' + */ + crossAlign: 'near' | 'center' | 'far'; + + /** + * Should the defined `min` and `max` values be presented as ticks even if they are not "nice". + * @default: true + */ + includeBounds: boolean; + + /** + * Distance in pixels to offset the label from the centre point of the tick (in the x direction for the x axis, and the y direction for the y axis). Note: this can cause labels at the edges to be cropped by the edge of the canvas + * @default 0 + */ + labelOffset: number; + + /** + * Minimum rotation for tick labels. Note: Only applicable to horizontal scales. + * @default 0 + */ + minRotation: number; + /** + * Maximum rotation for tick labels when rotating to condense labels. Note: Rotation doesn't occur until necessary. Note: Only applicable to horizontal scales. + * @default 50 + */ + maxRotation: number; + /** + * Flips tick labels around axis, displaying the labels inside the chart instead of outside. Note: Only applicable to vertical scales. + * @default false + */ + mirror: boolean; + /** + * Padding between the tick label and the axis. When set on a vertical axis, this applies in the horizontal (X) direction. When set on a horizontal axis, this applies in the vertical (Y) direction. + * @default 0 + */ + padding: number; + /** + * Maximum number of ticks and gridlines to show. + * @default 11 + */ + maxTicksLimit: number; + }; +} + +export type CategoryScaleOptions = Omit & { + min: string | number; + max: string | number; + labels: string[] | string[][]; +}; + +export type CategoryScale = Scale +export const CategoryScale: ChartComponent & { + prototype: CategoryScale; + new (cfg: AnyObject): CategoryScale; +}; + +export type LinearScaleOptions = CartesianScaleOptions & { + + /** + * if true, scale will include 0 if it is not already included. + * @default true + */ + beginAtZero: boolean; + /** + * Adjustment used when calculating the maximum data value. + */ + suggestedMin?: number; + /** + * Adjustment used when calculating the minimum data value. + */ + suggestedMax?: number; + /** + * Percentage (string ending with %) or amount (number) for added room in the scale range above and below data. + */ + grace?: string | number; + + ticks: { + /** + * The Intl.NumberFormat options used by the default label formatter + */ + format: Intl.NumberFormatOptions; + + /** + * if defined and stepSize is not specified, the step size will be rounded to this many decimal places. + */ + precision: number; + + /** + * User defined fixed step size for the scale + */ + stepSize: number; + + /** + * User defined count of ticks + */ + count: number; + }; +}; + +export type LinearScale = Scale +export const LinearScale: ChartComponent & { + prototype: LinearScale; + new (cfg: AnyObject): LinearScale; +}; + +export type LogarithmicScaleOptions = CartesianScaleOptions & { + /** + * Adjustment used when calculating the maximum data value. + */ + suggestedMin?: number; + /** + * Adjustment used when calculating the minimum data value. + */ + suggestedMax?: number; + + ticks: { + /** + * The Intl.NumberFormat options used by the default label formatter + */ + format: Intl.NumberFormatOptions; + }; +}; + +export type LogarithmicScale = Scale +export const LogarithmicScale: ChartComponent & { + prototype: LogarithmicScale; + new (cfg: AnyObject): LogarithmicScale; +}; + +export type TimeScaleOptions = Omit & { + min: string | number; + max: string | number; + suggestedMin: string | number; + suggestedMax: string | number; + /** + * Scale boundary strategy (bypassed by min/max time options) + * - `data`: make sure data are fully visible, ticks outside are removed + * - `ticks`: make sure ticks are fully visible, data outside are truncated + * @since 2.7.0 + * @default 'data' + */ + bounds: 'ticks' | 'data'; + + /** + * options for creating a new adapter instance + */ + adapters: { + date: unknown; + }; + + time: { + /** + * Custom parser for dates. + */ + parser: string | ((v: unknown) => number); + /** + * If defined, dates will be rounded to the start of this unit. See Time Units below for the allowed units. + */ + round: false | TimeUnit; + /** + * If boolean and true and the unit is set to 'week', then the first day of the week will be Monday. Otherwise, it will be Sunday. + * If `number`, the index of the first day of the week (0 - Sunday, 6 - Saturday). + * @default false + */ + isoWeekday: boolean | number; + /** + * Sets how different time units are displayed. + */ + displayFormats: { + [key: string]: string; + }; + /** + * The format string to use for the tooltip. + */ + tooltipFormat: string; + /** + * If defined, will force the unit to be a certain type. See Time Units section below for details. + * @default false + */ + unit: false | TimeUnit; + + /** + * The number of units between grid lines. + * @default 1 + */ + stepSize: number; + /** + * The minimum display format to be used for a time unit. + * @default 'millisecond' + */ + minUnit: TimeUnit; + }; + + ticks: { + /** + * Ticks generation input values: + * - 'auto': generates "optimal" ticks based on scale size and time options. + * - 'data': generates ticks from data (including labels from data {t|x|y} objects). + * - 'labels': generates ticks from user given `data.labels` values ONLY. + * @see https://github.com/chartjs/Chart.js/pull/4507 + * @since 2.7.0 + * @default 'auto' + */ + source: 'labels' | 'auto' | 'data'; + }; +}; + +export interface TimeScale extends Scale { + getDataTimestamps(): number[]; + getLabelTimestamps(): string[]; + normalize(values: number[]): number[]; +} + +export const TimeScale: ChartComponent & { + prototype: TimeScale; + new (cfg: AnyObject): TimeScale; +}; + +export type TimeSeriesScale = TimeScale +export const TimeSeriesScale: ChartComponent & { + prototype: TimeSeriesScale; + new (cfg: AnyObject): TimeSeriesScale; +}; + +export type RadialLinearScaleOptions = CoreScaleOptions & { + animate: boolean; + + angleLines: { + /** + * if true, angle lines are shown. + * @default true + */ + display: boolean; + /** + * Color of angled lines. + * @default 'rgba(0, 0, 0, 0.1)' + */ + color: Scriptable; + /** + * Width of angled lines. + * @default 1 + */ + lineWidth: Scriptable; + /** + * Length and spacing of dashes on angled lines. See MDN. + * @default [] + */ + borderDash: Scriptable; + /** + * Offset for line dashes. See MDN. + * @default 0 + */ + borderDashOffset: Scriptable; + }; + + /** + * if true, scale will include 0 if it is not already included. + * @default false + */ + beginAtZero: boolean; + + grid: GridLineOptions; + + /** + * User defined minimum number for the scale, overrides minimum value from data. + */ + min: number; + /** + * User defined maximum number for the scale, overrides maximum value from data. + */ + max: number; + + pointLabels: { + /** + * Background color of the point label. + * @default undefined + */ + backdropColor: Scriptable; + /** + * Padding of label backdrop. + * @default 2 + */ + backdropPadding: Scriptable; + + /** + * if true, point labels are shown. + * @default true + */ + display: boolean; + /** + * Color of label + * @see Defaults.color + */ + color: Scriptable; + /** + */ + font: Scriptable; + + /** + * Callback function to transform data labels to point labels. The default implementation simply returns the current string. + */ + callback: (label: string, index: number) => string | string[] | number | number[]; + + /** + * if true, point labels are centered. + * @default false + */ + centerPointLabels: boolean; + }; + + /** + * Adjustment used when calculating the maximum data value. + */ + suggestedMax: number; + /** + * Adjustment used when calculating the minimum data value. + */ + suggestedMin: number; + + ticks: TickOptions & { + /** + * The Intl.NumberFormat options used by the default label formatter + */ + format: Intl.NumberFormatOptions; + + /** + * Maximum number of ticks and gridlines to show. + * @default 11 + */ + maxTicksLimit: number; + + /** + * if defined and stepSize is not specified, the step size will be rounded to this many decimal places. + */ + precision: number; + + /** + * User defined fixed step size for the scale. + */ + stepSize: number; + + /** + * User defined number of ticks + */ + count: number; + }; +}; + +export interface RadialLinearScale extends Scale { + setCenterPoint(leftMovement: number, rightMovement: number, topMovement: number, bottomMovement: number): void; + getIndexAngle(index: number): number; + getDistanceFromCenterForValue(value: number): number; + getValueForDistanceFromCenter(distance: number): number; + getPointPosition(index: number, distanceFromCenter: number): { x: number; y: number; angle: number }; + getPointPositionForValue(index: number, value: number): { x: number; y: number; angle: number }; + getPointLabelPosition(index: number): ChartArea; + getBasePosition(index: number): { x: number; y: number; angle: number }; +} +export const RadialLinearScale: ChartComponent & { + prototype: RadialLinearScale; + new (cfg: AnyObject): RadialLinearScale; +}; + +export interface CartesianScaleTypeRegistry { + linear: { + options: LinearScaleOptions; + }; + logarithmic: { + options: LogarithmicScaleOptions; + }; + category: { + options: CategoryScaleOptions; + }; + time: { + options: TimeScaleOptions; + }; + timeseries: { + options: TimeScaleOptions; + }; +} + +export interface RadialScaleTypeRegistry { + radialLinear: { + options: RadialLinearScaleOptions; + }; +} + +export interface ScaleTypeRegistry extends CartesianScaleTypeRegistry, RadialScaleTypeRegistry { +} + +export type ScaleType = keyof ScaleTypeRegistry; + +interface CartesianParsedData { + x: number; + y: number; + + // Only specified when stacked bars are enabled + _stacks?: { + // Key is the stack ID which is generally the axis ID + [key: string]: { + // Inner key is the datasetIndex + [key: number]: number; + } + } +} + +interface BarParsedData extends CartesianParsedData { + // Only specified if floating bars are show + _custom?: { + barStart: number; + barEnd: number; + start: number; + end: number; + min: number; + max: number; + } +} + +interface BubbleParsedData extends CartesianParsedData { + // The bubble radius value + _custom: number; +} + +interface RadialParsedData { + r: number; +} + +export interface ChartTypeRegistry { + bar: { + chartOptions: BarControllerChartOptions; + datasetOptions: BarControllerDatasetOptions; + defaultDataPoint: number; + metaExtensions: {}; + parsedDataType: BarParsedData, + scales: keyof CartesianScaleTypeRegistry; + }; + line: { + chartOptions: LineControllerChartOptions; + datasetOptions: LineControllerDatasetOptions & FillerControllerDatasetOptions; + defaultDataPoint: ScatterDataPoint | number | null; + metaExtensions: {}; + parsedDataType: CartesianParsedData; + scales: keyof CartesianScaleTypeRegistry; + }; + scatter: { + chartOptions: ScatterControllerChartOptions; + datasetOptions: ScatterControllerDatasetOptions; + defaultDataPoint: ScatterDataPoint | number | null; + metaExtensions: {}; + parsedDataType: CartesianParsedData; + scales: keyof CartesianScaleTypeRegistry; + }; + bubble: { + chartOptions: unknown; + datasetOptions: BubbleControllerDatasetOptions; + defaultDataPoint: BubbleDataPoint; + metaExtensions: {}; + parsedDataType: BubbleParsedData; + scales: keyof CartesianScaleTypeRegistry; + }; + pie: { + chartOptions: PieControllerChartOptions; + datasetOptions: PieControllerDatasetOptions; + defaultDataPoint: PieDataPoint; + metaExtensions: PieMetaExtensions; + parsedDataType: number; + scales: keyof CartesianScaleTypeRegistry; + }; + doughnut: { + chartOptions: DoughnutControllerChartOptions; + datasetOptions: DoughnutControllerDatasetOptions; + defaultDataPoint: DoughnutDataPoint; + metaExtensions: DoughnutMetaExtensions; + parsedDataType: number; + scales: keyof CartesianScaleTypeRegistry; + }; + polarArea: { + chartOptions: PolarAreaControllerChartOptions; + datasetOptions: PolarAreaControllerDatasetOptions; + defaultDataPoint: number; + metaExtensions: {}; + parsedDataType: RadialParsedData; + scales: keyof RadialScaleTypeRegistry; + }; + radar: { + chartOptions: RadarControllerChartOptions; + datasetOptions: RadarControllerDatasetOptions & FillerControllerDatasetOptions; + defaultDataPoint: number | null; + metaExtensions: {}; + parsedDataType: RadialParsedData; + scales: keyof RadialScaleTypeRegistry; + }; +} + +export type ChartType = keyof ChartTypeRegistry; + +export type ScaleOptionsByType = + { [key in ScaleType]: { type: key } & ScaleTypeRegistry[key]['options'] }[TScale] +; + +// Convenience alias for creating and manipulating scale options in user code +export type ScaleOptions = DeepPartial>; + +export type DatasetChartOptions = { + [key in TType]: { + datasets: ChartTypeRegistry[key]['datasetOptions']; + }; +}; + +export type ScaleChartOptions = { + scales: { + [key: string]: ScaleOptionsByType; + }; +}; + +export type ChartOptions = DeepPartial< +CoreChartOptions & +ElementChartOptions & +PluginChartOptions & +DatasetChartOptions & +ScaleChartOptions & +ChartTypeRegistry[TType]['chartOptions'] +>; + +export type DefaultDataPoint = DistributiveArray; + +export type ParsedDataType = ChartTypeRegistry[TType]['parsedDataType']; + +export interface ChartDatasetProperties { + type?: TType; + data: TData; +} + +export type ChartDataset< + TType extends ChartType = ChartType, + TData = DefaultDataPoint +> = DeepPartial< +{ [key in ChartType]: { type: key } & ChartTypeRegistry[key]['datasetOptions'] }[TType] +> & ChartDatasetProperties; + +/** + * TData represents the data point type. If unspecified, a default is provided + * based on the chart type. + * TLabel represents the label type + */ +export interface ChartData< + TType extends ChartType = ChartType, + TData = DefaultDataPoint, + TLabel = unknown +> { + labels?: TLabel[]; + datasets: ChartDataset[]; +} + +export interface ChartConfiguration< + TType extends ChartType = ChartType, + TData = DefaultDataPoint, + TLabel = unknown +> { + type: TType; + data: ChartData; + options?: ChartOptions; + plugins?: Plugin[]; +} diff --git a/node_modules/chart.js/types/layout.d.ts b/node_modules/chart.js/types/layout.d.ts new file mode 100644 index 00000000..4c770711 --- /dev/null +++ b/node_modules/chart.js/types/layout.d.ts @@ -0,0 +1,65 @@ +import { ChartArea } from './geometric'; + +export type LayoutPosition = 'left' | 'top' | 'right' | 'bottom' | 'center' | 'chartArea' | {[scaleId: string]: number}; + +export interface LayoutItem { + /** + * The position of the item in the chart layout. Possible values are + */ + position: LayoutPosition; + /** + * The weight used to sort the item. Higher weights are further away from the chart area + */ + weight: number; + /** + * if true, and the item is horizontal, then push vertical boxes down + */ + fullSize: boolean; + /** + * Width of item. Must be valid after update() + */ + width: number; + /** + * Height of item. Must be valid after update() + */ + height: number; + /** + * Left edge of the item. Set by layout system and cannot be used in update + */ + left: number; + /** + * Top edge of the item. Set by layout system and cannot be used in update + */ + top: number; + /** + * Right edge of the item. Set by layout system and cannot be used in update + */ + right: number; + /** + * Bottom edge of the item. Set by layout system and cannot be used in update + */ + bottom: number; + + /** + * Called before the layout process starts + */ + beforeLayout?(): void; + /** + * Draws the element + */ + draw(chartArea: ChartArea): void; + /** + * Returns an object with padding on the edges + */ + getPadding?(): ChartArea; + /** + * returns true if the layout item is horizontal (ie. top or bottom) + */ + isHorizontal(): boolean; + /** + * Takes two parameters: width and height. + * @param width + * @param height + */ + update(width: number, height: number, margins?: ChartArea): void; +} diff --git a/node_modules/chart.js/types/utils.d.ts b/node_modules/chart.js/types/utils.d.ts new file mode 100644 index 00000000..8313d9fa --- /dev/null +++ b/node_modules/chart.js/types/utils.d.ts @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/ban-types */ + +// DeepPartial implementation taken from the utility-types NPM package, which is +// Copyright (c) 2016 Piotr Witek (http://piotrwitek.github.io) +// and used under the terms of the MIT license +export type DeepPartial = T extends Function + ? T + : T extends Array + ? _DeepPartialArray + : T extends object + ? _DeepPartialObject + : T | undefined; + +type _DeepPartialArray = Array> +type _DeepPartialObject = { [P in keyof T]?: DeepPartial }; + +export type DistributiveArray = [T] extends [unknown] ? Array : never + +// https://stackoverflow.com/a/50375286 +export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..8627f416 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "project-github-tracker", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "chart.js": "^3.7.1" + } + }, + "node_modules/chart.js": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", + "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" + } + }, + "dependencies": { + "chart.js": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", + "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..832728d9 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "chart.js": "^3.7.1" + } +} From 89e9e119f99bcd60dd32bab19a135efd08a6682e Mon Sep 17 00:00:00 2001 From: idanaslund Date: Wed, 23 Feb 2022 15:49:22 +0100 Subject: [PATCH 07/28] removed node, fetched profile and sorted repos --- code/.gitignore => .gitignore | 2 +- code/script.js | 51 +- code/style.css | 11 +- node_modules/.package-lock.json | 12 - node_modules/chart.js/LICENSE.md | 9 - node_modules/chart.js/README.md | 38 - node_modules/chart.js/auto/auto.esm.d.ts | 4 - node_modules/chart.js/auto/auto.esm.js | 5 - node_modules/chart.js/auto/auto.js | 1 - node_modules/chart.js/auto/package.json | 8 - node_modules/chart.js/dist/chart.esm.js | 10627 ------------- node_modules/chart.js/dist/chart.js | 13269 ---------------- node_modules/chart.js/dist/chart.min.js | 13 - .../chart.js/dist/chunks/helpers.segment.js | 2503 --- node_modules/chart.js/dist/helpers.esm.js | 7 - .../chart.js/helpers/helpers.esm.d.ts | 1 - node_modules/chart.js/helpers/helpers.esm.js | 1 - node_modules/chart.js/helpers/helpers.js | 1 - node_modules/chart.js/helpers/package.json | 8 - node_modules/chart.js/package.json | 111 - node_modules/chart.js/types/adapters.d.ts | 63 - node_modules/chart.js/types/animation.d.ts | 33 - node_modules/chart.js/types/basic.d.ts | 3 - node_modules/chart.js/types/color.d.ts | 1 - node_modules/chart.js/types/element.d.ts | 17 - node_modules/chart.js/types/geometric.d.ts | 37 - .../types/helpers/helpers.canvas.d.ts | 101 - .../types/helpers/helpers.collection.d.ts | 20 - .../chart.js/types/helpers/helpers.color.d.ts | 33 - .../chart.js/types/helpers/helpers.core.d.ts | 157 - .../chart.js/types/helpers/helpers.curve.d.ts | 34 - .../chart.js/types/helpers/helpers.dom.d.ts | 20 - .../types/helpers/helpers.easing.d.ts | 5 - .../types/helpers/helpers.extras.d.ts | 23 - .../types/helpers/helpers.interpolation.d.ts | 1 - .../chart.js/types/helpers/helpers.intl.d.ts | 7 - .../chart.js/types/helpers/helpers.math.d.ts | 17 - .../types/helpers/helpers.options.d.ts | 61 - .../chart.js/types/helpers/helpers.rtl.d.ts | 12 - .../types/helpers/helpers.segment.d.ts | 1 - .../chart.js/types/helpers/index.d.ts | 15 - node_modules/chart.js/types/index.esm.d.ts | 3601 ----- node_modules/chart.js/types/layout.d.ts | 65 - node_modules/chart.js/types/utils.d.ts | 21 - package-lock.json | 24 - package.json | 5 - 46 files changed, 40 insertions(+), 31019 deletions(-) rename code/.gitignore => .gitignore (72%) delete mode 100644 node_modules/.package-lock.json delete mode 100644 node_modules/chart.js/LICENSE.md delete mode 100644 node_modules/chart.js/README.md delete mode 100644 node_modules/chart.js/auto/auto.esm.d.ts delete mode 100644 node_modules/chart.js/auto/auto.esm.js delete mode 100644 node_modules/chart.js/auto/auto.js delete mode 100644 node_modules/chart.js/auto/package.json delete mode 100644 node_modules/chart.js/dist/chart.esm.js delete mode 100644 node_modules/chart.js/dist/chart.js delete mode 100644 node_modules/chart.js/dist/chart.min.js delete mode 100644 node_modules/chart.js/dist/chunks/helpers.segment.js delete mode 100644 node_modules/chart.js/dist/helpers.esm.js delete mode 100644 node_modules/chart.js/helpers/helpers.esm.d.ts delete mode 100644 node_modules/chart.js/helpers/helpers.esm.js delete mode 100644 node_modules/chart.js/helpers/helpers.js delete mode 100644 node_modules/chart.js/helpers/package.json delete mode 100644 node_modules/chart.js/package.json delete mode 100644 node_modules/chart.js/types/adapters.d.ts delete mode 100644 node_modules/chart.js/types/animation.d.ts delete mode 100644 node_modules/chart.js/types/basic.d.ts delete mode 100644 node_modules/chart.js/types/color.d.ts delete mode 100644 node_modules/chart.js/types/element.d.ts delete mode 100644 node_modules/chart.js/types/geometric.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.canvas.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.collection.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.color.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.core.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.curve.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.dom.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.easing.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.extras.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.interpolation.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.intl.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.math.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.options.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.rtl.d.ts delete mode 100644 node_modules/chart.js/types/helpers/helpers.segment.d.ts delete mode 100644 node_modules/chart.js/types/helpers/index.d.ts delete mode 100644 node_modules/chart.js/types/index.esm.d.ts delete mode 100644 node_modules/chart.js/types/layout.d.ts delete mode 100644 node_modules/chart.js/types/utils.d.ts delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/code/.gitignore b/.gitignore similarity index 72% rename from code/.gitignore rename to .gitignore index 6994c809..3b56b9b4 100644 --- a/code/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ #All files that should be hidden: -token.js \ No newline at end of file +code/token.js \ No newline at end of file diff --git a/code/script.js b/code/script.js index 300b6e03..233e3f72 100644 --- a/code/script.js +++ b/code/script.js @@ -1,50 +1,57 @@ // DOM selectors const projects = document.getElementById('projects') const username = 'idanaslund' - - -//const API_TOKEN = TOKEN OR process.env.API_KEY -//console.log(TOKEN) +const profile = document.getElementById('profile') let API_URL = `https://api.github.com/users/${username}/repos` + //Get the token here!! -//const options = { - // method: 'GET', - // headers: { - //Authorization: `token ${API_TOKEN}` - //} -//} +const options = { + method: 'GET', + headers: { + Authorization: `token ${API_TOKEN}` + } +} const addingProfile = () => { - profile.innerHTML += `Username: ${username}` + fetch(`https://api.github.com/users/${username}`, options) + .then((res) => res.json()) + .then((profileInfo) => { + console.log (profileInfo) + profile.innerHTML += ` + + ${profileInfo.login}` + }) } addingProfile() const findingAllRepos = () => { -fetch(API_URL) +fetch(API_URL, options) .then((res) => res.json()) .then((repos) => { console.log(repos) + console.log(API_TOKEN) - - repos.forEach((repo) => { + const forkedRepos = repos.filter( + repo => repo.fork && repo.name.startsWith('project-') + ) + + forkedRepos.forEach((repo) => { projects.innerHTML += `

${repo.name}

`}) }) //How to get the reponame here? - let API_URL_PR = `https://api.github.com/repos/Technigo/${reponame}/pulls` + //let API_URL_PR = `https://api.github.com/repos/Technigo/${reponame}/pulls` - fetch(API_URL_PR) - .then((res) => res.json()) - .then((pulls) => { - console.log(pulls) + // fetch(API_URL_PR) + // .then((res) => res.json()) + // .then((pulls) => { + // console.log(pulls) - }) - -} + } findingAllRepos() diff --git a/code/style.css b/code/style.css index 1e652f06..e49d95e5 100644 --- a/code/style.css +++ b/code/style.css @@ -29,6 +29,11 @@ h1 { } +.profile img { + border-radius: 50%; + height: 20vh; +} + .projects { display: flex; flex-direction: row; @@ -46,4 +51,8 @@ h1 { -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -} \ No newline at end of file +} + +/*@media (min-width: 668px) and (max-width: 1024px) + +@media (min-width: 1025px) */ \ No newline at end of file diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json deleted file mode 100644 index 28bd1f48..00000000 --- a/node_modules/.package-lock.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "project-github-tracker", - "lockfileVersion": 2, - "requires": true, - "packages": { - "node_modules/chart.js": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", - "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" - } - } -} diff --git a/node_modules/chart.js/LICENSE.md b/node_modules/chart.js/LICENSE.md deleted file mode 100644 index 5060fabc..00000000 --- a/node_modules/chart.js/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2021 Chart.js Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/chart.js/README.md b/node_modules/chart.js/README.md deleted file mode 100644 index f485b4eb..00000000 --- a/node_modules/chart.js/README.md +++ /dev/null @@ -1,38 +0,0 @@ -

- - https://www.chartjs.org/
-
- Simple yet flexible JavaScript charting for designers & developers -

- -

- Downloads - GitHub Workflow Status - Coverage - Awesome - Slack -

- -## Documentation - -All the links point to the new version 3 of the lib. - -* [Introduction](https://www.chartjs.org/docs/latest/) -* [Getting Started](https://www.chartjs.org/docs/latest/getting-started/index) -* [General](https://www.chartjs.org/docs/latest/general/data-structures) -* [Configuration](https://www.chartjs.org/docs/latest/configuration/index) -* [Charts](https://www.chartjs.org/docs/latest/charts/line) -* [Axes](https://www.chartjs.org/docs/latest/axes/index) -* [Developers](https://www.chartjs.org/docs/latest/developers/index) -* [Popular Extensions](https://github.com/chartjs/awesome) -* [Samples](https://www.chartjs.org/samples/) - -In case you are looking for the docs of version 2, you will have to specify the specific version in the url like this: [https://www.chartjs.org/docs/2.9.4/](https://www.chartjs.org/docs/2.9.4/) - -## Contributing - -Instructions on building and testing Chart.js can be found in [the documentation](https://www.chartjs.org/docs/master/developers/contributing.html#building-and-testing). Before submitting an issue or a pull request, please take a moment to look over the [contributing guidelines](https://www.chartjs.org/docs/master/developers/contributing) first. For support, please post questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/chartjs) with the `chartjs` tag. - -## License - -Chart.js is available under the [MIT license](LICENSE.md). diff --git a/node_modules/chart.js/auto/auto.esm.d.ts b/node_modules/chart.js/auto/auto.esm.d.ts deleted file mode 100644 index f0bc3805..00000000 --- a/node_modules/chart.js/auto/auto.esm.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Chart } from '../types/index.esm'; - -export * from '../types/index.esm'; -export default Chart; diff --git a/node_modules/chart.js/auto/auto.esm.js b/node_modules/chart.js/auto/auto.esm.js deleted file mode 100644 index 42626764..00000000 --- a/node_modules/chart.js/auto/auto.esm.js +++ /dev/null @@ -1,5 +0,0 @@ -import {Chart, registerables} from '../dist/chart.esm'; - -Chart.register(...registerables); - -export default Chart; diff --git a/node_modules/chart.js/auto/auto.js b/node_modules/chart.js/auto/auto.js deleted file mode 100644 index 235580fe..00000000 --- a/node_modules/chart.js/auto/auto.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../dist/chart'); diff --git a/node_modules/chart.js/auto/package.json b/node_modules/chart.js/auto/package.json deleted file mode 100644 index c2ad5b2c..00000000 --- a/node_modules/chart.js/auto/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "chart.js-auto", - "private": true, - "description": "auto registering package", - "main": "auto.js", - "module": "auto.esm.js", - "types": "auto.esm.d.ts" -} diff --git a/node_modules/chart.js/dist/chart.esm.js b/node_modules/chart.js/dist/chart.esm.js deleted file mode 100644 index 2306fa88..00000000 --- a/node_modules/chart.js/dist/chart.esm.js +++ /dev/null @@ -1,10627 +0,0 @@ -/*! - * Chart.js v3.7.1 - * https://www.chartjs.org - * (c) 2022 Chart.js Contributors - * Released under the MIT License - */ -import { r as requestAnimFrame, a as resolve, e as effects, c as color, d as defaults, i as isObject, b as isArray, v as valueOrDefault, u as unlistenArrayEvents, l as listenArrayEvents, f as resolveObjectKey, g as isNumberFinite, h as createContext, j as defined, s as sign, k as isNullOrUndef, _ as _arrayUnique, t as toRadians, m as toPercentage, n as toDimension, T as TAU, o as formatNumber, p as _angleBetween, H as HALF_PI, P as PI, q as isNumber, w as _limitValue, x as _lookupByKey, y as getRelativePosition$1, z as _isPointInArea, A as _rlookupByKey, B as getAngleFromPoint, C as toPadding, D as each, E as getMaximumSize, F as _getParentNode, G as readUsedSize, I as throttled, J as supportsEventListenerOptions, K as _isDomSupported, L as log10, M as _factorize, N as finiteOrDefault, O as callback, Q as _addGrace, R as toDegrees, S as _measureText, U as _int16Range, V as _alignPixel, W as clipArea, X as renderText, Y as unclipArea, Z as toFont, $ as _toLeftRightCenter, a0 as _alignStartEnd, a1 as overrides, a2 as merge, a3 as _capitalize, a4 as descriptors, a5 as isFunction, a6 as _attachContext, a7 as _createResolver, a8 as _descriptors, a9 as mergeIf, aa as uid, ab as debounce, ac as retinaScale, ad as clearCanvas, ae as setsEqual, af as _elementsEqual, ag as _isClickEvent, ah as _isBetween, ai as _readValueToProps, aj as _updateBezierControlPoints, ak as _computeSegments, al as _boundSegments, am as _steppedInterpolation, an as _bezierInterpolation, ao as _pointInLine, ap as _steppedLineTo, aq as _bezierCurveTo, ar as drawPoint, as as addRoundedRectPath, at as toTRBL, au as toTRBLCorners, av as _boundSegment, aw as _normalizeAngle, ax as getRtlAdapter, ay as overrideTextDirection, az as _textX, aA as restoreTextDirection, aB as noop, aC as distanceBetweenPoints, aD as _setMinAndMaxByKey, aE as niceNum, aF as almostWhole, aG as almostEquals, aH as _decimalPlaces, aI as _longestText, aJ as _filterBetween, aK as _lookup } from './chunks/helpers.segment.js'; -export { d as defaults } from './chunks/helpers.segment.js'; - -class Animator { - constructor() { - this._request = null; - this._charts = new Map(); - this._running = false; - this._lastDate = undefined; - } - _notify(chart, anims, date, type) { - const callbacks = anims.listeners[type]; - const numSteps = anims.duration; - callbacks.forEach(fn => fn({ - chart, - initial: anims.initial, - numSteps, - currentStep: Math.min(date - anims.start, numSteps) - })); - } - _refresh() { - if (this._request) { - return; - } - this._running = true; - this._request = requestAnimFrame.call(window, () => { - this._update(); - this._request = null; - if (this._running) { - this._refresh(); - } - }); - } - _update(date = Date.now()) { - let remaining = 0; - this._charts.forEach((anims, chart) => { - if (!anims.running || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - let draw = false; - let item; - for (; i >= 0; --i) { - item = items[i]; - if (item._active) { - if (item._total > anims.duration) { - anims.duration = item._total; - } - item.tick(date); - draw = true; - } else { - items[i] = items[items.length - 1]; - items.pop(); - } - } - if (draw) { - chart.draw(); - this._notify(chart, anims, date, 'progress'); - } - if (!items.length) { - anims.running = false; - this._notify(chart, anims, date, 'complete'); - anims.initial = false; - } - remaining += items.length; - }); - this._lastDate = date; - if (remaining === 0) { - this._running = false; - } - } - _getAnims(chart) { - const charts = this._charts; - let anims = charts.get(chart); - if (!anims) { - anims = { - running: false, - initial: true, - items: [], - listeners: { - complete: [], - progress: [] - } - }; - charts.set(chart, anims); - } - return anims; - } - listen(chart, event, cb) { - this._getAnims(chart).listeners[event].push(cb); - } - add(chart, items) { - if (!items || !items.length) { - return; - } - this._getAnims(chart).items.push(...items); - } - has(chart) { - return this._getAnims(chart).items.length > 0; - } - start(chart) { - const anims = this._charts.get(chart); - if (!anims) { - return; - } - anims.running = true; - anims.start = Date.now(); - anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); - this._refresh(); - } - running(chart) { - if (!this._running) { - return false; - } - const anims = this._charts.get(chart); - if (!anims || !anims.running || !anims.items.length) { - return false; - } - return true; - } - stop(chart) { - const anims = this._charts.get(chart); - if (!anims || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - for (; i >= 0; --i) { - items[i].cancel(); - } - anims.items = []; - this._notify(chart, anims, Date.now(), 'complete'); - } - remove(chart) { - return this._charts.delete(chart); - } -} -var animator = new Animator(); - -const transparent = 'transparent'; -const interpolators = { - boolean(from, to, factor) { - return factor > 0.5 ? to : from; - }, - color(from, to, factor) { - const c0 = color(from || transparent); - const c1 = c0.valid && color(to || transparent); - return c1 && c1.valid - ? c1.mix(c0, factor).hexString() - : to; - }, - number(from, to, factor) { - return from + (to - from) * factor; - } -}; -class Animation { - constructor(cfg, target, prop, to) { - const currentValue = target[prop]; - to = resolve([cfg.to, to, currentValue, cfg.from]); - const from = resolve([cfg.from, currentValue, to]); - this._active = true; - this._fn = cfg.fn || interpolators[cfg.type || typeof from]; - this._easing = effects[cfg.easing] || effects.linear; - this._start = Math.floor(Date.now() + (cfg.delay || 0)); - this._duration = this._total = Math.floor(cfg.duration); - this._loop = !!cfg.loop; - this._target = target; - this._prop = prop; - this._from = from; - this._to = to; - this._promises = undefined; - } - active() { - return this._active; - } - update(cfg, to, date) { - if (this._active) { - this._notify(false); - const currentValue = this._target[this._prop]; - const elapsed = date - this._start; - const remain = this._duration - elapsed; - this._start = date; - this._duration = Math.floor(Math.max(remain, cfg.duration)); - this._total += elapsed; - this._loop = !!cfg.loop; - this._to = resolve([cfg.to, to, currentValue, cfg.from]); - this._from = resolve([cfg.from, currentValue, to]); - } - } - cancel() { - if (this._active) { - this.tick(Date.now()); - this._active = false; - this._notify(false); - } - } - tick(date) { - const elapsed = date - this._start; - const duration = this._duration; - const prop = this._prop; - const from = this._from; - const loop = this._loop; - const to = this._to; - let factor; - this._active = from !== to && (loop || (elapsed < duration)); - if (!this._active) { - this._target[prop] = to; - this._notify(true); - return; - } - if (elapsed < 0) { - this._target[prop] = from; - return; - } - factor = (elapsed / duration) % 2; - factor = loop && factor > 1 ? 2 - factor : factor; - factor = this._easing(Math.min(1, Math.max(0, factor))); - this._target[prop] = this._fn(from, to, factor); - } - wait() { - const promises = this._promises || (this._promises = []); - return new Promise((res, rej) => { - promises.push({res, rej}); - }); - } - _notify(resolved) { - const method = resolved ? 'res' : 'rej'; - const promises = this._promises || []; - for (let i = 0; i < promises.length; i++) { - promises[i][method](); - } - } -} - -const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; -const colors = ['color', 'borderColor', 'backgroundColor']; -defaults.set('animation', { - delay: undefined, - duration: 1000, - easing: 'easeOutQuart', - fn: undefined, - from: undefined, - loop: undefined, - to: undefined, - type: undefined, -}); -const animationOptions = Object.keys(defaults.animation); -defaults.describe('animation', { - _fallback: false, - _indexable: false, - _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn', -}); -defaults.set('animations', { - colors: { - type: 'color', - properties: colors - }, - numbers: { - type: 'number', - properties: numbers - }, -}); -defaults.describe('animations', { - _fallback: 'animation', -}); -defaults.set('transitions', { - active: { - animation: { - duration: 400 - } - }, - resize: { - animation: { - duration: 0 - } - }, - show: { - animations: { - colors: { - from: 'transparent' - }, - visible: { - type: 'boolean', - duration: 0 - }, - } - }, - hide: { - animations: { - colors: { - to: 'transparent' - }, - visible: { - type: 'boolean', - easing: 'linear', - fn: v => v | 0 - }, - } - } -}); -class Animations { - constructor(chart, config) { - this._chart = chart; - this._properties = new Map(); - this.configure(config); - } - configure(config) { - if (!isObject(config)) { - return; - } - const animatedProps = this._properties; - Object.getOwnPropertyNames(config).forEach(key => { - const cfg = config[key]; - if (!isObject(cfg)) { - return; - } - const resolved = {}; - for (const option of animationOptions) { - resolved[option] = cfg[option]; - } - (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => { - if (prop === key || !animatedProps.has(prop)) { - animatedProps.set(prop, resolved); - } - }); - }); - } - _animateOptions(target, values) { - const newOptions = values.options; - const options = resolveTargetOptions(target, newOptions); - if (!options) { - return []; - } - const animations = this._createAnimations(options, newOptions); - if (newOptions.$shared) { - awaitAll(target.options.$animations, newOptions).then(() => { - target.options = newOptions; - }, () => { - }); - } - return animations; - } - _createAnimations(target, values) { - const animatedProps = this._properties; - const animations = []; - const running = target.$animations || (target.$animations = {}); - const props = Object.keys(values); - const date = Date.now(); - let i; - for (i = props.length - 1; i >= 0; --i) { - const prop = props[i]; - if (prop.charAt(0) === '$') { - continue; - } - if (prop === 'options') { - animations.push(...this._animateOptions(target, values)); - continue; - } - const value = values[prop]; - let animation = running[prop]; - const cfg = animatedProps.get(prop); - if (animation) { - if (cfg && animation.active()) { - animation.update(cfg, value, date); - continue; - } else { - animation.cancel(); - } - } - if (!cfg || !cfg.duration) { - target[prop] = value; - continue; - } - running[prop] = animation = new Animation(cfg, target, prop, value); - animations.push(animation); - } - return animations; - } - update(target, values) { - if (this._properties.size === 0) { - Object.assign(target, values); - return; - } - const animations = this._createAnimations(target, values); - if (animations.length) { - animator.add(this._chart, animations); - return true; - } - } -} -function awaitAll(animations, properties) { - const running = []; - const keys = Object.keys(properties); - for (let i = 0; i < keys.length; i++) { - const anim = animations[keys[i]]; - if (anim && anim.active()) { - running.push(anim.wait()); - } - } - return Promise.all(running); -} -function resolveTargetOptions(target, newOptions) { - if (!newOptions) { - return; - } - let options = target.options; - if (!options) { - target.options = newOptions; - return; - } - if (options.$shared) { - target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); - } - return options; -} - -function scaleClip(scale, allowedOverflow) { - const opts = scale && scale.options || {}; - const reverse = opts.reverse; - const min = opts.min === undefined ? allowedOverflow : 0; - const max = opts.max === undefined ? allowedOverflow : 0; - return { - start: reverse ? max : min, - end: reverse ? min : max - }; -} -function defaultClip(xScale, yScale, allowedOverflow) { - if (allowedOverflow === false) { - return false; - } - const x = scaleClip(xScale, allowedOverflow); - const y = scaleClip(yScale, allowedOverflow); - return { - top: y.end, - right: x.end, - bottom: y.start, - left: x.start - }; -} -function toClip(value) { - let t, r, b, l; - if (isObject(value)) { - t = value.top; - r = value.right; - b = value.bottom; - l = value.left; - } else { - t = r = b = l = value; - } - return { - top: t, - right: r, - bottom: b, - left: l, - disabled: value === false - }; -} -function getSortedDatasetIndices(chart, filterVisible) { - const keys = []; - const metasets = chart._getSortedDatasetMetas(filterVisible); - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - keys.push(metasets[i].index); - } - return keys; -} -function applyStack(stack, value, dsIndex, options = {}) { - const keys = stack.keys; - const singleMode = options.mode === 'single'; - let i, ilen, datasetIndex, otherValue; - if (value === null) { - return; - } - for (i = 0, ilen = keys.length; i < ilen; ++i) { - datasetIndex = +keys[i]; - if (datasetIndex === dsIndex) { - if (options.all) { - continue; - } - break; - } - otherValue = stack.values[datasetIndex]; - if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) { - value += otherValue; - } - } - return value; -} -function convertObjectDataToArray(data) { - const keys = Object.keys(data); - const adata = new Array(keys.length); - let i, ilen, key; - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - adata[i] = { - x: key, - y: data[key] - }; - } - return adata; -} -function isStacked(scale, meta) { - const stacked = scale && scale.options.stacked; - return stacked || (stacked === undefined && meta.stack !== undefined); -} -function getStackKey(indexScale, valueScale, meta) { - return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; -} -function getUserBounds(scale) { - const {min, max, minDefined, maxDefined} = scale.getUserBounds(); - return { - min: minDefined ? min : Number.NEGATIVE_INFINITY, - max: maxDefined ? max : Number.POSITIVE_INFINITY - }; -} -function getOrCreateStack(stacks, stackKey, indexValue) { - const subStack = stacks[stackKey] || (stacks[stackKey] = {}); - return subStack[indexValue] || (subStack[indexValue] = {}); -} -function getLastIndexInStack(stack, vScale, positive, type) { - for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) { - const value = stack[meta.index]; - if ((positive && value > 0) || (!positive && value < 0)) { - return meta.index; - } - } - return null; -} -function updateStacks(controller, parsed) { - const {chart, _cachedMeta: meta} = controller; - const stacks = chart._stacks || (chart._stacks = {}); - const {iScale, vScale, index: datasetIndex} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const key = getStackKey(iScale, vScale, meta); - const ilen = parsed.length; - let stack; - for (let i = 0; i < ilen; ++i) { - const item = parsed[i]; - const {[iAxis]: index, [vAxis]: value} = item; - const itemStacks = item._stacks || (item._stacks = {}); - stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); - stack[datasetIndex] = value; - stack._top = getLastIndexInStack(stack, vScale, true, meta.type); - stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); - } -} -function getFirstScaleId(chart, axis) { - const scales = chart.scales; - return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); -} -function createDatasetContext(parent, index) { - return createContext(parent, - { - active: false, - dataset: undefined, - datasetIndex: index, - index, - mode: 'default', - type: 'dataset' - } - ); -} -function createDataContext(parent, index, element) { - return createContext(parent, { - active: false, - dataIndex: index, - parsed: undefined, - raw: undefined, - element, - index, - mode: 'default', - type: 'data' - }); -} -function clearStacks(meta, items) { - const datasetIndex = meta.controller.index; - const axis = meta.vScale && meta.vScale.axis; - if (!axis) { - return; - } - items = items || meta._parsed; - for (const parsed of items) { - const stacks = parsed._stacks; - if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { - return; - } - delete stacks[axis][datasetIndex]; - } -} -const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none'; -const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached); -const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked - && {keys: getSortedDatasetIndices(chart, true), values: null}; -class DatasetController { - constructor(chart, datasetIndex) { - this.chart = chart; - this._ctx = chart.ctx; - this.index = datasetIndex; - this._cachedDataOpts = {}; - this._cachedMeta = this.getMeta(); - this._type = this._cachedMeta.type; - this.options = undefined; - this._parsing = false; - this._data = undefined; - this._objectData = undefined; - this._sharedOptions = undefined; - this._drawStart = undefined; - this._drawCount = undefined; - this.enableOptionSharing = false; - this.$context = undefined; - this._syncList = []; - this.initialize(); - } - initialize() { - const meta = this._cachedMeta; - this.configure(); - this.linkScales(); - meta._stacked = isStacked(meta.vScale, meta); - this.addElements(); - } - updateIndex(datasetIndex) { - if (this.index !== datasetIndex) { - clearStacks(this._cachedMeta); - } - this.index = datasetIndex; - } - linkScales() { - const chart = this.chart; - const meta = this._cachedMeta; - const dataset = this.getDataset(); - const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; - const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); - const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); - const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); - const indexAxis = meta.indexAxis; - const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); - const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); - meta.xScale = this.getScaleForId(xid); - meta.yScale = this.getScaleForId(yid); - meta.rScale = this.getScaleForId(rid); - meta.iScale = this.getScaleForId(iid); - meta.vScale = this.getScaleForId(vid); - } - getDataset() { - return this.chart.data.datasets[this.index]; - } - getMeta() { - return this.chart.getDatasetMeta(this.index); - } - getScaleForId(scaleID) { - return this.chart.scales[scaleID]; - } - _getOtherScale(scale) { - const meta = this._cachedMeta; - return scale === meta.iScale - ? meta.vScale - : meta.iScale; - } - reset() { - this._update('reset'); - } - _destroy() { - const meta = this._cachedMeta; - if (this._data) { - unlistenArrayEvents(this._data, this); - } - if (meta._stacked) { - clearStacks(meta); - } - } - _dataCheck() { - const dataset = this.getDataset(); - const data = dataset.data || (dataset.data = []); - const _data = this._data; - if (isObject(data)) { - this._data = convertObjectDataToArray(data); - } else if (_data !== data) { - if (_data) { - unlistenArrayEvents(_data, this); - const meta = this._cachedMeta; - clearStacks(meta); - meta._parsed = []; - } - if (data && Object.isExtensible(data)) { - listenArrayEvents(data, this); - } - this._syncList = []; - this._data = data; - } - } - addElements() { - const meta = this._cachedMeta; - this._dataCheck(); - if (this.datasetElementType) { - meta.dataset = new this.datasetElementType(); - } - } - buildOrUpdateElements(resetNewElements) { - const meta = this._cachedMeta; - const dataset = this.getDataset(); - let stackChanged = false; - this._dataCheck(); - const oldStacked = meta._stacked; - meta._stacked = isStacked(meta.vScale, meta); - if (meta.stack !== dataset.stack) { - stackChanged = true; - clearStacks(meta); - meta.stack = dataset.stack; - } - this._resyncElements(resetNewElements); - if (stackChanged || oldStacked !== meta._stacked) { - updateStacks(this, meta._parsed); - } - } - configure() { - const config = this.chart.config; - const scopeKeys = config.datasetScopeKeys(this._type); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); - this.options = config.createResolver(scopes, this.getContext()); - this._parsing = this.options.parsing; - this._cachedDataOpts = {}; - } - parse(start, count) { - const {_cachedMeta: meta, _data: data} = this; - const {iScale, _stacked} = meta; - const iAxis = iScale.axis; - let sorted = start === 0 && count === data.length ? true : meta._sorted; - let prev = start > 0 && meta._parsed[start - 1]; - let i, cur, parsed; - if (this._parsing === false) { - meta._parsed = data; - meta._sorted = true; - parsed = data; - } else { - if (isArray(data[start])) { - parsed = this.parseArrayData(meta, data, start, count); - } else if (isObject(data[start])) { - parsed = this.parseObjectData(meta, data, start, count); - } else { - parsed = this.parsePrimitiveData(meta, data, start, count); - } - const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]); - for (i = 0; i < count; ++i) { - meta._parsed[i + start] = cur = parsed[i]; - if (sorted) { - if (isNotInOrderComparedToPrev()) { - sorted = false; - } - prev = cur; - } - } - meta._sorted = sorted; - } - if (_stacked) { - updateStacks(this, parsed); - } - } - parsePrimitiveData(meta, data, start, count) { - const {iScale, vScale} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = new Array(count); - let i, ilen, index; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - parsed[i] = { - [iAxis]: singleScale || iScale.parse(labels[index], index), - [vAxis]: vScale.parse(data[index], index) - }; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const {xScale, yScale} = meta; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(item[0], index), - y: yScale.parse(item[1], index) - }; - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const {xScale, yScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(resolveObjectKey(item, xAxisKey), index), - y: yScale.parse(resolveObjectKey(item, yAxisKey), index) - }; - } - return parsed; - } - getParsed(index) { - return this._cachedMeta._parsed[index]; - } - getDataElement(index) { - return this._cachedMeta.data[index]; - } - applyStack(scale, parsed, mode) { - const chart = this.chart; - const meta = this._cachedMeta; - const value = parsed[scale.axis]; - const stack = { - keys: getSortedDatasetIndices(chart, true), - values: parsed._stacks[scale.axis] - }; - return applyStack(stack, value, meta.index, {mode}); - } - updateRangeFromParsed(range, scale, parsed, stack) { - const parsedValue = parsed[scale.axis]; - let value = parsedValue === null ? NaN : parsedValue; - const values = stack && parsed._stacks[scale.axis]; - if (stack && values) { - stack.values = values; - value = applyStack(stack, parsedValue, this._cachedMeta.index); - } - range.min = Math.min(range.min, value); - range.max = Math.max(range.max, value); - } - getMinMax(scale, canStack) { - const meta = this._cachedMeta; - const _parsed = meta._parsed; - const sorted = meta._sorted && scale === meta.iScale; - const ilen = _parsed.length; - const otherScale = this._getOtherScale(scale); - const stack = createStack(canStack, meta, this.chart); - const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; - const {min: otherMin, max: otherMax} = getUserBounds(otherScale); - let i, parsed; - function _skip() { - parsed = _parsed[i]; - const otherValue = parsed[otherScale.axis]; - return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; - } - for (i = 0; i < ilen; ++i) { - if (_skip()) { - continue; - } - this.updateRangeFromParsed(range, scale, parsed, stack); - if (sorted) { - break; - } - } - if (sorted) { - for (i = ilen - 1; i >= 0; --i) { - if (_skip()) { - continue; - } - this.updateRangeFromParsed(range, scale, parsed, stack); - break; - } - } - return range; - } - getAllParsedValues(scale) { - const parsed = this._cachedMeta._parsed; - const values = []; - let i, ilen, value; - for (i = 0, ilen = parsed.length; i < ilen; ++i) { - value = parsed[i][scale.axis]; - if (isNumberFinite(value)) { - values.push(value); - } - } - return values; - } - getMaxOverflow() { - return false; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const vScale = meta.vScale; - const parsed = this.getParsed(index); - return { - label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', - value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' - }; - } - _update(mode) { - const meta = this._cachedMeta; - this.update(mode || 'default'); - meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); - } - update(mode) {} - draw() { - const ctx = this._ctx; - const chart = this.chart; - const meta = this._cachedMeta; - const elements = meta.data || []; - const area = chart.chartArea; - const active = []; - const start = this._drawStart || 0; - const count = this._drawCount || (elements.length - start); - const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; - let i; - if (meta.dataset) { - meta.dataset.draw(ctx, area, start, count); - } - for (i = start; i < start + count; ++i) { - const element = elements[i]; - if (element.hidden) { - continue; - } - if (element.active && drawActiveElementsOnTop) { - active.push(element); - } else { - element.draw(ctx, area); - } - } - for (i = 0; i < active.length; ++i) { - active[i].draw(ctx, area); - } - } - getStyle(index, active) { - const mode = active ? 'active' : 'default'; - return index === undefined && this._cachedMeta.dataset - ? this.resolveDatasetElementOptions(mode) - : this.resolveDataElementOptions(index || 0, mode); - } - getContext(index, active, mode) { - const dataset = this.getDataset(); - let context; - if (index >= 0 && index < this._cachedMeta.data.length) { - const element = this._cachedMeta.data[index]; - context = element.$context || - (element.$context = createDataContext(this.getContext(), index, element)); - context.parsed = this.getParsed(index); - context.raw = dataset.data[index]; - context.index = context.dataIndex = index; - } else { - context = this.$context || - (this.$context = createDatasetContext(this.chart.getContext(), this.index)); - context.dataset = dataset; - context.index = context.datasetIndex = this.index; - } - context.active = !!active; - context.mode = mode; - return context; - } - resolveDatasetElementOptions(mode) { - return this._resolveElementOptions(this.datasetElementType.id, mode); - } - resolveDataElementOptions(index, mode) { - return this._resolveElementOptions(this.dataElementType.id, mode, index); - } - _resolveElementOptions(elementType, mode = 'default', index) { - const active = mode === 'active'; - const cache = this._cachedDataOpts; - const cacheKey = elementType + '-' + mode; - const cached = cache[cacheKey]; - const sharing = this.enableOptionSharing && defined(index); - if (cached) { - return cloneIfNotShared(cached, sharing); - } - const config = this.chart.config; - const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); - const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, '']; - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - const names = Object.keys(defaults.elements[elementType]); - const context = () => this.getContext(index, active); - const values = config.resolveNamedOptions(scopes, names, context, prefixes); - if (values.$shared) { - values.$shared = sharing; - cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); - } - return values; - } - _resolveAnimations(index, transition, active) { - const chart = this.chart; - const cache = this._cachedDataOpts; - const cacheKey = `animation-${transition}`; - const cached = cache[cacheKey]; - if (cached) { - return cached; - } - let options; - if (chart.options.animation !== false) { - const config = this.chart.config; - const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - options = config.createResolver(scopes, this.getContext(index, active, transition)); - } - const animations = new Animations(chart, options && options.animations); - if (options && options._cacheable) { - cache[cacheKey] = Object.freeze(animations); - } - return animations; - } - getSharedOptions(options) { - if (!options.$shared) { - return; - } - return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); - } - includeOptions(mode, sharedOptions) { - return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; - } - updateElement(element, index, properties, mode) { - if (isDirectUpdateMode(mode)) { - Object.assign(element, properties); - } else { - this._resolveAnimations(index, mode).update(element, properties); - } - } - updateSharedOptions(sharedOptions, mode, newOptions) { - if (sharedOptions && !isDirectUpdateMode(mode)) { - this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); - } - } - _setStyle(element, index, mode, active) { - element.active = active; - const options = this.getStyle(index, active); - this._resolveAnimations(index, mode, active).update(element, { - options: (!active && this.getSharedOptions(options)) || options - }); - } - removeHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', false); - } - setHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', true); - } - _removeDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', false); - } - } - _setDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', true); - } - } - _resyncElements(resetNewElements) { - const data = this._data; - const elements = this._cachedMeta.data; - for (const [method, arg1, arg2] of this._syncList) { - this[method](arg1, arg2); - } - this._syncList = []; - const numMeta = elements.length; - const numData = data.length; - const count = Math.min(numData, numMeta); - if (count) { - this.parse(0, count); - } - if (numData > numMeta) { - this._insertElements(numMeta, numData - numMeta, resetNewElements); - } else if (numData < numMeta) { - this._removeElements(numData, numMeta - numData); - } - } - _insertElements(start, count, resetNewElements = true) { - const meta = this._cachedMeta; - const data = meta.data; - const end = start + count; - let i; - const move = (arr) => { - arr.length += count; - for (i = arr.length - 1; i >= end; i--) { - arr[i] = arr[i - count]; - } - }; - move(data); - for (i = start; i < end; ++i) { - data[i] = new this.dataElementType(); - } - if (this._parsing) { - move(meta._parsed); - } - this.parse(start, count); - if (resetNewElements) { - this.updateElements(data, start, count, 'reset'); - } - } - updateElements(element, start, count, mode) {} - _removeElements(start, count) { - const meta = this._cachedMeta; - if (this._parsing) { - const removed = meta._parsed.splice(start, count); - if (meta._stacked) { - clearStacks(meta, removed); - } - } - meta.data.splice(start, count); - } - _sync(args) { - if (this._parsing) { - this._syncList.push(args); - } else { - const [method, arg1, arg2] = args; - this[method](arg1, arg2); - } - this.chart._dataChanges.push([this.index, ...args]); - } - _onDataPush() { - const count = arguments.length; - this._sync(['_insertElements', this.getDataset().data.length - count, count]); - } - _onDataPop() { - this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]); - } - _onDataShift() { - this._sync(['_removeElements', 0, 1]); - } - _onDataSplice(start, count) { - if (count) { - this._sync(['_removeElements', start, count]); - } - const newCount = arguments.length - 2; - if (newCount) { - this._sync(['_insertElements', start, newCount]); - } - } - _onDataUnshift() { - this._sync(['_insertElements', 0, arguments.length]); - } -} -DatasetController.defaults = {}; -DatasetController.prototype.datasetElementType = null; -DatasetController.prototype.dataElementType = null; - -function getAllScaleValues(scale, type) { - if (!scale._cache.$bar) { - const visibleMetas = scale.getMatchingVisibleMetas(type); - let values = []; - for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) { - values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); - } - scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b)); - } - return scale._cache.$bar; -} -function computeMinSampleSize(meta) { - const scale = meta.iScale; - const values = getAllScaleValues(scale, meta.type); - let min = scale._length; - let i, ilen, curr, prev; - const updateMinAndPrev = () => { - if (curr === 32767 || curr === -32768) { - return; - } - if (defined(prev)) { - min = Math.min(min, Math.abs(curr - prev) || min); - } - prev = curr; - }; - for (i = 0, ilen = values.length; i < ilen; ++i) { - curr = scale.getPixelForValue(values[i]); - updateMinAndPrev(); - } - prev = undefined; - for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { - curr = scale.getPixelForTick(i); - updateMinAndPrev(); - } - return min; -} -function computeFitCategoryTraits(index, ruler, options, stackCount) { - const thickness = options.barThickness; - let size, ratio; - if (isNullOrUndef(thickness)) { - size = ruler.min * options.categoryPercentage; - ratio = options.barPercentage; - } else { - size = thickness * stackCount; - ratio = 1; - } - return { - chunk: size / stackCount, - ratio, - start: ruler.pixels[index] - (size / 2) - }; -} -function computeFlexCategoryTraits(index, ruler, options, stackCount) { - const pixels = ruler.pixels; - const curr = pixels[index]; - let prev = index > 0 ? pixels[index - 1] : null; - let next = index < pixels.length - 1 ? pixels[index + 1] : null; - const percent = options.categoryPercentage; - if (prev === null) { - prev = curr - (next === null ? ruler.end - ruler.start : next - curr); - } - if (next === null) { - next = curr + curr - prev; - } - const start = curr - (curr - Math.min(prev, next)) / 2 * percent; - const size = Math.abs(next - prev) / 2 * percent; - return { - chunk: size / stackCount, - ratio: options.barPercentage, - start - }; -} -function parseFloatBar(entry, item, vScale, i) { - const startValue = vScale.parse(entry[0], i); - const endValue = vScale.parse(entry[1], i); - const min = Math.min(startValue, endValue); - const max = Math.max(startValue, endValue); - let barStart = min; - let barEnd = max; - if (Math.abs(min) > Math.abs(max)) { - barStart = max; - barEnd = min; - } - item[vScale.axis] = barEnd; - item._custom = { - barStart, - barEnd, - start: startValue, - end: endValue, - min, - max - }; -} -function parseValue(entry, item, vScale, i) { - if (isArray(entry)) { - parseFloatBar(entry, item, vScale, i); - } else { - item[vScale.axis] = vScale.parse(entry, i); - } - return item; -} -function parseArrayOrPrimitive(meta, data, start, count) { - const iScale = meta.iScale; - const vScale = meta.vScale; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = []; - let i, ilen, item, entry; - for (i = start, ilen = start + count; i < ilen; ++i) { - entry = data[i]; - item = {}; - item[iScale.axis] = singleScale || iScale.parse(labels[i], i); - parsed.push(parseValue(entry, item, vScale, i)); - } - return parsed; -} -function isFloatBar(custom) { - return custom && custom.barStart !== undefined && custom.barEnd !== undefined; -} -function barSign(size, vScale, actualBase) { - if (size !== 0) { - return sign(size); - } - return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); -} -function borderProps(properties) { - let reverse, start, end, top, bottom; - if (properties.horizontal) { - reverse = properties.base > properties.x; - start = 'left'; - end = 'right'; - } else { - reverse = properties.base < properties.y; - start = 'bottom'; - end = 'top'; - } - if (reverse) { - top = 'end'; - bottom = 'start'; - } else { - top = 'start'; - bottom = 'end'; - } - return {start, end, reverse, top, bottom}; -} -function setBorderSkipped(properties, options, stack, index) { - let edge = options.borderSkipped; - const res = {}; - if (!edge) { - properties.borderSkipped = res; - return; - } - const {start, end, reverse, top, bottom} = borderProps(properties); - if (edge === 'middle' && stack) { - properties.enableBorderRadius = true; - if ((stack._top || 0) === index) { - edge = top; - } else if ((stack._bottom || 0) === index) { - edge = bottom; - } else { - res[parseEdge(bottom, start, end, reverse)] = true; - edge = top; - } - } - res[parseEdge(edge, start, end, reverse)] = true; - properties.borderSkipped = res; -} -function parseEdge(edge, a, b, reverse) { - if (reverse) { - edge = swap(edge, a, b); - edge = startEnd(edge, b, a); - } else { - edge = startEnd(edge, a, b); - } - return edge; -} -function swap(orig, v1, v2) { - return orig === v1 ? v2 : orig === v2 ? v1 : orig; -} -function startEnd(v, start, end) { - return v === 'start' ? start : v === 'end' ? end : v; -} -function setInflateAmount(properties, {inflateAmount}, ratio) { - properties.inflateAmount = inflateAmount === 'auto' - ? ratio === 1 ? 0.33 : 0 - : inflateAmount; -} -class BarController extends DatasetController { - parsePrimitiveData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseArrayData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseObjectData(meta, data, start, count) { - const {iScale, vScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; - const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; - const parsed = []; - let i, ilen, item, obj; - for (i = start, ilen = start + count; i < ilen; ++i) { - obj = data[i]; - item = {}; - item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); - parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); - } - return parsed; - } - updateRangeFromParsed(range, scale, parsed, stack) { - super.updateRangeFromParsed(range, scale, parsed, stack); - const custom = parsed._custom; - if (custom && scale === this._cachedMeta.vScale) { - range.min = Math.min(range.min, custom.min); - range.max = Math.max(range.max, custom.max); - } - } - getMaxOverflow() { - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {iScale, vScale} = meta; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const value = isFloatBar(custom) - ? '[' + custom.start + ', ' + custom.end + ']' - : '' + vScale.getLabelForValue(parsed[vScale.axis]); - return { - label: '' + iScale.getLabelForValue(parsed[iScale.axis]), - value - }; - } - initialize() { - this.enableOptionSharing = true; - super.initialize(); - const meta = this._cachedMeta; - meta.stack = this.getDataset().stack; - } - update(mode) { - const meta = this._cachedMeta; - this.updateElements(meta.data, 0, meta.data.length, mode); - } - updateElements(bars, start, count, mode) { - const reset = mode === 'reset'; - const {index, _cachedMeta: {vScale}} = this; - const base = vScale.getBasePixel(); - const horizontal = vScale.isHorizontal(); - const ruler = this._getRuler(); - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - this.updateSharedOptions(sharedOptions, mode, firstOpts); - for (let i = start; i < start + count; i++) { - const parsed = this.getParsed(i); - const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i); - const ipixels = this._calculateBarIndexPixels(i, ruler); - const stack = (parsed._stacks || {})[vScale.axis]; - const properties = { - horizontal, - base: vpixels.base, - enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom), - x: horizontal ? vpixels.head : ipixels.center, - y: horizontal ? ipixels.center : vpixels.head, - height: horizontal ? ipixels.size : Math.abs(vpixels.size), - width: horizontal ? Math.abs(vpixels.size) : ipixels.size - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); - } - const options = properties.options || bars[i].options; - setBorderSkipped(properties, options, stack, index); - setInflateAmount(properties, options, ruler.ratio); - this.updateElement(bars[i], i, properties, mode); - } - } - _getStacks(last, dataIndex) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const metasets = iScale.getMatchingVisibleMetas(this._type); - const stacked = iScale.options.stacked; - const ilen = metasets.length; - const stacks = []; - let i, item; - for (i = 0; i < ilen; ++i) { - item = metasets[i]; - if (!item.controller.options.grouped) { - continue; - } - if (typeof dataIndex !== 'undefined') { - const val = item.controller.getParsed(dataIndex)[ - item.controller._cachedMeta.vScale.axis - ]; - if (isNullOrUndef(val) || isNaN(val)) { - continue; - } - } - if (stacked === false || stacks.indexOf(item.stack) === -1 || - (stacked === undefined && item.stack === undefined)) { - stacks.push(item.stack); - } - if (item.index === last) { - break; - } - } - if (!stacks.length) { - stacks.push(undefined); - } - return stacks; - } - _getStackCount(index) { - return this._getStacks(undefined, index).length; - } - _getStackIndex(datasetIndex, name, dataIndex) { - const stacks = this._getStacks(datasetIndex, dataIndex); - const index = (name !== undefined) - ? stacks.indexOf(name) - : -1; - return (index === -1) - ? stacks.length - 1 - : index; - } - _getRuler() { - const opts = this.options; - const meta = this._cachedMeta; - const iScale = meta.iScale; - const pixels = []; - let i, ilen; - for (i = 0, ilen = meta.data.length; i < ilen; ++i) { - pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); - } - const barThickness = opts.barThickness; - const min = barThickness || computeMinSampleSize(meta); - return { - min, - pixels, - start: iScale._startPixel, - end: iScale._endPixel, - stackCount: this._getStackCount(), - scale: iScale, - grouped: opts.grouped, - ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage - }; - } - _calculateBarValuePixels(index) { - const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; - const actualBase = baseValue || 0; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const floating = isFloatBar(custom); - let value = parsed[vScale.axis]; - let start = 0; - let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; - let head, size; - if (length !== value) { - start = length - value; - length = value; - } - if (floating) { - value = custom.barStart; - length = custom.barEnd - custom.barStart; - if (value !== 0 && sign(value) !== sign(custom.barEnd)) { - start = 0; - } - start += value; - } - const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; - let base = vScale.getPixelForValue(startValue); - if (this.chart.getDataVisibility(index)) { - head = vScale.getPixelForValue(start + length); - } else { - head = base; - } - size = head - base; - if (Math.abs(size) < minBarLength) { - size = barSign(size, vScale, actualBase) * minBarLength; - if (value === actualBase) { - base -= size / 2; - } - head = base + size; - } - if (base === vScale.getPixelForValue(actualBase)) { - const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; - base += halfGrid; - size -= halfGrid; - } - return { - size, - base, - head, - center: head + size / 2 - }; - } - _calculateBarIndexPixels(index, ruler) { - const scale = ruler.scale; - const options = this.options; - const skipNull = options.skipNull; - const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); - let center, size; - if (ruler.grouped) { - const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; - const range = options.barThickness === 'flex' - ? computeFlexCategoryTraits(index, ruler, options, stackCount) - : computeFitCategoryTraits(index, ruler, options, stackCount); - const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); - center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); - size = Math.min(maxBarThickness, range.chunk * range.ratio); - } else { - center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); - size = Math.min(maxBarThickness, ruler.min * ruler.ratio); - } - return { - base: center - size / 2, - head: center + size / 2, - center, - size - }; - } - draw() { - const meta = this._cachedMeta; - const vScale = meta.vScale; - const rects = meta.data; - const ilen = rects.length; - let i = 0; - for (; i < ilen; ++i) { - if (this.getParsed(i)[vScale.axis] !== null) { - rects[i].draw(this._ctx); - } - } - } -} -BarController.id = 'bar'; -BarController.defaults = { - datasetElementType: false, - dataElementType: 'bar', - categoryPercentage: 0.8, - barPercentage: 0.9, - grouped: true, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'base', 'width', 'height'] - } - } -}; -BarController.overrides = { - scales: { - _index_: { - type: 'category', - offset: true, - grid: { - offset: true - } - }, - _value_: { - type: 'linear', - beginAtZero: true, - } - } -}; - -class BubbleController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - parsePrimitiveData(meta, data, start, count) { - const parsed = super.parsePrimitiveData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const parsed = super.parseArrayData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const parsed = super.parseObjectData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - getMaxOverflow() { - const data = this._cachedMeta.data; - let max = 0; - for (let i = data.length - 1; i >= 0; --i) { - max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); - } - return max > 0 && max; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {xScale, yScale} = meta; - const parsed = this.getParsed(index); - const x = xScale.getLabelForValue(parsed.x); - const y = yScale.getLabelForValue(parsed.y); - const r = parsed._custom; - return { - label: meta.label, - value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' - }; - } - update(mode) { - const points = this._cachedMeta.data; - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const parsed = !reset && this.getParsed(i); - const properties = {}; - const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); - const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); - properties.skip = isNaN(iPixel) || isNaN(vPixel); - if (includeOptions) { - properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - if (reset) { - properties.options.radius = 0; - } - } - this.updateElement(point, i, properties, mode); - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - resolveDataElementOptions(index, mode) { - const parsed = this.getParsed(index); - let values = super.resolveDataElementOptions(index, mode); - if (values.$shared) { - values = Object.assign({}, values, {$shared: false}); - } - const radius = values.radius; - if (mode !== 'active') { - values.radius = 0; - } - values.radius += valueOrDefault(parsed && parsed._custom, radius); - return values; - } -} -BubbleController.id = 'bubble'; -BubbleController.defaults = { - datasetElementType: false, - dataElementType: 'point', - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'borderWidth', 'radius'] - } - } -}; -BubbleController.overrides = { - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' - } - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - } - } - } - } -}; - -function getRatioAndOffset(rotation, circumference, cutout) { - let ratioX = 1; - let ratioY = 1; - let offsetX = 0; - let offsetY = 0; - if (circumference < TAU) { - const startAngle = rotation; - const endAngle = startAngle + circumference; - const startX = Math.cos(startAngle); - const startY = Math.sin(startAngle); - const endX = Math.cos(endAngle); - const endY = Math.sin(endAngle); - const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); - const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); - const maxX = calcMax(0, startX, endX); - const maxY = calcMax(HALF_PI, startY, endY); - const minX = calcMin(PI, startX, endX); - const minY = calcMin(PI + HALF_PI, startY, endY); - ratioX = (maxX - minX) / 2; - ratioY = (maxY - minY) / 2; - offsetX = -(maxX + minX) / 2; - offsetY = -(maxY + minY) / 2; - } - return {ratioX, ratioY, offsetX, offsetY}; -} -class DoughnutController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.enableOptionSharing = true; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.offsetX = undefined; - this.offsetY = undefined; - } - linkScales() {} - parse(start, count) { - const data = this.getDataset().data; - const meta = this._cachedMeta; - if (this._parsing === false) { - meta._parsed = data; - } else { - let getter = (i) => +data[i]; - if (isObject(data[start])) { - const {key = 'value'} = this._parsing; - getter = (i) => +resolveObjectKey(data[i], key); - } - let i, ilen; - for (i = start, ilen = start + count; i < ilen; ++i) { - meta._parsed[i] = getter(i); - } - } - } - _getRotation() { - return toRadians(this.options.rotation - 90); - } - _getCircumference() { - return toRadians(this.options.circumference); - } - _getRotationExtents() { - let min = TAU; - let max = -TAU; - for (let i = 0; i < this.chart.data.datasets.length; ++i) { - if (this.chart.isDatasetVisible(i)) { - const controller = this.chart.getDatasetMeta(i).controller; - const rotation = controller._getRotation(); - const circumference = controller._getCircumference(); - min = Math.min(min, rotation); - max = Math.max(max, rotation + circumference); - } - } - return { - rotation: min, - circumference: max - min, - }; - } - update(mode) { - const chart = this.chart; - const {chartArea} = chart; - const meta = this._cachedMeta; - const arcs = meta.data; - const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; - const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); - const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); - const chartWeight = this._getRingWeight(this.index); - const {circumference, rotation} = this._getRotationExtents(); - const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout); - const maxWidth = (chartArea.width - spacing) / ratioX; - const maxHeight = (chartArea.height - spacing) / ratioY; - const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); - const outerRadius = toDimension(this.options.radius, maxRadius); - const innerRadius = Math.max(outerRadius * cutout, 0); - const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); - this.offsetX = offsetX * outerRadius; - this.offsetY = offsetY * outerRadius; - meta.total = this.calculateTotal(); - this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); - this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); - this.updateElements(arcs, 0, arcs.length, mode); - } - _circumference(i, reset) { - const opts = this.options; - const meta = this._cachedMeta; - const circumference = this._getCircumference(); - if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { - return 0; - } - return this.calculateCircumference(meta._parsed[i] * circumference / TAU); - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const animationOpts = opts.animation; - const centerX = (chartArea.left + chartArea.right) / 2; - const centerY = (chartArea.top + chartArea.bottom) / 2; - const animateScale = reset && animationOpts.animateScale; - const innerRadius = animateScale ? 0 : this.innerRadius; - const outerRadius = animateScale ? 0 : this.outerRadius; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - let startAngle = this._getRotation(); - let i; - for (i = 0; i < start; ++i) { - startAngle += this._circumference(i, reset); - } - for (i = start; i < start + count; ++i) { - const circumference = this._circumference(i, reset); - const arc = arcs[i]; - const properties = { - x: centerX + this.offsetX, - y: centerY + this.offsetY, - startAngle, - endAngle: startAngle + circumference, - circumference, - outerRadius, - innerRadius - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); - } - startAngle += circumference; - this.updateElement(arc, i, properties, mode); - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - calculateTotal() { - const meta = this._cachedMeta; - const metaData = meta.data; - let total = 0; - let i; - for (i = 0; i < metaData.length; i++) { - const value = meta._parsed[i]; - if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { - total += Math.abs(value); - } - } - return total; - } - calculateCircumference(value) { - const total = this._cachedMeta.total; - if (total > 0 && !isNaN(value)) { - return TAU * (Math.abs(value) / total); - } - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index], chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - getMaxBorderWidth(arcs) { - let max = 0; - const chart = this.chart; - let i, ilen, meta, controller, options; - if (!arcs) { - for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { - if (chart.isDatasetVisible(i)) { - meta = chart.getDatasetMeta(i); - arcs = meta.data; - controller = meta.controller; - break; - } - } - } - if (!arcs) { - return 0; - } - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - options = controller.resolveDataElementOptions(i); - if (options.borderAlign !== 'inner') { - max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); - } - } - return max; - } - getMaxOffset(arcs) { - let max = 0; - for (let i = 0, ilen = arcs.length; i < ilen; ++i) { - const options = this.resolveDataElementOptions(i); - max = Math.max(max, options.offset || 0, options.hoverOffset || 0); - } - return max; - } - _getRingWeightOffset(datasetIndex) { - let ringWeightOffset = 0; - for (let i = 0; i < datasetIndex; ++i) { - if (this.chart.isDatasetVisible(i)) { - ringWeightOffset += this._getRingWeight(i); - } - } - return ringWeightOffset; - } - _getRingWeight(datasetIndex) { - return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); - } - _getVisibleDatasetWeightTotal() { - return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; - } -} -DoughnutController.id = 'doughnut'; -DoughnutController.defaults = { - datasetElementType: false, - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: false - }, - animations: { - numbers: { - type: 'number', - properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing'] - }, - }, - cutout: '50%', - rotation: 0, - circumference: 360, - radius: '100%', - spacing: 0, - indexAxis: 'r', -}; -DoughnutController.descriptors = { - _scriptable: (name) => name !== 'spacing', - _indexable: (name) => name !== 'spacing', -}; -DoughnutController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; - }, - label(tooltipItem) { - let dataLabel = tooltipItem.label; - const value = ': ' + tooltipItem.formattedValue; - if (isArray(dataLabel)) { - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - return dataLabel; - } - } - } - } -}; - -class LineController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - update(mode) { - const meta = this._cachedMeta; - const {dataset: line, data: points = [], _dataset} = meta; - const animationsDisabled = this.chart._animationsDisabled; - let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); - this._drawStart = start; - this._drawCount = count; - if (scaleRangesChanged(meta)) { - start = 0; - count = points.length; - } - line._chart = this.chart; - line._datasetIndex = this.index; - line._decimated = !!_dataset._decimated; - line.points = points; - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; - } - options.segment = this.options.segment; - this.updateElement(line, undefined, { - animated: !animationsDisabled, - options - }, mode); - this.updateElements(points, start, count, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale, _stacked, _dataset} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const {spanGaps, segment} = this.options; - const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; - const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; - let prevParsed = start > 0 && this.getParsed(start - 1); - for (let i = start; i < start + count; ++i) { - const point = points[i]; - const parsed = this.getParsed(i); - const properties = directUpdate ? point : {}; - const nullData = isNullOrUndef(parsed[vAxis]); - const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); - const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); - properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; - properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; - if (segment) { - properties.parsed = parsed; - properties.raw = _dataset.data[i]; - } - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); - } - if (!directUpdate) { - this.updateElement(point, i, properties, mode); - } - prevParsed = parsed; - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - getMaxOverflow() { - const meta = this._cachedMeta; - const dataset = meta.dataset; - const border = dataset.options && dataset.options.borderWidth || 0; - const data = meta.data || []; - if (!data.length) { - return border; - } - const firstPoint = data[0].size(this.resolveDataElementOptions(0)); - const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); - return Math.max(border, firstPoint, lastPoint) / 2; - } - draw() { - const meta = this._cachedMeta; - meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); - super.draw(); - } -} -LineController.id = 'line'; -LineController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - showLine: true, - spanGaps: false, -}; -LineController.overrides = { - scales: { - _index_: { - type: 'category', - }, - _value_: { - type: 'linear', - }, - } -}; -function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { - const pointCount = points.length; - let start = 0; - let count = pointCount; - if (meta._sorted) { - const {iScale, _parsed} = meta; - const axis = iScale.axis; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(Math.min( - _lookupByKey(_parsed, iScale.axis, min).lo, - animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), - 0, pointCount - 1); - } - if (maxDefined) { - count = _limitValue(Math.max( - _lookupByKey(_parsed, iScale.axis, max).hi + 1, - animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), - start, pointCount) - start; - } else { - count = pointCount - start; - } - } - return {start, count}; -} -function scaleRangesChanged(meta) { - const {xScale, yScale, _scaleRanges} = meta; - const newRanges = { - xmin: xScale.min, - xmax: xScale.max, - ymin: yScale.min, - ymax: yScale.max - }; - if (!_scaleRanges) { - meta._scaleRanges = newRanges; - return true; - } - const changed = _scaleRanges.xmin !== xScale.min - || _scaleRanges.xmax !== xScale.max - || _scaleRanges.ymin !== yScale.min - || _scaleRanges.ymax !== yScale.max; - Object.assign(_scaleRanges, newRanges); - return changed; -} - -class PolarAreaController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.innerRadius = undefined; - this.outerRadius = undefined; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index].r, chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - update(mode) { - const arcs = this._cachedMeta.data; - this._updateRadius(); - this.updateElements(arcs, 0, arcs.length, mode); - } - _updateRadius() { - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); - const outerRadius = Math.max(minSize / 2, 0); - const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); - const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); - this.outerRadius = outerRadius - (radiusLength * this.index); - this.innerRadius = this.outerRadius - radiusLength; - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const dataset = this.getDataset(); - const opts = chart.options; - const animationOpts = opts.animation; - const scale = this._cachedMeta.rScale; - const centerX = scale.xCenter; - const centerY = scale.yCenter; - const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; - let angle = datasetStartAngle; - let i; - const defaultAngle = 360 / this.countVisibleElements(); - for (i = 0; i < start; ++i) { - angle += this._computeAngle(i, mode, defaultAngle); - } - for (i = start; i < start + count; i++) { - const arc = arcs[i]; - let startAngle = angle; - let endAngle = angle + this._computeAngle(i, mode, defaultAngle); - let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; - angle = endAngle; - if (reset) { - if (animationOpts.animateScale) { - outerRadius = 0; - } - if (animationOpts.animateRotate) { - startAngle = endAngle = datasetStartAngle; - } - } - const properties = { - x: centerX, - y: centerY, - innerRadius: 0, - outerRadius, - startAngle, - endAngle, - options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) - }; - this.updateElement(arc, i, properties, mode); - } - } - countVisibleElements() { - const dataset = this.getDataset(); - const meta = this._cachedMeta; - let count = 0; - meta.data.forEach((element, index) => { - if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { - count++; - } - }); - return count; - } - _computeAngle(index, mode, defaultAngle) { - return this.chart.getDataVisibility(index) - ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) - : 0; - } -} -PolarAreaController.id = 'polarArea'; -PolarAreaController.defaults = { - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: true - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] - }, - }, - indexAxis: 'r', - startAngle: 0, -}; -PolarAreaController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; - }, - label(context) { - return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; - } - } - } - }, - scales: { - r: { - type: 'radialLinear', - angleLines: { - display: false - }, - beginAtZero: true, - grid: { - circular: true - }, - pointLabels: { - display: false - }, - startAngle: 0 - } - } -}; - -class PieController extends DoughnutController { -} -PieController.id = 'pie'; -PieController.defaults = { - cutout: 0, - rotation: 0, - circumference: 360, - radius: '100%' -}; - -class RadarController extends DatasetController { - getLabelAndValue(index) { - const vScale = this._cachedMeta.vScale; - const parsed = this.getParsed(index); - return { - label: vScale.getLabels()[index], - value: '' + vScale.getLabelForValue(parsed[vScale.axis]) - }; - } - update(mode) { - const meta = this._cachedMeta; - const line = meta.dataset; - const points = meta.data || []; - const labels = meta.iScale.getLabels(); - line.points = points; - if (mode !== 'resize') { - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; - } - const properties = { - _loop: true, - _fullLoop: labels.length === points.length, - options - }; - this.updateElement(line, undefined, properties, mode); - } - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const dataset = this.getDataset(); - const scale = this._cachedMeta.rScale; - const reset = mode === 'reset'; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); - const x = reset ? scale.xCenter : pointPosition.x; - const y = reset ? scale.yCenter : pointPosition.y; - const properties = { - x, - y, - angle: pointPosition.angle, - skip: isNaN(x) || isNaN(y), - options - }; - this.updateElement(point, i, properties, mode); - } - } -} -RadarController.id = 'radar'; -RadarController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - indexAxis: 'r', - showLine: true, - elements: { - line: { - fill: 'start' - } - }, -}; -RadarController.overrides = { - aspectRatio: 1, - scales: { - r: { - type: 'radialLinear', - } - } -}; - -class ScatterController extends LineController { -} -ScatterController.id = 'scatter'; -ScatterController.defaults = { - showLine: false, - fill: false -}; -ScatterController.overrides = { - interaction: { - mode: 'point' - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - }, - label(item) { - return '(' + item.label + ', ' + item.formattedValue + ')'; - } - } - } - }, - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' - } - } -}; - -var controllers = /*#__PURE__*/Object.freeze({ -__proto__: null, -BarController: BarController, -BubbleController: BubbleController, -DoughnutController: DoughnutController, -LineController: LineController, -PolarAreaController: PolarAreaController, -PieController: PieController, -RadarController: RadarController, -ScatterController: ScatterController -}); - -function abstract() { - throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); -} -class DateAdapter { - constructor(options) { - this.options = options || {}; - } - formats() { - return abstract(); - } - parse(value, format) { - return abstract(); - } - format(timestamp, format) { - return abstract(); - } - add(timestamp, amount, unit) { - return abstract(); - } - diff(a, b, unit) { - return abstract(); - } - startOf(timestamp, unit, weekday) { - return abstract(); - } - endOf(timestamp, unit) { - return abstract(); - } -} -DateAdapter.override = function(members) { - Object.assign(DateAdapter.prototype, members); -}; -var adapters = { - _date: DateAdapter -}; - -function getRelativePosition(e, chart) { - if ('native' in e) { - return { - x: e.x, - y: e.y - }; - } - return getRelativePosition$1(e, chart); -} -function evaluateAllVisibleItems(chart, handler) { - const metasets = chart.getSortedVisibleDatasetMetas(); - let index, data, element; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - ({index, data} = metasets[i]); - for (let j = 0, jlen = data.length; j < jlen; ++j) { - element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function binarySearch(metaset, axis, value, intersect) { - const {controller, data, _sorted} = metaset; - const iScale = controller._cachedMeta.iScale; - if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { - const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; - if (!intersect) { - return lookupMethod(data, axis, value); - } else if (controller._sharedOptions) { - const el = data[0]; - const range = typeof el.getRange === 'function' && el.getRange(axis); - if (range) { - const start = lookupMethod(data, axis, value - range); - const end = lookupMethod(data, axis, value + range); - return {lo: start.lo, hi: end.hi}; - } - } - } - return {lo: 0, hi: data.length - 1}; -} -function optimizedEvaluateItems(chart, axis, position, handler, intersect) { - const metasets = chart.getSortedVisibleDatasetMetas(); - const value = position[axis]; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - const {index, data} = metasets[i]; - const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); - for (let j = lo; j <= hi; ++j) { - const element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function getDistanceMetricForAxis(axis) { - const useX = axis.indexOf('x') !== -1; - const useY = axis.indexOf('y') !== -1; - return function(pt1, pt2) { - const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; - const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; - return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); - }; -} -function getIntersectItems(chart, position, axis, useFinalPosition) { - const items = []; - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return items; - } - const evaluationFunc = function(element, datasetIndex, index) { - if (element.inRange(position.x, position.y, useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - }; - optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); - return items; -} -function getNearestRadialItems(chart, position, axis, useFinalPosition) { - let items = []; - function evaluationFunc(element, datasetIndex, index) { - const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition); - const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y}); - if (_angleBetween(angle, startAngle, endAngle)) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) { - let items = []; - const distanceMetric = getDistanceMetricForAxis(axis); - let minDistance = Number.POSITIVE_INFINITY; - function evaluationFunc(element, datasetIndex, index) { - const inRange = element.inRange(position.x, position.y, useFinalPosition); - if (intersect && !inRange) { - return; - } - const center = element.getCenterPoint(useFinalPosition); - const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding); - if (!pointInArea && !inRange) { - return; - } - const distance = distanceMetric(position, center); - if (distance < minDistance) { - items = [{element, datasetIndex, index}]; - minDistance = distance; - } else if (distance === minDistance) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestItems(chart, position, axis, intersect, useFinalPosition) { - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return []; - } - return axis === 'r' && !intersect - ? getNearestRadialItems(chart, position, axis, useFinalPosition) - : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition); -} -function getAxisItems(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const items = []; - const axis = options.axis; - const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; - let intersectsItem = false; - evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { - if (element[rangeMethod](position[axis], useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - if (element.inRange(position.x, position.y, useFinalPosition)) { - intersectsItem = true; - } - }); - if (options.intersect && !intersectsItem) { - return []; - } - return items; -} -var Interaction = { - modes: { - index(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'x'; - const items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) - : getNearestItems(chart, position, axis, false, useFinalPosition); - const elements = []; - if (!items.length) { - return []; - } - chart.getSortedVisibleDatasetMetas().forEach((meta) => { - const index = items[0].index; - const element = meta.data[index]; - if (element && !element.skip) { - elements.push({element, datasetIndex: meta.index, index}); - } - }); - return elements; - }, - dataset(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - let items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) : - getNearestItems(chart, position, axis, false, useFinalPosition); - if (items.length > 0) { - const datasetIndex = items[0].datasetIndex; - const data = chart.getDatasetMeta(datasetIndex).data; - items = []; - for (let i = 0; i < data.length; ++i) { - items.push({element: data[i], datasetIndex, index: i}); - } - } - return items; - }, - point(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getIntersectItems(chart, position, axis, useFinalPosition); - }, - nearest(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); - }, - x(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition); - }, - y(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition); - } - } -}; - -const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; -function filterByPosition(array, position) { - return array.filter(v => v.pos === position); -} -function filterDynamicPositionByAxis(array, axis) { - return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); -} -function sortByWeight(array, reverse) { - return array.sort((a, b) => { - const v0 = reverse ? b : a; - const v1 = reverse ? a : b; - return v0.weight === v1.weight ? - v0.index - v1.index : - v0.weight - v1.weight; - }); -} -function wrapBoxes(boxes) { - const layoutBoxes = []; - let i, ilen, box, pos, stack, stackWeight; - for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { - box = boxes[i]; - ({position: pos, options: {stack, stackWeight = 1}} = box); - layoutBoxes.push({ - index: i, - box, - pos, - horizontal: box.isHorizontal(), - weight: box.weight, - stack: stack && (pos + stack), - stackWeight - }); - } - return layoutBoxes; -} -function buildStacks(layouts) { - const stacks = {}; - for (const wrap of layouts) { - const {stack, pos, stackWeight} = wrap; - if (!stack || !STATIC_POSITIONS.includes(pos)) { - continue; - } - const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0}); - _stack.count++; - _stack.weight += stackWeight; - } - return stacks; -} -function setLayoutDims(layouts, params) { - const stacks = buildStacks(layouts); - const {vBoxMaxWidth, hBoxMaxHeight} = params; - let i, ilen, layout; - for (i = 0, ilen = layouts.length; i < ilen; ++i) { - layout = layouts[i]; - const {fullSize} = layout.box; - const stack = stacks[layout.stack]; - const factor = stack && layout.stackWeight / stack.weight; - if (layout.horizontal) { - layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; - layout.height = hBoxMaxHeight; - } else { - layout.width = vBoxMaxWidth; - layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; - } - } - return stacks; -} -function buildLayoutBoxes(boxes) { - const layoutBoxes = wrapBoxes(boxes); - const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true); - const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); - const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); - const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); - const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); - const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); - const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); - return { - fullSize, - leftAndTop: left.concat(top), - rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), - chartArea: filterByPosition(layoutBoxes, 'chartArea'), - vertical: left.concat(right).concat(centerVertical), - horizontal: top.concat(bottom).concat(centerHorizontal) - }; -} -function getCombinedMax(maxPadding, chartArea, a, b) { - return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); -} -function updateMaxPadding(maxPadding, boxPadding) { - maxPadding.top = Math.max(maxPadding.top, boxPadding.top); - maxPadding.left = Math.max(maxPadding.left, boxPadding.left); - maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); - maxPadding.right = Math.max(maxPadding.right, boxPadding.right); -} -function updateDims(chartArea, params, layout, stacks) { - const {pos, box} = layout; - const maxPadding = chartArea.maxPadding; - if (!isObject(pos)) { - if (layout.size) { - chartArea[pos] -= layout.size; - } - const stack = stacks[layout.stack] || {size: 0, count: 1}; - stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); - layout.size = stack.size / stack.count; - chartArea[pos] += layout.size; - } - if (box.getPadding) { - updateMaxPadding(maxPadding, box.getPadding()); - } - const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); - const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); - const widthChanged = newWidth !== chartArea.w; - const heightChanged = newHeight !== chartArea.h; - chartArea.w = newWidth; - chartArea.h = newHeight; - return layout.horizontal - ? {same: widthChanged, other: heightChanged} - : {same: heightChanged, other: widthChanged}; -} -function handleMaxPadding(chartArea) { - const maxPadding = chartArea.maxPadding; - function updatePos(pos) { - const change = Math.max(maxPadding[pos] - chartArea[pos], 0); - chartArea[pos] += change; - return change; - } - chartArea.y += updatePos('top'); - chartArea.x += updatePos('left'); - updatePos('right'); - updatePos('bottom'); -} -function getMargins(horizontal, chartArea) { - const maxPadding = chartArea.maxPadding; - function marginForPositions(positions) { - const margin = {left: 0, top: 0, right: 0, bottom: 0}; - positions.forEach((pos) => { - margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); - }); - return margin; - } - return horizontal - ? marginForPositions(['left', 'right']) - : marginForPositions(['top', 'bottom']); -} -function fitBoxes(boxes, chartArea, params, stacks) { - const refitBoxes = []; - let i, ilen, layout, box, refit, changed; - for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) { - layout = boxes[i]; - box = layout.box; - box.update( - layout.width || chartArea.w, - layout.height || chartArea.h, - getMargins(layout.horizontal, chartArea) - ); - const {same, other} = updateDims(chartArea, params, layout, stacks); - refit |= same && refitBoxes.length; - changed = changed || other; - if (!box.fullSize) { - refitBoxes.push(layout); - } - } - return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; -} -function setBoxDims(box, left, top, width, height) { - box.top = top; - box.left = left; - box.right = left + width; - box.bottom = top + height; - box.width = width; - box.height = height; -} -function placeBoxes(boxes, chartArea, params, stacks) { - const userPadding = params.padding; - let {x, y} = chartArea; - for (const layout of boxes) { - const box = layout.box; - const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1}; - const weight = (layout.stackWeight / stack.weight) || 1; - if (layout.horizontal) { - const width = chartArea.w * weight; - const height = stack.size || box.height; - if (defined(stack.start)) { - y = stack.start; - } - if (box.fullSize) { - setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); - } else { - setBoxDims(box, chartArea.left + stack.placed, y, width, height); - } - stack.start = y; - stack.placed += width; - y = box.bottom; - } else { - const height = chartArea.h * weight; - const width = stack.size || box.width; - if (defined(stack.start)) { - x = stack.start; - } - if (box.fullSize) { - setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); - } else { - setBoxDims(box, x, chartArea.top + stack.placed, width, height); - } - stack.start = x; - stack.placed += height; - x = box.right; - } - } - chartArea.x = x; - chartArea.y = y; -} -defaults.set('layout', { - autoPadding: true, - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } -}); -var layouts = { - addBox(chart, item) { - if (!chart.boxes) { - chart.boxes = []; - } - item.fullSize = item.fullSize || false; - item.position = item.position || 'top'; - item.weight = item.weight || 0; - item._layers = item._layers || function() { - return [{ - z: 0, - draw(chartArea) { - item.draw(chartArea); - } - }]; - }; - chart.boxes.push(item); - }, - removeBox(chart, layoutItem) { - const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; - if (index !== -1) { - chart.boxes.splice(index, 1); - } - }, - configure(chart, item, options) { - item.fullSize = options.fullSize; - item.position = options.position; - item.weight = options.weight; - }, - update(chart, width, height, minPadding) { - if (!chart) { - return; - } - const padding = toPadding(chart.options.layout.padding); - const availableWidth = Math.max(width - padding.width, 0); - const availableHeight = Math.max(height - padding.height, 0); - const boxes = buildLayoutBoxes(chart.boxes); - const verticalBoxes = boxes.vertical; - const horizontalBoxes = boxes.horizontal; - each(chart.boxes, box => { - if (typeof box.beforeLayout === 'function') { - box.beforeLayout(); - } - }); - const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => - wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; - const params = Object.freeze({ - outerWidth: width, - outerHeight: height, - padding, - availableWidth, - availableHeight, - vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, - hBoxMaxHeight: availableHeight / 2 - }); - const maxPadding = Object.assign({}, padding); - updateMaxPadding(maxPadding, toPadding(minPadding)); - const chartArea = Object.assign({ - maxPadding, - w: availableWidth, - h: availableHeight, - x: padding.left, - y: padding.top - }, padding); - const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); - fitBoxes(boxes.fullSize, chartArea, params, stacks); - fitBoxes(verticalBoxes, chartArea, params, stacks); - if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { - fitBoxes(verticalBoxes, chartArea, params, stacks); - } - handleMaxPadding(chartArea); - placeBoxes(boxes.leftAndTop, chartArea, params, stacks); - chartArea.x += chartArea.w; - chartArea.y += chartArea.h; - placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); - chart.chartArea = { - left: chartArea.left, - top: chartArea.top, - right: chartArea.left + chartArea.w, - bottom: chartArea.top + chartArea.h, - height: chartArea.h, - width: chartArea.w, - }; - each(boxes.chartArea, (layout) => { - const box = layout.box; - Object.assign(box, chart.chartArea); - box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0}); - }); - } -}; - -class BasePlatform { - acquireContext(canvas, aspectRatio) {} - releaseContext(context) { - return false; - } - addEventListener(chart, type, listener) {} - removeEventListener(chart, type, listener) {} - getDevicePixelRatio() { - return 1; - } - getMaximumSize(element, width, height, aspectRatio) { - width = Math.max(0, width || element.width); - height = height || element.height; - return { - width, - height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) - }; - } - isAttached(canvas) { - return true; - } - updateConfig(config) { - } -} - -class BasicPlatform extends BasePlatform { - acquireContext(item) { - return item && item.getContext && item.getContext('2d') || null; - } - updateConfig(config) { - config.options.animation = false; - } -} - -const EXPANDO_KEY = '$chartjs'; -const EVENT_TYPES = { - touchstart: 'mousedown', - touchmove: 'mousemove', - touchend: 'mouseup', - pointerenter: 'mouseenter', - pointerdown: 'mousedown', - pointermove: 'mousemove', - pointerup: 'mouseup', - pointerleave: 'mouseout', - pointerout: 'mouseout' -}; -const isNullOrEmpty = value => value === null || value === ''; -function initCanvas(canvas, aspectRatio) { - const style = canvas.style; - const renderHeight = canvas.getAttribute('height'); - const renderWidth = canvas.getAttribute('width'); - canvas[EXPANDO_KEY] = { - initial: { - height: renderHeight, - width: renderWidth, - style: { - display: style.display, - height: style.height, - width: style.width - } - } - }; - style.display = style.display || 'block'; - style.boxSizing = style.boxSizing || 'border-box'; - if (isNullOrEmpty(renderWidth)) { - const displayWidth = readUsedSize(canvas, 'width'); - if (displayWidth !== undefined) { - canvas.width = displayWidth; - } - } - if (isNullOrEmpty(renderHeight)) { - if (canvas.style.height === '') { - canvas.height = canvas.width / (aspectRatio || 2); - } else { - const displayHeight = readUsedSize(canvas, 'height'); - if (displayHeight !== undefined) { - canvas.height = displayHeight; - } - } - } - return canvas; -} -const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; -function addListener(node, type, listener) { - node.addEventListener(type, listener, eventListenerOptions); -} -function removeListener(chart, type, listener) { - chart.canvas.removeEventListener(type, listener, eventListenerOptions); -} -function fromNativeEvent(event, chart) { - const type = EVENT_TYPES[event.type] || event.type; - const {x, y} = getRelativePosition$1(event, chart); - return { - type, - chart, - native: event, - x: x !== undefined ? x : null, - y: y !== undefined ? y : null, - }; -} -function nodeListContains(nodeList, canvas) { - for (const node of nodeList) { - if (node === canvas || node.contains(canvas)) { - return true; - } - } -} -function createAttachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.addedNodes, canvas); - trigger = trigger && !nodeListContains(entry.removedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -function createDetachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.removedNodes, canvas); - trigger = trigger && !nodeListContains(entry.addedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -const drpListeningCharts = new Map(); -let oldDevicePixelRatio = 0; -function onWindowResize() { - const dpr = window.devicePixelRatio; - if (dpr === oldDevicePixelRatio) { - return; - } - oldDevicePixelRatio = dpr; - drpListeningCharts.forEach((resize, chart) => { - if (chart.currentDevicePixelRatio !== dpr) { - resize(); - } - }); -} -function listenDevicePixelRatioChanges(chart, resize) { - if (!drpListeningCharts.size) { - window.addEventListener('resize', onWindowResize); - } - drpListeningCharts.set(chart, resize); -} -function unlistenDevicePixelRatioChanges(chart) { - drpListeningCharts.delete(chart); - if (!drpListeningCharts.size) { - window.removeEventListener('resize', onWindowResize); - } -} -function createResizeObserver(chart, type, listener) { - const canvas = chart.canvas; - const container = canvas && _getParentNode(canvas); - if (!container) { - return; - } - const resize = throttled((width, height) => { - const w = container.clientWidth; - listener(width, height); - if (w < container.clientWidth) { - listener(); - } - }, window); - const observer = new ResizeObserver(entries => { - const entry = entries[0]; - const width = entry.contentRect.width; - const height = entry.contentRect.height; - if (width === 0 && height === 0) { - return; - } - resize(width, height); - }); - observer.observe(container); - listenDevicePixelRatioChanges(chart, resize); - return observer; -} -function releaseObserver(chart, type, observer) { - if (observer) { - observer.disconnect(); - } - if (type === 'resize') { - unlistenDevicePixelRatioChanges(chart); - } -} -function createProxyAndListen(chart, type, listener) { - const canvas = chart.canvas; - const proxy = throttled((event) => { - if (chart.ctx !== null) { - listener(fromNativeEvent(event, chart)); - } - }, chart, (args) => { - const event = args[0]; - return [event, event.offsetX, event.offsetY]; - }); - addListener(canvas, type, proxy); - return proxy; -} -class DomPlatform extends BasePlatform { - acquireContext(canvas, aspectRatio) { - const context = canvas && canvas.getContext && canvas.getContext('2d'); - if (context && context.canvas === canvas) { - initCanvas(canvas, aspectRatio); - return context; - } - return null; - } - releaseContext(context) { - const canvas = context.canvas; - if (!canvas[EXPANDO_KEY]) { - return false; - } - const initial = canvas[EXPANDO_KEY].initial; - ['height', 'width'].forEach((prop) => { - const value = initial[prop]; - if (isNullOrUndef(value)) { - canvas.removeAttribute(prop); - } else { - canvas.setAttribute(prop, value); - } - }); - const style = initial.style || {}; - Object.keys(style).forEach((key) => { - canvas.style[key] = style[key]; - }); - canvas.width = canvas.width; - delete canvas[EXPANDO_KEY]; - return true; - } - addEventListener(chart, type, listener) { - this.removeEventListener(chart, type); - const proxies = chart.$proxies || (chart.$proxies = {}); - const handlers = { - attach: createAttachObserver, - detach: createDetachObserver, - resize: createResizeObserver - }; - const handler = handlers[type] || createProxyAndListen; - proxies[type] = handler(chart, type, listener); - } - removeEventListener(chart, type) { - const proxies = chart.$proxies || (chart.$proxies = {}); - const proxy = proxies[type]; - if (!proxy) { - return; - } - const handlers = { - attach: releaseObserver, - detach: releaseObserver, - resize: releaseObserver - }; - const handler = handlers[type] || removeListener; - handler(chart, type, proxy); - proxies[type] = undefined; - } - getDevicePixelRatio() { - return window.devicePixelRatio; - } - getMaximumSize(canvas, width, height, aspectRatio) { - return getMaximumSize(canvas, width, height, aspectRatio); - } - isAttached(canvas) { - const container = _getParentNode(canvas); - return !!(container && container.isConnected); - } -} - -function _detectPlatform(canvas) { - if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { - return BasicPlatform; - } - return DomPlatform; -} - -class Element { - constructor() { - this.x = undefined; - this.y = undefined; - this.active = false; - this.options = undefined; - this.$animations = undefined; - } - tooltipPosition(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - hasValue() { - return isNumber(this.x) && isNumber(this.y); - } - getProps(props, final) { - const anims = this.$animations; - if (!final || !anims) { - return this; - } - const ret = {}; - props.forEach(prop => { - ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; - }); - return ret; - } -} -Element.defaults = {}; -Element.defaultRoutes = undefined; - -const formatters = { - values(value) { - return isArray(value) ? value : '' + value; - }, - numeric(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const locale = this.chart.options.locale; - let notation; - let delta = tickValue; - if (ticks.length > 1) { - const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); - if (maxTick < 1e-4 || maxTick > 1e+15) { - notation = 'scientific'; - } - delta = calculateDelta(tickValue, ticks); - } - const logDelta = log10(Math.abs(delta)); - const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); - const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; - Object.assign(options, this.options.ticks.format); - return formatNumber(tickValue, locale, options); - }, - logarithmic(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); - if (remain === 1 || remain === 2 || remain === 5) { - return formatters.numeric.call(this, tickValue, index, ticks); - } - return ''; - } -}; -function calculateDelta(tickValue, ticks) { - let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; - if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { - delta = tickValue - Math.floor(tickValue); - } - return delta; -} -var Ticks = {formatters}; - -defaults.set('scale', { - display: true, - offset: false, - reverse: false, - beginAtZero: false, - bounds: 'ticks', - grace: 0, - grid: { - display: true, - lineWidth: 1, - drawBorder: true, - drawOnChartArea: true, - drawTicks: true, - tickLength: 8, - tickWidth: (_ctx, options) => options.lineWidth, - tickColor: (_ctx, options) => options.color, - offset: false, - borderDash: [], - borderDashOffset: 0.0, - borderWidth: 1 - }, - title: { - display: false, - text: '', - padding: { - top: 4, - bottom: 4 - } - }, - ticks: { - minRotation: 0, - maxRotation: 50, - mirror: false, - textStrokeWidth: 0, - textStrokeColor: '', - padding: 3, - display: true, - autoSkip: true, - autoSkipPadding: 3, - labelOffset: 0, - callback: Ticks.formatters.values, - minor: {}, - major: {}, - align: 'center', - crossAlign: 'near', - showLabelBackdrop: false, - backdropColor: 'rgba(255, 255, 255, 0.75)', - backdropPadding: 2, - } -}); -defaults.route('scale.ticks', 'color', '', 'color'); -defaults.route('scale.grid', 'color', '', 'borderColor'); -defaults.route('scale.grid', 'borderColor', '', 'borderColor'); -defaults.route('scale.title', 'color', '', 'color'); -defaults.describe('scale', { - _fallback: false, - _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', - _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash', -}); -defaults.describe('scales', { - _fallback: 'scale', -}); -defaults.describe('scale.ticks', { - _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback', - _indexable: (name) => name !== 'backdropPadding', -}); - -function autoSkip(scale, ticks) { - const tickOpts = scale.options.ticks; - const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale); - const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; - const numMajorIndices = majorIndices.length; - const first = majorIndices[0]; - const last = majorIndices[numMajorIndices - 1]; - const newTicks = []; - if (numMajorIndices > ticksLimit) { - skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); - return newTicks; - } - const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); - if (numMajorIndices > 0) { - let i, ilen; - const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; - skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); - for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { - skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); - } - skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); - return newTicks; - } - skip(ticks, newTicks, spacing); - return newTicks; -} -function determineMaxTicks(scale) { - const offset = scale.options.offset; - const tickLength = scale._tickSize(); - const maxScale = scale._length / tickLength + (offset ? 0 : 1); - const maxChart = scale._maxLength / tickLength; - return Math.floor(Math.min(maxScale, maxChart)); -} -function calculateSpacing(majorIndices, ticks, ticksLimit) { - const evenMajorSpacing = getEvenSpacing(majorIndices); - const spacing = ticks.length / ticksLimit; - if (!evenMajorSpacing) { - return Math.max(spacing, 1); - } - const factors = _factorize(evenMajorSpacing); - for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { - const factor = factors[i]; - if (factor > spacing) { - return factor; - } - } - return Math.max(spacing, 1); -} -function getMajorIndices(ticks) { - const result = []; - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (ticks[i].major) { - result.push(i); - } - } - return result; -} -function skipMajors(ticks, newTicks, majorIndices, spacing) { - let count = 0; - let next = majorIndices[0]; - let i; - spacing = Math.ceil(spacing); - for (i = 0; i < ticks.length; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = majorIndices[count * spacing]; - } - } -} -function skip(ticks, newTicks, spacing, majorStart, majorEnd) { - const start = valueOrDefault(majorStart, 0); - const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); - let count = 0; - let length, i, next; - spacing = Math.ceil(spacing); - if (majorEnd) { - length = majorEnd - majorStart; - spacing = length / Math.floor(length / spacing); - } - next = start; - while (next < 0) { - count++; - next = Math.round(start + count * spacing); - } - for (i = Math.max(start, 0); i < end; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = Math.round(start + count * spacing); - } - } -} -function getEvenSpacing(arr) { - const len = arr.length; - let i, diff; - if (len < 2) { - return false; - } - for (diff = arr[0], i = 1; i < len; ++i) { - if (arr[i] - arr[i - 1] !== diff) { - return false; - } - } - return diff; -} - -const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align; -const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; -function sample(arr, numItems) { - const result = []; - const increment = arr.length / numItems; - const len = arr.length; - let i = 0; - for (; i < len; i += increment) { - result.push(arr[Math.floor(i)]); - } - return result; -} -function getPixelForGridLine(scale, index, offsetGridLines) { - const length = scale.ticks.length; - const validIndex = Math.min(index, length - 1); - const start = scale._startPixel; - const end = scale._endPixel; - const epsilon = 1e-6; - let lineValue = scale.getPixelForTick(validIndex); - let offset; - if (offsetGridLines) { - if (length === 1) { - offset = Math.max(lineValue - start, end - lineValue); - } else if (index === 0) { - offset = (scale.getPixelForTick(1) - lineValue) / 2; - } else { - offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; - } - lineValue += validIndex < index ? offset : -offset; - if (lineValue < start - epsilon || lineValue > end + epsilon) { - return; - } - } - return lineValue; -} -function garbageCollect(caches, length) { - each(caches, (cache) => { - const gc = cache.gc; - const gcLen = gc.length / 2; - let i; - if (gcLen > length) { - for (i = 0; i < gcLen; ++i) { - delete cache.data[gc[i]]; - } - gc.splice(0, gcLen); - } - }); -} -function getTickMarkLength(options) { - return options.drawTicks ? options.tickLength : 0; -} -function getTitleHeight(options, fallback) { - if (!options.display) { - return 0; - } - const font = toFont(options.font, fallback); - const padding = toPadding(options.padding); - const lines = isArray(options.text) ? options.text.length : 1; - return (lines * font.lineHeight) + padding.height; -} -function createScaleContext(parent, scale) { - return createContext(parent, { - scale, - type: 'scale' - }); -} -function createTickContext(parent, index, tick) { - return createContext(parent, { - tick, - index, - type: 'tick' - }); -} -function titleAlign(align, position, reverse) { - let ret = _toLeftRightCenter(align); - if ((reverse && position !== 'right') || (!reverse && position === 'right')) { - ret = reverseAlign(ret); - } - return ret; -} -function titleArgs(scale, offset, position, align) { - const {top, left, bottom, right, chart} = scale; - const {chartArea, scales} = chart; - let rotation = 0; - let maxWidth, titleX, titleY; - const height = bottom - top; - const width = right - left; - if (scale.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; - } else if (position === 'center') { - titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; - } else { - titleY = offsetFromEdge(scale, position, offset); - } - maxWidth = right - left; - } else { - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; - } else if (position === 'center') { - titleX = (chartArea.left + chartArea.right) / 2 - width + offset; - } else { - titleX = offsetFromEdge(scale, position, offset); - } - titleY = _alignStartEnd(align, bottom, top); - rotation = position === 'left' ? -HALF_PI : HALF_PI; - } - return {titleX, titleY, maxWidth, rotation}; -} -class Scale extends Element { - constructor(cfg) { - super(); - this.id = cfg.id; - this.type = cfg.type; - this.options = undefined; - this.ctx = cfg.ctx; - this.chart = cfg.chart; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this._margins = { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - this.maxWidth = undefined; - this.maxHeight = undefined; - this.paddingTop = undefined; - this.paddingBottom = undefined; - this.paddingLeft = undefined; - this.paddingRight = undefined; - this.axis = undefined; - this.labelRotation = undefined; - this.min = undefined; - this.max = undefined; - this._range = undefined; - this.ticks = []; - this._gridLineItems = null; - this._labelItems = null; - this._labelSizes = null; - this._length = 0; - this._maxLength = 0; - this._longestTextCache = {}; - this._startPixel = undefined; - this._endPixel = undefined; - this._reversePixels = false; - this._userMax = undefined; - this._userMin = undefined; - this._suggestedMax = undefined; - this._suggestedMin = undefined; - this._ticksLength = 0; - this._borderValue = 0; - this._cache = {}; - this._dataLimitsCached = false; - this.$context = undefined; - } - init(options) { - this.options = options.setContext(this.getContext()); - this.axis = options.axis; - this._userMin = this.parse(options.min); - this._userMax = this.parse(options.max); - this._suggestedMin = this.parse(options.suggestedMin); - this._suggestedMax = this.parse(options.suggestedMax); - } - parse(raw, index) { - return raw; - } - getUserBounds() { - let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this; - _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); - _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); - _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); - _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); - return { - min: finiteOrDefault(_userMin, _suggestedMin), - max: finiteOrDefault(_userMax, _suggestedMax), - minDefined: isNumberFinite(_userMin), - maxDefined: isNumberFinite(_userMax) - }; - } - getMinMax(canStack) { - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - let range; - if (minDefined && maxDefined) { - return {min, max}; - } - const metas = this.getMatchingVisibleMetas(); - for (let i = 0, ilen = metas.length; i < ilen; ++i) { - range = metas[i].controller.getMinMax(this, canStack); - if (!minDefined) { - min = Math.min(min, range.min); - } - if (!maxDefined) { - max = Math.max(max, range.max); - } - } - min = maxDefined && min > max ? max : min; - max = minDefined && min > max ? min : max; - return { - min: finiteOrDefault(min, finiteOrDefault(max, min)), - max: finiteOrDefault(max, finiteOrDefault(min, max)) - }; - } - getPadding() { - return { - left: this.paddingLeft || 0, - top: this.paddingTop || 0, - right: this.paddingRight || 0, - bottom: this.paddingBottom || 0 - }; - } - getTicks() { - return this.ticks; - } - getLabels() { - const data = this.chart.data; - return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; - } - beforeLayout() { - this._cache = {}; - this._dataLimitsCached = false; - } - beforeUpdate() { - callback(this.options.beforeUpdate, [this]); - } - update(maxWidth, maxHeight, margins) { - const {beginAtZero, grace, ticks: tickOpts} = this.options; - const sampleSize = tickOpts.sampleSize; - this.beforeUpdate(); - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins = Object.assign({ - left: 0, - right: 0, - top: 0, - bottom: 0 - }, margins); - this.ticks = null; - this._labelSizes = null; - this._gridLineItems = null; - this._labelItems = null; - this.beforeSetDimensions(); - this.setDimensions(); - this.afterSetDimensions(); - this._maxLength = this.isHorizontal() - ? this.width + margins.left + margins.right - : this.height + margins.top + margins.bottom; - if (!this._dataLimitsCached) { - this.beforeDataLimits(); - this.determineDataLimits(); - this.afterDataLimits(); - this._range = _addGrace(this, grace, beginAtZero); - this._dataLimitsCached = true; - } - this.beforeBuildTicks(); - this.ticks = this.buildTicks() || []; - this.afterBuildTicks(); - const samplingEnabled = sampleSize < this.ticks.length; - this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); - this.configure(); - this.beforeCalculateLabelRotation(); - this.calculateLabelRotation(); - this.afterCalculateLabelRotation(); - if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { - this.ticks = autoSkip(this, this.ticks); - this._labelSizes = null; - } - if (samplingEnabled) { - this._convertTicksToLabels(this.ticks); - } - this.beforeFit(); - this.fit(); - this.afterFit(); - this.afterUpdate(); - } - configure() { - let reversePixels = this.options.reverse; - let startPixel, endPixel; - if (this.isHorizontal()) { - startPixel = this.left; - endPixel = this.right; - } else { - startPixel = this.top; - endPixel = this.bottom; - reversePixels = !reversePixels; - } - this._startPixel = startPixel; - this._endPixel = endPixel; - this._reversePixels = reversePixels; - this._length = endPixel - startPixel; - this._alignToPixels = this.options.alignToPixels; - } - afterUpdate() { - callback(this.options.afterUpdate, [this]); - } - beforeSetDimensions() { - callback(this.options.beforeSetDimensions, [this]); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = 0; - this.right = this.width; - } else { - this.height = this.maxHeight; - this.top = 0; - this.bottom = this.height; - } - this.paddingLeft = 0; - this.paddingTop = 0; - this.paddingRight = 0; - this.paddingBottom = 0; - } - afterSetDimensions() { - callback(this.options.afterSetDimensions, [this]); - } - _callHooks(name) { - this.chart.notifyPlugins(name, this.getContext()); - callback(this.options[name], [this]); - } - beforeDataLimits() { - this._callHooks('beforeDataLimits'); - } - determineDataLimits() {} - afterDataLimits() { - this._callHooks('afterDataLimits'); - } - beforeBuildTicks() { - this._callHooks('beforeBuildTicks'); - } - buildTicks() { - return []; - } - afterBuildTicks() { - this._callHooks('afterBuildTicks'); - } - beforeTickToLabelConversion() { - callback(this.options.beforeTickToLabelConversion, [this]); - } - generateTickLabels(ticks) { - const tickOpts = this.options.ticks; - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - tick = ticks[i]; - tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this); - } - } - afterTickToLabelConversion() { - callback(this.options.afterTickToLabelConversion, [this]); - } - beforeCalculateLabelRotation() { - callback(this.options.beforeCalculateLabelRotation, [this]); - } - calculateLabelRotation() { - const options = this.options; - const tickOpts = options.ticks; - const numTicks = this.ticks.length; - const minRotation = tickOpts.minRotation || 0; - const maxRotation = tickOpts.maxRotation; - let labelRotation = minRotation; - let tickWidth, maxHeight, maxLabelDiagonal; - if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { - this.labelRotation = minRotation; - return; - } - const labelSizes = this._getLabelSizes(); - const maxLabelWidth = labelSizes.widest.width; - const maxLabelHeight = labelSizes.highest.height; - const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); - tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); - if (maxLabelWidth + 6 > tickWidth) { - tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); - maxHeight = this.maxHeight - getTickMarkLength(options.grid) - - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); - maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); - labelRotation = toDegrees(Math.min( - Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), - Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)) - )); - labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); - } - this.labelRotation = labelRotation; - } - afterCalculateLabelRotation() { - callback(this.options.afterCalculateLabelRotation, [this]); - } - beforeFit() { - callback(this.options.beforeFit, [this]); - } - fit() { - const minSize = { - width: 0, - height: 0 - }; - const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this; - const display = this._isVisible(); - const isHorizontal = this.isHorizontal(); - if (display) { - const titleHeight = getTitleHeight(titleOpts, chart.options.font); - if (isHorizontal) { - minSize.width = this.maxWidth; - minSize.height = getTickMarkLength(gridOpts) + titleHeight; - } else { - minSize.height = this.maxHeight; - minSize.width = getTickMarkLength(gridOpts) + titleHeight; - } - if (tickOpts.display && this.ticks.length) { - const {first, last, widest, highest} = this._getLabelSizes(); - const tickPadding = tickOpts.padding * 2; - const angleRadians = toRadians(this.labelRotation); - const cos = Math.cos(angleRadians); - const sin = Math.sin(angleRadians); - if (isHorizontal) { - const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; - minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); - } else { - const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; - minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); - } - this._calculatePadding(first, last, sin, cos); - } - } - this._handleMargins(); - if (isHorizontal) { - this.width = this._length = chart.width - this._margins.left - this._margins.right; - this.height = minSize.height; - } else { - this.width = minSize.width; - this.height = this._length = chart.height - this._margins.top - this._margins.bottom; - } - } - _calculatePadding(first, last, sin, cos) { - const {ticks: {align, padding}, position} = this.options; - const isRotated = this.labelRotation !== 0; - const labelsBelowTicks = position !== 'top' && this.axis === 'x'; - if (this.isHorizontal()) { - const offsetLeft = this.getPixelForTick(0) - this.left; - const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); - let paddingLeft = 0; - let paddingRight = 0; - if (isRotated) { - if (labelsBelowTicks) { - paddingLeft = cos * first.width; - paddingRight = sin * last.height; - } else { - paddingLeft = sin * first.height; - paddingRight = cos * last.width; - } - } else if (align === 'start') { - paddingRight = last.width; - } else if (align === 'end') { - paddingLeft = first.width; - } else { - paddingLeft = first.width / 2; - paddingRight = last.width / 2; - } - this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); - this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); - } else { - let paddingTop = last.height / 2; - let paddingBottom = first.height / 2; - if (align === 'start') { - paddingTop = 0; - paddingBottom = first.height; - } else if (align === 'end') { - paddingTop = last.height; - paddingBottom = 0; - } - this.paddingTop = paddingTop + padding; - this.paddingBottom = paddingBottom + padding; - } - } - _handleMargins() { - if (this._margins) { - this._margins.left = Math.max(this.paddingLeft, this._margins.left); - this._margins.top = Math.max(this.paddingTop, this._margins.top); - this._margins.right = Math.max(this.paddingRight, this._margins.right); - this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); - } - } - afterFit() { - callback(this.options.afterFit, [this]); - } - isHorizontal() { - const {axis, position} = this.options; - return position === 'top' || position === 'bottom' || axis === 'x'; - } - isFullSize() { - return this.options.fullSize; - } - _convertTicksToLabels(ticks) { - this.beforeTickToLabelConversion(); - this.generateTickLabels(ticks); - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (isNullOrUndef(ticks[i].label)) { - ticks.splice(i, 1); - ilen--; - i--; - } - } - this.afterTickToLabelConversion(); - } - _getLabelSizes() { - let labelSizes = this._labelSizes; - if (!labelSizes) { - const sampleSize = this.options.ticks.sampleSize; - let ticks = this.ticks; - if (sampleSize < ticks.length) { - ticks = sample(ticks, sampleSize); - } - this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length); - } - return labelSizes; - } - _computeLabelSizes(ticks, length) { - const {ctx, _longestTextCache: caches} = this; - const widths = []; - const heights = []; - let widestLabelSize = 0; - let highestLabelSize = 0; - let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; - for (i = 0; i < length; ++i) { - label = ticks[i].label; - tickFont = this._resolveTickFontOptions(i); - ctx.font = fontString = tickFont.string; - cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; - lineHeight = tickFont.lineHeight; - width = height = 0; - if (!isNullOrUndef(label) && !isArray(label)) { - width = _measureText(ctx, cache.data, cache.gc, width, label); - height = lineHeight; - } else if (isArray(label)) { - for (j = 0, jlen = label.length; j < jlen; ++j) { - nestedLabel = label[j]; - if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { - width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); - height += lineHeight; - } - } - } - widths.push(width); - heights.push(height); - widestLabelSize = Math.max(width, widestLabelSize); - highestLabelSize = Math.max(height, highestLabelSize); - } - garbageCollect(caches, length); - const widest = widths.indexOf(widestLabelSize); - const highest = heights.indexOf(highestLabelSize); - const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0}); - return { - first: valueAt(0), - last: valueAt(length - 1), - widest: valueAt(widest), - highest: valueAt(highest), - widths, - heights, - }; - } - getLabelForValue(value) { - return value; - } - getPixelForValue(value, index) { - return NaN; - } - getValueForPixel(pixel) {} - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getPixelForDecimal(decimal) { - if (this._reversePixels) { - decimal = 1 - decimal; - } - const pixel = this._startPixel + decimal * this._length; - return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); - } - getDecimalForPixel(pixel) { - const decimal = (pixel - this._startPixel) / this._length; - return this._reversePixels ? 1 - decimal : decimal; - } - getBasePixel() { - return this.getPixelForValue(this.getBaseValue()); - } - getBaseValue() { - const {min, max} = this; - return min < 0 && max < 0 ? max : - min > 0 && max > 0 ? min : - 0; - } - getContext(index) { - const ticks = this.ticks || []; - if (index >= 0 && index < ticks.length) { - const tick = ticks[index]; - return tick.$context || - (tick.$context = createTickContext(this.getContext(), index, tick)); - } - return this.$context || - (this.$context = createScaleContext(this.chart.getContext(), this)); - } - _tickSize() { - const optionTicks = this.options.ticks; - const rot = toRadians(this.labelRotation); - const cos = Math.abs(Math.cos(rot)); - const sin = Math.abs(Math.sin(rot)); - const labelSizes = this._getLabelSizes(); - const padding = optionTicks.autoSkipPadding || 0; - const w = labelSizes ? labelSizes.widest.width + padding : 0; - const h = labelSizes ? labelSizes.highest.height + padding : 0; - return this.isHorizontal() - ? h * cos > w * sin ? w / cos : h / sin - : h * sin < w * cos ? h / cos : w / sin; - } - _isVisible() { - const display = this.options.display; - if (display !== 'auto') { - return !!display; - } - return this.getMatchingVisibleMetas().length > 0; - } - _computeGridLineItems(chartArea) { - const axis = this.axis; - const chart = this.chart; - const options = this.options; - const {grid, position} = options; - const offset = grid.offset; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const ticksLength = ticks.length + (offset ? 1 : 0); - const tl = getTickMarkLength(grid); - const items = []; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0; - const axisHalfWidth = axisWidth / 2; - const alignBorderValue = function(pixel) { - return _alignPixel(chart, pixel, axisWidth); - }; - let borderValue, i, lineValue, alignedLineValue; - let tx1, ty1, tx2, ty2, x1, y1, x2, y2; - if (position === 'top') { - borderValue = alignBorderValue(this.bottom); - ty1 = this.bottom - tl; - ty2 = borderValue - axisHalfWidth; - y1 = alignBorderValue(chartArea.top) + axisHalfWidth; - y2 = chartArea.bottom; - } else if (position === 'bottom') { - borderValue = alignBorderValue(this.top); - y1 = chartArea.top; - y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; - ty1 = borderValue + axisHalfWidth; - ty2 = this.top + tl; - } else if (position === 'left') { - borderValue = alignBorderValue(this.right); - tx1 = this.right - tl; - tx2 = borderValue - axisHalfWidth; - x1 = alignBorderValue(chartArea.left) + axisHalfWidth; - x2 = chartArea.right; - } else if (position === 'right') { - borderValue = alignBorderValue(this.left); - x1 = chartArea.left; - x2 = alignBorderValue(chartArea.right) - axisHalfWidth; - tx1 = borderValue + axisHalfWidth; - tx2 = this.left + tl; - } else if (axis === 'x') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - y1 = chartArea.top; - y2 = chartArea.bottom; - ty1 = borderValue + axisHalfWidth; - ty2 = ty1 + tl; - } else if (axis === 'y') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - tx1 = borderValue - axisHalfWidth; - tx2 = tx1 - tl; - x1 = chartArea.left; - x2 = chartArea.right; - } - const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); - const step = Math.max(1, Math.ceil(ticksLength / limit)); - for (i = 0; i < ticksLength; i += step) { - const optsAtIndex = grid.setContext(this.getContext(i)); - const lineWidth = optsAtIndex.lineWidth; - const lineColor = optsAtIndex.color; - const borderDash = grid.borderDash || []; - const borderDashOffset = optsAtIndex.borderDashOffset; - const tickWidth = optsAtIndex.tickWidth; - const tickColor = optsAtIndex.tickColor; - const tickBorderDash = optsAtIndex.tickBorderDash || []; - const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; - lineValue = getPixelForGridLine(this, i, offset); - if (lineValue === undefined) { - continue; - } - alignedLineValue = _alignPixel(chart, lineValue, lineWidth); - if (isHorizontal) { - tx1 = tx2 = x1 = x2 = alignedLineValue; - } else { - ty1 = ty2 = y1 = y2 = alignedLineValue; - } - items.push({ - tx1, - ty1, - tx2, - ty2, - x1, - y1, - x2, - y2, - width: lineWidth, - color: lineColor, - borderDash, - borderDashOffset, - tickWidth, - tickColor, - tickBorderDash, - tickBorderDashOffset, - }); - } - this._ticksLength = ticksLength; - this._borderValue = borderValue; - return items; - } - _computeLabelItems(chartArea) { - const axis = this.axis; - const options = this.options; - const {position, ticks: optionTicks} = options; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const {align, crossAlign, padding, mirror} = optionTicks; - const tl = getTickMarkLength(options.grid); - const tickAndPadding = tl + padding; - const hTickAndPadding = mirror ? -padding : tickAndPadding; - const rotation = -toRadians(this.labelRotation); - const items = []; - let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; - let textBaseline = 'middle'; - if (position === 'top') { - y = this.bottom - hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'bottom') { - y = this.top + hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'left') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (position === 'right') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (axis === 'x') { - if (position === 'center') { - y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; - } - textAlign = this._getXAxisLabelAlignment(); - } else if (axis === 'y') { - if (position === 'center') { - x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - x = this.chart.scales[positionAxisID].getPixelForValue(value); - } - textAlign = this._getYAxisLabelAlignment(tl).textAlign; - } - if (axis === 'y') { - if (align === 'start') { - textBaseline = 'top'; - } else if (align === 'end') { - textBaseline = 'bottom'; - } - } - const labelSizes = this._getLabelSizes(); - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - label = tick.label; - const optsAtIndex = optionTicks.setContext(this.getContext(i)); - pixel = this.getPixelForTick(i) + optionTicks.labelOffset; - font = this._resolveTickFontOptions(i); - lineHeight = font.lineHeight; - lineCount = isArray(label) ? label.length : 1; - const halfCount = lineCount / 2; - const color = optsAtIndex.color; - const strokeColor = optsAtIndex.textStrokeColor; - const strokeWidth = optsAtIndex.textStrokeWidth; - if (isHorizontal) { - x = pixel; - if (position === 'top') { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = -lineCount * lineHeight + lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; - } else { - textOffset = -labelSizes.highest.height + lineHeight / 2; - } - } else { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; - } else { - textOffset = labelSizes.highest.height - lineCount * lineHeight; - } - } - if (mirror) { - textOffset *= -1; - } - } else { - y = pixel; - textOffset = (1 - lineCount) * lineHeight / 2; - } - let backdrop; - if (optsAtIndex.showLabelBackdrop) { - const labelPadding = toPadding(optsAtIndex.backdropPadding); - const height = labelSizes.heights[i]; - const width = labelSizes.widths[i]; - let top = y + textOffset - labelPadding.top; - let left = x - labelPadding.left; - switch (textBaseline) { - case 'middle': - top -= height / 2; - break; - case 'bottom': - top -= height; - break; - } - switch (textAlign) { - case 'center': - left -= width / 2; - break; - case 'right': - left -= width; - break; - } - backdrop = { - left, - top, - width: width + labelPadding.width, - height: height + labelPadding.height, - color: optsAtIndex.backdropColor, - }; - } - items.push({ - rotation, - label, - font, - color, - strokeColor, - strokeWidth, - textOffset, - textAlign, - textBaseline, - translation: [x, y], - backdrop, - }); - } - return items; - } - _getXAxisLabelAlignment() { - const {position, ticks} = this.options; - const rotation = -toRadians(this.labelRotation); - if (rotation) { - return position === 'top' ? 'left' : 'right'; - } - let align = 'center'; - if (ticks.align === 'start') { - align = 'left'; - } else if (ticks.align === 'end') { - align = 'right'; - } - return align; - } - _getYAxisLabelAlignment(tl) { - const {position, ticks: {crossAlign, mirror, padding}} = this.options; - const labelSizes = this._getLabelSizes(); - const tickAndPadding = tl + padding; - const widest = labelSizes.widest.width; - let textAlign; - let x; - if (position === 'left') { - if (mirror) { - x = this.right + padding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += (widest / 2); - } else { - textAlign = 'right'; - x += widest; - } - } else { - x = this.right - tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x = this.left; - } - } - } else if (position === 'right') { - if (mirror) { - x = this.left + padding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x -= widest; - } - } else { - x = this.left + tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += widest / 2; - } else { - textAlign = 'right'; - x = this.right; - } - } - } else { - textAlign = 'right'; - } - return {textAlign, x}; - } - _computeLabelArea() { - if (this.options.ticks.mirror) { - return; - } - const chart = this.chart; - const position = this.options.position; - if (position === 'left' || position === 'right') { - return {top: 0, left: this.left, bottom: chart.height, right: this.right}; - } if (position === 'top' || position === 'bottom') { - return {top: this.top, left: 0, bottom: this.bottom, right: chart.width}; - } - } - drawBackground() { - const {ctx, options: {backgroundColor}, left, top, width, height} = this; - if (backgroundColor) { - ctx.save(); - ctx.fillStyle = backgroundColor; - ctx.fillRect(left, top, width, height); - ctx.restore(); - } - } - getLineWidthForValue(value) { - const grid = this.options.grid; - if (!this._isVisible() || !grid.display) { - return 0; - } - const ticks = this.ticks; - const index = ticks.findIndex(t => t.value === value); - if (index >= 0) { - const opts = grid.setContext(this.getContext(index)); - return opts.lineWidth; - } - return 0; - } - drawGrid(chartArea) { - const grid = this.options.grid; - const ctx = this.ctx; - const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); - let i, ilen; - const drawLine = (p1, p2, style) => { - if (!style.width || !style.color) { - return; - } - ctx.save(); - ctx.lineWidth = style.width; - ctx.strokeStyle = style.color; - ctx.setLineDash(style.borderDash || []); - ctx.lineDashOffset = style.borderDashOffset; - ctx.beginPath(); - ctx.moveTo(p1.x, p1.y); - ctx.lineTo(p2.x, p2.y); - ctx.stroke(); - ctx.restore(); - }; - if (grid.display) { - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - if (grid.drawOnChartArea) { - drawLine( - {x: item.x1, y: item.y1}, - {x: item.x2, y: item.y2}, - item - ); - } - if (grid.drawTicks) { - drawLine( - {x: item.tx1, y: item.ty1}, - {x: item.tx2, y: item.ty2}, - { - color: item.tickColor, - width: item.tickWidth, - borderDash: item.tickBorderDash, - borderDashOffset: item.tickBorderDashOffset - } - ); - } - } - } - } - drawBorder() { - const {chart, ctx, options: {grid}} = this; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0; - if (!axisWidth) { - return; - } - const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; - const borderValue = this._borderValue; - let x1, x2, y1, y2; - if (this.isHorizontal()) { - x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; - x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; - y1 = y2 = borderValue; - } else { - y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; - y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; - x1 = x2 = borderValue; - } - ctx.save(); - ctx.lineWidth = borderOpts.borderWidth; - ctx.strokeStyle = borderOpts.borderColor; - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); - ctx.restore(); - } - drawLabels(chartArea) { - const optionTicks = this.options.ticks; - if (!optionTicks.display) { - return; - } - const ctx = this.ctx; - const area = this._computeLabelArea(); - if (area) { - clipArea(ctx, area); - } - const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - const tickFont = item.font; - const label = item.label; - if (item.backdrop) { - ctx.fillStyle = item.backdrop.color; - ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); - } - let y = item.textOffset; - renderText(ctx, label, 0, y, tickFont, item); - } - if (area) { - unclipArea(ctx); - } - } - drawTitle() { - const {ctx, options: {position, title, reverse}} = this; - if (!title.display) { - return; - } - const font = toFont(title.font); - const padding = toPadding(title.padding); - const align = title.align; - let offset = font.lineHeight / 2; - if (position === 'bottom' || position === 'center' || isObject(position)) { - offset += padding.bottom; - if (isArray(title.text)) { - offset += font.lineHeight * (title.text.length - 1); - } - } else { - offset += padding.top; - } - const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align); - renderText(ctx, title.text, 0, 0, font, { - color: title.color, - maxWidth, - rotation, - textAlign: titleAlign(align, position, reverse), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } - draw(chartArea) { - if (!this._isVisible()) { - return; - } - this.drawBackground(); - this.drawGrid(chartArea); - this.drawBorder(); - this.drawTitle(); - this.drawLabels(chartArea); - } - _layers() { - const opts = this.options; - const tz = opts.ticks && opts.ticks.z || 0; - const gz = valueOrDefault(opts.grid && opts.grid.z, -1); - if (!this._isVisible() || this.draw !== Scale.prototype.draw) { - return [{ - z: tz, - draw: (chartArea) => { - this.draw(chartArea); - } - }]; - } - return [{ - z: gz, - draw: (chartArea) => { - this.drawBackground(); - this.drawGrid(chartArea); - this.drawTitle(); - } - }, { - z: gz + 1, - draw: () => { - this.drawBorder(); - } - }, { - z: tz, - draw: (chartArea) => { - this.drawLabels(chartArea); - } - }]; - } - getMatchingVisibleMetas(type) { - const metas = this.chart.getSortedVisibleDatasetMetas(); - const axisID = this.axis + 'AxisID'; - const result = []; - let i, ilen; - for (i = 0, ilen = metas.length; i < ilen; ++i) { - const meta = metas[i]; - if (meta[axisID] === this.id && (!type || meta.type === type)) { - result.push(meta); - } - } - return result; - } - _resolveTickFontOptions(index) { - const opts = this.options.ticks.setContext(this.getContext(index)); - return toFont(opts.font); - } - _maxDigits() { - const fontSize = this._resolveTickFontOptions(0).lineHeight; - return (this.isHorizontal() ? this.width : this.height) / fontSize; - } -} - -class TypedRegistry { - constructor(type, scope, override) { - this.type = type; - this.scope = scope; - this.override = override; - this.items = Object.create(null); - } - isForType(type) { - return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); - } - register(item) { - const proto = Object.getPrototypeOf(item); - let parentScope; - if (isIChartComponent(proto)) { - parentScope = this.register(proto); - } - const items = this.items; - const id = item.id; - const scope = this.scope + '.' + id; - if (!id) { - throw new Error('class does not have id: ' + item); - } - if (id in items) { - return scope; - } - items[id] = item; - registerDefaults(item, scope, parentScope); - if (this.override) { - defaults.override(item.id, item.overrides); - } - return scope; - } - get(id) { - return this.items[id]; - } - unregister(item) { - const items = this.items; - const id = item.id; - const scope = this.scope; - if (id in items) { - delete items[id]; - } - if (scope && id in defaults[scope]) { - delete defaults[scope][id]; - if (this.override) { - delete overrides[id]; - } - } - } -} -function registerDefaults(item, scope, parentScope) { - const itemDefaults = merge(Object.create(null), [ - parentScope ? defaults.get(parentScope) : {}, - defaults.get(scope), - item.defaults - ]); - defaults.set(scope, itemDefaults); - if (item.defaultRoutes) { - routeDefaults(scope, item.defaultRoutes); - } - if (item.descriptors) { - defaults.describe(scope, item.descriptors); - } -} -function routeDefaults(scope, routes) { - Object.keys(routes).forEach(property => { - const propertyParts = property.split('.'); - const sourceName = propertyParts.pop(); - const sourceScope = [scope].concat(propertyParts).join('.'); - const parts = routes[property].split('.'); - const targetName = parts.pop(); - const targetScope = parts.join('.'); - defaults.route(sourceScope, sourceName, targetScope, targetName); - }); -} -function isIChartComponent(proto) { - return 'id' in proto && 'defaults' in proto; -} - -class Registry { - constructor() { - this.controllers = new TypedRegistry(DatasetController, 'datasets', true); - this.elements = new TypedRegistry(Element, 'elements'); - this.plugins = new TypedRegistry(Object, 'plugins'); - this.scales = new TypedRegistry(Scale, 'scales'); - this._typedRegistries = [this.controllers, this.scales, this.elements]; - } - add(...args) { - this._each('register', args); - } - remove(...args) { - this._each('unregister', args); - } - addControllers(...args) { - this._each('register', args, this.controllers); - } - addElements(...args) { - this._each('register', args, this.elements); - } - addPlugins(...args) { - this._each('register', args, this.plugins); - } - addScales(...args) { - this._each('register', args, this.scales); - } - getController(id) { - return this._get(id, this.controllers, 'controller'); - } - getElement(id) { - return this._get(id, this.elements, 'element'); - } - getPlugin(id) { - return this._get(id, this.plugins, 'plugin'); - } - getScale(id) { - return this._get(id, this.scales, 'scale'); - } - removeControllers(...args) { - this._each('unregister', args, this.controllers); - } - removeElements(...args) { - this._each('unregister', args, this.elements); - } - removePlugins(...args) { - this._each('unregister', args, this.plugins); - } - removeScales(...args) { - this._each('unregister', args, this.scales); - } - _each(method, args, typedRegistry) { - [...args].forEach(arg => { - const reg = typedRegistry || this._getRegistryForType(arg); - if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) { - this._exec(method, reg, arg); - } else { - each(arg, item => { - const itemReg = typedRegistry || this._getRegistryForType(item); - this._exec(method, itemReg, item); - }); - } - }); - } - _exec(method, registry, component) { - const camelMethod = _capitalize(method); - callback(component['before' + camelMethod], [], component); - registry[method](component); - callback(component['after' + camelMethod], [], component); - } - _getRegistryForType(type) { - for (let i = 0; i < this._typedRegistries.length; i++) { - const reg = this._typedRegistries[i]; - if (reg.isForType(type)) { - return reg; - } - } - return this.plugins; - } - _get(id, typedRegistry, type) { - const item = typedRegistry.get(id); - if (item === undefined) { - throw new Error('"' + id + '" is not a registered ' + type + '.'); - } - return item; - } -} -var registry = new Registry(); - -class PluginService { - constructor() { - this._init = []; - } - notify(chart, hook, args, filter) { - if (hook === 'beforeInit') { - this._init = this._createDescriptors(chart, true); - this._notify(this._init, chart, 'install'); - } - const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); - const result = this._notify(descriptors, chart, hook, args); - if (hook === 'afterDestroy') { - this._notify(descriptors, chart, 'stop'); - this._notify(this._init, chart, 'uninstall'); - } - return result; - } - _notify(descriptors, chart, hook, args) { - args = args || {}; - for (const descriptor of descriptors) { - const plugin = descriptor.plugin; - const method = plugin[hook]; - const params = [chart, args, descriptor.options]; - if (callback(method, params, plugin) === false && args.cancelable) { - return false; - } - } - return true; - } - invalidate() { - if (!isNullOrUndef(this._cache)) { - this._oldCache = this._cache; - this._cache = undefined; - } - } - _descriptors(chart) { - if (this._cache) { - return this._cache; - } - const descriptors = this._cache = this._createDescriptors(chart); - this._notifyStateChanges(chart); - return descriptors; - } - _createDescriptors(chart, all) { - const config = chart && chart.config; - const options = valueOrDefault(config.options && config.options.plugins, {}); - const plugins = allPlugins(config); - return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); - } - _notifyStateChanges(chart) { - const previousDescriptors = this._oldCache || []; - const descriptors = this._cache; - const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id)); - this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); - this._notify(diff(descriptors, previousDescriptors), chart, 'start'); - } -} -function allPlugins(config) { - const plugins = []; - const keys = Object.keys(registry.plugins.items); - for (let i = 0; i < keys.length; i++) { - plugins.push(registry.getPlugin(keys[i])); - } - const local = config.plugins || []; - for (let i = 0; i < local.length; i++) { - const plugin = local[i]; - if (plugins.indexOf(plugin) === -1) { - plugins.push(plugin); - } - } - return plugins; -} -function getOpts(options, all) { - if (!all && options === false) { - return null; - } - if (options === true) { - return {}; - } - return options; -} -function createDescriptors(chart, plugins, options, all) { - const result = []; - const context = chart.getContext(); - for (let i = 0; i < plugins.length; i++) { - const plugin = plugins[i]; - const id = plugin.id; - const opts = getOpts(options[id], all); - if (opts === null) { - continue; - } - result.push({ - plugin, - options: pluginOpts(chart.config, plugin, opts, context) - }); - } - return result; -} -function pluginOpts(config, plugin, opts, context) { - const keys = config.pluginScopeKeys(plugin); - const scopes = config.getOptionScopes(opts, keys); - return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true}); -} - -function getIndexAxis(type, options) { - const datasetDefaults = defaults.datasets[type] || {}; - const datasetOptions = (options.datasets || {})[type] || {}; - return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; -} -function getAxisFromDefaultScaleID(id, indexAxis) { - let axis = id; - if (id === '_index_') { - axis = indexAxis; - } else if (id === '_value_') { - axis = indexAxis === 'x' ? 'y' : 'x'; - } - return axis; -} -function getDefaultScaleIDFromAxis(axis, indexAxis) { - return axis === indexAxis ? '_index_' : '_value_'; -} -function axisFromPosition(position) { - if (position === 'top' || position === 'bottom') { - return 'x'; - } - if (position === 'left' || position === 'right') { - return 'y'; - } -} -function determineAxis(id, scaleOptions) { - if (id === 'x' || id === 'y') { - return id; - } - return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); -} -function mergeScaleConfig(config, options) { - const chartDefaults = overrides[config.type] || {scales: {}}; - const configScales = options.scales || {}; - const chartIndexAxis = getIndexAxis(config.type, options); - const firstIDs = Object.create(null); - const scales = Object.create(null); - Object.keys(configScales).forEach(id => { - const scaleConf = configScales[id]; - if (!isObject(scaleConf)) { - return console.error(`Invalid scale configuration for scale: ${id}`); - } - if (scaleConf._proxy) { - return console.warn(`Ignoring resolver passed as options for scale: ${id}`); - } - const axis = determineAxis(id, scaleConf); - const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); - const defaultScaleOptions = chartDefaults.scales || {}; - firstIDs[axis] = firstIDs[axis] || id; - scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]); - }); - config.data.datasets.forEach(dataset => { - const type = dataset.type || config.type; - const indexAxis = dataset.indexAxis || getIndexAxis(type, options); - const datasetDefaults = overrides[type] || {}; - const defaultScaleOptions = datasetDefaults.scales || {}; - Object.keys(defaultScaleOptions).forEach(defaultID => { - const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); - const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; - scales[id] = scales[id] || Object.create(null); - mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); - }); - }); - Object.keys(scales).forEach(key => { - const scale = scales[key]; - mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); - }); - return scales; -} -function initOptions(config) { - const options = config.options || (config.options = {}); - options.plugins = valueOrDefault(options.plugins, {}); - options.scales = mergeScaleConfig(config, options); -} -function initData(data) { - data = data || {}; - data.datasets = data.datasets || []; - data.labels = data.labels || []; - return data; -} -function initConfig(config) { - config = config || {}; - config.data = initData(config.data); - initOptions(config); - return config; -} -const keyCache = new Map(); -const keysCached = new Set(); -function cachedKeys(cacheKey, generate) { - let keys = keyCache.get(cacheKey); - if (!keys) { - keys = generate(); - keyCache.set(cacheKey, keys); - keysCached.add(keys); - } - return keys; -} -const addIfFound = (set, obj, key) => { - const opts = resolveObjectKey(obj, key); - if (opts !== undefined) { - set.add(opts); - } -}; -class Config { - constructor(config) { - this._config = initConfig(config); - this._scopeCache = new Map(); - this._resolverCache = new Map(); - } - get platform() { - return this._config.platform; - } - get type() { - return this._config.type; - } - set type(type) { - this._config.type = type; - } - get data() { - return this._config.data; - } - set data(data) { - this._config.data = initData(data); - } - get options() { - return this._config.options; - } - set options(options) { - this._config.options = options; - } - get plugins() { - return this._config.plugins; - } - update() { - const config = this._config; - this.clearCache(); - initOptions(config); - } - clearCache() { - this._scopeCache.clear(); - this._resolverCache.clear(); - } - datasetScopeKeys(datasetType) { - return cachedKeys(datasetType, - () => [[ - `datasets.${datasetType}`, - '' - ]]); - } - datasetAnimationScopeKeys(datasetType, transition) { - return cachedKeys(`${datasetType}.transition.${transition}`, - () => [ - [ - `datasets.${datasetType}.transitions.${transition}`, - `transitions.${transition}`, - ], - [ - `datasets.${datasetType}`, - '' - ] - ]); - } - datasetElementScopeKeys(datasetType, elementType) { - return cachedKeys(`${datasetType}-${elementType}`, - () => [[ - `datasets.${datasetType}.elements.${elementType}`, - `datasets.${datasetType}`, - `elements.${elementType}`, - '' - ]]); - } - pluginScopeKeys(plugin) { - const id = plugin.id; - const type = this.type; - return cachedKeys(`${type}-plugin-${id}`, - () => [[ - `plugins.${id}`, - ...plugin.additionalOptionScopes || [], - ]]); - } - _cachedScopes(mainScope, resetCache) { - const _scopeCache = this._scopeCache; - let cache = _scopeCache.get(mainScope); - if (!cache || resetCache) { - cache = new Map(); - _scopeCache.set(mainScope, cache); - } - return cache; - } - getOptionScopes(mainScope, keyLists, resetCache) { - const {options, type} = this; - const cache = this._cachedScopes(mainScope, resetCache); - const cached = cache.get(keyLists); - if (cached) { - return cached; - } - const scopes = new Set(); - keyLists.forEach(keys => { - if (mainScope) { - scopes.add(mainScope); - keys.forEach(key => addIfFound(scopes, mainScope, key)); - } - keys.forEach(key => addIfFound(scopes, options, key)); - keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); - keys.forEach(key => addIfFound(scopes, defaults, key)); - keys.forEach(key => addIfFound(scopes, descriptors, key)); - }); - const array = Array.from(scopes); - if (array.length === 0) { - array.push(Object.create(null)); - } - if (keysCached.has(keyLists)) { - cache.set(keyLists, array); - } - return array; - } - chartOptionScopes() { - const {options, type} = this; - return [ - options, - overrides[type] || {}, - defaults.datasets[type] || {}, - {type}, - defaults, - descriptors - ]; - } - resolveNamedOptions(scopes, names, context, prefixes = ['']) { - const result = {$shared: true}; - const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes); - let options = resolver; - if (needContext(resolver, names)) { - result.$shared = false; - context = isFunction(context) ? context() : context; - const subResolver = this.createResolver(scopes, context, subPrefixes); - options = _attachContext(resolver, context, subResolver); - } - for (const prop of names) { - result[prop] = options[prop]; - } - return result; - } - createResolver(scopes, context, prefixes = [''], descriptorDefaults) { - const {resolver} = getResolver(this._resolverCache, scopes, prefixes); - return isObject(context) - ? _attachContext(resolver, context, undefined, descriptorDefaults) - : resolver; - } -} -function getResolver(resolverCache, scopes, prefixes) { - let cache = resolverCache.get(scopes); - if (!cache) { - cache = new Map(); - resolverCache.set(scopes, cache); - } - const cacheKey = prefixes.join(); - let cached = cache.get(cacheKey); - if (!cached) { - const resolver = _createResolver(scopes, prefixes); - cached = { - resolver, - subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover')) - }; - cache.set(cacheKey, cached); - } - return cached; -} -const hasFunction = value => isObject(value) - && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false); -function needContext(proxy, names) { - const {isScriptable, isIndexable} = _descriptors(proxy); - for (const prop of names) { - const scriptable = isScriptable(prop); - const indexable = isIndexable(prop); - const value = (indexable || scriptable) && proxy[prop]; - if ((scriptable && (isFunction(value) || hasFunction(value))) - || (indexable && isArray(value))) { - return true; - } - } - return false; -} - -var version = "3.7.1"; - -const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; -function positionIsHorizontal(position, axis) { - return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); -} -function compare2Level(l1, l2) { - return function(a, b) { - return a[l1] === b[l1] - ? a[l2] - b[l2] - : a[l1] - b[l1]; - }; -} -function onAnimationsComplete(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - chart.notifyPlugins('afterRender'); - callback(animationOptions && animationOptions.onComplete, [context], chart); -} -function onAnimationProgress(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - callback(animationOptions && animationOptions.onProgress, [context], chart); -} -function getCanvas(item) { - if (_isDomSupported() && typeof item === 'string') { - item = document.getElementById(item); - } else if (item && item.length) { - item = item[0]; - } - if (item && item.canvas) { - item = item.canvas; - } - return item; -} -const instances = {}; -const getChart = (key) => { - const canvas = getCanvas(key); - return Object.values(instances).filter((c) => c.canvas === canvas).pop(); -}; -function moveNumericKeys(obj, start, move) { - const keys = Object.keys(obj); - for (const key of keys) { - const intKey = +key; - if (intKey >= start) { - const value = obj[key]; - delete obj[key]; - if (move > 0 || intKey > start) { - obj[intKey + move] = value; - } - } - } -} -function determineLastEvent(e, lastEvent, inChartArea, isClick) { - if (!inChartArea || e.type === 'mouseout') { - return null; - } - if (isClick) { - return lastEvent; - } - return e; -} -class Chart { - constructor(item, userConfig) { - const config = this.config = new Config(userConfig); - const initialCanvas = getCanvas(item); - const existingChart = getChart(initialCanvas); - if (existingChart) { - throw new Error( - 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + - ' must be destroyed before the canvas can be reused.' - ); - } - const options = config.createResolver(config.chartOptionScopes(), this.getContext()); - this.platform = new (config.platform || _detectPlatform(initialCanvas))(); - this.platform.updateConfig(config); - const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); - const canvas = context && context.canvas; - const height = canvas && canvas.height; - const width = canvas && canvas.width; - this.id = uid(); - this.ctx = context; - this.canvas = canvas; - this.width = width; - this.height = height; - this._options = options; - this._aspectRatio = this.aspectRatio; - this._layers = []; - this._metasets = []; - this._stacks = undefined; - this.boxes = []; - this.currentDevicePixelRatio = undefined; - this.chartArea = undefined; - this._active = []; - this._lastEvent = undefined; - this._listeners = {}; - this._responsiveListeners = undefined; - this._sortedMetasets = []; - this.scales = {}; - this._plugins = new PluginService(); - this.$proxies = {}; - this._hiddenIndices = {}; - this.attached = false; - this._animationsDisabled = undefined; - this.$context = undefined; - this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0); - this._dataChanges = []; - instances[this.id] = this; - if (!context || !canvas) { - console.error("Failed to create chart: can't acquire context from the given item"); - return; - } - animator.listen(this, 'complete', onAnimationsComplete); - animator.listen(this, 'progress', onAnimationProgress); - this._initialize(); - if (this.attached) { - this.update(); - } - } - get aspectRatio() { - const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this; - if (!isNullOrUndef(aspectRatio)) { - return aspectRatio; - } - if (maintainAspectRatio && _aspectRatio) { - return _aspectRatio; - } - return height ? width / height : null; - } - get data() { - return this.config.data; - } - set data(data) { - this.config.data = data; - } - get options() { - return this._options; - } - set options(options) { - this.config.options = options; - } - _initialize() { - this.notifyPlugins('beforeInit'); - if (this.options.responsive) { - this.resize(); - } else { - retinaScale(this, this.options.devicePixelRatio); - } - this.bindEvents(); - this.notifyPlugins('afterInit'); - return this; - } - clear() { - clearCanvas(this.canvas, this.ctx); - return this; - } - stop() { - animator.stop(this); - return this; - } - resize(width, height) { - if (!animator.running(this)) { - this._resize(width, height); - } else { - this._resizeBeforeDraw = {width, height}; - } - } - _resize(width, height) { - const options = this.options; - const canvas = this.canvas; - const aspectRatio = options.maintainAspectRatio && this.aspectRatio; - const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); - const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); - const mode = this.width ? 'resize' : 'attach'; - this.width = newSize.width; - this.height = newSize.height; - this._aspectRatio = this.aspectRatio; - if (!retinaScale(this, newRatio, true)) { - return; - } - this.notifyPlugins('resize', {size: newSize}); - callback(options.onResize, [this, newSize], this); - if (this.attached) { - if (this._doResize(mode)) { - this.render(); - } - } - } - ensureScalesHaveIDs() { - const options = this.options; - const scalesOptions = options.scales || {}; - each(scalesOptions, (axisOptions, axisID) => { - axisOptions.id = axisID; - }); - } - buildOrUpdateScales() { - const options = this.options; - const scaleOpts = options.scales; - const scales = this.scales; - const updated = Object.keys(scales).reduce((obj, id) => { - obj[id] = false; - return obj; - }, {}); - let items = []; - if (scaleOpts) { - items = items.concat( - Object.keys(scaleOpts).map((id) => { - const scaleOptions = scaleOpts[id]; - const axis = determineAxis(id, scaleOptions); - const isRadial = axis === 'r'; - const isHorizontal = axis === 'x'; - return { - options: scaleOptions, - dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', - dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' - }; - }) - ); - } - each(items, (item) => { - const scaleOptions = item.options; - const id = scaleOptions.id; - const axis = determineAxis(id, scaleOptions); - const scaleType = valueOrDefault(scaleOptions.type, item.dtype); - if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { - scaleOptions.position = item.dposition; - } - updated[id] = true; - let scale = null; - if (id in scales && scales[id].type === scaleType) { - scale = scales[id]; - } else { - const scaleClass = registry.getScale(scaleType); - scale = new scaleClass({ - id, - type: scaleType, - ctx: this.ctx, - chart: this - }); - scales[scale.id] = scale; - } - scale.init(scaleOptions, options); - }); - each(updated, (hasUpdated, id) => { - if (!hasUpdated) { - delete scales[id]; - } - }); - each(scales, (scale) => { - layouts.configure(this, scale, scale.options); - layouts.addBox(this, scale); - }); - } - _updateMetasets() { - const metasets = this._metasets; - const numData = this.data.datasets.length; - const numMeta = metasets.length; - metasets.sort((a, b) => a.index - b.index); - if (numMeta > numData) { - for (let i = numData; i < numMeta; ++i) { - this._destroyDatasetMeta(i); - } - metasets.splice(numData, numMeta - numData); - } - this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); - } - _removeUnreferencedMetasets() { - const {_metasets: metasets, data: {datasets}} = this; - if (metasets.length > datasets.length) { - delete this._stacks; - } - metasets.forEach((meta, index) => { - if (datasets.filter(x => x === meta._dataset).length === 0) { - this._destroyDatasetMeta(index); - } - }); - } - buildOrUpdateControllers() { - const newControllers = []; - const datasets = this.data.datasets; - let i, ilen; - this._removeUnreferencedMetasets(); - for (i = 0, ilen = datasets.length; i < ilen; i++) { - const dataset = datasets[i]; - let meta = this.getDatasetMeta(i); - const type = dataset.type || this.config.type; - if (meta.type && meta.type !== type) { - this._destroyDatasetMeta(i); - meta = this.getDatasetMeta(i); - } - meta.type = type; - meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); - meta.order = dataset.order || 0; - meta.index = i; - meta.label = '' + dataset.label; - meta.visible = this.isDatasetVisible(i); - if (meta.controller) { - meta.controller.updateIndex(i); - meta.controller.linkScales(); - } else { - const ControllerClass = registry.getController(type); - const {datasetElementType, dataElementType} = defaults.datasets[type]; - Object.assign(ControllerClass.prototype, { - dataElementType: registry.getElement(dataElementType), - datasetElementType: datasetElementType && registry.getElement(datasetElementType) - }); - meta.controller = new ControllerClass(this, i); - newControllers.push(meta.controller); - } - } - this._updateMetasets(); - return newControllers; - } - _resetElements() { - each(this.data.datasets, (dataset, datasetIndex) => { - this.getDatasetMeta(datasetIndex).controller.reset(); - }, this); - } - reset() { - this._resetElements(); - this.notifyPlugins('reset'); - } - update(mode) { - const config = this.config; - config.update(); - const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); - const animsDisabled = this._animationsDisabled = !options.animation; - this._updateScales(); - this._checkEventBindings(); - this._updateHiddenIndices(); - this._plugins.invalidate(); - if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) { - return; - } - const newControllers = this.buildOrUpdateControllers(); - this.notifyPlugins('beforeElementsUpdate'); - let minPadding = 0; - for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) { - const {controller} = this.getDatasetMeta(i); - const reset = !animsDisabled && newControllers.indexOf(controller) === -1; - controller.buildOrUpdateElements(reset); - minPadding = Math.max(+controller.getMaxOverflow(), minPadding); - } - minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; - this._updateLayout(minPadding); - if (!animsDisabled) { - each(newControllers, (controller) => { - controller.reset(); - }); - } - this._updateDatasets(mode); - this.notifyPlugins('afterUpdate', {mode}); - this._layers.sort(compare2Level('z', '_idx')); - const {_active, _lastEvent} = this; - if (_lastEvent) { - this._eventHandler(_lastEvent, true); - } else if (_active.length) { - this._updateHoverStyles(_active, _active, true); - } - this.render(); - } - _updateScales() { - each(this.scales, (scale) => { - layouts.removeBox(this, scale); - }); - this.ensureScalesHaveIDs(); - this.buildOrUpdateScales(); - } - _checkEventBindings() { - const options = this.options; - const existingEvents = new Set(Object.keys(this._listeners)); - const newEvents = new Set(options.events); - if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { - this.unbindEvents(); - this.bindEvents(); - } - } - _updateHiddenIndices() { - const {_hiddenIndices} = this; - const changes = this._getUniformDataChanges() || []; - for (const {method, start, count} of changes) { - const move = method === '_removeElements' ? -count : count; - moveNumericKeys(_hiddenIndices, start, move); - } - } - _getUniformDataChanges() { - const _dataChanges = this._dataChanges; - if (!_dataChanges || !_dataChanges.length) { - return; - } - this._dataChanges = []; - const datasetCount = this.data.datasets.length; - const makeSet = (idx) => new Set( - _dataChanges - .filter(c => c[0] === idx) - .map((c, i) => i + ',' + c.splice(1).join(',')) - ); - const changeSet = makeSet(0); - for (let i = 1; i < datasetCount; i++) { - if (!setsEqual(changeSet, makeSet(i))) { - return; - } - } - return Array.from(changeSet) - .map(c => c.split(',')) - .map(a => ({method: a[1], start: +a[2], count: +a[3]})); - } - _updateLayout(minPadding) { - if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) { - return; - } - layouts.update(this, this.width, this.height, minPadding); - const area = this.chartArea; - const noArea = area.width <= 0 || area.height <= 0; - this._layers = []; - each(this.boxes, (box) => { - if (noArea && box.position === 'chartArea') { - return; - } - if (box.configure) { - box.configure(); - } - this._layers.push(...box._layers()); - }, this); - this._layers.forEach((item, index) => { - item._idx = index; - }); - this.notifyPlugins('afterLayout'); - } - _updateDatasets(mode) { - if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { - return; - } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this.getDatasetMeta(i).controller.configure(); - } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); - } - this.notifyPlugins('afterDatasetsUpdate', {mode}); - } - _updateDataset(index, mode) { - const meta = this.getDatasetMeta(index); - const args = {meta, index, mode, cancelable: true}; - if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { - return; - } - meta.controller._update(mode); - args.cancelable = false; - this.notifyPlugins('afterDatasetUpdate', args); - } - render() { - if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) { - return; - } - if (animator.has(this)) { - if (this.attached && !animator.running(this)) { - animator.start(this); - } - } else { - this.draw(); - onAnimationsComplete({chart: this}); - } - } - draw() { - let i; - if (this._resizeBeforeDraw) { - const {width, height} = this._resizeBeforeDraw; - this._resize(width, height); - this._resizeBeforeDraw = null; - } - this.clear(); - if (this.width <= 0 || this.height <= 0) { - return; - } - if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) { - return; - } - const layers = this._layers; - for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { - layers[i].draw(this.chartArea); - } - this._drawDatasets(); - for (; i < layers.length; ++i) { - layers[i].draw(this.chartArea); - } - this.notifyPlugins('afterDraw'); - } - _getSortedDatasetMetas(filterVisible) { - const metasets = this._sortedMetasets; - const result = []; - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - const meta = metasets[i]; - if (!filterVisible || meta.visible) { - result.push(meta); - } - } - return result; - } - getSortedVisibleDatasetMetas() { - return this._getSortedDatasetMetas(true); - } - _drawDatasets() { - if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) { - return; - } - const metasets = this.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - this._drawDataset(metasets[i]); - } - this.notifyPlugins('afterDatasetsDraw'); - } - _drawDataset(meta) { - const ctx = this.ctx; - const clip = meta._clip; - const useClip = !clip.disabled; - const area = this.chartArea; - const args = { - meta, - index: meta.index, - cancelable: true - }; - if (this.notifyPlugins('beforeDatasetDraw', args) === false) { - return; - } - if (useClip) { - clipArea(ctx, { - left: clip.left === false ? 0 : area.left - clip.left, - right: clip.right === false ? this.width : area.right + clip.right, - top: clip.top === false ? 0 : area.top - clip.top, - bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom - }); - } - meta.controller.draw(); - if (useClip) { - unclipArea(ctx); - } - args.cancelable = false; - this.notifyPlugins('afterDatasetDraw', args); - } - getElementsAtEventForMode(e, mode, options, useFinalPosition) { - const method = Interaction.modes[mode]; - if (typeof method === 'function') { - return method(this, e, options, useFinalPosition); - } - return []; - } - getDatasetMeta(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - const metasets = this._metasets; - let meta = metasets.filter(x => x && x._dataset === dataset).pop(); - if (!meta) { - meta = { - type: null, - data: [], - dataset: null, - controller: null, - hidden: null, - xAxisID: null, - yAxisID: null, - order: dataset && dataset.order || 0, - index: datasetIndex, - _dataset: dataset, - _parsed: [], - _sorted: false - }; - metasets.push(meta); - } - return meta; - } - getContext() { - return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'})); - } - getVisibleDatasetCount() { - return this.getSortedVisibleDatasetMetas().length; - } - isDatasetVisible(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - if (!dataset) { - return false; - } - const meta = this.getDatasetMeta(datasetIndex); - return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; - } - setDatasetVisibility(datasetIndex, visible) { - const meta = this.getDatasetMeta(datasetIndex); - meta.hidden = !visible; - } - toggleDataVisibility(index) { - this._hiddenIndices[index] = !this._hiddenIndices[index]; - } - getDataVisibility(index) { - return !this._hiddenIndices[index]; - } - _updateVisibility(datasetIndex, dataIndex, visible) { - const mode = visible ? 'show' : 'hide'; - const meta = this.getDatasetMeta(datasetIndex); - const anims = meta.controller._resolveAnimations(undefined, mode); - if (defined(dataIndex)) { - meta.data[dataIndex].hidden = !visible; - this.update(); - } else { - this.setDatasetVisibility(datasetIndex, visible); - anims.update(meta, {visible}); - this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); - } - } - hide(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, false); - } - show(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, true); - } - _destroyDatasetMeta(datasetIndex) { - const meta = this._metasets[datasetIndex]; - if (meta && meta.controller) { - meta.controller._destroy(); - } - delete this._metasets[datasetIndex]; - } - _stop() { - let i, ilen; - this.stop(); - animator.remove(this); - for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._destroyDatasetMeta(i); - } - } - destroy() { - this.notifyPlugins('beforeDestroy'); - const {canvas, ctx} = this; - this._stop(); - this.config.clearCache(); - if (canvas) { - this.unbindEvents(); - clearCanvas(canvas, ctx); - this.platform.releaseContext(ctx); - this.canvas = null; - this.ctx = null; - } - this.notifyPlugins('destroy'); - delete instances[this.id]; - this.notifyPlugins('afterDestroy'); - } - toBase64Image(...args) { - return this.canvas.toDataURL(...args); - } - bindEvents() { - this.bindUserEvents(); - if (this.options.responsive) { - this.bindResponsiveEvents(); - } else { - this.attached = true; - } - } - bindUserEvents() { - const listeners = this._listeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const listener = (e, x, y) => { - e.offsetX = x; - e.offsetY = y; - this._eventHandler(e); - }; - each(this.options.events, (type) => _add(type, listener)); - } - bindResponsiveEvents() { - if (!this._responsiveListeners) { - this._responsiveListeners = {}; - } - const listeners = this._responsiveListeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const _remove = (type, listener) => { - if (listeners[type]) { - platform.removeEventListener(this, type, listener); - delete listeners[type]; - } - }; - const listener = (width, height) => { - if (this.canvas) { - this.resize(width, height); - } - }; - let detached; - const attached = () => { - _remove('attach', attached); - this.attached = true; - this.resize(); - _add('resize', listener); - _add('detach', detached); - }; - detached = () => { - this.attached = false; - _remove('resize', listener); - this._stop(); - this._resize(0, 0); - _add('attach', attached); - }; - if (platform.isAttached(this.canvas)) { - attached(); - } else { - detached(); - } - } - unbindEvents() { - each(this._listeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._listeners = {}; - each(this._responsiveListeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._responsiveListeners = undefined; - } - updateHoverStyle(items, mode, enabled) { - const prefix = enabled ? 'set' : 'remove'; - let meta, item, i, ilen; - if (mode === 'dataset') { - meta = this.getDatasetMeta(items[0].datasetIndex); - meta.controller['_' + prefix + 'DatasetHoverStyle'](); - } - for (i = 0, ilen = items.length; i < ilen; ++i) { - item = items[i]; - const controller = item && this.getDatasetMeta(item.datasetIndex).controller; - if (controller) { - controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); - } - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements) { - const lastActive = this._active || []; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('No dataset found at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(active, lastActive); - if (changed) { - this._active = active; - this._lastEvent = null; - this._updateHoverStyles(active, lastActive); - } - } - notifyPlugins(hook, args, filter) { - return this._plugins.notify(this, hook, args, filter); - } - _updateHoverStyles(active, lastActive, replay) { - const hoverOptions = this.options.hover; - const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index)); - const deactivated = diff(lastActive, active); - const activated = replay ? active : diff(active, lastActive); - if (deactivated.length) { - this.updateHoverStyle(deactivated, hoverOptions.mode, false); - } - if (activated.length && hoverOptions.mode) { - this.updateHoverStyle(activated, hoverOptions.mode, true); - } - } - _eventHandler(e, replay) { - const args = { - event: e, - replay, - cancelable: true, - inChartArea: _isPointInArea(e, this.chartArea, this._minPadding) - }; - const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type); - if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { - return; - } - const changed = this._handleEvent(e, replay, args.inChartArea); - args.cancelable = false; - this.notifyPlugins('afterEvent', args, eventFilter); - if (changed || args.changed) { - this.render(); - } - return this; - } - _handleEvent(e, replay, inChartArea) { - const {_active: lastActive = [], options} = this; - const useFinalPosition = replay; - const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); - const isClick = _isClickEvent(e); - const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); - if (inChartArea) { - this._lastEvent = null; - callback(options.onHover, [e, active, this], this); - if (isClick) { - callback(options.onClick, [e, active, this], this); - } - } - const changed = !_elementsEqual(active, lastActive); - if (changed || replay) { - this._active = active; - this._updateHoverStyles(active, lastActive, replay); - } - this._lastEvent = lastEvent; - return changed; - } - _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const hoverOptions = this.options.hover; - return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); - } -} -const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); -const enumerable = true; -Object.defineProperties(Chart, { - defaults: { - enumerable, - value: defaults - }, - instances: { - enumerable, - value: instances - }, - overrides: { - enumerable, - value: overrides - }, - registry: { - enumerable, - value: registry - }, - version: { - enumerable, - value: version - }, - getChart: { - enumerable, - value: getChart - }, - register: { - enumerable, - value: (...items) => { - registry.add(...items); - invalidatePlugins(); - } - }, - unregister: { - enumerable, - value: (...items) => { - registry.remove(...items); - invalidatePlugins(); - } - } -}); - -function clipArc(ctx, element, endAngle) { - const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; - let angleMargin = pixelMargin / outerRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); - if (innerRadius > pixelMargin) { - angleMargin = pixelMargin / innerRadius; - ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); - } else { - ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); - } - ctx.closePath(); - ctx.clip(); -} -function toRadiusCorners(value) { - return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']); -} -function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { - const o = toRadiusCorners(arc.options.borderRadius); - const halfThickness = (outerRadius - innerRadius) / 2; - const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); - const computeOuterLimit = (val) => { - const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; - return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); - }; - return { - outerStart: computeOuterLimit(o.outerStart), - outerEnd: computeOuterLimit(o.outerEnd), - innerStart: _limitValue(o.innerStart, 0, innerLimit), - innerEnd: _limitValue(o.innerEnd, 0, innerLimit), - }; -} -function rThetaToXY(r, theta, x, y) { - return { - x: x + r * Math.cos(theta), - y: y + r * Math.sin(theta), - }; -} -function pathArc(ctx, element, offset, spacing, end) { - const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element; - const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); - const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; - let spacingOffset = 0; - const alpha = end - start; - if (spacing) { - const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; - const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; - const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; - const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha; - spacingOffset = (alpha - adjustedAngle) / 2; - } - const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; - const angleOffset = (alpha - beta) / 2; - const startAngle = start + angleOffset + spacingOffset; - const endAngle = end - angleOffset - spacingOffset; - const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); - const outerStartAdjustedRadius = outerRadius - outerStart; - const outerEndAdjustedRadius = outerRadius - outerEnd; - const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; - const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; - const innerStartAdjustedRadius = innerRadius + innerStart; - const innerEndAdjustedRadius = innerRadius + innerEnd; - const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; - const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle); - if (outerEnd > 0) { - const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); - } - const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); - ctx.lineTo(p4.x, p4.y); - if (innerEnd > 0) { - const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); - } - ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true); - if (innerStart > 0) { - const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); - } - const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); - ctx.lineTo(p8.x, p8.y); - if (outerStart > 0) { - const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); - } - ctx.closePath(); -} -function drawArc(ctx, element, offset, spacing) { - const {fullCircles, startAngle, circumference} = element; - let endAngle = element.endAngle; - if (fullCircles) { - pathArc(ctx, element, offset, spacing, startAngle + TAU); - for (let i = 0; i < fullCircles; ++i) { - ctx.fill(); - } - if (!isNaN(circumference)) { - endAngle = startAngle + circumference % TAU; - if (circumference % TAU === 0) { - endAngle += TAU; - } - } - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.fill(); - return endAngle; -} -function drawFullCircleBorders(ctx, element, inner) { - const {x, y, startAngle, pixelMargin, fullCircles} = element; - const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); - const innerRadius = element.innerRadius + pixelMargin; - let i; - if (inner) { - clipArc(ctx, element, startAngle + TAU); - } - ctx.beginPath(); - ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } -} -function drawBorder(ctx, element, offset, spacing, endAngle) { - const {options} = element; - const {borderWidth, borderJoinStyle} = options; - const inner = options.borderAlign === 'inner'; - if (!borderWidth) { - return; - } - if (inner) { - ctx.lineWidth = borderWidth * 2; - ctx.lineJoin = borderJoinStyle || 'round'; - } else { - ctx.lineWidth = borderWidth; - ctx.lineJoin = borderJoinStyle || 'bevel'; - } - if (element.fullCircles) { - drawFullCircleBorders(ctx, element, inner); - } - if (inner) { - clipArc(ctx, element, endAngle); - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.stroke(); -} -class ArcElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.circumference = undefined; - this.startAngle = undefined; - this.endAngle = undefined; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.pixelMargin = 0; - this.fullCircles = 0; - if (cfg) { - Object.assign(this, cfg); - } - } - inRange(chartX, chartY, useFinalPosition) { - const point = this.getProps(['x', 'y'], useFinalPosition); - const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); - const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference' - ], useFinalPosition); - const rAdjust = this.options.spacing / 2; - const _circumference = valueOrDefault(circumference, endAngle - startAngle); - const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); - const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); - return (betweenAngles && withinRadius); - } - getCenterPoint(useFinalPosition) { - const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ - 'x', - 'y', - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference', - ], useFinalPosition); - const {offset, spacing} = this.options; - const halfAngle = (startAngle + endAngle) / 2; - const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; - return { - x: x + Math.cos(halfAngle) * halfRadius, - y: y + Math.sin(halfAngle) * halfRadius - }; - } - tooltipPosition(useFinalPosition) { - return this.getCenterPoint(useFinalPosition); - } - draw(ctx) { - const {options, circumference} = this; - const offset = (options.offset || 0) / 2; - const spacing = (options.spacing || 0) / 2; - this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; - this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; - if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { - return; - } - ctx.save(); - let radiusOffset = 0; - if (offset) { - radiusOffset = offset / 2; - const halfAngle = (this.startAngle + this.endAngle) / 2; - ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset); - if (this.circumference >= PI) { - radiusOffset = offset; - } - } - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - const endAngle = drawArc(ctx, this, radiusOffset, spacing); - drawBorder(ctx, this, radiusOffset, spacing, endAngle); - ctx.restore(); - } -} -ArcElement.id = 'arc'; -ArcElement.defaults = { - borderAlign: 'center', - borderColor: '#fff', - borderJoinStyle: undefined, - borderRadius: 0, - borderWidth: 2, - offset: 0, - spacing: 0, - angle: undefined, -}; -ArcElement.defaultRoutes = { - backgroundColor: 'backgroundColor' -}; - -function setStyle(ctx, options, style = options) { - ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); - ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); - ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); - ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); - ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); - ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); -} -function lineTo(ctx, previous, target) { - ctx.lineTo(target.x, target.y); -} -function getLineMethod(options) { - if (options.stepped) { - return _steppedLineTo; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierCurveTo; - } - return lineTo; -} -function pathVars(points, segment, params = {}) { - const count = points.length; - const {start: paramsStart = 0, end: paramsEnd = count - 1} = params; - const {start: segmentStart, end: segmentEnd} = segment; - const start = Math.max(paramsStart, segmentStart); - const end = Math.min(paramsEnd, segmentEnd); - const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; - return { - count, - start, - loop: segment.loop, - ilen: end < start && !outside ? count + end - start : end - start - }; -} -function pathSegment(ctx, line, segment, params) { - const {points, options} = line; - const {count, start, loop, ilen} = pathVars(points, segment, params); - const lineMethod = getLineMethod(options); - let {move = true, reverse} = params || {}; - let i, point, prev; - for (i = 0; i <= ilen; ++i) { - point = points[(start + (reverse ? ilen - i : i)) % count]; - if (point.skip) { - continue; - } else if (move) { - ctx.moveTo(point.x, point.y); - move = false; - } else { - lineMethod(ctx, prev, point, reverse, options.stepped); - } - prev = point; - } - if (loop) { - point = points[(start + (reverse ? ilen : 0)) % count]; - lineMethod(ctx, prev, point, reverse, options.stepped); - } - return !!loop; -} -function fastPathSegment(ctx, line, segment, params) { - const points = line.points; - const {count, start, ilen} = pathVars(points, segment, params); - const {move = true, reverse} = params || {}; - let avgX = 0; - let countX = 0; - let i, point, prevX, minY, maxY, lastY; - const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; - const drawX = () => { - if (minY !== maxY) { - ctx.lineTo(avgX, maxY); - ctx.lineTo(avgX, minY); - ctx.lineTo(avgX, lastY); - } - }; - if (move) { - point = points[pointIndex(0)]; - ctx.moveTo(point.x, point.y); - } - for (i = 0; i <= ilen; ++i) { - point = points[pointIndex(i)]; - if (point.skip) { - continue; - } - const x = point.x; - const y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - } else if (y > maxY) { - maxY = y; - } - avgX = (countX * avgX + x) / ++countX; - } else { - drawX(); - ctx.lineTo(x, y); - prevX = truncX; - countX = 0; - minY = maxY = y; - } - lastY = y; - } - drawX(); -} -function _getSegmentMethod(line) { - const opts = line.options; - const borderDash = opts.borderDash && opts.borderDash.length; - const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; - return useFastPath ? fastPathSegment : pathSegment; -} -function _getInterpolationMethod(options) { - if (options.stepped) { - return _steppedInterpolation; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierInterpolation; - } - return _pointInLine; -} -function strokePathWithCache(ctx, line, start, count) { - let path = line._path; - if (!path) { - path = line._path = new Path2D(); - if (line.path(path, start, count)) { - path.closePath(); - } - } - setStyle(ctx, line.options); - ctx.stroke(path); -} -function strokePathDirect(ctx, line, start, count) { - const {segments, options} = line; - const segmentMethod = _getSegmentMethod(line); - for (const segment of segments) { - setStyle(ctx, options, segment.style); - ctx.beginPath(); - if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) { - ctx.closePath(); - } - ctx.stroke(); - } -} -const usePath2D = typeof Path2D === 'function'; -function draw(ctx, line, start, count) { - if (usePath2D && !line.options.segment) { - strokePathWithCache(ctx, line, start, count); - } else { - strokePathDirect(ctx, line, start, count); - } -} -class LineElement extends Element { - constructor(cfg) { - super(); - this.animated = true; - this.options = undefined; - this._chart = undefined; - this._loop = undefined; - this._fullLoop = undefined; - this._path = undefined; - this._points = undefined; - this._segments = undefined; - this._decimated = false; - this._pointsUpdated = false; - this._datasetIndex = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - updateControlPoints(chartArea, indexAxis) { - const options = this.options; - if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { - const loop = options.spanGaps ? this._loop : this._fullLoop; - _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); - this._pointsUpdated = true; - } - } - set points(points) { - this._points = points; - delete this._segments; - delete this._path; - this._pointsUpdated = false; - } - get points() { - return this._points; - } - get segments() { - return this._segments || (this._segments = _computeSegments(this, this.options.segment)); - } - first() { - const segments = this.segments; - const points = this.points; - return segments.length && points[segments[0].start]; - } - last() { - const segments = this.segments; - const points = this.points; - const count = segments.length; - return count && points[segments[count - 1].end]; - } - interpolate(point, property) { - const options = this.options; - const value = point[property]; - const points = this.points; - const segments = _boundSegments(this, {property, start: value, end: value}); - if (!segments.length) { - return; - } - const result = []; - const _interpolate = _getInterpolationMethod(options); - let i, ilen; - for (i = 0, ilen = segments.length; i < ilen; ++i) { - const {start, end} = segments[i]; - const p1 = points[start]; - const p2 = points[end]; - if (p1 === p2) { - result.push(p1); - continue; - } - const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); - const interpolated = _interpolate(p1, p2, t, options.stepped); - interpolated[property] = point[property]; - result.push(interpolated); - } - return result.length === 1 ? result[0] : result; - } - pathSegment(ctx, segment, params) { - const segmentMethod = _getSegmentMethod(this); - return segmentMethod(ctx, this, segment, params); - } - path(ctx, start, count) { - const segments = this.segments; - const segmentMethod = _getSegmentMethod(this); - let loop = this._loop; - start = start || 0; - count = count || (this.points.length - start); - for (const segment of segments) { - loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1}); - } - return !!loop; - } - draw(ctx, chartArea, start, count) { - const options = this.options || {}; - const points = this.points || []; - if (points.length && options.borderWidth) { - ctx.save(); - draw(ctx, this, start, count); - ctx.restore(); - } - if (this.animated) { - this._pointsUpdated = false; - this._path = undefined; - } - } -} -LineElement.id = 'line'; -LineElement.defaults = { - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0, - borderJoinStyle: 'miter', - borderWidth: 3, - capBezierPoints: true, - cubicInterpolationMode: 'default', - fill: false, - spanGaps: false, - stepped: false, - tension: 0, -}; -LineElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; -LineElement.descriptors = { - _scriptable: true, - _indexable: (name) => name !== 'borderDash' && name !== 'fill', -}; - -function inRange$1(el, pos, axis, useFinalPosition) { - const options = el.options; - const {[axis]: value} = el.getProps([axis], useFinalPosition); - return (Math.abs(pos - value) < options.radius + options.hitRadius); -} -class PointElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.parsed = undefined; - this.skip = undefined; - this.stop = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - inRange(mouseX, mouseY, useFinalPosition) { - const options = this.options; - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); - } - inXRange(mouseX, useFinalPosition) { - return inRange$1(this, mouseX, 'x', useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange$1(this, mouseY, 'y', useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - size(options) { - options = options || this.options || {}; - let radius = options.radius || 0; - radius = Math.max(radius, radius && options.hoverRadius || 0); - const borderWidth = radius && options.borderWidth || 0; - return (radius + borderWidth) * 2; - } - draw(ctx, area) { - const options = this.options; - if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { - return; - } - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.fillStyle = options.backgroundColor; - drawPoint(ctx, options, this.x, this.y); - } - getRange() { - const options = this.options || {}; - return options.radius + options.hitRadius; - } -} -PointElement.id = 'point'; -PointElement.defaults = { - borderWidth: 1, - hitRadius: 1, - hoverBorderWidth: 1, - hoverRadius: 4, - pointStyle: 'circle', - radius: 3, - rotation: 0 -}; -PointElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; - -function getBarBounds(bar, useFinalPosition) { - const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); - let left, right, top, bottom, half; - if (bar.horizontal) { - half = height / 2; - left = Math.min(x, base); - right = Math.max(x, base); - top = y - half; - bottom = y + half; - } else { - half = width / 2; - left = x - half; - right = x + half; - top = Math.min(y, base); - bottom = Math.max(y, base); - } - return {left, top, right, bottom}; -} -function skipOrLimit(skip, value, min, max) { - return skip ? 0 : _limitValue(value, min, max); -} -function parseBorderWidth(bar, maxW, maxH) { - const value = bar.options.borderWidth; - const skip = bar.borderSkipped; - const o = toTRBL(value); - return { - t: skipOrLimit(skip.top, o.top, 0, maxH), - r: skipOrLimit(skip.right, o.right, 0, maxW), - b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), - l: skipOrLimit(skip.left, o.left, 0, maxW) - }; -} -function parseBorderRadius(bar, maxW, maxH) { - const {enableBorderRadius} = bar.getProps(['enableBorderRadius']); - const value = bar.options.borderRadius; - const o = toTRBLCorners(value); - const maxR = Math.min(maxW, maxH); - const skip = bar.borderSkipped; - const enableBorder = enableBorderRadius || isObject(value); - return { - topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), - topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), - bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), - bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) - }; -} -function boundingRects(bar) { - const bounds = getBarBounds(bar); - const width = bounds.right - bounds.left; - const height = bounds.bottom - bounds.top; - const border = parseBorderWidth(bar, width / 2, height / 2); - const radius = parseBorderRadius(bar, width / 2, height / 2); - return { - outer: { - x: bounds.left, - y: bounds.top, - w: width, - h: height, - radius - }, - inner: { - x: bounds.left + border.l, - y: bounds.top + border.t, - w: width - border.l - border.r, - h: height - border.t - border.b, - radius: { - topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), - topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), - bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), - bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)), - } - } - }; -} -function inRange(bar, x, y, useFinalPosition) { - const skipX = x === null; - const skipY = y === null; - const skipBoth = skipX && skipY; - const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); - return bounds - && (skipX || _isBetween(x, bounds.left, bounds.right)) - && (skipY || _isBetween(y, bounds.top, bounds.bottom)); -} -function hasRadius(radius) { - return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; -} -function addNormalRectPath(ctx, rect) { - ctx.rect(rect.x, rect.y, rect.w, rect.h); -} -function inflateRect(rect, amount, refRect = {}) { - const x = rect.x !== refRect.x ? -amount : 0; - const y = rect.y !== refRect.y ? -amount : 0; - const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; - const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; - return { - x: rect.x + x, - y: rect.y + y, - w: rect.w + w, - h: rect.h + h, - radius: rect.radius - }; -} -class BarElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.horizontal = undefined; - this.base = undefined; - this.width = undefined; - this.height = undefined; - this.inflateAmount = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - draw(ctx) { - const {inflateAmount, options: {borderColor, backgroundColor}} = this; - const {inner, outer} = boundingRects(this); - const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; - ctx.save(); - if (outer.w !== inner.w || outer.h !== inner.h) { - ctx.beginPath(); - addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); - ctx.clip(); - addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); - ctx.fillStyle = borderColor; - ctx.fill('evenodd'); - } - ctx.beginPath(); - addRectPath(ctx, inflateRect(inner, inflateAmount)); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - inRange(mouseX, mouseY, useFinalPosition) { - return inRange(this, mouseX, mouseY, useFinalPosition); - } - inXRange(mouseX, useFinalPosition) { - return inRange(this, mouseX, null, useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange(this, null, mouseY, useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); - return { - x: horizontal ? (x + base) / 2 : x, - y: horizontal ? y : (y + base) / 2 - }; - } - getRange(axis) { - return axis === 'x' ? this.width / 2 : this.height / 2; - } -} -BarElement.id = 'bar'; -BarElement.defaults = { - borderSkipped: 'start', - borderWidth: 0, - borderRadius: 0, - inflateAmount: 'auto', - pointStyle: undefined -}; -BarElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; - -var elements = /*#__PURE__*/Object.freeze({ -__proto__: null, -ArcElement: ArcElement, -LineElement: LineElement, -PointElement: PointElement, -BarElement: BarElement -}); - -function lttbDecimation(data, start, count, availableWidth, options) { - const samples = options.samples || availableWidth; - if (samples >= count) { - return data.slice(start, start + count); - } - const decimated = []; - const bucketWidth = (count - 2) / (samples - 2); - let sampledIndex = 0; - const endIndex = start + count - 1; - let a = start; - let i, maxAreaPoint, maxArea, area, nextA; - decimated[sampledIndex++] = data[a]; - for (i = 0; i < samples - 2; i++) { - let avgX = 0; - let avgY = 0; - let j; - const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; - const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; - const avgRangeLength = avgRangeEnd - avgRangeStart; - for (j = avgRangeStart; j < avgRangeEnd; j++) { - avgX += data[j].x; - avgY += data[j].y; - } - avgX /= avgRangeLength; - avgY /= avgRangeLength; - const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; - const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; - const {x: pointAx, y: pointAy} = data[a]; - maxArea = area = -1; - for (j = rangeOffs; j < rangeTo; j++) { - area = 0.5 * Math.abs( - (pointAx - avgX) * (data[j].y - pointAy) - - (pointAx - data[j].x) * (avgY - pointAy) - ); - if (area > maxArea) { - maxArea = area; - maxAreaPoint = data[j]; - nextA = j; - } - } - decimated[sampledIndex++] = maxAreaPoint; - a = nextA; - } - decimated[sampledIndex++] = data[endIndex]; - return decimated; -} -function minMaxDecimation(data, start, count, availableWidth) { - let avgX = 0; - let countX = 0; - let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; - const decimated = []; - const endIndex = start + count - 1; - const xMin = data[start].x; - const xMax = data[endIndex].x; - const dx = xMax - xMin; - for (i = start; i < start + count; ++i) { - point = data[i]; - x = (point.x - xMin) / dx * availableWidth; - y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - minIndex = i; - } else if (y > maxY) { - maxY = y; - maxIndex = i; - } - avgX = (countX * avgX + point.x) / ++countX; - } else { - const lastIndex = i - 1; - if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { - const intermediateIndex1 = Math.min(minIndex, maxIndex); - const intermediateIndex2 = Math.max(minIndex, maxIndex); - if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex1], - x: avgX, - }); - } - if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex2], - x: avgX - }); - } - } - if (i > 0 && lastIndex !== startIndex) { - decimated.push(data[lastIndex]); - } - decimated.push(point); - prevX = truncX; - countX = 0; - minY = maxY = y; - minIndex = maxIndex = startIndex = i; - } - } - return decimated; -} -function cleanDecimatedDataset(dataset) { - if (dataset._decimated) { - const data = dataset._data; - delete dataset._decimated; - delete dataset._data; - Object.defineProperty(dataset, 'data', {value: data}); - } -} -function cleanDecimatedData(chart) { - chart.data.datasets.forEach((dataset) => { - cleanDecimatedDataset(dataset); - }); -} -function getStartAndCountOfVisiblePointsSimplified(meta, points) { - const pointCount = points.length; - let start = 0; - let count; - const {iScale} = meta; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); - } - if (maxDefined) { - count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; - } else { - count = pointCount - start; - } - return {start, count}; -} -var plugin_decimation = { - id: 'decimation', - defaults: { - algorithm: 'min-max', - enabled: false, - }, - beforeElementsUpdate: (chart, args, options) => { - if (!options.enabled) { - cleanDecimatedData(chart); - return; - } - const availableWidth = chart.width; - chart.data.datasets.forEach((dataset, datasetIndex) => { - const {_data, indexAxis} = dataset; - const meta = chart.getDatasetMeta(datasetIndex); - const data = _data || dataset.data; - if (resolve([indexAxis, chart.options.indexAxis]) === 'y') { - return; - } - if (meta.type !== 'line') { - return; - } - const xAxis = chart.scales[meta.xAxisID]; - if (xAxis.type !== 'linear' && xAxis.type !== 'time') { - return; - } - if (chart.options.parsing) { - return; - } - let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data); - const threshold = options.threshold || 4 * availableWidth; - if (count <= threshold) { - cleanDecimatedDataset(dataset); - return; - } - if (isNullOrUndef(_data)) { - dataset._data = data; - delete dataset.data; - Object.defineProperty(dataset, 'data', { - configurable: true, - enumerable: true, - get: function() { - return this._decimated; - }, - set: function(d) { - this._data = d; - } - }); - } - let decimated; - switch (options.algorithm) { - case 'lttb': - decimated = lttbDecimation(data, start, count, availableWidth, options); - break; - case 'min-max': - decimated = minMaxDecimation(data, start, count, availableWidth); - break; - default: - throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); - } - dataset._decimated = decimated; - }); - }, - destroy(chart) { - cleanDecimatedData(chart); - } -}; - -function getLineByIndex(chart, index) { - const meta = chart.getDatasetMeta(index); - const visible = meta && chart.isDatasetVisible(index); - return visible ? meta.dataset : null; -} -function parseFillOption(line) { - const options = line.options; - const fillOption = options.fill; - let fill = valueOrDefault(fillOption && fillOption.target, fillOption); - if (fill === undefined) { - fill = !!options.backgroundColor; - } - if (fill === false || fill === null) { - return false; - } - if (fill === true) { - return 'origin'; - } - return fill; -} -function decodeFill(line, index, count) { - const fill = parseFillOption(line); - if (isObject(fill)) { - return isNaN(fill.value) ? false : fill; - } - let target = parseFloat(fill); - if (isNumberFinite(target) && Math.floor(target) === target) { - if (fill[0] === '-' || fill[0] === '+') { - target = index + target; - } - if (target === index || target < 0 || target >= count) { - return false; - } - return target; - } - return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill; -} -function computeLinearBoundary(source) { - const {scale = {}, fill} = source; - let target = null; - let horizontal; - if (fill === 'start') { - target = scale.bottom; - } else if (fill === 'end') { - target = scale.top; - } else if (isObject(fill)) { - target = scale.getPixelForValue(fill.value); - } else if (scale.getBasePixel) { - target = scale.getBasePixel(); - } - if (isNumberFinite(target)) { - horizontal = scale.isHorizontal(); - return { - x: horizontal ? target : null, - y: horizontal ? null : target - }; - } - return null; -} -class simpleArc { - constructor(opts) { - this.x = opts.x; - this.y = opts.y; - this.radius = opts.radius; - } - pathSegment(ctx, bounds, opts) { - const {x, y, radius} = this; - bounds = bounds || {start: 0, end: TAU}; - ctx.arc(x, y, radius, bounds.end, bounds.start, true); - return !opts.bounds; - } - interpolate(point) { - const {x, y, radius} = this; - const angle = point.angle; - return { - x: x + Math.cos(angle) * radius, - y: y + Math.sin(angle) * radius, - angle - }; - } -} -function computeCircularBoundary(source) { - const {scale, fill} = source; - const options = scale.options; - const length = scale.getLabels().length; - const target = []; - const start = options.reverse ? scale.max : scale.min; - const end = options.reverse ? scale.min : scale.max; - let i, center, value; - if (fill === 'start') { - value = start; - } else if (fill === 'end') { - value = end; - } else if (isObject(fill)) { - value = fill.value; - } else { - value = scale.getBaseValue(); - } - if (options.grid.circular) { - center = scale.getPointPositionForValue(0, start); - return new simpleArc({ - x: center.x, - y: center.y, - radius: scale.getDistanceFromCenterForValue(value) - }); - } - for (i = 0; i < length; ++i) { - target.push(scale.getPointPositionForValue(i, value)); - } - return target; -} -function computeBoundary(source) { - const scale = source.scale || {}; - if (scale.getPointPositionForValue) { - return computeCircularBoundary(source); - } - return computeLinearBoundary(source); -} -function findSegmentEnd(start, end, points) { - for (;end > start; end--) { - const point = points[end]; - if (!isNaN(point.x) && !isNaN(point.y)) { - break; - } - } - return end; -} -function pointsFromSegments(boundary, line) { - const {x = null, y = null} = boundary || {}; - const linePoints = line.points; - const points = []; - line.segments.forEach(({start, end}) => { - end = findSegmentEnd(start, end, linePoints); - const first = linePoints[start]; - const last = linePoints[end]; - if (y !== null) { - points.push({x: first.x, y}); - points.push({x: last.x, y}); - } else if (x !== null) { - points.push({x, y: first.y}); - points.push({x, y: last.y}); - } - }); - return points; -} -function buildStackLine(source) { - const {scale, index, line} = source; - const points = []; - const segments = line.segments; - const sourcePoints = line.points; - const linesBelow = getLinesBelow(scale, index); - linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - for (let j = segment.start; j <= segment.end; j++) { - addPointsBelow(points, sourcePoints[j], linesBelow); - } - } - return new LineElement({points, options: {}}); -} -function getLinesBelow(scale, index) { - const below = []; - const metas = scale.getMatchingVisibleMetas('line'); - for (let i = 0; i < metas.length; i++) { - const meta = metas[i]; - if (meta.index === index) { - break; - } - if (!meta.hidden) { - below.unshift(meta.dataset); - } - } - return below; -} -function addPointsBelow(points, sourcePoint, linesBelow) { - const postponed = []; - for (let j = 0; j < linesBelow.length; j++) { - const line = linesBelow[j]; - const {first, last, point} = findPoint(line, sourcePoint, 'x'); - if (!point || (first && last)) { - continue; - } - if (first) { - postponed.unshift(point); - } else { - points.push(point); - if (!last) { - break; - } - } - } - points.push(...postponed); -} -function findPoint(line, sourcePoint, property) { - const point = line.interpolate(sourcePoint, property); - if (!point) { - return {}; - } - const pointValue = point[property]; - const segments = line.segments; - const linePoints = line.points; - let first = false; - let last = false; - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - const firstValue = linePoints[segment.start][property]; - const lastValue = linePoints[segment.end][property]; - if (_isBetween(pointValue, firstValue, lastValue)) { - first = pointValue === firstValue; - last = pointValue === lastValue; - break; - } - } - return {first, last, point}; -} -function getTarget(source) { - const {chart, fill, line} = source; - if (isNumberFinite(fill)) { - return getLineByIndex(chart, fill); - } - if (fill === 'stack') { - return buildStackLine(source); - } - if (fill === 'shape') { - return true; - } - const boundary = computeBoundary(source); - if (boundary instanceof simpleArc) { - return boundary; - } - return createBoundaryLine(boundary, line); -} -function createBoundaryLine(boundary, line) { - let points = []; - let _loop = false; - if (isArray(boundary)) { - _loop = true; - points = boundary; - } else { - points = pointsFromSegments(boundary, line); - } - return points.length ? new LineElement({ - points, - options: {tension: 0}, - _loop, - _fullLoop: _loop - }) : null; -} -function resolveTarget(sources, index, propagate) { - const source = sources[index]; - let fill = source.fill; - const visited = [index]; - let target; - if (!propagate) { - return fill; - } - while (fill !== false && visited.indexOf(fill) === -1) { - if (!isNumberFinite(fill)) { - return fill; - } - target = sources[fill]; - if (!target) { - return false; - } - if (target.visible) { - return fill; - } - visited.push(fill); - fill = target.fill; - } - return false; -} -function _clip(ctx, target, clipY) { - const {segments, points} = target; - let first = true; - let lineLoop = false; - ctx.beginPath(); - for (const segment of segments) { - const {start, end} = segment; - const firstPoint = points[start]; - const lastPoint = points[findSegmentEnd(start, end, points)]; - if (first) { - ctx.moveTo(firstPoint.x, firstPoint.y); - first = false; - } else { - ctx.lineTo(firstPoint.x, clipY); - ctx.lineTo(firstPoint.x, firstPoint.y); - } - lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop}); - if (lineLoop) { - ctx.closePath(); - } else { - ctx.lineTo(lastPoint.x, clipY); - } - } - ctx.lineTo(target.first().x, clipY); - ctx.closePath(); - ctx.clip(); -} -function getBounds(property, first, last, loop) { - if (loop) { - return; - } - let start = first[property]; - let end = last[property]; - if (property === 'angle') { - start = _normalizeAngle(start); - end = _normalizeAngle(end); - } - return {property, start, end}; -} -function _getEdge(a, b, prop, fn) { - if (a && b) { - return fn(a[prop], b[prop]); - } - return a ? a[prop] : b ? b[prop] : 0; -} -function _segments(line, target, property) { - const segments = line.segments; - const points = line.points; - const tpoints = target.points; - const parts = []; - for (const segment of segments) { - let {start, end} = segment; - end = findSegmentEnd(start, end, points); - const bounds = getBounds(property, points[start], points[end], segment.loop); - if (!target.segments) { - parts.push({ - source: segment, - target: bounds, - start: points[start], - end: points[end] - }); - continue; - } - const targetSegments = _boundSegments(target, bounds); - for (const tgt of targetSegments) { - const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); - const fillSources = _boundSegment(segment, points, subBounds); - for (const fillSource of fillSources) { - parts.push({ - source: fillSource, - target: tgt, - start: { - [property]: _getEdge(bounds, subBounds, 'start', Math.max) - }, - end: { - [property]: _getEdge(bounds, subBounds, 'end', Math.min) - } - }); - } - } - } - return parts; -} -function clipBounds(ctx, scale, bounds) { - const {top, bottom} = scale.chart.chartArea; - const {property, start, end} = bounds || {}; - if (property === 'x') { - ctx.beginPath(); - ctx.rect(start, top, end - start, bottom - top); - ctx.clip(); - } -} -function interpolatedLineTo(ctx, target, point, property) { - const interpolatedPoint = target.interpolate(point, property); - if (interpolatedPoint) { - ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); - } -} -function _fill(ctx, cfg) { - const {line, target, property, color, scale} = cfg; - const segments = _segments(line, target, property); - for (const {source: src, target: tgt, start, end} of segments) { - const {style: {backgroundColor = color} = {}} = src; - const notShape = target !== true; - ctx.save(); - ctx.fillStyle = backgroundColor; - clipBounds(ctx, scale, notShape && getBounds(property, start, end)); - ctx.beginPath(); - const lineLoop = !!line.pathSegment(ctx, src); - let loop; - if (notShape) { - if (lineLoop) { - ctx.closePath(); - } else { - interpolatedLineTo(ctx, target, end, property); - } - const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); - loop = lineLoop && targetLoop; - if (!loop) { - interpolatedLineTo(ctx, target, start, property); - } - } - ctx.closePath(); - ctx.fill(loop ? 'evenodd' : 'nonzero'); - ctx.restore(); - } -} -function doFill(ctx, cfg) { - const {line, target, above, below, area, scale} = cfg; - const property = line._loop ? 'angle' : cfg.axis; - ctx.save(); - if (property === 'x' && below !== above) { - _clip(ctx, target, area.top); - _fill(ctx, {line, target, color: above, scale, property}); - ctx.restore(); - ctx.save(); - _clip(ctx, target, area.bottom); - } - _fill(ctx, {line, target, color: below, scale, property}); - ctx.restore(); -} -function drawfill(ctx, source, area) { - const target = getTarget(source); - const {line, scale, axis} = source; - const lineOpts = line.options; - const fillOption = lineOpts.fill; - const color = lineOpts.backgroundColor; - const {above = color, below = color} = fillOption || {}; - if (target && line.points.length) { - clipArea(ctx, area); - doFill(ctx, {line, target, above, below, area, scale, axis}); - unclipArea(ctx); - } -} -var plugin_filler = { - id: 'filler', - afterDatasetsUpdate(chart, _args, options) { - const count = (chart.data.datasets || []).length; - const sources = []; - let meta, i, line, source; - for (i = 0; i < count; ++i) { - meta = chart.getDatasetMeta(i); - line = meta.dataset; - source = null; - if (line && line.options && line instanceof LineElement) { - source = { - visible: chart.isDatasetVisible(i), - index: i, - fill: decodeFill(line, i, count), - chart, - axis: meta.controller.options.indexAxis, - scale: meta.vScale, - line, - }; - } - meta.$filler = source; - sources.push(source); - } - for (i = 0; i < count; ++i) { - source = sources[i]; - if (!source || source.fill === false) { - continue; - } - source.fill = resolveTarget(sources, i, options.propagate); - } - }, - beforeDraw(chart, _args, options) { - const draw = options.drawTime === 'beforeDraw'; - const metasets = chart.getSortedVisibleDatasetMetas(); - const area = chart.chartArea; - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (!source) { - continue; - } - source.line.updateControlPoints(area, source.axis); - if (draw) { - drawfill(chart.ctx, source, area); - } - } - }, - beforeDatasetsDraw(chart, _args, options) { - if (options.drawTime !== 'beforeDatasetsDraw') { - return; - } - const metasets = chart.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (source) { - drawfill(chart.ctx, source, chart.chartArea); - } - } - }, - beforeDatasetDraw(chart, args, options) { - const source = args.meta.$filler; - if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') { - return; - } - drawfill(chart.ctx, source, chart.chartArea); - }, - defaults: { - propagate: true, - drawTime: 'beforeDatasetDraw' - } -}; - -const getBoxSize = (labelOpts, fontSize) => { - let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts; - if (labelOpts.usePointStyle) { - boxHeight = Math.min(boxHeight, fontSize); - boxWidth = Math.min(boxWidth, fontSize); - } - return { - boxWidth, - boxHeight, - itemHeight: Math.max(fontSize, boxHeight) - }; -}; -const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; -class Legend extends Element { - constructor(config) { - super(); - this._added = false; - this.legendHitBoxes = []; - this._hoveredItem = null; - this.doughnutMode = false; - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this.legendItems = undefined; - this.columnSizes = undefined; - this.lineWidths = undefined; - this.maxHeight = undefined; - this.maxWidth = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.height = undefined; - this.width = undefined; - this._margins = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight, margins) { - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins; - this.setDimensions(); - this.buildLabels(); - this.fit(); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = this._margins.left; - this.right = this.width; - } else { - this.height = this.maxHeight; - this.top = this._margins.top; - this.bottom = this.height; - } - } - buildLabels() { - const labelOpts = this.options.labels || {}; - let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || []; - if (labelOpts.filter) { - legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data)); - } - if (labelOpts.sort) { - legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data)); - } - if (this.options.reverse) { - legendItems.reverse(); - } - this.legendItems = legendItems; - } - fit() { - const {options, ctx} = this; - if (!options.display) { - this.width = this.height = 0; - return; - } - const labelOpts = options.labels; - const labelFont = toFont(labelOpts.font); - const fontSize = labelFont.size; - const titleHeight = this._computeTitleHeight(); - const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize); - let width, height; - ctx.font = labelFont.string; - if (this.isHorizontal()) { - width = this.maxWidth; - height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } else { - height = this.maxHeight; - width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } - this.width = Math.min(width, options.maxWidth || this.maxWidth); - this.height = Math.min(height, options.maxHeight || this.maxHeight); - } - _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxWidth, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const lineWidths = this.lineWidths = [0]; - const lineHeight = itemHeight + padding; - let totalHeight = titleHeight; - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - let row = -1; - let top = -lineHeight; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { - totalHeight += lineHeight; - lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; - top += lineHeight; - row++; - } - hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight}; - lineWidths[lineWidths.length - 1] += itemWidth + padding; - }); - return totalHeight; - } - _fitCols(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxHeight, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const columnSizes = this.columnSizes = []; - const heightLimit = maxHeight - titleHeight; - let totalWidth = padding; - let currentColWidth = 0; - let currentColHeight = 0; - let left = 0; - let col = 0; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { - totalWidth += currentColWidth + padding; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - left += currentColWidth + padding; - col++; - currentColWidth = currentColHeight = 0; - } - hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight}; - currentColWidth = Math.max(currentColWidth, itemWidth); - currentColHeight += itemHeight + padding; - }); - totalWidth += currentColWidth; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - return totalWidth; - } - adjustHitBoxes() { - if (!this.options.display) { - return; - } - const titleHeight = this._computeTitleHeight(); - const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this; - const rtlHelper = getRtlAdapter(rtl, this.left, this.width); - if (this.isHorizontal()) { - let row = 0; - let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); - for (const hitbox of hitboxes) { - if (row !== hitbox.row) { - row = hitbox.row; - left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); - } - hitbox.top += this.top + titleHeight + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); - left += hitbox.width + padding; - } - } else { - let col = 0; - let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); - for (const hitbox of hitboxes) { - if (hitbox.col !== col) { - col = hitbox.col; - top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); - } - hitbox.top = top; - hitbox.left += this.left + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); - top += hitbox.height + padding; - } - } - } - isHorizontal() { - return this.options.position === 'top' || this.options.position === 'bottom'; - } - draw() { - if (this.options.display) { - const ctx = this.ctx; - clipArea(ctx, this); - this._draw(); - unclipArea(ctx); - } - } - _draw() { - const {options: opts, columnSizes, lineWidths, ctx} = this; - const {align, labels: labelOpts} = opts; - const defaultColor = defaults.color; - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const labelFont = toFont(labelOpts.font); - const {color: fontColor, padding} = labelOpts; - const fontSize = labelFont.size; - const halfFontSize = fontSize / 2; - let cursor; - this.drawTitle(); - ctx.textAlign = rtlHelper.textAlign('left'); - ctx.textBaseline = 'middle'; - ctx.lineWidth = 0.5; - ctx.font = labelFont.string; - const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize); - const drawLegendBox = function(x, y, legendItem) { - if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { - return; - } - ctx.save(); - const lineWidth = valueOrDefault(legendItem.lineWidth, 1); - ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); - ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); - ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); - ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); - ctx.lineWidth = lineWidth; - ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); - ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); - if (labelOpts.usePointStyle) { - const drawOptions = { - radius: boxWidth * Math.SQRT2 / 2, - pointStyle: legendItem.pointStyle, - rotation: legendItem.rotation, - borderWidth: lineWidth - }; - const centerX = rtlHelper.xPlus(x, boxWidth / 2); - const centerY = y + halfFontSize; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); - const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); - const borderRadius = toTRBLCorners(legendItem.borderRadius); - ctx.beginPath(); - if (Object.values(borderRadius).some(v => v !== 0)) { - addRoundedRectPath(ctx, { - x: xBoxLeft, - y: yBoxTop, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); - } else { - ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); - } - ctx.fill(); - if (lineWidth !== 0) { - ctx.stroke(); - } - } - ctx.restore(); - }; - const fillText = function(x, y, legendItem) { - renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, { - strikethrough: legendItem.hidden, - textAlign: rtlHelper.textAlign(legendItem.textAlign) - }); - }; - const isHorizontal = this.isHorizontal(); - const titleHeight = this._computeTitleHeight(); - if (isHorizontal) { - cursor = { - x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), - y: this.top + padding + titleHeight, - line: 0 - }; - } else { - cursor = { - x: this.left + padding, - y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), - line: 0 - }; - } - overrideTextDirection(this.ctx, opts.textDirection); - const lineHeight = itemHeight + padding; - this.legendItems.forEach((legendItem, i) => { - ctx.strokeStyle = legendItem.fontColor || fontColor; - ctx.fillStyle = legendItem.fontColor || fontColor; - const textWidth = ctx.measureText(legendItem.text).width; - const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); - const width = boxWidth + halfFontSize + textWidth; - let x = cursor.x; - let y = cursor.y; - rtlHelper.setWidth(this.width); - if (isHorizontal) { - if (i > 0 && x + width + padding > this.right) { - y = cursor.y += lineHeight; - cursor.line++; - x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); - } - } else if (i > 0 && y + lineHeight > this.bottom) { - x = cursor.x = x + columnSizes[cursor.line].width + padding; - cursor.line++; - y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); - } - const realX = rtlHelper.x(x); - drawLegendBox(realX, y, legendItem); - x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); - fillText(rtlHelper.x(x), y, legendItem); - if (isHorizontal) { - cursor.x += width + padding; - } else { - cursor.y += lineHeight; - } - }); - restoreTextDirection(this.ctx, opts.textDirection); - } - drawTitle() { - const opts = this.options; - const titleOpts = opts.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - if (!titleOpts.display) { - return; - } - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const ctx = this.ctx; - const position = titleOpts.position; - const halfFontSize = titleFont.size / 2; - const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; - let y; - let left = this.left; - let maxWidth = this.width; - if (this.isHorizontal()) { - maxWidth = Math.max(...this.lineWidths); - y = this.top + topPaddingPlusHalfFontSize; - left = _alignStartEnd(opts.align, left, this.right - maxWidth); - } else { - const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0); - y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); - } - const x = _alignStartEnd(position, left, left + maxWidth); - ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); - ctx.textBaseline = 'middle'; - ctx.strokeStyle = titleOpts.color; - ctx.fillStyle = titleOpts.color; - ctx.font = titleFont.string; - renderText(ctx, titleOpts.text, x, y, titleFont); - } - _computeTitleHeight() { - const titleOpts = this.options.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; - } - _getLegendItemAt(x, y) { - let i, hitBox, lh; - if (_isBetween(x, this.left, this.right) - && _isBetween(y, this.top, this.bottom)) { - lh = this.legendHitBoxes; - for (i = 0; i < lh.length; ++i) { - hitBox = lh[i]; - if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) - && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { - return this.legendItems[i]; - } - } - } - return null; - } - handleEvent(e) { - const opts = this.options; - if (!isListened(e.type, opts)) { - return; - } - const hoveredItem = this._getLegendItemAt(e.x, e.y); - if (e.type === 'mousemove') { - const previous = this._hoveredItem; - const sameItem = itemsEqual(previous, hoveredItem); - if (previous && !sameItem) { - callback(opts.onLeave, [e, previous, this], this); - } - this._hoveredItem = hoveredItem; - if (hoveredItem && !sameItem) { - callback(opts.onHover, [e, hoveredItem, this], this); - } - } else if (hoveredItem) { - callback(opts.onClick, [e, hoveredItem, this], this); - } - } -} -function isListened(type, opts) { - if (type === 'mousemove' && (opts.onHover || opts.onLeave)) { - return true; - } - if (opts.onClick && (type === 'click' || type === 'mouseup')) { - return true; - } - return false; -} -var plugin_legend = { - id: 'legend', - _element: Legend, - start(chart, _args, options) { - const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart}); - layouts.configure(chart, legend, options); - layouts.addBox(chart, legend); - }, - stop(chart) { - layouts.removeBox(chart, chart.legend); - delete chart.legend; - }, - beforeUpdate(chart, _args, options) { - const legend = chart.legend; - layouts.configure(chart, legend, options); - legend.options = options; - }, - afterUpdate(chart) { - const legend = chart.legend; - legend.buildLabels(); - legend.adjustHitBoxes(); - }, - afterEvent(chart, args) { - if (!args.replay) { - chart.legend.handleEvent(args.event); - } - }, - defaults: { - display: true, - position: 'top', - align: 'center', - fullSize: true, - reverse: false, - weight: 1000, - onClick(e, legendItem, legend) { - const index = legendItem.datasetIndex; - const ci = legend.chart; - if (ci.isDatasetVisible(index)) { - ci.hide(index); - legendItem.hidden = true; - } else { - ci.show(index); - legendItem.hidden = false; - } - }, - onHover: null, - onLeave: null, - labels: { - color: (ctx) => ctx.chart.options.color, - boxWidth: 40, - padding: 10, - generateLabels(chart) { - const datasets = chart.data.datasets; - const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options; - return chart._getSortedDatasetMetas().map((meta) => { - const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); - const borderWidth = toPadding(style.borderWidth); - return { - text: datasets[meta.index].label, - fillStyle: style.backgroundColor, - fontColor: color, - hidden: !meta.visible, - lineCap: style.borderCapStyle, - lineDash: style.borderDash, - lineDashOffset: style.borderDashOffset, - lineJoin: style.borderJoinStyle, - lineWidth: (borderWidth.width + borderWidth.height) / 4, - strokeStyle: style.borderColor, - pointStyle: pointStyle || style.pointStyle, - rotation: style.rotation, - textAlign: textAlign || style.textAlign, - borderRadius: 0, - datasetIndex: meta.index - }; - }, this); - } - }, - title: { - color: (ctx) => ctx.chart.options.color, - display: false, - position: 'center', - text: '', - } - }, - descriptors: { - _scriptable: (name) => !name.startsWith('on'), - labels: { - _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name), - } - }, -}; - -class Title extends Element { - constructor(config) { - super(); - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this._padding = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight) { - const opts = this.options; - this.left = 0; - this.top = 0; - if (!opts.display) { - this.width = this.height = this.right = this.bottom = 0; - return; - } - this.width = this.right = maxWidth; - this.height = this.bottom = maxHeight; - const lineCount = isArray(opts.text) ? opts.text.length : 1; - this._padding = toPadding(opts.padding); - const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; - if (this.isHorizontal()) { - this.height = textSize; - } else { - this.width = textSize; - } - } - isHorizontal() { - const pos = this.options.position; - return pos === 'top' || pos === 'bottom'; - } - _drawArgs(offset) { - const {top, left, bottom, right, options} = this; - const align = options.align; - let rotation = 0; - let maxWidth, titleX, titleY; - if (this.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - titleY = top + offset; - maxWidth = right - left; - } else { - if (options.position === 'left') { - titleX = left + offset; - titleY = _alignStartEnd(align, bottom, top); - rotation = PI * -0.5; - } else { - titleX = right - offset; - titleY = _alignStartEnd(align, top, bottom); - rotation = PI * 0.5; - } - maxWidth = bottom - top; - } - return {titleX, titleY, maxWidth, rotation}; - } - draw() { - const ctx = this.ctx; - const opts = this.options; - if (!opts.display) { - return; - } - const fontOpts = toFont(opts.font); - const lineHeight = fontOpts.lineHeight; - const offset = lineHeight / 2 + this._padding.top; - const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset); - renderText(ctx, opts.text, 0, 0, fontOpts, { - color: opts.color, - maxWidth, - rotation, - textAlign: _toLeftRightCenter(opts.align), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } -} -function createTitle(chart, titleOpts) { - const title = new Title({ - ctx: chart.ctx, - options: titleOpts, - chart - }); - layouts.configure(chart, title, titleOpts); - layouts.addBox(chart, title); - chart.titleBlock = title; -} -var plugin_title = { - id: 'title', - _element: Title, - start(chart, _args, options) { - createTitle(chart, options); - }, - stop(chart) { - const titleBlock = chart.titleBlock; - layouts.removeBox(chart, titleBlock); - delete chart.titleBlock; - }, - beforeUpdate(chart, _args, options) { - const title = chart.titleBlock; - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'bold', - }, - fullSize: true, - padding: 10, - position: 'top', - text: '', - weight: 2000 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, -}; - -const map = new WeakMap(); -var plugin_subtitle = { - id: 'subtitle', - start(chart, _args, options) { - const title = new Title({ - ctx: chart.ctx, - options, - chart - }); - layouts.configure(chart, title, options); - layouts.addBox(chart, title); - map.set(chart, title); - }, - stop(chart) { - layouts.removeBox(chart, map.get(chart)); - map.delete(chart); - }, - beforeUpdate(chart, _args, options) { - const title = map.get(chart); - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'normal', - }, - fullSize: true, - padding: 0, - position: 'top', - text: '', - weight: 1500 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, -}; - -const positioners = { - average(items) { - if (!items.length) { - return false; - } - let i, len; - let x = 0; - let y = 0; - let count = 0; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const pos = el.tooltipPosition(); - x += pos.x; - y += pos.y; - ++count; - } - } - return { - x: x / count, - y: y / count - }; - }, - nearest(items, eventPosition) { - if (!items.length) { - return false; - } - let x = eventPosition.x; - let y = eventPosition.y; - let minDistance = Number.POSITIVE_INFINITY; - let i, len, nearestElement; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const center = el.getCenterPoint(); - const d = distanceBetweenPoints(eventPosition, center); - if (d < minDistance) { - minDistance = d; - nearestElement = el; - } - } - } - if (nearestElement) { - const tp = nearestElement.tooltipPosition(); - x = tp.x; - y = tp.y; - } - return { - x, - y - }; - } -}; -function pushOrConcat(base, toPush) { - if (toPush) { - if (isArray(toPush)) { - Array.prototype.push.apply(base, toPush); - } else { - base.push(toPush); - } - } - return base; -} -function splitNewlines(str) { - if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { - return str.split('\n'); - } - return str; -} -function createTooltipItem(chart, item) { - const {element, datasetIndex, index} = item; - const controller = chart.getDatasetMeta(datasetIndex).controller; - const {label, value} = controller.getLabelAndValue(index); - return { - chart, - label, - parsed: controller.getParsed(index), - raw: chart.data.datasets[datasetIndex].data[index], - formattedValue: value, - dataset: controller.getDataset(), - dataIndex: index, - datasetIndex, - element - }; -} -function getTooltipSize(tooltip, options) { - const ctx = tooltip.chart.ctx; - const {body, footer, title} = tooltip; - const {boxWidth, boxHeight} = options; - const bodyFont = toFont(options.bodyFont); - const titleFont = toFont(options.titleFont); - const footerFont = toFont(options.footerFont); - const titleLineCount = title.length; - const footerLineCount = footer.length; - const bodyLineItemCount = body.length; - const padding = toPadding(options.padding); - let height = padding.height; - let width = 0; - let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); - combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; - if (titleLineCount) { - height += titleLineCount * titleFont.lineHeight - + (titleLineCount - 1) * options.titleSpacing - + options.titleMarginBottom; - } - if (combinedBodyLength) { - const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; - height += bodyLineItemCount * bodyLineHeight - + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight - + (combinedBodyLength - 1) * options.bodySpacing; - } - if (footerLineCount) { - height += options.footerMarginTop - + footerLineCount * footerFont.lineHeight - + (footerLineCount - 1) * options.footerSpacing; - } - let widthPadding = 0; - const maxLineWidth = function(line) { - width = Math.max(width, ctx.measureText(line).width + widthPadding); - }; - ctx.save(); - ctx.font = titleFont.string; - each(tooltip.title, maxLineWidth); - ctx.font = bodyFont.string; - each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); - widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0; - each(body, (bodyItem) => { - each(bodyItem.before, maxLineWidth); - each(bodyItem.lines, maxLineWidth); - each(bodyItem.after, maxLineWidth); - }); - widthPadding = 0; - ctx.font = footerFont.string; - each(tooltip.footer, maxLineWidth); - ctx.restore(); - width += padding.width; - return {width, height}; -} -function determineYAlign(chart, size) { - const {y, height} = size; - if (y < height / 2) { - return 'top'; - } else if (y > (chart.height - height / 2)) { - return 'bottom'; - } - return 'center'; -} -function doesNotFitWithAlign(xAlign, chart, options, size) { - const {x, width} = size; - const caret = options.caretSize + options.caretPadding; - if (xAlign === 'left' && x + width + caret > chart.width) { - return true; - } - if (xAlign === 'right' && x - width - caret < 0) { - return true; - } -} -function determineXAlign(chart, options, size, yAlign) { - const {x, width} = size; - const {width: chartWidth, chartArea: {left, right}} = chart; - let xAlign = 'center'; - if (yAlign === 'center') { - xAlign = x <= (left + right) / 2 ? 'left' : 'right'; - } else if (x <= width / 2) { - xAlign = 'left'; - } else if (x >= chartWidth - width / 2) { - xAlign = 'right'; - } - if (doesNotFitWithAlign(xAlign, chart, options, size)) { - xAlign = 'center'; - } - return xAlign; -} -function determineAlignment(chart, options, size) { - const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); - return { - xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), - yAlign - }; -} -function alignX(size, xAlign) { - let {x, width} = size; - if (xAlign === 'right') { - x -= width; - } else if (xAlign === 'center') { - x -= (width / 2); - } - return x; -} -function alignY(size, yAlign, paddingAndSize) { - let {y, height} = size; - if (yAlign === 'top') { - y += paddingAndSize; - } else if (yAlign === 'bottom') { - y -= height + paddingAndSize; - } else { - y -= (height / 2); - } - return y; -} -function getBackgroundPoint(options, size, alignment, chart) { - const {caretSize, caretPadding, cornerRadius} = options; - const {xAlign, yAlign} = alignment; - const paddingAndSize = caretSize + caretPadding; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - let x = alignX(size, xAlign); - const y = alignY(size, yAlign, paddingAndSize); - if (yAlign === 'center') { - if (xAlign === 'left') { - x += paddingAndSize; - } else if (xAlign === 'right') { - x -= paddingAndSize; - } - } else if (xAlign === 'left') { - x -= Math.max(topLeft, bottomLeft) + caretSize; - } else if (xAlign === 'right') { - x += Math.max(topRight, bottomRight) + caretSize; - } - return { - x: _limitValue(x, 0, chart.width - size.width), - y: _limitValue(y, 0, chart.height - size.height) - }; -} -function getAlignedX(tooltip, align, options) { - const padding = toPadding(options.padding); - return align === 'center' - ? tooltip.x + tooltip.width / 2 - : align === 'right' - ? tooltip.x + tooltip.width - padding.right - : tooltip.x + padding.left; -} -function getBeforeAfterBodyLines(callback) { - return pushOrConcat([], splitNewlines(callback)); -} -function createTooltipContext(parent, tooltip, tooltipItems) { - return createContext(parent, { - tooltip, - tooltipItems, - type: 'tooltip' - }); -} -function overrideCallbacks(callbacks, context) { - const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; - return override ? callbacks.override(override) : callbacks; -} -class Tooltip extends Element { - constructor(config) { - super(); - this.opacity = 0; - this._active = []; - this._eventPosition = undefined; - this._size = undefined; - this._cachedAnimations = undefined; - this._tooltipItems = []; - this.$animations = undefined; - this.$context = undefined; - this.chart = config.chart || config._chart; - this._chart = this.chart; - this.options = config.options; - this.dataPoints = undefined; - this.title = undefined; - this.beforeBody = undefined; - this.body = undefined; - this.afterBody = undefined; - this.footer = undefined; - this.xAlign = undefined; - this.yAlign = undefined; - this.x = undefined; - this.y = undefined; - this.height = undefined; - this.width = undefined; - this.caretX = undefined; - this.caretY = undefined; - this.labelColors = undefined; - this.labelPointStyles = undefined; - this.labelTextColors = undefined; - } - initialize(options) { - this.options = options; - this._cachedAnimations = undefined; - this.$context = undefined; - } - _resolveAnimations() { - const cached = this._cachedAnimations; - if (cached) { - return cached; - } - const chart = this.chart; - const options = this.options.setContext(this.getContext()); - const opts = options.enabled && chart.options.animation && options.animations; - const animations = new Animations(this.chart, opts); - if (opts._cacheable) { - this._cachedAnimations = Object.freeze(animations); - } - return animations; - } - getContext() { - return this.$context || - (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); - } - getTitle(context, options) { - const {callbacks} = options; - const beforeTitle = callbacks.beforeTitle.apply(this, [context]); - const title = callbacks.title.apply(this, [context]); - const afterTitle = callbacks.afterTitle.apply(this, [context]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeTitle)); - lines = pushOrConcat(lines, splitNewlines(title)); - lines = pushOrConcat(lines, splitNewlines(afterTitle)); - return lines; - } - getBeforeBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems])); - } - getBody(tooltipItems, options) { - const {callbacks} = options; - const bodyItems = []; - each(tooltipItems, (context) => { - const bodyItem = { - before: [], - lines: [], - after: [] - }; - const scoped = overrideCallbacks(callbacks, context); - pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context))); - pushOrConcat(bodyItem.lines, scoped.label.call(this, context)); - pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context))); - bodyItems.push(bodyItem); - }); - return bodyItems; - } - getAfterBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems])); - } - getFooter(tooltipItems, options) { - const {callbacks} = options; - const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]); - const footer = callbacks.footer.apply(this, [tooltipItems]); - const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeFooter)); - lines = pushOrConcat(lines, splitNewlines(footer)); - lines = pushOrConcat(lines, splitNewlines(afterFooter)); - return lines; - } - _createItems(options) { - const active = this._active; - const data = this.chart.data; - const labelColors = []; - const labelPointStyles = []; - const labelTextColors = []; - let tooltipItems = []; - let i, len; - for (i = 0, len = active.length; i < len; ++i) { - tooltipItems.push(createTooltipItem(this.chart, active[i])); - } - if (options.filter) { - tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); - } - if (options.itemSort) { - tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); - } - each(tooltipItems, (context) => { - const scoped = overrideCallbacks(options.callbacks, context); - labelColors.push(scoped.labelColor.call(this, context)); - labelPointStyles.push(scoped.labelPointStyle.call(this, context)); - labelTextColors.push(scoped.labelTextColor.call(this, context)); - }); - this.labelColors = labelColors; - this.labelPointStyles = labelPointStyles; - this.labelTextColors = labelTextColors; - this.dataPoints = tooltipItems; - return tooltipItems; - } - update(changed, replay) { - const options = this.options.setContext(this.getContext()); - const active = this._active; - let properties; - let tooltipItems = []; - if (!active.length) { - if (this.opacity !== 0) { - properties = { - opacity: 0 - }; - } - } else { - const position = positioners[options.position].call(this, active, this._eventPosition); - tooltipItems = this._createItems(options); - this.title = this.getTitle(tooltipItems, options); - this.beforeBody = this.getBeforeBody(tooltipItems, options); - this.body = this.getBody(tooltipItems, options); - this.afterBody = this.getAfterBody(tooltipItems, options); - this.footer = this.getFooter(tooltipItems, options); - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, size); - const alignment = determineAlignment(this.chart, options, positionAndSize); - const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - properties = { - opacity: 1, - x: backgroundPoint.x, - y: backgroundPoint.y, - width: size.width, - height: size.height, - caretX: position.x, - caretY: position.y - }; - } - this._tooltipItems = tooltipItems; - this.$context = undefined; - if (properties) { - this._resolveAnimations().update(this, properties); - } - if (changed && options.external) { - options.external.call(this, {chart: this.chart, tooltip: this, replay}); - } - } - drawCaret(tooltipPoint, ctx, size, options) { - const caretPosition = this.getCaretPosition(tooltipPoint, size, options); - ctx.lineTo(caretPosition.x1, caretPosition.y1); - ctx.lineTo(caretPosition.x2, caretPosition.y2); - ctx.lineTo(caretPosition.x3, caretPosition.y3); - } - getCaretPosition(tooltipPoint, size, options) { - const {xAlign, yAlign} = this; - const {caretSize, cornerRadius} = options; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - const {x: ptX, y: ptY} = tooltipPoint; - const {width, height} = size; - let x1, x2, x3, y1, y2, y3; - if (yAlign === 'center') { - y2 = ptY + (height / 2); - if (xAlign === 'left') { - x1 = ptX; - x2 = x1 - caretSize; - y1 = y2 + caretSize; - y3 = y2 - caretSize; - } else { - x1 = ptX + width; - x2 = x1 + caretSize; - y1 = y2 - caretSize; - y3 = y2 + caretSize; - } - x3 = x1; - } else { - if (xAlign === 'left') { - x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize); - } else if (xAlign === 'right') { - x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; - } else { - x2 = this.caretX; - } - if (yAlign === 'top') { - y1 = ptY; - y2 = y1 - caretSize; - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } else { - y1 = ptY + height; - y2 = y1 + caretSize; - x1 = x2 + caretSize; - x3 = x2 - caretSize; - } - y3 = y1; - } - return {x1, x2, x3, y1, y2, y3}; - } - drawTitle(pt, ctx, options) { - const title = this.title; - const length = title.length; - let titleFont, titleSpacing, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.titleAlign, options); - ctx.textAlign = rtlHelper.textAlign(options.titleAlign); - ctx.textBaseline = 'middle'; - titleFont = toFont(options.titleFont); - titleSpacing = options.titleSpacing; - ctx.fillStyle = options.titleColor; - ctx.font = titleFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); - pt.y += titleFont.lineHeight + titleSpacing; - if (i + 1 === length) { - pt.y += options.titleMarginBottom - titleSpacing; - } - } - } - } - _drawColorBox(ctx, pt, i, rtlHelper, options) { - const labelColors = this.labelColors[i]; - const labelPointStyle = this.labelPointStyles[i]; - const {boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - const colorX = getAlignedX(this, 'left', options); - const rtlColorX = rtlHelper.x(colorX); - const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; - const colorY = pt.y + yOffSet; - if (options.usePointStyle) { - const drawOptions = { - radius: Math.min(boxWidth, boxHeight) / 2, - pointStyle: labelPointStyle.pointStyle, - rotation: labelPointStyle.rotation, - borderWidth: 1 - }; - const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; - const centerY = colorY + boxHeight / 2; - ctx.strokeStyle = options.multiKeyBackground; - ctx.fillStyle = options.multiKeyBackground; - drawPoint(ctx, drawOptions, centerX, centerY); - ctx.strokeStyle = labelColors.borderColor; - ctx.fillStyle = labelColors.backgroundColor; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - ctx.lineWidth = labelColors.borderWidth || 1; - ctx.strokeStyle = labelColors.borderColor; - ctx.setLineDash(labelColors.borderDash || []); - ctx.lineDashOffset = labelColors.borderDashOffset || 0; - const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding); - const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2); - const borderRadius = toTRBLCorners(labelColors.borderRadius); - if (Object.values(borderRadius).some(v => v !== 0)) { - ctx.beginPath(); - ctx.fillStyle = options.multiKeyBackground; - addRoundedRectPath(ctx, { - x: outerX, - y: colorY, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); - ctx.fill(); - ctx.stroke(); - ctx.fillStyle = labelColors.backgroundColor; - ctx.beginPath(); - addRoundedRectPath(ctx, { - x: innerX, - y: colorY + 1, - w: boxWidth - 2, - h: boxHeight - 2, - radius: borderRadius, - }); - ctx.fill(); - } else { - ctx.fillStyle = options.multiKeyBackground; - ctx.fillRect(outerX, colorY, boxWidth, boxHeight); - ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); - ctx.fillStyle = labelColors.backgroundColor; - ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); - } - } - ctx.fillStyle = this.labelTextColors[i]; - } - drawBody(pt, ctx, options) { - const {body} = this; - const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - let bodyLineHeight = bodyFont.lineHeight; - let xLinePadding = 0; - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - const fillLineOfText = function(line) { - ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); - pt.y += bodyLineHeight + bodySpacing; - }; - const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); - let bodyItem, textColor, lines, i, j, ilen, jlen; - ctx.textAlign = bodyAlign; - ctx.textBaseline = 'middle'; - ctx.font = bodyFont.string; - pt.x = getAlignedX(this, bodyAlignForCalculation, options); - ctx.fillStyle = options.bodyColor; - each(this.beforeBody, fillLineOfText); - xLinePadding = displayColors && bodyAlignForCalculation !== 'right' - ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding) - : 0; - for (i = 0, ilen = body.length; i < ilen; ++i) { - bodyItem = body[i]; - textColor = this.labelTextColors[i]; - ctx.fillStyle = textColor; - each(bodyItem.before, fillLineOfText); - lines = bodyItem.lines; - if (displayColors && lines.length) { - this._drawColorBox(ctx, pt, i, rtlHelper, options); - bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); - } - for (j = 0, jlen = lines.length; j < jlen; ++j) { - fillLineOfText(lines[j]); - bodyLineHeight = bodyFont.lineHeight; - } - each(bodyItem.after, fillLineOfText); - } - xLinePadding = 0; - bodyLineHeight = bodyFont.lineHeight; - each(this.afterBody, fillLineOfText); - pt.y -= bodySpacing; - } - drawFooter(pt, ctx, options) { - const footer = this.footer; - const length = footer.length; - let footerFont, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.footerAlign, options); - pt.y += options.footerMarginTop; - ctx.textAlign = rtlHelper.textAlign(options.footerAlign); - ctx.textBaseline = 'middle'; - footerFont = toFont(options.footerFont); - ctx.fillStyle = options.footerColor; - ctx.font = footerFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); - pt.y += footerFont.lineHeight + options.footerSpacing; - } - } - } - drawBackground(pt, ctx, tooltipSize, options) { - const {xAlign, yAlign} = this; - const {x, y} = pt; - const {width, height} = tooltipSize; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius); - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.beginPath(); - ctx.moveTo(x + topLeft, y); - if (yAlign === 'top') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width - topRight, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); - if (yAlign === 'center' && xAlign === 'right') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width, y + height - bottomRight); - ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); - if (yAlign === 'bottom') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + bottomLeft, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); - if (yAlign === 'center' && xAlign === 'left') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x, y + topLeft); - ctx.quadraticCurveTo(x, y, x + topLeft, y); - ctx.closePath(); - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } - } - _updateAnimationTarget(options) { - const chart = this.chart; - const anims = this.$animations; - const animX = anims && anims.x; - const animY = anims && anims.y; - if (animX || animY) { - const position = positioners[options.position].call(this, this._active, this._eventPosition); - if (!position) { - return; - } - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, this._size); - const alignment = determineAlignment(chart, options, positionAndSize); - const point = getBackgroundPoint(options, positionAndSize, alignment, chart); - if (animX._to !== point.x || animY._to !== point.y) { - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - this.width = size.width; - this.height = size.height; - this.caretX = position.x; - this.caretY = position.y; - this._resolveAnimations().update(this, point); - } - } - } - draw(ctx) { - const options = this.options.setContext(this.getContext()); - let opacity = this.opacity; - if (!opacity) { - return; - } - this._updateAnimationTarget(options); - const tooltipSize = { - width: this.width, - height: this.height - }; - const pt = { - x: this.x, - y: this.y - }; - opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; - const padding = toPadding(options.padding); - const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; - if (options.enabled && hasTooltipContent) { - ctx.save(); - ctx.globalAlpha = opacity; - this.drawBackground(pt, ctx, tooltipSize, options); - overrideTextDirection(ctx, options.textDirection); - pt.y += padding.top; - this.drawTitle(pt, ctx, options); - this.drawBody(pt, ctx, options); - this.drawFooter(pt, ctx, options); - restoreTextDirection(ctx, options.textDirection); - ctx.restore(); - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements, eventPosition) { - const lastActive = this._active; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.chart.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('Cannot find a dataset at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(lastActive, active); - const positionChanged = this._positionChanged(active, eventPosition); - if (changed || positionChanged) { - this._active = active; - this._eventPosition = eventPosition; - this._ignoreReplayEvents = true; - this.update(true); - } - } - handleEvent(e, replay, inChartArea = true) { - if (replay && this._ignoreReplayEvents) { - return false; - } - this._ignoreReplayEvents = false; - const options = this.options; - const lastActive = this._active || []; - const active = this._getActiveElements(e, lastActive, replay, inChartArea); - const positionChanged = this._positionChanged(active, e); - const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; - if (changed) { - this._active = active; - if (options.enabled || options.external) { - this._eventPosition = { - x: e.x, - y: e.y - }; - this.update(true, replay); - } - } - return changed; - } - _getActiveElements(e, lastActive, replay, inChartArea) { - const options = this.options; - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); - if (options.reverse) { - active.reverse(); - } - return active; - } - _positionChanged(active, e) { - const {caretX, caretY, options} = this; - const position = positioners[options.position].call(this, active, e); - return position !== false && (caretX !== position.x || caretY !== position.y); - } -} -Tooltip.positioners = positioners; -var plugin_tooltip = { - id: 'tooltip', - _element: Tooltip, - positioners, - afterInit(chart, _args, options) { - if (options) { - chart.tooltip = new Tooltip({chart, options}); - } - }, - beforeUpdate(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - reset(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - afterDraw(chart) { - const tooltip = chart.tooltip; - const args = { - tooltip - }; - if (chart.notifyPlugins('beforeTooltipDraw', args) === false) { - return; - } - if (tooltip) { - tooltip.draw(chart.ctx); - } - chart.notifyPlugins('afterTooltipDraw', args); - }, - afterEvent(chart, args) { - if (chart.tooltip) { - const useFinalPosition = args.replay; - if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { - args.changed = true; - } - } - }, - defaults: { - enabled: true, - external: null, - position: 'average', - backgroundColor: 'rgba(0,0,0,0.8)', - titleColor: '#fff', - titleFont: { - weight: 'bold', - }, - titleSpacing: 2, - titleMarginBottom: 6, - titleAlign: 'left', - bodyColor: '#fff', - bodySpacing: 2, - bodyFont: { - }, - bodyAlign: 'left', - footerColor: '#fff', - footerSpacing: 2, - footerMarginTop: 6, - footerFont: { - weight: 'bold', - }, - footerAlign: 'left', - padding: 6, - caretPadding: 2, - caretSize: 5, - cornerRadius: 6, - boxHeight: (ctx, opts) => opts.bodyFont.size, - boxWidth: (ctx, opts) => opts.bodyFont.size, - multiKeyBackground: '#fff', - displayColors: true, - boxPadding: 0, - borderColor: 'rgba(0,0,0,0)', - borderWidth: 0, - animation: { - duration: 400, - easing: 'easeOutQuart', - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], - }, - opacity: { - easing: 'linear', - duration: 200 - } - }, - callbacks: { - beforeTitle: noop, - title(tooltipItems) { - if (tooltipItems.length > 0) { - const item = tooltipItems[0]; - const labels = item.chart.data.labels; - const labelCount = labels ? labels.length : 0; - if (this && this.options && this.options.mode === 'dataset') { - return item.dataset.label || ''; - } else if (item.label) { - return item.label; - } else if (labelCount > 0 && item.dataIndex < labelCount) { - return labels[item.dataIndex]; - } - } - return ''; - }, - afterTitle: noop, - beforeBody: noop, - beforeLabel: noop, - label(tooltipItem) { - if (this && this.options && this.options.mode === 'dataset') { - return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; - } - let label = tooltipItem.dataset.label || ''; - if (label) { - label += ': '; - } - const value = tooltipItem.formattedValue; - if (!isNullOrUndef(value)) { - label += value; - } - return label; - }, - labelColor(tooltipItem) { - const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); - const options = meta.controller.getStyle(tooltipItem.dataIndex); - return { - borderColor: options.borderColor, - backgroundColor: options.backgroundColor, - borderWidth: options.borderWidth, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderRadius: 0, - }; - }, - labelTextColor() { - return this.options.bodyColor; - }, - labelPointStyle(tooltipItem) { - const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); - const options = meta.controller.getStyle(tooltipItem.dataIndex); - return { - pointStyle: options.pointStyle, - rotation: options.rotation, - }; - }, - afterLabel: noop, - afterBody: noop, - beforeFooter: noop, - footer: noop, - afterFooter: noop - } - }, - defaultRoutes: { - bodyFont: 'font', - footerFont: 'font', - titleFont: 'font' - }, - descriptors: { - _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external', - _indexable: false, - callbacks: { - _scriptable: false, - _indexable: false, - }, - animation: { - _fallback: false - }, - animations: { - _fallback: 'animation' - } - }, - additionalOptionScopes: ['interaction'] -}; - -var plugins = /*#__PURE__*/Object.freeze({ -__proto__: null, -Decimation: plugin_decimation, -Filler: plugin_filler, -Legend: plugin_legend, -SubTitle: plugin_subtitle, -Title: plugin_title, -Tooltip: plugin_tooltip -}); - -const addIfString = (labels, raw, index, addedLabels) => { - if (typeof raw === 'string') { - index = labels.push(raw) - 1; - addedLabels.unshift({index, label: raw}); - } else if (isNaN(raw)) { - index = null; - } - return index; -}; -function findOrAddLabel(labels, raw, index, addedLabels) { - const first = labels.indexOf(raw); - if (first === -1) { - return addIfString(labels, raw, index, addedLabels); - } - const last = labels.lastIndexOf(raw); - return first !== last ? index : first; -} -const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max); -class CategoryScale extends Scale { - constructor(cfg) { - super(cfg); - this._startValue = undefined; - this._valueRange = 0; - this._addedLabels = []; - } - init(scaleOptions) { - const added = this._addedLabels; - if (added.length) { - const labels = this.getLabels(); - for (const {index, label} of added) { - if (labels[index] === label) { - labels.splice(index, 1); - } - } - this._addedLabels = []; - } - super.init(scaleOptions); - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; - } - const labels = this.getLabels(); - index = isFinite(index) && labels[index] === raw ? index - : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); - return validIndex(index, labels.length - 1); - } - determineDataLimits() { - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this.getMinMax(true); - if (this.options.bounds === 'ticks') { - if (!minDefined) { - min = 0; - } - if (!maxDefined) { - max = this.getLabels().length - 1; - } - } - this.min = min; - this.max = max; - } - buildTicks() { - const min = this.min; - const max = this.max; - const offset = this.options.offset; - const ticks = []; - let labels = this.getLabels(); - labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); - this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); - this._startValue = this.min - (offset ? 0.5 : 0); - for (let value = min; value <= max; value++) { - ticks.push({value}); - } - return ticks; - } - getLabelForValue(value) { - const labels = this.getLabels(); - if (value >= 0 && value < labels.length) { - return labels[value]; - } - return value; - } - configure() { - super.configure(); - if (!this.isHorizontal()) { - this._reversePixels = !this._reversePixels; - } - } - getPixelForValue(value) { - if (typeof value !== 'number') { - value = this.parse(value); - } - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getValueForPixel(pixel) { - return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); - } - getBasePixel() { - return this.bottom; - } -} -CategoryScale.id = 'category'; -CategoryScale.defaults = { - ticks: { - callback: CategoryScale.prototype.getLabelForValue - } -}; - -function generateTicks$1(generationOptions, dataRange) { - const ticks = []; - const MIN_SPACING = 1e-14; - const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions; - const unit = step || 1; - const maxSpaces = maxTicks - 1; - const {min: rmin, max: rmax} = dataRange; - const minDefined = !isNullOrUndef(min); - const maxDefined = !isNullOrUndef(max); - const countDefined = !isNullOrUndef(count); - const minSpacing = (rmax - rmin) / (maxDigits + 1); - let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; - let factor, niceMin, niceMax, numSpaces; - if (spacing < MIN_SPACING && !minDefined && !maxDefined) { - return [{value: rmin}, {value: rmax}]; - } - numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); - if (numSpaces > maxSpaces) { - spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; - } - if (!isNullOrUndef(precision)) { - factor = Math.pow(10, precision); - spacing = Math.ceil(spacing * factor) / factor; - } - if (bounds === 'ticks') { - niceMin = Math.floor(rmin / spacing) * spacing; - niceMax = Math.ceil(rmax / spacing) * spacing; - } else { - niceMin = rmin; - niceMax = rmax; - } - if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { - numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); - spacing = (max - min) / numSpaces; - niceMin = min; - niceMax = max; - } else if (countDefined) { - niceMin = minDefined ? min : niceMin; - niceMax = maxDefined ? max : niceMax; - numSpaces = count - 1; - spacing = (niceMax - niceMin) / numSpaces; - } else { - numSpaces = (niceMax - niceMin) / spacing; - if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { - numSpaces = Math.round(numSpaces); - } else { - numSpaces = Math.ceil(numSpaces); - } - } - const decimalPlaces = Math.max( - _decimalPlaces(spacing), - _decimalPlaces(niceMin) - ); - factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); - niceMin = Math.round(niceMin * factor) / factor; - niceMax = Math.round(niceMax * factor) / factor; - let j = 0; - if (minDefined) { - if (includeBounds && niceMin !== min) { - ticks.push({value: min}); - if (niceMin < min) { - j++; - } - if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { - j++; - } - } else if (niceMin < min) { - j++; - } - } - for (; j < numSpaces; ++j) { - ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); - } - if (maxDefined && includeBounds && niceMax !== max) { - if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { - ticks[ticks.length - 1].value = max; - } else { - ticks.push({value: max}); - } - } else if (!maxDefined || niceMax === max) { - ticks.push({value: niceMax}); - } - return ticks; -} -function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) { - const rad = toRadians(minRotation); - const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; - const length = 0.75 * minSpacing * ('' + value).length; - return Math.min(minSpacing / ratio, length); -} -class LinearScaleBase extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._endValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; - } - if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { - return null; - } - return +raw; - } - handleTickRangeOptions() { - const {beginAtZero} = this.options; - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - if (beginAtZero) { - const minSign = sign(min); - const maxSign = sign(max); - if (minSign < 0 && maxSign < 0) { - setMax(0); - } else if (minSign > 0 && maxSign > 0) { - setMin(0); - } - } - if (min === max) { - let offset = 1; - if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) { - offset = Math.abs(max * 0.05); - } - setMax(max + offset); - if (!beginAtZero) { - setMin(min - offset); - } - } - this.min = min; - this.max = max; - } - getTickLimit() { - const tickOpts = this.options.ticks; - let {maxTicksLimit, stepSize} = tickOpts; - let maxTicks; - if (stepSize) { - maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; - if (maxTicks > 1000) { - console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); - maxTicks = 1000; - } - } else { - maxTicks = this.computeTickLimit(); - maxTicksLimit = maxTicksLimit || 11; - } - if (maxTicksLimit) { - maxTicks = Math.min(maxTicksLimit, maxTicks); - } - return maxTicks; - } - computeTickLimit() { - return Number.POSITIVE_INFINITY; - } - buildTicks() { - const opts = this.options; - const tickOpts = opts.ticks; - let maxTicks = this.getTickLimit(); - maxTicks = Math.max(2, maxTicks); - const numericGeneratorOptions = { - maxTicks, - bounds: opts.bounds, - min: opts.min, - max: opts.max, - precision: tickOpts.precision, - step: tickOpts.stepSize, - count: tickOpts.count, - maxDigits: this._maxDigits(), - horizontal: this.isHorizontal(), - minRotation: tickOpts.minRotation || 0, - includeBounds: tickOpts.includeBounds !== false - }; - const dataRange = this._range || this; - const ticks = generateTicks$1(numericGeneratorOptions, dataRange); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); - } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; - } - return ticks; - } - configure() { - const ticks = this.ticks; - let start = this.min; - let end = this.max; - super.configure(); - if (this.options.offset && ticks.length) { - const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; - start -= offset; - end += offset; - } - this._startValue = start; - this._endValue = end; - this._valueRange = end - start; - } - getLabelForValue(value) { - return formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } -} - -class LinearScale extends LinearScaleBase { - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? min : 0; - this.max = isNumberFinite(max) ? max : 1; - this.handleTickRangeOptions(); - } - computeTickLimit() { - const horizontal = this.isHorizontal(); - const length = horizontal ? this.width : this.height; - const minRotation = toRadians(this.options.ticks.minRotation); - const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; - const tickFont = this._resolveTickFontOptions(0); - return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); - } - getPixelForValue(value) { - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; - } -} -LinearScale.id = 'linear'; -LinearScale.defaults = { - ticks: { - callback: Ticks.formatters.numeric - } -}; - -function isMajor(tickVal) { - const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); - return remain === 1; -} -function generateTicks(generationOptions, dataRange) { - const endExp = Math.floor(log10(dataRange.max)); - const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); - const ticks = []; - let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); - let exp = Math.floor(log10(tickVal)); - let significand = Math.floor(tickVal / Math.pow(10, exp)); - let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; - do { - ticks.push({value: tickVal, major: isMajor(tickVal)}); - ++significand; - if (significand === 10) { - significand = 1; - ++exp; - precision = exp >= 0 ? 1 : precision; - } - tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; - } while (exp < endExp || (exp === endExp && significand < endSignificand)); - const lastTick = finiteOrDefault(generationOptions.max, tickVal); - ticks.push({value: lastTick, major: isMajor(tickVal)}); - return ticks; -} -class LogarithmicScale extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); - if (value === 0) { - this._zero = true; - return undefined; - } - return isNumberFinite(value) && value > 0 ? value : null; - } - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? Math.max(0, min) : null; - this.max = isNumberFinite(max) ? Math.max(0, max) : null; - if (this.options.beginAtZero) { - this._zero = true; - } - this.handleTickRangeOptions(); - } - handleTickRangeOptions() { - const {minDefined, maxDefined} = this.getUserBounds(); - let min = this.min; - let max = this.max; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m); - if (min === max) { - if (min <= 0) { - setMin(1); - setMax(10); - } else { - setMin(exp(min, -1)); - setMax(exp(max, +1)); - } - } - if (min <= 0) { - setMin(exp(max, -1)); - } - if (max <= 0) { - setMax(exp(min, +1)); - } - if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) { - setMin(exp(min, -1)); - } - this.min = min; - this.max = max; - } - buildTicks() { - const opts = this.options; - const generationOptions = { - min: this._userMin, - max: this._userMax - }; - const ticks = generateTicks(generationOptions, this); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); - } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; - } - return ticks; - } - getLabelForValue(value) { - return value === undefined - ? '0' - : formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } - configure() { - const start = this.min; - super.configure(); - this._startValue = log10(start); - this._valueRange = log10(this.max) - log10(start); - } - getPixelForValue(value) { - if (value === undefined || value === 0) { - value = this.min; - } - if (value === null || isNaN(value)) { - return NaN; - } - return this.getPixelForDecimal(value === this.min - ? 0 - : (log10(value) - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - const decimal = this.getDecimalForPixel(pixel); - return Math.pow(10, this._startValue + decimal * this._valueRange); - } -} -LogarithmicScale.id = 'logarithmic'; -LogarithmicScale.defaults = { - ticks: { - callback: Ticks.formatters.logarithmic, - major: { - enabled: true - } - } -}; - -function getTickBackdropHeight(opts) { - const tickOpts = opts.ticks; - if (tickOpts.display && opts.display) { - const padding = toPadding(tickOpts.backdropPadding); - return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; - } - return 0; -} -function measureLabelSize(ctx, font, label) { - label = isArray(label) ? label : [label]; - return { - w: _longestText(ctx, font.string, label), - h: label.length * font.lineHeight - }; -} -function determineLimits(angle, pos, size, min, max) { - if (angle === min || angle === max) { - return { - start: pos - (size / 2), - end: pos + (size / 2) - }; - } else if (angle < min || angle > max) { - return { - start: pos - size, - end: pos - }; - } - return { - start: pos, - end: pos + size - }; -} -function fitWithPointLabels(scale) { - const orig = { - l: scale.left + scale._padding.left, - r: scale.right - scale._padding.right, - t: scale.top + scale._padding.top, - b: scale.bottom - scale._padding.bottom - }; - const limits = Object.assign({}, orig); - const labelSizes = []; - const padding = []; - const valueCount = scale._pointLabels.length; - const pointLabelOpts = scale.options.pointLabels; - const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); - padding[i] = opts.padding; - const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); - const plFont = toFont(opts.font); - const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); - labelSizes[i] = textSize; - const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); - const angle = Math.round(toDegrees(angleRadians)); - const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); - const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); - updateLimits(limits, orig, angleRadians, hLimits, vLimits); - } - scale.setCenterPoint( - orig.l - limits.l, - limits.r - orig.r, - orig.t - limits.t, - limits.b - orig.b - ); - scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); -} -function updateLimits(limits, orig, angle, hLimits, vLimits) { - const sin = Math.abs(Math.sin(angle)); - const cos = Math.abs(Math.cos(angle)); - let x = 0; - let y = 0; - if (hLimits.start < orig.l) { - x = (orig.l - hLimits.start) / sin; - limits.l = Math.min(limits.l, orig.l - x); - } else if (hLimits.end > orig.r) { - x = (hLimits.end - orig.r) / sin; - limits.r = Math.max(limits.r, orig.r + x); - } - if (vLimits.start < orig.t) { - y = (orig.t - vLimits.start) / cos; - limits.t = Math.min(limits.t, orig.t - y); - } else if (vLimits.end > orig.b) { - y = (vLimits.end - orig.b) / cos; - limits.b = Math.max(limits.b, orig.b + y); - } -} -function buildPointLabelItems(scale, labelSizes, padding) { - const items = []; - const valueCount = scale._pointLabels.length; - const opts = scale.options; - const extra = getTickBackdropHeight(opts) / 2; - const outerDistance = scale.drawingArea; - const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle); - const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); - const size = labelSizes[i]; - const y = yForAngle(pointLabelPosition.y, size.h, angle); - const textAlign = getTextAlignForAngle(angle); - const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); - items.push({ - x: pointLabelPosition.x, - y, - textAlign, - left, - top: y, - right: left + size.w, - bottom: y + size.h - }); - } - return items; -} -function getTextAlignForAngle(angle) { - if (angle === 0 || angle === 180) { - return 'center'; - } else if (angle < 180) { - return 'left'; - } - return 'right'; -} -function leftForTextAlign(x, w, align) { - if (align === 'right') { - x -= w; - } else if (align === 'center') { - x -= (w / 2); - } - return x; -} -function yForAngle(y, h, angle) { - if (angle === 90 || angle === 270) { - y -= (h / 2); - } else if (angle > 270 || angle < 90) { - y -= h; - } - return y; -} -function drawPointLabels(scale, labelCount) { - const {ctx, options: {pointLabels}} = scale; - for (let i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); - const plFont = toFont(optsAtIndex.font); - const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i]; - const {backdropColor} = optsAtIndex; - if (!isNullOrUndef(backdropColor)) { - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillStyle = backdropColor; - ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height); - } - renderText( - ctx, - scale._pointLabels[i], - x, - y + (plFont.lineHeight / 2), - plFont, - { - color: optsAtIndex.color, - textAlign: textAlign, - textBaseline: 'middle' - } - ); - } -} -function pathRadiusLine(scale, radius, circular, labelCount) { - const {ctx} = scale; - if (circular) { - ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); - } else { - let pointPosition = scale.getPointPosition(0, radius); - ctx.moveTo(pointPosition.x, pointPosition.y); - for (let i = 1; i < labelCount; i++) { - pointPosition = scale.getPointPosition(i, radius); - ctx.lineTo(pointPosition.x, pointPosition.y); - } - } -} -function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { - const ctx = scale.ctx; - const circular = gridLineOpts.circular; - const {color, lineWidth} = gridLineOpts; - if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { - return; - } - ctx.save(); - ctx.strokeStyle = color; - ctx.lineWidth = lineWidth; - ctx.setLineDash(gridLineOpts.borderDash); - ctx.lineDashOffset = gridLineOpts.borderDashOffset; - ctx.beginPath(); - pathRadiusLine(scale, radius, circular, labelCount); - ctx.closePath(); - ctx.stroke(); - ctx.restore(); -} -function createPointLabelContext(parent, index, label) { - return createContext(parent, { - label, - index, - type: 'pointLabel' - }); -} -class RadialLinearScale extends LinearScaleBase { - constructor(cfg) { - super(cfg); - this.xCenter = undefined; - this.yCenter = undefined; - this.drawingArea = undefined; - this._pointLabels = []; - this._pointLabelItems = []; - } - setDimensions() { - const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); - const w = this.width = this.maxWidth - padding.width; - const h = this.height = this.maxHeight - padding.height; - this.xCenter = Math.floor(this.left + w / 2 + padding.left); - this.yCenter = Math.floor(this.top + h / 2 + padding.top); - this.drawingArea = Math.floor(Math.min(w, h) / 2); - } - determineDataLimits() { - const {min, max} = this.getMinMax(false); - this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; - this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; - this.handleTickRangeOptions(); - } - computeTickLimit() { - return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); - } - generateTickLabels(ticks) { - LinearScaleBase.prototype.generateTickLabels.call(this, ticks); - this._pointLabels = this.getLabels() - .map((value, index) => { - const label = callback(this.options.pointLabels.callback, [value, index], this); - return label || label === 0 ? label : ''; - }) - .filter((v, i) => this.chart.getDataVisibility(i)); - } - fit() { - const opts = this.options; - if (opts.display && opts.pointLabels.display) { - fitWithPointLabels(this); - } else { - this.setCenterPoint(0, 0, 0, 0); - } - } - setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { - this.xCenter += Math.floor((leftMovement - rightMovement) / 2); - this.yCenter += Math.floor((topMovement - bottomMovement) / 2); - this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); - } - getIndexAngle(index) { - const angleMultiplier = TAU / (this._pointLabels.length || 1); - const startAngle = this.options.startAngle || 0; - return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); - } - getDistanceFromCenterForValue(value) { - if (isNullOrUndef(value)) { - return NaN; - } - const scalingFactor = this.drawingArea / (this.max - this.min); - if (this.options.reverse) { - return (this.max - value) * scalingFactor; - } - return (value - this.min) * scalingFactor; - } - getValueForDistanceFromCenter(distance) { - if (isNullOrUndef(distance)) { - return NaN; - } - const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); - return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; - } - getPointLabelContext(index) { - const pointLabels = this._pointLabels || []; - if (index >= 0 && index < pointLabels.length) { - const pointLabel = pointLabels[index]; - return createPointLabelContext(this.getContext(), index, pointLabel); - } - } - getPointPosition(index, distanceFromCenter, additionalAngle = 0) { - const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; - return { - x: Math.cos(angle) * distanceFromCenter + this.xCenter, - y: Math.sin(angle) * distanceFromCenter + this.yCenter, - angle - }; - } - getPointPositionForValue(index, value) { - return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); - } - getBasePosition(index) { - return this.getPointPositionForValue(index || 0, this.getBaseValue()); - } - getPointLabelPosition(index) { - const {left, top, right, bottom} = this._pointLabelItems[index]; - return { - left, - top, - right, - bottom, - }; - } - drawBackground() { - const {backgroundColor, grid: {circular}} = this.options; - if (backgroundColor) { - const ctx = this.ctx; - ctx.save(); - ctx.beginPath(); - pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); - ctx.closePath(); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - } - drawGrid() { - const ctx = this.ctx; - const opts = this.options; - const {angleLines, grid} = opts; - const labelCount = this._pointLabels.length; - let i, offset, position; - if (opts.pointLabels.display) { - drawPointLabels(this, labelCount); - } - if (grid.display) { - this.ticks.forEach((tick, index) => { - if (index !== 0) { - offset = this.getDistanceFromCenterForValue(tick.value); - const optsAtIndex = grid.setContext(this.getContext(index - 1)); - drawRadiusLine(this, optsAtIndex, offset, labelCount); - } - }); - } - if (angleLines.display) { - ctx.save(); - for (i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); - const {color, lineWidth} = optsAtIndex; - if (!lineWidth || !color) { - continue; - } - ctx.lineWidth = lineWidth; - ctx.strokeStyle = color; - ctx.setLineDash(optsAtIndex.borderDash); - ctx.lineDashOffset = optsAtIndex.borderDashOffset; - offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); - position = this.getPointPosition(i, offset); - ctx.beginPath(); - ctx.moveTo(this.xCenter, this.yCenter); - ctx.lineTo(position.x, position.y); - ctx.stroke(); - } - ctx.restore(); - } - } - drawBorder() {} - drawLabels() { - const ctx = this.ctx; - const opts = this.options; - const tickOpts = opts.ticks; - if (!tickOpts.display) { - return; - } - const startAngle = this.getIndexAngle(0); - let offset, width; - ctx.save(); - ctx.translate(this.xCenter, this.yCenter); - ctx.rotate(startAngle); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - this.ticks.forEach((tick, index) => { - if (index === 0 && !opts.reverse) { - return; - } - const optsAtIndex = tickOpts.setContext(this.getContext(index)); - const tickFont = toFont(optsAtIndex.font); - offset = this.getDistanceFromCenterForValue(this.ticks[index].value); - if (optsAtIndex.showLabelBackdrop) { - ctx.font = tickFont.string; - width = ctx.measureText(tick.label).width; - ctx.fillStyle = optsAtIndex.backdropColor; - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillRect( - -width / 2 - padding.left, - -offset - tickFont.size / 2 - padding.top, - width + padding.width, - tickFont.size + padding.height - ); - } - renderText(ctx, tick.label, 0, -offset, tickFont, { - color: optsAtIndex.color, - }); - }); - ctx.restore(); - } - drawTitle() {} -} -RadialLinearScale.id = 'radialLinear'; -RadialLinearScale.defaults = { - display: true, - animate: true, - position: 'chartArea', - angleLines: { - display: true, - lineWidth: 1, - borderDash: [], - borderDashOffset: 0.0 - }, - grid: { - circular: false - }, - startAngle: 0, - ticks: { - showLabelBackdrop: true, - callback: Ticks.formatters.numeric - }, - pointLabels: { - backdropColor: undefined, - backdropPadding: 2, - display: true, - font: { - size: 10 - }, - callback(label) { - return label; - }, - padding: 5, - centerPointLabels: false - } -}; -RadialLinearScale.defaultRoutes = { - 'angleLines.color': 'borderColor', - 'pointLabels.color': 'color', - 'ticks.color': 'color' -}; -RadialLinearScale.descriptors = { - angleLines: { - _fallback: 'grid' - } -}; - -const INTERVALS = { - millisecond: {common: true, size: 1, steps: 1000}, - second: {common: true, size: 1000, steps: 60}, - minute: {common: true, size: 60000, steps: 60}, - hour: {common: true, size: 3600000, steps: 24}, - day: {common: true, size: 86400000, steps: 30}, - week: {common: false, size: 604800000, steps: 4}, - month: {common: true, size: 2.628e9, steps: 12}, - quarter: {common: false, size: 7.884e9, steps: 4}, - year: {common: true, size: 3.154e10} -}; -const UNITS = (Object.keys(INTERVALS)); -function sorter(a, b) { - return a - b; -} -function parse(scale, input) { - if (isNullOrUndef(input)) { - return null; - } - const adapter = scale._adapter; - const {parser, round, isoWeekday} = scale._parseOpts; - let value = input; - if (typeof parser === 'function') { - value = parser(value); - } - if (!isNumberFinite(value)) { - value = typeof parser === 'string' - ? adapter.parse(value, parser) - : adapter.parse(value); - } - if (value === null) { - return null; - } - if (round) { - value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) - ? adapter.startOf(value, 'isoWeek', isoWeekday) - : adapter.startOf(value, round); - } - return +value; -} -function determineUnitForAutoTicks(minUnit, min, max, capacity) { - const ilen = UNITS.length; - for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { - const interval = INTERVALS[UNITS[i]]; - const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; - if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { - return UNITS[i]; - } - } - return UNITS[ilen - 1]; -} -function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { - for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { - const unit = UNITS[i]; - if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { - return unit; - } - } - return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; -} -function determineMajorUnit(unit) { - for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { - if (INTERVALS[UNITS[i]].common) { - return UNITS[i]; - } - } -} -function addTick(ticks, time, timestamps) { - if (!timestamps) { - ticks[time] = true; - } else if (timestamps.length) { - const {lo, hi} = _lookup(timestamps, time); - const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; - ticks[timestamp] = true; - } -} -function setMajorTicks(scale, ticks, map, majorUnit) { - const adapter = scale._adapter; - const first = +adapter.startOf(ticks[0].value, majorUnit); - const last = ticks[ticks.length - 1].value; - let major, index; - for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { - index = map[major]; - if (index >= 0) { - ticks[index].major = true; - } - } - return ticks; -} -function ticksFromTimestamps(scale, values, majorUnit) { - const ticks = []; - const map = {}; - const ilen = values.length; - let i, value; - for (i = 0; i < ilen; ++i) { - value = values[i]; - map[value] = i; - ticks.push({ - value, - major: false - }); - } - return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); -} -class TimeScale extends Scale { - constructor(props) { - super(props); - this._cache = { - data: [], - labels: [], - all: [] - }; - this._unit = 'day'; - this._majorUnit = undefined; - this._offsets = {}; - this._normalized = false; - this._parseOpts = undefined; - } - init(scaleOpts, opts) { - const time = scaleOpts.time || (scaleOpts.time = {}); - const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); - mergeIf(time.displayFormats, adapter.formats()); - this._parseOpts = { - parser: time.parser, - round: time.round, - isoWeekday: time.isoWeekday - }; - super.init(scaleOpts); - this._normalized = opts.normalized; - } - parse(raw, index) { - if (raw === undefined) { - return null; - } - return parse(this, raw); - } - beforeLayout() { - super.beforeLayout(); - this._cache = { - data: [], - labels: [], - all: [] - }; - } - determineDataLimits() { - const options = this.options; - const adapter = this._adapter; - const unit = options.time.unit || 'day'; - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - function _applyBounds(bounds) { - if (!minDefined && !isNaN(bounds.min)) { - min = Math.min(min, bounds.min); - } - if (!maxDefined && !isNaN(bounds.max)) { - max = Math.max(max, bounds.max); - } - } - if (!minDefined || !maxDefined) { - _applyBounds(this._getLabelBounds()); - if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { - _applyBounds(this.getMinMax(false)); - } - } - min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); - max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; - this.min = Math.min(min, max - 1); - this.max = Math.max(min + 1, max); - } - _getLabelBounds() { - const arr = this.getLabelTimestamps(); - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - if (arr.length) { - min = arr[0]; - max = arr[arr.length - 1]; - } - return {min, max}; - } - buildTicks() { - const options = this.options; - const timeOpts = options.time; - const tickOpts = options.ticks; - const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); - if (options.bounds === 'ticks' && timestamps.length) { - this.min = this._userMin || timestamps[0]; - this.max = this._userMax || timestamps[timestamps.length - 1]; - } - const min = this.min; - const max = this.max; - const ticks = _filterBetween(timestamps, min, max); - this._unit = timeOpts.unit || (tickOpts.autoSkip - ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) - : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); - this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined - : determineMajorUnit(this._unit); - this.initOffsets(timestamps); - if (options.reverse) { - ticks.reverse(); - } - return ticksFromTimestamps(this, ticks, this._majorUnit); - } - initOffsets(timestamps) { - let start = 0; - let end = 0; - let first, last; - if (this.options.offset && timestamps.length) { - first = this.getDecimalForValue(timestamps[0]); - if (timestamps.length === 1) { - start = 1 - first; - } else { - start = (this.getDecimalForValue(timestamps[1]) - first) / 2; - } - last = this.getDecimalForValue(timestamps[timestamps.length - 1]); - if (timestamps.length === 1) { - end = last; - } else { - end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; - } - } - const limit = timestamps.length < 3 ? 0.5 : 0.25; - start = _limitValue(start, 0, limit); - end = _limitValue(end, 0, limit); - this._offsets = {start, end, factor: 1 / (start + 1 + end)}; - } - _generate() { - const adapter = this._adapter; - const min = this.min; - const max = this.max; - const options = this.options; - const timeOpts = options.time; - const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); - const stepSize = valueOrDefault(timeOpts.stepSize, 1); - const weekday = minor === 'week' ? timeOpts.isoWeekday : false; - const hasWeekday = isNumber(weekday) || weekday === true; - const ticks = {}; - let first = min; - let time, count; - if (hasWeekday) { - first = +adapter.startOf(first, 'isoWeek', weekday); - } - first = +adapter.startOf(first, hasWeekday ? 'day' : minor); - if (adapter.diff(max, min, minor) > 100000 * stepSize) { - throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); - } - const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); - for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) { - addTick(ticks, time, timestamps); - } - if (time === max || options.bounds === 'ticks' || count === 1) { - addTick(ticks, time, timestamps); - } - return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); - } - getLabelForValue(value) { - const adapter = this._adapter; - const timeOpts = this.options.time; - if (timeOpts.tooltipFormat) { - return adapter.format(value, timeOpts.tooltipFormat); - } - return adapter.format(value, timeOpts.displayFormats.datetime); - } - _tickFormatFunction(time, index, ticks, format) { - const options = this.options; - const formats = options.time.displayFormats; - const unit = this._unit; - const majorUnit = this._majorUnit; - const minorFormat = unit && formats[unit]; - const majorFormat = majorUnit && formats[majorUnit]; - const tick = ticks[index]; - const major = majorUnit && majorFormat && tick && tick.major; - const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat)); - const formatter = options.ticks.callback; - return formatter ? callback(formatter, [label, index, ticks], this) : label; - } - generateTickLabels(ticks) { - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - tick.label = this._tickFormatFunction(tick.value, i, ticks); - } - } - getDecimalForValue(value) { - return value === null ? NaN : (value - this.min) / (this.max - this.min); - } - getPixelForValue(value) { - const offsets = this._offsets; - const pos = this.getDecimalForValue(value); - return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return this.min + pos * (this.max - this.min); - } - _getLabelSize(label) { - const ticksOpts = this.options.ticks; - const tickLabelWidth = this.ctx.measureText(label).width; - const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); - const cosRotation = Math.cos(angle); - const sinRotation = Math.sin(angle); - const tickFontSize = this._resolveTickFontOptions(0).size; - return { - w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), - h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) - }; - } - _getLabelCapacity(exampleTime) { - const timeOpts = this.options.time; - const displayFormats = timeOpts.displayFormats; - const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; - const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format); - const size = this._getLabelSize(exampleLabel); - const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; - return capacity > 0 ? capacity : 1; - } - getDataTimestamps() { - let timestamps = this._cache.data || []; - let i, ilen; - if (timestamps.length) { - return timestamps; - } - const metas = this.getMatchingVisibleMetas(); - if (this._normalized && metas.length) { - return (this._cache.data = metas[0].controller.getAllParsedValues(this)); - } - for (i = 0, ilen = metas.length; i < ilen; ++i) { - timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); - } - return (this._cache.data = this.normalize(timestamps)); - } - getLabelTimestamps() { - const timestamps = this._cache.labels || []; - let i, ilen; - if (timestamps.length) { - return timestamps; - } - const labels = this.getLabels(); - for (i = 0, ilen = labels.length; i < ilen; ++i) { - timestamps.push(parse(this, labels[i])); - } - return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps)); - } - normalize(values) { - return _arrayUnique(values.sort(sorter)); - } -} -TimeScale.id = 'time'; -TimeScale.defaults = { - bounds: 'data', - adapters: {}, - time: { - parser: false, - unit: false, - round: false, - isoWeekday: false, - minUnit: 'millisecond', - displayFormats: {} - }, - ticks: { - source: 'auto', - major: { - enabled: false - } - } -}; - -function interpolate(table, val, reverse) { - let lo = 0; - let hi = table.length - 1; - let prevSource, nextSource, prevTarget, nextTarget; - if (reverse) { - if (val >= table[lo].pos && val <= table[hi].pos) { - ({lo, hi} = _lookupByKey(table, 'pos', val)); - } - ({pos: prevSource, time: prevTarget} = table[lo]); - ({pos: nextSource, time: nextTarget} = table[hi]); - } else { - if (val >= table[lo].time && val <= table[hi].time) { - ({lo, hi} = _lookupByKey(table, 'time', val)); - } - ({time: prevSource, pos: prevTarget} = table[lo]); - ({time: nextSource, pos: nextTarget} = table[hi]); - } - const span = nextSource - prevSource; - return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; -} -class TimeSeriesScale extends TimeScale { - constructor(props) { - super(props); - this._table = []; - this._minPos = undefined; - this._tableRange = undefined; - } - initOffsets() { - const timestamps = this._getTimestampsForTable(); - const table = this._table = this.buildLookupTable(timestamps); - this._minPos = interpolate(table, this.min); - this._tableRange = interpolate(table, this.max) - this._minPos; - super.initOffsets(timestamps); - } - buildLookupTable(timestamps) { - const {min, max} = this; - const items = []; - const table = []; - let i, ilen, prev, curr, next; - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - curr = timestamps[i]; - if (curr >= min && curr <= max) { - items.push(curr); - } - } - if (items.length < 2) { - return [ - {time: min, pos: 0}, - {time: max, pos: 1} - ]; - } - for (i = 0, ilen = items.length; i < ilen; ++i) { - next = items[i + 1]; - prev = items[i - 1]; - curr = items[i]; - if (Math.round((next + prev) / 2) !== curr) { - table.push({time: curr, pos: i / (ilen - 1)}); - } - } - return table; - } - _getTimestampsForTable() { - let timestamps = this._cache.all || []; - if (timestamps.length) { - return timestamps; - } - const data = this.getDataTimestamps(); - const label = this.getLabelTimestamps(); - if (data.length && label.length) { - timestamps = this.normalize(data.concat(label)); - } else { - timestamps = data.length ? data : label; - } - timestamps = this._cache.all = timestamps; - return timestamps; - } - getDecimalForValue(value) { - return (interpolate(this._table, value) - this._minPos) / this._tableRange; - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return interpolate(this._table, decimal * this._tableRange + this._minPos, true); - } -} -TimeSeriesScale.id = 'timeseries'; -TimeSeriesScale.defaults = TimeScale.defaults; - -var scales = /*#__PURE__*/Object.freeze({ -__proto__: null, -CategoryScale: CategoryScale, -LinearScale: LinearScale, -LogarithmicScale: LogarithmicScale, -RadialLinearScale: RadialLinearScale, -TimeScale: TimeScale, -TimeSeriesScale: TimeSeriesScale -}); - -const registerables = [ - controllers, - elements, - plugins, - scales, -]; - -export { Animation, Animations, ArcElement, BarController, BarElement, BasePlatform, BasicPlatform, BubbleController, CategoryScale, Chart, DatasetController, plugin_decimation as Decimation, DomPlatform, DoughnutController, Element, plugin_filler as Filler, Interaction, plugin_legend as Legend, LineController, LineElement, LinearScale, LogarithmicScale, PieController, PointElement, PolarAreaController, RadarController, RadialLinearScale, Scale, ScatterController, plugin_subtitle as SubTitle, Ticks, TimeScale, TimeSeriesScale, plugin_title as Title, plugin_tooltip as Tooltip, adapters as _adapters, _detectPlatform, animator, controllers, elements, layouts, plugins, registerables, registry, scales }; diff --git a/node_modules/chart.js/dist/chart.js b/node_modules/chart.js/dist/chart.js deleted file mode 100644 index 58990616..00000000 --- a/node_modules/chart.js/dist/chart.js +++ /dev/null @@ -1,13269 +0,0 @@ -/*! - * Chart.js v3.7.1 - * https://www.chartjs.org - * (c) 2022 Chart.js Contributors - * Released under the MIT License - */ -(function (global, factory) { -typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : -typeof define === 'function' && define.amd ? define(factory) : -(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chart = factory()); -})(this, (function () { 'use strict'; - -function fontString(pixelSize, fontStyle, fontFamily) { - return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; -} -const requestAnimFrame = (function() { - if (typeof window === 'undefined') { - return function(callback) { - return callback(); - }; - } - return window.requestAnimationFrame; -}()); -function throttled(fn, thisArg, updateFn) { - const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args)); - let ticking = false; - let args = []; - return function(...rest) { - args = updateArgs(rest); - if (!ticking) { - ticking = true; - requestAnimFrame.call(window, () => { - ticking = false; - fn.apply(thisArg, args); - }); - } - }; -} -function debounce(fn, delay) { - let timeout; - return function(...args) { - if (delay) { - clearTimeout(timeout); - timeout = setTimeout(fn, delay, args); - } else { - fn.apply(this, args); - } - return delay; - }; -} -const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; -const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; -const _textX = (align, left, right, rtl) => { - const check = rtl ? 'left' : 'right'; - return align === check ? right : align === 'center' ? (left + right) / 2 : left; -}; - -class Animator { - constructor() { - this._request = null; - this._charts = new Map(); - this._running = false; - this._lastDate = undefined; - } - _notify(chart, anims, date, type) { - const callbacks = anims.listeners[type]; - const numSteps = anims.duration; - callbacks.forEach(fn => fn({ - chart, - initial: anims.initial, - numSteps, - currentStep: Math.min(date - anims.start, numSteps) - })); - } - _refresh() { - if (this._request) { - return; - } - this._running = true; - this._request = requestAnimFrame.call(window, () => { - this._update(); - this._request = null; - if (this._running) { - this._refresh(); - } - }); - } - _update(date = Date.now()) { - let remaining = 0; - this._charts.forEach((anims, chart) => { - if (!anims.running || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - let draw = false; - let item; - for (; i >= 0; --i) { - item = items[i]; - if (item._active) { - if (item._total > anims.duration) { - anims.duration = item._total; - } - item.tick(date); - draw = true; - } else { - items[i] = items[items.length - 1]; - items.pop(); - } - } - if (draw) { - chart.draw(); - this._notify(chart, anims, date, 'progress'); - } - if (!items.length) { - anims.running = false; - this._notify(chart, anims, date, 'complete'); - anims.initial = false; - } - remaining += items.length; - }); - this._lastDate = date; - if (remaining === 0) { - this._running = false; - } - } - _getAnims(chart) { - const charts = this._charts; - let anims = charts.get(chart); - if (!anims) { - anims = { - running: false, - initial: true, - items: [], - listeners: { - complete: [], - progress: [] - } - }; - charts.set(chart, anims); - } - return anims; - } - listen(chart, event, cb) { - this._getAnims(chart).listeners[event].push(cb); - } - add(chart, items) { - if (!items || !items.length) { - return; - } - this._getAnims(chart).items.push(...items); - } - has(chart) { - return this._getAnims(chart).items.length > 0; - } - start(chart) { - const anims = this._charts.get(chart); - if (!anims) { - return; - } - anims.running = true; - anims.start = Date.now(); - anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); - this._refresh(); - } - running(chart) { - if (!this._running) { - return false; - } - const anims = this._charts.get(chart); - if (!anims || !anims.running || !anims.items.length) { - return false; - } - return true; - } - stop(chart) { - const anims = this._charts.get(chart); - if (!anims || !anims.items.length) { - return; - } - const items = anims.items; - let i = items.length - 1; - for (; i >= 0; --i) { - items[i].cancel(); - } - anims.items = []; - this._notify(chart, anims, Date.now(), 'complete'); - } - remove(chart) { - return this._charts.delete(chart); - } -} -var animator = new Animator(); - -/*! - * @kurkle/color v0.1.9 - * https://github.com/kurkle/color#readme - * (c) 2020 Jukka Kurkela - * Released under the MIT License - */ -const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; -const hex = '0123456789ABCDEF'; -const h1 = (b) => hex[b & 0xF]; -const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; -const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF)); -function isShort(v) { - return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); -} -function hexParse(str) { - var len = str.length; - var ret; - if (str[0] === '#') { - if (len === 4 || len === 5) { - ret = { - r: 255 & map$1[str[1]] * 17, - g: 255 & map$1[str[2]] * 17, - b: 255 & map$1[str[3]] * 17, - a: len === 5 ? map$1[str[4]] * 17 : 255 - }; - } else if (len === 7 || len === 9) { - ret = { - r: map$1[str[1]] << 4 | map$1[str[2]], - g: map$1[str[3]] << 4 | map$1[str[4]], - b: map$1[str[5]] << 4 | map$1[str[6]], - a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255 - }; - } - } - return ret; -} -function hexString(v) { - var f = isShort(v) ? h1 : h2; - return v - ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') - : v; -} -function round(v) { - return v + 0.5 | 0; -} -const lim = (v, l, h) => Math.max(Math.min(v, h), l); -function p2b(v) { - return lim(round(v * 2.55), 0, 255); -} -function n2b(v) { - return lim(round(v * 255), 0, 255); -} -function b2n(v) { - return lim(round(v / 2.55) / 100, 0, 1); -} -function n2p(v) { - return lim(round(v * 100), 0, 100); -} -const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; -function rgbParse(str) { - const m = RGB_RE.exec(str); - let a = 255; - let r, g, b; - if (!m) { - return; - } - if (m[7] !== r) { - const v = +m[7]; - a = 255 & (m[8] ? p2b(v) : v * 255); - } - r = +m[1]; - g = +m[3]; - b = +m[5]; - r = 255 & (m[2] ? p2b(r) : r); - g = 255 & (m[4] ? p2b(g) : g); - b = 255 & (m[6] ? p2b(b) : b); - return { - r: r, - g: g, - b: b, - a: a - }; -} -function rgbString(v) { - return v && ( - v.a < 255 - ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` - : `rgb(${v.r}, ${v.g}, ${v.b})` - ); -} -const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; -function hsl2rgbn(h, s, l) { - const a = s * Math.min(l, 1 - l); - const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return [f(0), f(8), f(4)]; -} -function hsv2rgbn(h, s, v) { - const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); - return [f(5), f(3), f(1)]; -} -function hwb2rgbn(h, w, b) { - const rgb = hsl2rgbn(h, 1, 0.5); - let i; - if (w + b > 1) { - i = 1 / (w + b); - w *= i; - b *= i; - } - for (i = 0; i < 3; i++) { - rgb[i] *= 1 - w - b; - rgb[i] += w; - } - return rgb; -} -function rgb2hsl(v) { - const range = 255; - const r = v.r / range; - const g = v.g / range; - const b = v.b / range; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const l = (max + min) / 2; - let h, s, d; - if (max !== min) { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - h = max === r - ? ((g - b) / d) + (g < b ? 6 : 0) - : max === g - ? (b - r) / d + 2 - : (r - g) / d + 4; - h = h * 60 + 0.5; - } - return [h | 0, s || 0, l]; -} -function calln(f, a, b, c) { - return ( - Array.isArray(a) - ? f(a[0], a[1], a[2]) - : f(a, b, c) - ).map(n2b); -} -function hsl2rgb(h, s, l) { - return calln(hsl2rgbn, h, s, l); -} -function hwb2rgb(h, w, b) { - return calln(hwb2rgbn, h, w, b); -} -function hsv2rgb(h, s, v) { - return calln(hsv2rgbn, h, s, v); -} -function hue(h) { - return (h % 360 + 360) % 360; -} -function hueParse(str) { - const m = HUE_RE.exec(str); - let a = 255; - let v; - if (!m) { - return; - } - if (m[5] !== v) { - a = m[6] ? p2b(+m[5]) : n2b(+m[5]); - } - const h = hue(+m[2]); - const p1 = +m[3] / 100; - const p2 = +m[4] / 100; - if (m[1] === 'hwb') { - v = hwb2rgb(h, p1, p2); - } else if (m[1] === 'hsv') { - v = hsv2rgb(h, p1, p2); - } else { - v = hsl2rgb(h, p1, p2); - } - return { - r: v[0], - g: v[1], - b: v[2], - a: a - }; -} -function rotate(v, deg) { - var h = rgb2hsl(v); - h[0] = hue(h[0] + deg); - h = hsl2rgb(h); - v.r = h[0]; - v.g = h[1]; - v.b = h[2]; -} -function hslString(v) { - if (!v) { - return; - } - const a = rgb2hsl(v); - const h = a[0]; - const s = n2p(a[1]); - const l = n2p(a[2]); - return v.a < 255 - ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` - : `hsl(${h}, ${s}%, ${l}%)`; -} -const map$1$1 = { - x: 'dark', - Z: 'light', - Y: 're', - X: 'blu', - W: 'gr', - V: 'medium', - U: 'slate', - A: 'ee', - T: 'ol', - S: 'or', - B: 'ra', - C: 'lateg', - D: 'ights', - R: 'in', - Q: 'turquois', - E: 'hi', - P: 'ro', - O: 'al', - N: 'le', - M: 'de', - L: 'yello', - F: 'en', - K: 'ch', - G: 'arks', - H: 'ea', - I: 'ightg', - J: 'wh' -}; -const names = { - OiceXe: 'f0f8ff', - antiquewEte: 'faebd7', - aqua: 'ffff', - aquamarRe: '7fffd4', - azuY: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '0', - blanKedOmond: 'ffebcd', - Xe: 'ff', - XeviTet: '8a2be2', - bPwn: 'a52a2a', - burlywood: 'deb887', - caMtXe: '5f9ea0', - KartYuse: '7fff00', - KocTate: 'd2691e', - cSO: 'ff7f50', - cSnflowerXe: '6495ed', - cSnsilk: 'fff8dc', - crimson: 'dc143c', - cyan: 'ffff', - xXe: '8b', - xcyan: '8b8b', - xgTMnPd: 'b8860b', - xWay: 'a9a9a9', - xgYF: '6400', - xgYy: 'a9a9a9', - xkhaki: 'bdb76b', - xmagFta: '8b008b', - xTivegYF: '556b2f', - xSange: 'ff8c00', - xScEd: '9932cc', - xYd: '8b0000', - xsOmon: 'e9967a', - xsHgYF: '8fbc8f', - xUXe: '483d8b', - xUWay: '2f4f4f', - xUgYy: '2f4f4f', - xQe: 'ced1', - xviTet: '9400d3', - dAppRk: 'ff1493', - dApskyXe: 'bfff', - dimWay: '696969', - dimgYy: '696969', - dodgerXe: '1e90ff', - fiYbrick: 'b22222', - flSOwEte: 'fffaf0', - foYstWAn: '228b22', - fuKsia: 'ff00ff', - gaRsbSo: 'dcdcdc', - ghostwEte: 'f8f8ff', - gTd: 'ffd700', - gTMnPd: 'daa520', - Way: '808080', - gYF: '8000', - gYFLw: 'adff2f', - gYy: '808080', - honeyMw: 'f0fff0', - hotpRk: 'ff69b4', - RdianYd: 'cd5c5c', - Rdigo: '4b0082', - ivSy: 'fffff0', - khaki: 'f0e68c', - lavFMr: 'e6e6fa', - lavFMrXsh: 'fff0f5', - lawngYF: '7cfc00', - NmoncEffon: 'fffacd', - ZXe: 'add8e6', - ZcSO: 'f08080', - Zcyan: 'e0ffff', - ZgTMnPdLw: 'fafad2', - ZWay: 'd3d3d3', - ZgYF: '90ee90', - ZgYy: 'd3d3d3', - ZpRk: 'ffb6c1', - ZsOmon: 'ffa07a', - ZsHgYF: '20b2aa', - ZskyXe: '87cefa', - ZUWay: '778899', - ZUgYy: '778899', - ZstAlXe: 'b0c4de', - ZLw: 'ffffe0', - lime: 'ff00', - limegYF: '32cd32', - lRF: 'faf0e6', - magFta: 'ff00ff', - maPon: '800000', - VaquamarRe: '66cdaa', - VXe: 'cd', - VScEd: 'ba55d3', - VpurpN: '9370db', - VsHgYF: '3cb371', - VUXe: '7b68ee', - VsprRggYF: 'fa9a', - VQe: '48d1cc', - VviTetYd: 'c71585', - midnightXe: '191970', - mRtcYam: 'f5fffa', - mistyPse: 'ffe4e1', - moccasR: 'ffe4b5', - navajowEte: 'ffdead', - navy: '80', - Tdlace: 'fdf5e6', - Tive: '808000', - TivedBb: '6b8e23', - Sange: 'ffa500', - SangeYd: 'ff4500', - ScEd: 'da70d6', - pOegTMnPd: 'eee8aa', - pOegYF: '98fb98', - pOeQe: 'afeeee', - pOeviTetYd: 'db7093', - papayawEp: 'ffefd5', - pHKpuff: 'ffdab9', - peru: 'cd853f', - pRk: 'ffc0cb', - plum: 'dda0dd', - powMrXe: 'b0e0e6', - purpN: '800080', - YbeccapurpN: '663399', - Yd: 'ff0000', - Psybrown: 'bc8f8f', - PyOXe: '4169e1', - saddNbPwn: '8b4513', - sOmon: 'fa8072', - sandybPwn: 'f4a460', - sHgYF: '2e8b57', - sHshell: 'fff5ee', - siFna: 'a0522d', - silver: 'c0c0c0', - skyXe: '87ceeb', - UXe: '6a5acd', - UWay: '708090', - UgYy: '708090', - snow: 'fffafa', - sprRggYF: 'ff7f', - stAlXe: '4682b4', - tan: 'd2b48c', - teO: '8080', - tEstN: 'd8bfd8', - tomato: 'ff6347', - Qe: '40e0d0', - viTet: 'ee82ee', - JHt: 'f5deb3', - wEte: 'ffffff', - wEtesmoke: 'f5f5f5', - Lw: 'ffff00', - LwgYF: '9acd32' -}; -function unpack() { - const unpacked = {}; - const keys = Object.keys(names); - const tkeys = Object.keys(map$1$1); - let i, j, k, ok, nk; - for (i = 0; i < keys.length; i++) { - ok = nk = keys[i]; - for (j = 0; j < tkeys.length; j++) { - k = tkeys[j]; - nk = nk.replace(k, map$1$1[k]); - } - k = parseInt(names[ok], 16); - unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; - } - return unpacked; -} -let names$1; -function nameParse(str) { - if (!names$1) { - names$1 = unpack(); - names$1.transparent = [0, 0, 0, 0]; - } - const a = names$1[str.toLowerCase()]; - return a && { - r: a[0], - g: a[1], - b: a[2], - a: a.length === 4 ? a[3] : 255 - }; -} -function modHSL(v, i, ratio) { - if (v) { - let tmp = rgb2hsl(v); - tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); - tmp = hsl2rgb(tmp); - v.r = tmp[0]; - v.g = tmp[1]; - v.b = tmp[2]; - } -} -function clone$1(v, proto) { - return v ? Object.assign(proto || {}, v) : v; -} -function fromObject(input) { - var v = {r: 0, g: 0, b: 0, a: 255}; - if (Array.isArray(input)) { - if (input.length >= 3) { - v = {r: input[0], g: input[1], b: input[2], a: 255}; - if (input.length > 3) { - v.a = n2b(input[3]); - } - } - } else { - v = clone$1(input, {r: 0, g: 0, b: 0, a: 1}); - v.a = n2b(v.a); - } - return v; -} -function functionParse(str) { - if (str.charAt(0) === 'r') { - return rgbParse(str); - } - return hueParse(str); -} -class Color { - constructor(input) { - if (input instanceof Color) { - return input; - } - const type = typeof input; - let v; - if (type === 'object') { - v = fromObject(input); - } else if (type === 'string') { - v = hexParse(input) || nameParse(input) || functionParse(input); - } - this._rgb = v; - this._valid = !!v; - } - get valid() { - return this._valid; - } - get rgb() { - var v = clone$1(this._rgb); - if (v) { - v.a = b2n(v.a); - } - return v; - } - set rgb(obj) { - this._rgb = fromObject(obj); - } - rgbString() { - return this._valid ? rgbString(this._rgb) : this._rgb; - } - hexString() { - return this._valid ? hexString(this._rgb) : this._rgb; - } - hslString() { - return this._valid ? hslString(this._rgb) : this._rgb; - } - mix(color, weight) { - const me = this; - if (color) { - const c1 = me.rgb; - const c2 = color.rgb; - let w2; - const p = weight === w2 ? 0.5 : weight; - const w = 2 * p - 1; - const a = c1.a - c2.a; - const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - w2 = 1 - w1; - c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; - c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; - c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; - c1.a = p * c1.a + (1 - p) * c2.a; - me.rgb = c1; - } - return me; - } - clone() { - return new Color(this.rgb); - } - alpha(a) { - this._rgb.a = n2b(a); - return this; - } - clearer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 - ratio; - return this; - } - greyscale() { - const rgb = this._rgb; - const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); - rgb.r = rgb.g = rgb.b = val; - return this; - } - opaquer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 + ratio; - return this; - } - negate() { - const v = this._rgb; - v.r = 255 - v.r; - v.g = 255 - v.g; - v.b = 255 - v.b; - return this; - } - lighten(ratio) { - modHSL(this._rgb, 2, ratio); - return this; - } - darken(ratio) { - modHSL(this._rgb, 2, -ratio); - return this; - } - saturate(ratio) { - modHSL(this._rgb, 1, ratio); - return this; - } - desaturate(ratio) { - modHSL(this._rgb, 1, -ratio); - return this; - } - rotate(deg) { - rotate(this._rgb, deg); - return this; - } -} -function index_esm(input) { - return new Color(input); -} - -const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern; -function color(value) { - return isPatternOrGradient(value) ? value : index_esm(value); -} -function getHoverColor(value) { - return isPatternOrGradient(value) - ? value - : index_esm(value).saturate(0.5).darken(0.1).hexString(); -} - -function noop() {} -const uid = (function() { - let id = 0; - return function() { - return id++; - }; -}()); -function isNullOrUndef(value) { - return value === null || typeof value === 'undefined'; -} -function isArray(value) { - if (Array.isArray && Array.isArray(value)) { - return true; - } - const type = Object.prototype.toString.call(value); - if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { - return true; - } - return false; -} -function isObject(value) { - return value !== null && Object.prototype.toString.call(value) === '[object Object]'; -} -const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value); -function finiteOrDefault(value, defaultValue) { - return isNumberFinite(value) ? value : defaultValue; -} -function valueOrDefault(value, defaultValue) { - return typeof value === 'undefined' ? defaultValue : value; -} -const toPercentage = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 - : value / dimension; -const toDimension = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 * dimension - : +value; -function callback(fn, args, thisArg) { - if (fn && typeof fn.call === 'function') { - return fn.apply(thisArg, args); - } -} -function each(loopable, fn, thisArg, reverse) { - let i, len, keys; - if (isArray(loopable)) { - len = loopable.length; - if (reverse) { - for (i = len - 1; i >= 0; i--) { - fn.call(thisArg, loopable[i], i); - } - } else { - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[i], i); - } - } - } else if (isObject(loopable)) { - keys = Object.keys(loopable); - len = keys.length; - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[keys[i]], keys[i]); - } - } -} -function _elementsEqual(a0, a1) { - let i, ilen, v0, v1; - if (!a0 || !a1 || a0.length !== a1.length) { - return false; - } - for (i = 0, ilen = a0.length; i < ilen; ++i) { - v0 = a0[i]; - v1 = a1[i]; - if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { - return false; - } - } - return true; -} -function clone(source) { - if (isArray(source)) { - return source.map(clone); - } - if (isObject(source)) { - const target = Object.create(null); - const keys = Object.keys(source); - const klen = keys.length; - let k = 0; - for (; k < klen; ++k) { - target[keys[k]] = clone(source[keys[k]]); - } - return target; - } - return source; -} -function isValidKey(key) { - return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; -} -function _merger(key, target, source, options) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - merge(tval, sval, options); - } else { - target[key] = clone(sval); - } -} -function merge(target, source, options) { - const sources = isArray(source) ? source : [source]; - const ilen = sources.length; - if (!isObject(target)) { - return target; - } - options = options || {}; - const merger = options.merger || _merger; - for (let i = 0; i < ilen; ++i) { - source = sources[i]; - if (!isObject(source)) { - continue; - } - const keys = Object.keys(source); - for (let k = 0, klen = keys.length; k < klen; ++k) { - merger(keys[k], target, source, options); - } - } - return target; -} -function mergeIf(target, source) { - return merge(target, source, {merger: _mergerIf}); -} -function _mergerIf(key, target, source) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - mergeIf(tval, sval); - } else if (!Object.prototype.hasOwnProperty.call(target, key)) { - target[key] = clone(sval); - } -} -function _deprecated(scope, value, previous, current) { - if (value !== undefined) { - console.warn(scope + ': "' + previous + - '" is deprecated. Please use "' + current + '" instead'); - } -} -const emptyString = ''; -const dot = '.'; -function indexOfDotOrLength(key, start) { - const idx = key.indexOf(dot, start); - return idx === -1 ? key.length : idx; -} -function resolveObjectKey(obj, key) { - if (key === emptyString) { - return obj; - } - let pos = 0; - let idx = indexOfDotOrLength(key, pos); - while (obj && idx > pos) { - obj = obj[key.substr(pos, idx - pos)]; - pos = idx + 1; - idx = indexOfDotOrLength(key, pos); - } - return obj; -} -function _capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); -} -const defined = (value) => typeof value !== 'undefined'; -const isFunction = (value) => typeof value === 'function'; -const setsEqual = (a, b) => { - if (a.size !== b.size) { - return false; - } - for (const item of a) { - if (!b.has(item)) { - return false; - } - } - return true; -}; -function _isClickEvent(e) { - return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; -} - -const overrides = Object.create(null); -const descriptors = Object.create(null); -function getScope$1(node, key) { - if (!key) { - return node; - } - const keys = key.split('.'); - for (let i = 0, n = keys.length; i < n; ++i) { - const k = keys[i]; - node = node[k] || (node[k] = Object.create(null)); - } - return node; -} -function set(root, scope, values) { - if (typeof scope === 'string') { - return merge(getScope$1(root, scope), values); - } - return merge(getScope$1(root, ''), scope); -} -class Defaults { - constructor(_descriptors) { - this.animation = undefined; - this.backgroundColor = 'rgba(0,0,0,0.1)'; - this.borderColor = 'rgba(0,0,0,0.1)'; - this.color = '#666'; - this.datasets = {}; - this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); - this.elements = {}; - this.events = [ - 'mousemove', - 'mouseout', - 'click', - 'touchstart', - 'touchmove' - ]; - this.font = { - family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - size: 12, - style: 'normal', - lineHeight: 1.2, - weight: null - }; - this.hover = {}; - this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); - this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); - this.hoverColor = (ctx, options) => getHoverColor(options.color); - this.indexAxis = 'x'; - this.interaction = { - mode: 'nearest', - intersect: true - }; - this.maintainAspectRatio = true; - this.onHover = null; - this.onClick = null; - this.parsing = true; - this.plugins = {}; - this.responsive = true; - this.scale = undefined; - this.scales = {}; - this.showLine = true; - this.drawActiveElementsOnTop = true; - this.describe(_descriptors); - } - set(scope, values) { - return set(this, scope, values); - } - get(scope) { - return getScope$1(this, scope); - } - describe(scope, values) { - return set(descriptors, scope, values); - } - override(scope, values) { - return set(overrides, scope, values); - } - route(scope, name, targetScope, targetName) { - const scopeObject = getScope$1(this, scope); - const targetScopeObject = getScope$1(this, targetScope); - const privateName = '_' + name; - Object.defineProperties(scopeObject, { - [privateName]: { - value: scopeObject[name], - writable: true - }, - [name]: { - enumerable: true, - get() { - const local = this[privateName]; - const target = targetScopeObject[targetName]; - if (isObject(local)) { - return Object.assign({}, target, local); - } - return valueOrDefault(local, target); - }, - set(value) { - this[privateName] = value; - } - } - }); - } -} -var defaults = new Defaults({ - _scriptable: (name) => !name.startsWith('on'), - _indexable: (name) => name !== 'events', - hover: { - _fallback: 'interaction' - }, - interaction: { - _scriptable: false, - _indexable: false, - } -}); - -const PI = Math.PI; -const TAU = 2 * PI; -const PITAU = TAU + PI; -const INFINITY = Number.POSITIVE_INFINITY; -const RAD_PER_DEG = PI / 180; -const HALF_PI = PI / 2; -const QUARTER_PI = PI / 4; -const TWO_THIRDS_PI = PI * 2 / 3; -const log10 = Math.log10; -const sign = Math.sign; -function niceNum(range) { - const roundedRange = Math.round(range); - range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; - const niceRange = Math.pow(10, Math.floor(log10(range))); - const fraction = range / niceRange; - const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; - return niceFraction * niceRange; -} -function _factorize(value) { - const result = []; - const sqrt = Math.sqrt(value); - let i; - for (i = 1; i < sqrt; i++) { - if (value % i === 0) { - result.push(i); - result.push(value / i); - } - } - if (sqrt === (sqrt | 0)) { - result.push(sqrt); - } - result.sort((a, b) => a - b).pop(); - return result; -} -function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); -} -function almostEquals(x, y, epsilon) { - return Math.abs(x - y) < epsilon; -} -function almostWhole(x, epsilon) { - const rounded = Math.round(x); - return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x); -} -function _setMinAndMaxByKey(array, target, property) { - let i, ilen, value; - for (i = 0, ilen = array.length; i < ilen; i++) { - value = array[i][property]; - if (!isNaN(value)) { - target.min = Math.min(target.min, value); - target.max = Math.max(target.max, value); - } - } -} -function toRadians(degrees) { - return degrees * (PI / 180); -} -function toDegrees(radians) { - return radians * (180 / PI); -} -function _decimalPlaces(x) { - if (!isNumberFinite(x)) { - return; - } - let e = 1; - let p = 0; - while (Math.round(x * e) / e !== x) { - e *= 10; - p++; - } - return p; -} -function getAngleFromPoint(centrePoint, anglePoint) { - const distanceFromXCenter = anglePoint.x - centrePoint.x; - const distanceFromYCenter = anglePoint.y - centrePoint.y; - const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); - let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); - if (angle < (-0.5 * PI)) { - angle += TAU; - } - return { - angle, - distance: radialDistanceFromCenter - }; -} -function distanceBetweenPoints(pt1, pt2) { - return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); -} -function _angleDiff(a, b) { - return (a - b + PITAU) % TAU - PI; -} -function _normalizeAngle(a) { - return (a % TAU + TAU) % TAU; -} -function _angleBetween(angle, start, end, sameAngleIsFullCircle) { - const a = _normalizeAngle(angle); - const s = _normalizeAngle(start); - const e = _normalizeAngle(end); - const angleToStart = _normalizeAngle(s - a); - const angleToEnd = _normalizeAngle(e - a); - const startToAngle = _normalizeAngle(a - s); - const endToAngle = _normalizeAngle(a - e); - return a === s || a === e || (sameAngleIsFullCircle && s === e) - || (angleToStart > angleToEnd && startToAngle < endToAngle); -} -function _limitValue(value, min, max) { - return Math.max(min, Math.min(max, value)); -} -function _int16Range(value) { - return _limitValue(value, -32768, 32767); -} -function _isBetween(value, start, end, epsilon = 1e-6) { - return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; -} - -function toFontString(font) { - if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { - return null; - } - return (font.style ? font.style + ' ' : '') - + (font.weight ? font.weight + ' ' : '') - + font.size + 'px ' - + font.family; -} -function _measureText(ctx, data, gc, longest, string) { - let textWidth = data[string]; - if (!textWidth) { - textWidth = data[string] = ctx.measureText(string).width; - gc.push(string); - } - if (textWidth > longest) { - longest = textWidth; - } - return longest; -} -function _longestText(ctx, font, arrayOfThings, cache) { - cache = cache || {}; - let data = cache.data = cache.data || {}; - let gc = cache.garbageCollect = cache.garbageCollect || []; - if (cache.font !== font) { - data = cache.data = {}; - gc = cache.garbageCollect = []; - cache.font = font; - } - ctx.save(); - ctx.font = font; - let longest = 0; - const ilen = arrayOfThings.length; - let i, j, jlen, thing, nestedThing; - for (i = 0; i < ilen; i++) { - thing = arrayOfThings[i]; - if (thing !== undefined && thing !== null && isArray(thing) !== true) { - longest = _measureText(ctx, data, gc, longest, thing); - } else if (isArray(thing)) { - for (j = 0, jlen = thing.length; j < jlen; j++) { - nestedThing = thing[j]; - if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { - longest = _measureText(ctx, data, gc, longest, nestedThing); - } - } - } - } - ctx.restore(); - const gcLen = gc.length / 2; - if (gcLen > arrayOfThings.length) { - for (i = 0; i < gcLen; i++) { - delete data[gc[i]]; - } - gc.splice(0, gcLen); - } - return longest; -} -function _alignPixel(chart, pixel, width) { - const devicePixelRatio = chart.currentDevicePixelRatio; - const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; - return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; -} -function clearCanvas(canvas, ctx) { - ctx = ctx || canvas.getContext('2d'); - ctx.save(); - ctx.resetTransform(); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.restore(); -} -function drawPoint(ctx, options, x, y) { - let type, xOffset, yOffset, size, cornerRadius; - const style = options.pointStyle; - const rotation = options.rotation; - const radius = options.radius; - let rad = (rotation || 0) * RAD_PER_DEG; - if (style && typeof style === 'object') { - type = style.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.save(); - ctx.translate(x, y); - ctx.rotate(rad); - ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); - ctx.restore(); - return; - } - } - if (isNaN(radius) || radius <= 0) { - return; - } - ctx.beginPath(); - switch (style) { - default: - ctx.arc(x, y, radius, 0, TAU); - ctx.closePath(); - break; - case 'triangle': - ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - ctx.closePath(); - break; - case 'rectRounded': - cornerRadius = radius * 0.516; - size = radius - cornerRadius; - xOffset = Math.cos(rad + QUARTER_PI) * size; - yOffset = Math.sin(rad + QUARTER_PI) * size; - ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); - ctx.closePath(); - break; - case 'rect': - if (!rotation) { - size = Math.SQRT1_2 * radius; - ctx.rect(x - size, y - size, 2 * size, 2 * size); - break; - } - rad += QUARTER_PI; - case 'rectRot': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + yOffset, y - xOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.lineTo(x - yOffset, y + xOffset); - ctx.closePath(); - break; - case 'crossRot': - rad += QUARTER_PI; - case 'cross': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'star': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - rad += QUARTER_PI; - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'line': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - break; - case 'dash': - ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); - break; - } - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } -} -function _isPointInArea(point, area, margin) { - margin = margin || 0.5; - return !area || (point && point.x > area.left - margin && point.x < area.right + margin && - point.y > area.top - margin && point.y < area.bottom + margin); -} -function clipArea(ctx, area) { - ctx.save(); - ctx.beginPath(); - ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); - ctx.clip(); -} -function unclipArea(ctx) { - ctx.restore(); -} -function _steppedLineTo(ctx, previous, target, flip, mode) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - if (mode === 'middle') { - const midpoint = (previous.x + target.x) / 2.0; - ctx.lineTo(midpoint, previous.y); - ctx.lineTo(midpoint, target.y); - } else if (mode === 'after' !== !!flip) { - ctx.lineTo(previous.x, target.y); - } else { - ctx.lineTo(target.x, previous.y); - } - ctx.lineTo(target.x, target.y); -} -function _bezierCurveTo(ctx, previous, target, flip) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - ctx.bezierCurveTo( - flip ? previous.cp1x : previous.cp2x, - flip ? previous.cp1y : previous.cp2y, - flip ? target.cp2x : target.cp1x, - flip ? target.cp2y : target.cp1y, - target.x, - target.y); -} -function renderText(ctx, text, x, y, font, opts = {}) { - const lines = isArray(text) ? text : [text]; - const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; - let i, line; - ctx.save(); - ctx.font = font.string; - setRenderOpts(ctx, opts); - for (i = 0; i < lines.length; ++i) { - line = lines[i]; - if (stroke) { - if (opts.strokeColor) { - ctx.strokeStyle = opts.strokeColor; - } - if (!isNullOrUndef(opts.strokeWidth)) { - ctx.lineWidth = opts.strokeWidth; - } - ctx.strokeText(line, x, y, opts.maxWidth); - } - ctx.fillText(line, x, y, opts.maxWidth); - decorateText(ctx, x, y, line, opts); - y += font.lineHeight; - } - ctx.restore(); -} -function setRenderOpts(ctx, opts) { - if (opts.translation) { - ctx.translate(opts.translation[0], opts.translation[1]); - } - if (!isNullOrUndef(opts.rotation)) { - ctx.rotate(opts.rotation); - } - if (opts.color) { - ctx.fillStyle = opts.color; - } - if (opts.textAlign) { - ctx.textAlign = opts.textAlign; - } - if (opts.textBaseline) { - ctx.textBaseline = opts.textBaseline; - } -} -function decorateText(ctx, x, y, line, opts) { - if (opts.strikethrough || opts.underline) { - const metrics = ctx.measureText(line); - const left = x - metrics.actualBoundingBoxLeft; - const right = x + metrics.actualBoundingBoxRight; - const top = y - metrics.actualBoundingBoxAscent; - const bottom = y + metrics.actualBoundingBoxDescent; - const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; - ctx.strokeStyle = ctx.fillStyle; - ctx.beginPath(); - ctx.lineWidth = opts.decorationWidth || 2; - ctx.moveTo(left, yDecoration); - ctx.lineTo(right, yDecoration); - ctx.stroke(); - } -} -function addRoundedRectPath(ctx, rect) { - const {x, y, w, h, radius} = rect; - ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true); - ctx.lineTo(x, y + h - radius.bottomLeft); - ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); - ctx.lineTo(x + w - radius.bottomRight, y + h); - ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); - ctx.lineTo(x + w, y + radius.topRight); - ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); - ctx.lineTo(x + radius.topLeft, y); -} - -function _lookup(table, value, cmp) { - cmp = cmp || ((index) => table[index] < value); - let hi = table.length - 1; - let lo = 0; - let mid; - while (hi - lo > 1) { - mid = (lo + hi) >> 1; - if (cmp(mid)) { - lo = mid; - } else { - hi = mid; - } - } - return {lo, hi}; -} -const _lookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] < value); -const _rlookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] >= value); -function _filterBetween(values, min, max) { - let start = 0; - let end = values.length; - while (start < end && values[start] < min) { - start++; - } - while (end > start && values[end - 1] > max) { - end--; - } - return start > 0 || end < values.length - ? values.slice(start, end) - : values; -} -const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; -function listenArrayEvents(array, listener) { - if (array._chartjs) { - array._chartjs.listeners.push(listener); - return; - } - Object.defineProperty(array, '_chartjs', { - configurable: true, - enumerable: false, - value: { - listeners: [listener] - } - }); - arrayEvents.forEach((key) => { - const method = '_onData' + _capitalize(key); - const base = array[key]; - Object.defineProperty(array, key, { - configurable: true, - enumerable: false, - value(...args) { - const res = base.apply(this, args); - array._chartjs.listeners.forEach((object) => { - if (typeof object[method] === 'function') { - object[method](...args); - } - }); - return res; - } - }); - }); -} -function unlistenArrayEvents(array, listener) { - const stub = array._chartjs; - if (!stub) { - return; - } - const listeners = stub.listeners; - const index = listeners.indexOf(listener); - if (index !== -1) { - listeners.splice(index, 1); - } - if (listeners.length > 0) { - return; - } - arrayEvents.forEach((key) => { - delete array[key]; - }); - delete array._chartjs; -} -function _arrayUnique(items) { - const set = new Set(); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - set.add(items[i]); - } - if (set.size === ilen) { - return items; - } - return Array.from(set); -} - -function _isDomSupported() { - return typeof window !== 'undefined' && typeof document !== 'undefined'; -} -function _getParentNode(domNode) { - let parent = domNode.parentNode; - if (parent && parent.toString() === '[object ShadowRoot]') { - parent = parent.host; - } - return parent; -} -function parseMaxStyle(styleValue, node, parentProperty) { - let valueInPixels; - if (typeof styleValue === 'string') { - valueInPixels = parseInt(styleValue, 10); - if (styleValue.indexOf('%') !== -1) { - valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; - } - } else { - valueInPixels = styleValue; - } - return valueInPixels; -} -const getComputedStyle = (element) => window.getComputedStyle(element, null); -function getStyle(el, property) { - return getComputedStyle(el).getPropertyValue(property); -} -const positions = ['top', 'right', 'bottom', 'left']; -function getPositionedStyle(styles, style, suffix) { - const result = {}; - suffix = suffix ? '-' + suffix : ''; - for (let i = 0; i < 4; i++) { - const pos = positions[i]; - result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; - } - result.width = result.left + result.right; - result.height = result.top + result.bottom; - return result; -} -const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot); -function getCanvasPosition(evt, canvas) { - const e = evt.native || evt; - const touches = e.touches; - const source = touches && touches.length ? touches[0] : e; - const {offsetX, offsetY} = source; - let box = false; - let x, y; - if (useOffsetPos(offsetX, offsetY, e.target)) { - x = offsetX; - y = offsetY; - } else { - const rect = canvas.getBoundingClientRect(); - x = source.clientX - rect.left; - y = source.clientY - rect.top; - box = true; - } - return {x, y, box}; -} -function getRelativePosition$1(evt, chart) { - const {canvas, currentDevicePixelRatio} = chart; - const style = getComputedStyle(canvas); - const borderBox = style.boxSizing === 'border-box'; - const paddings = getPositionedStyle(style, 'padding'); - const borders = getPositionedStyle(style, 'border', 'width'); - const {x, y, box} = getCanvasPosition(evt, canvas); - const xOffset = paddings.left + (box && borders.left); - const yOffset = paddings.top + (box && borders.top); - let {width, height} = chart; - if (borderBox) { - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - return { - x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), - y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) - }; -} -function getContainerSize(canvas, width, height) { - let maxWidth, maxHeight; - if (width === undefined || height === undefined) { - const container = _getParentNode(canvas); - if (!container) { - width = canvas.clientWidth; - height = canvas.clientHeight; - } else { - const rect = container.getBoundingClientRect(); - const containerStyle = getComputedStyle(container); - const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); - const containerPadding = getPositionedStyle(containerStyle, 'padding'); - width = rect.width - containerPadding.width - containerBorder.width; - height = rect.height - containerPadding.height - containerBorder.height; - maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); - maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); - } - } - return { - width, - height, - maxWidth: maxWidth || INFINITY, - maxHeight: maxHeight || INFINITY - }; -} -const round1 = v => Math.round(v * 10) / 10; -function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { - const style = getComputedStyle(canvas); - const margins = getPositionedStyle(style, 'margin'); - const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; - const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; - const containerSize = getContainerSize(canvas, bbWidth, bbHeight); - let {width, height} = containerSize; - if (style.boxSizing === 'content-box') { - const borders = getPositionedStyle(style, 'border', 'width'); - const paddings = getPositionedStyle(style, 'padding'); - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - width = Math.max(0, width - margins.width); - height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); - width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); - height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); - if (width && !height) { - height = round1(width / 2); - } - return { - width, - height - }; -} -function retinaScale(chart, forceRatio, forceStyle) { - const pixelRatio = forceRatio || 1; - const deviceHeight = Math.floor(chart.height * pixelRatio); - const deviceWidth = Math.floor(chart.width * pixelRatio); - chart.height = deviceHeight / pixelRatio; - chart.width = deviceWidth / pixelRatio; - const canvas = chart.canvas; - if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) { - canvas.style.height = `${chart.height}px`; - canvas.style.width = `${chart.width}px`; - } - if (chart.currentDevicePixelRatio !== pixelRatio - || canvas.height !== deviceHeight - || canvas.width !== deviceWidth) { - chart.currentDevicePixelRatio = pixelRatio; - canvas.height = deviceHeight; - canvas.width = deviceWidth; - chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - return true; - } - return false; -} -const supportsEventListenerOptions = (function() { - let passiveSupported = false; - try { - const options = { - get passive() { - passiveSupported = true; - return false; - } - }; - window.addEventListener('test', null, options); - window.removeEventListener('test', null, options); - } catch (e) { - } - return passiveSupported; -}()); -function readUsedSize(element, property) { - const value = getStyle(element, property); - const matches = value && value.match(/^(\d+)(\.\d+)?px$/); - return matches ? +matches[1] : undefined; -} - -function getRelativePosition(e, chart) { - if ('native' in e) { - return { - x: e.x, - y: e.y - }; - } - return getRelativePosition$1(e, chart); -} -function evaluateAllVisibleItems(chart, handler) { - const metasets = chart.getSortedVisibleDatasetMetas(); - let index, data, element; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - ({index, data} = metasets[i]); - for (let j = 0, jlen = data.length; j < jlen; ++j) { - element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function binarySearch(metaset, axis, value, intersect) { - const {controller, data, _sorted} = metaset; - const iScale = controller._cachedMeta.iScale; - if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { - const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; - if (!intersect) { - return lookupMethod(data, axis, value); - } else if (controller._sharedOptions) { - const el = data[0]; - const range = typeof el.getRange === 'function' && el.getRange(axis); - if (range) { - const start = lookupMethod(data, axis, value - range); - const end = lookupMethod(data, axis, value + range); - return {lo: start.lo, hi: end.hi}; - } - } - } - return {lo: 0, hi: data.length - 1}; -} -function optimizedEvaluateItems(chart, axis, position, handler, intersect) { - const metasets = chart.getSortedVisibleDatasetMetas(); - const value = position[axis]; - for (let i = 0, ilen = metasets.length; i < ilen; ++i) { - const {index, data} = metasets[i]; - const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); - for (let j = lo; j <= hi; ++j) { - const element = data[j]; - if (!element.skip) { - handler(element, index, j); - } - } - } -} -function getDistanceMetricForAxis(axis) { - const useX = axis.indexOf('x') !== -1; - const useY = axis.indexOf('y') !== -1; - return function(pt1, pt2) { - const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; - const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; - return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); - }; -} -function getIntersectItems(chart, position, axis, useFinalPosition) { - const items = []; - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return items; - } - const evaluationFunc = function(element, datasetIndex, index) { - if (element.inRange(position.x, position.y, useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - }; - optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); - return items; -} -function getNearestRadialItems(chart, position, axis, useFinalPosition) { - let items = []; - function evaluationFunc(element, datasetIndex, index) { - const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition); - const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y}); - if (_angleBetween(angle, startAngle, endAngle)) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) { - let items = []; - const distanceMetric = getDistanceMetricForAxis(axis); - let minDistance = Number.POSITIVE_INFINITY; - function evaluationFunc(element, datasetIndex, index) { - const inRange = element.inRange(position.x, position.y, useFinalPosition); - if (intersect && !inRange) { - return; - } - const center = element.getCenterPoint(useFinalPosition); - const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding); - if (!pointInArea && !inRange) { - return; - } - const distance = distanceMetric(position, center); - if (distance < minDistance) { - items = [{element, datasetIndex, index}]; - minDistance = distance; - } else if (distance === minDistance) { - items.push({element, datasetIndex, index}); - } - } - optimizedEvaluateItems(chart, axis, position, evaluationFunc); - return items; -} -function getNearestItems(chart, position, axis, intersect, useFinalPosition) { - if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) { - return []; - } - return axis === 'r' && !intersect - ? getNearestRadialItems(chart, position, axis, useFinalPosition) - : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition); -} -function getAxisItems(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const items = []; - const axis = options.axis; - const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; - let intersectsItem = false; - evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { - if (element[rangeMethod](position[axis], useFinalPosition)) { - items.push({element, datasetIndex, index}); - } - if (element.inRange(position.x, position.y, useFinalPosition)) { - intersectsItem = true; - } - }); - if (options.intersect && !intersectsItem) { - return []; - } - return items; -} -var Interaction = { - modes: { - index(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'x'; - const items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) - : getNearestItems(chart, position, axis, false, useFinalPosition); - const elements = []; - if (!items.length) { - return []; - } - chart.getSortedVisibleDatasetMetas().forEach((meta) => { - const index = items[0].index; - const element = meta.data[index]; - if (element && !element.skip) { - elements.push({element, datasetIndex: meta.index, index}); - } - }); - return elements; - }, - dataset(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - let items = options.intersect - ? getIntersectItems(chart, position, axis, useFinalPosition) : - getNearestItems(chart, position, axis, false, useFinalPosition); - if (items.length > 0) { - const datasetIndex = items[0].datasetIndex; - const data = chart.getDatasetMeta(datasetIndex).data; - items = []; - for (let i = 0; i < data.length; ++i) { - items.push({element: data[i], datasetIndex, index: i}); - } - } - return items; - }, - point(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getIntersectItems(chart, position, axis, useFinalPosition); - }, - nearest(chart, e, options, useFinalPosition) { - const position = getRelativePosition(e, chart); - const axis = options.axis || 'xy'; - return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); - }, - x(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition); - }, - y(chart, e, options, useFinalPosition) { - return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition); - } - } -}; - -const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); -const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/); -function toLineHeight(value, size) { - const matches = ('' + value).match(LINE_HEIGHT); - if (!matches || matches[1] === 'normal') { - return size * 1.2; - } - value = +matches[2]; - switch (matches[3]) { - case 'px': - return value; - case '%': - value /= 100; - break; - } - return size * value; -} -const numberOrZero = v => +v || 0; -function _readValueToProps(value, props) { - const ret = {}; - const objProps = isObject(props); - const keys = objProps ? Object.keys(props) : props; - const read = isObject(value) - ? objProps - ? prop => valueOrDefault(value[prop], value[props[prop]]) - : prop => value[prop] - : () => value; - for (const prop of keys) { - ret[prop] = numberOrZero(read(prop)); - } - return ret; -} -function toTRBL(value) { - return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'}); -} -function toTRBLCorners(value) { - return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']); -} -function toPadding(value) { - const obj = toTRBL(value); - obj.width = obj.left + obj.right; - obj.height = obj.top + obj.bottom; - return obj; -} -function toFont(options, fallback) { - options = options || {}; - fallback = fallback || defaults.font; - let size = valueOrDefault(options.size, fallback.size); - if (typeof size === 'string') { - size = parseInt(size, 10); - } - let style = valueOrDefault(options.style, fallback.style); - if (style && !('' + style).match(FONT_STYLE)) { - console.warn('Invalid font style specified: "' + style + '"'); - style = ''; - } - const font = { - family: valueOrDefault(options.family, fallback.family), - lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), - size, - style, - weight: valueOrDefault(options.weight, fallback.weight), - string: '' - }; - font.string = toFontString(font); - return font; -} -function resolve(inputs, context, index, info) { - let cacheable = true; - let i, ilen, value; - for (i = 0, ilen = inputs.length; i < ilen; ++i) { - value = inputs[i]; - if (value === undefined) { - continue; - } - if (context !== undefined && typeof value === 'function') { - value = value(context); - cacheable = false; - } - if (index !== undefined && isArray(value)) { - value = value[index % value.length]; - cacheable = false; - } - if (value !== undefined) { - if (info && !cacheable) { - info.cacheable = false; - } - return value; - } - } -} -function _addGrace(minmax, grace, beginAtZero) { - const {min, max} = minmax; - const change = toDimension(grace, (max - min) / 2); - const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; - return { - min: keepZero(min, -Math.abs(change)), - max: keepZero(max, change) - }; -} -function createContext(parentContext, context) { - return Object.assign(Object.create(parentContext), context); -} - -const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; -function filterByPosition(array, position) { - return array.filter(v => v.pos === position); -} -function filterDynamicPositionByAxis(array, axis) { - return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); -} -function sortByWeight(array, reverse) { - return array.sort((a, b) => { - const v0 = reverse ? b : a; - const v1 = reverse ? a : b; - return v0.weight === v1.weight ? - v0.index - v1.index : - v0.weight - v1.weight; - }); -} -function wrapBoxes(boxes) { - const layoutBoxes = []; - let i, ilen, box, pos, stack, stackWeight; - for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { - box = boxes[i]; - ({position: pos, options: {stack, stackWeight = 1}} = box); - layoutBoxes.push({ - index: i, - box, - pos, - horizontal: box.isHorizontal(), - weight: box.weight, - stack: stack && (pos + stack), - stackWeight - }); - } - return layoutBoxes; -} -function buildStacks(layouts) { - const stacks = {}; - for (const wrap of layouts) { - const {stack, pos, stackWeight} = wrap; - if (!stack || !STATIC_POSITIONS.includes(pos)) { - continue; - } - const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0}); - _stack.count++; - _stack.weight += stackWeight; - } - return stacks; -} -function setLayoutDims(layouts, params) { - const stacks = buildStacks(layouts); - const {vBoxMaxWidth, hBoxMaxHeight} = params; - let i, ilen, layout; - for (i = 0, ilen = layouts.length; i < ilen; ++i) { - layout = layouts[i]; - const {fullSize} = layout.box; - const stack = stacks[layout.stack]; - const factor = stack && layout.stackWeight / stack.weight; - if (layout.horizontal) { - layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; - layout.height = hBoxMaxHeight; - } else { - layout.width = vBoxMaxWidth; - layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; - } - } - return stacks; -} -function buildLayoutBoxes(boxes) { - const layoutBoxes = wrapBoxes(boxes); - const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true); - const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); - const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); - const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); - const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); - const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); - const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); - return { - fullSize, - leftAndTop: left.concat(top), - rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), - chartArea: filterByPosition(layoutBoxes, 'chartArea'), - vertical: left.concat(right).concat(centerVertical), - horizontal: top.concat(bottom).concat(centerHorizontal) - }; -} -function getCombinedMax(maxPadding, chartArea, a, b) { - return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); -} -function updateMaxPadding(maxPadding, boxPadding) { - maxPadding.top = Math.max(maxPadding.top, boxPadding.top); - maxPadding.left = Math.max(maxPadding.left, boxPadding.left); - maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); - maxPadding.right = Math.max(maxPadding.right, boxPadding.right); -} -function updateDims(chartArea, params, layout, stacks) { - const {pos, box} = layout; - const maxPadding = chartArea.maxPadding; - if (!isObject(pos)) { - if (layout.size) { - chartArea[pos] -= layout.size; - } - const stack = stacks[layout.stack] || {size: 0, count: 1}; - stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); - layout.size = stack.size / stack.count; - chartArea[pos] += layout.size; - } - if (box.getPadding) { - updateMaxPadding(maxPadding, box.getPadding()); - } - const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); - const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); - const widthChanged = newWidth !== chartArea.w; - const heightChanged = newHeight !== chartArea.h; - chartArea.w = newWidth; - chartArea.h = newHeight; - return layout.horizontal - ? {same: widthChanged, other: heightChanged} - : {same: heightChanged, other: widthChanged}; -} -function handleMaxPadding(chartArea) { - const maxPadding = chartArea.maxPadding; - function updatePos(pos) { - const change = Math.max(maxPadding[pos] - chartArea[pos], 0); - chartArea[pos] += change; - return change; - } - chartArea.y += updatePos('top'); - chartArea.x += updatePos('left'); - updatePos('right'); - updatePos('bottom'); -} -function getMargins(horizontal, chartArea) { - const maxPadding = chartArea.maxPadding; - function marginForPositions(positions) { - const margin = {left: 0, top: 0, right: 0, bottom: 0}; - positions.forEach((pos) => { - margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); - }); - return margin; - } - return horizontal - ? marginForPositions(['left', 'right']) - : marginForPositions(['top', 'bottom']); -} -function fitBoxes(boxes, chartArea, params, stacks) { - const refitBoxes = []; - let i, ilen, layout, box, refit, changed; - for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) { - layout = boxes[i]; - box = layout.box; - box.update( - layout.width || chartArea.w, - layout.height || chartArea.h, - getMargins(layout.horizontal, chartArea) - ); - const {same, other} = updateDims(chartArea, params, layout, stacks); - refit |= same && refitBoxes.length; - changed = changed || other; - if (!box.fullSize) { - refitBoxes.push(layout); - } - } - return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; -} -function setBoxDims(box, left, top, width, height) { - box.top = top; - box.left = left; - box.right = left + width; - box.bottom = top + height; - box.width = width; - box.height = height; -} -function placeBoxes(boxes, chartArea, params, stacks) { - const userPadding = params.padding; - let {x, y} = chartArea; - for (const layout of boxes) { - const box = layout.box; - const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1}; - const weight = (layout.stackWeight / stack.weight) || 1; - if (layout.horizontal) { - const width = chartArea.w * weight; - const height = stack.size || box.height; - if (defined(stack.start)) { - y = stack.start; - } - if (box.fullSize) { - setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); - } else { - setBoxDims(box, chartArea.left + stack.placed, y, width, height); - } - stack.start = y; - stack.placed += width; - y = box.bottom; - } else { - const height = chartArea.h * weight; - const width = stack.size || box.width; - if (defined(stack.start)) { - x = stack.start; - } - if (box.fullSize) { - setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); - } else { - setBoxDims(box, x, chartArea.top + stack.placed, width, height); - } - stack.start = x; - stack.placed += height; - x = box.right; - } - } - chartArea.x = x; - chartArea.y = y; -} -defaults.set('layout', { - autoPadding: true, - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } -}); -var layouts = { - addBox(chart, item) { - if (!chart.boxes) { - chart.boxes = []; - } - item.fullSize = item.fullSize || false; - item.position = item.position || 'top'; - item.weight = item.weight || 0; - item._layers = item._layers || function() { - return [{ - z: 0, - draw(chartArea) { - item.draw(chartArea); - } - }]; - }; - chart.boxes.push(item); - }, - removeBox(chart, layoutItem) { - const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; - if (index !== -1) { - chart.boxes.splice(index, 1); - } - }, - configure(chart, item, options) { - item.fullSize = options.fullSize; - item.position = options.position; - item.weight = options.weight; - }, - update(chart, width, height, minPadding) { - if (!chart) { - return; - } - const padding = toPadding(chart.options.layout.padding); - const availableWidth = Math.max(width - padding.width, 0); - const availableHeight = Math.max(height - padding.height, 0); - const boxes = buildLayoutBoxes(chart.boxes); - const verticalBoxes = boxes.vertical; - const horizontalBoxes = boxes.horizontal; - each(chart.boxes, box => { - if (typeof box.beforeLayout === 'function') { - box.beforeLayout(); - } - }); - const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => - wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; - const params = Object.freeze({ - outerWidth: width, - outerHeight: height, - padding, - availableWidth, - availableHeight, - vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, - hBoxMaxHeight: availableHeight / 2 - }); - const maxPadding = Object.assign({}, padding); - updateMaxPadding(maxPadding, toPadding(minPadding)); - const chartArea = Object.assign({ - maxPadding, - w: availableWidth, - h: availableHeight, - x: padding.left, - y: padding.top - }, padding); - const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); - fitBoxes(boxes.fullSize, chartArea, params, stacks); - fitBoxes(verticalBoxes, chartArea, params, stacks); - if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { - fitBoxes(verticalBoxes, chartArea, params, stacks); - } - handleMaxPadding(chartArea); - placeBoxes(boxes.leftAndTop, chartArea, params, stacks); - chartArea.x += chartArea.w; - chartArea.y += chartArea.h; - placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); - chart.chartArea = { - left: chartArea.left, - top: chartArea.top, - right: chartArea.left + chartArea.w, - bottom: chartArea.top + chartArea.h, - height: chartArea.h, - width: chartArea.w, - }; - each(boxes.chartArea, (layout) => { - const box = layout.box; - Object.assign(box, chart.chartArea); - box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0}); - }); - } -}; - -function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) { - if (!defined(fallback)) { - fallback = _resolve('_fallback', scopes); - } - const cache = { - [Symbol.toStringTag]: 'Object', - _cacheable: true, - _scopes: scopes, - _rootScopes: rootScopes, - _fallback: fallback, - _getTarget: getTarget, - override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback), - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete target._keys; - delete scopes[0][prop]; - return true; - }, - get(target, prop) { - return _cached(target, prop, - () => _resolveWithPrefixes(prop, prefixes, scopes, target)); - }, - getOwnPropertyDescriptor(target, prop) { - return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(scopes[0]); - }, - has(target, prop) { - return getKeysFromAllScopes(target).includes(prop); - }, - ownKeys(target) { - return getKeysFromAllScopes(target); - }, - set(target, prop, value) { - const storage = target._storage || (target._storage = getTarget()); - target[prop] = storage[prop] = value; - delete target._keys; - return true; - } - }); -} -function _attachContext(proxy, context, subProxy, descriptorDefaults) { - const cache = { - _cacheable: false, - _proxy: proxy, - _context: context, - _subProxy: subProxy, - _stack: new Set(), - _descriptors: _descriptors(proxy, descriptorDefaults), - setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults), - override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete proxy[prop]; - return true; - }, - get(target, prop, receiver) { - return _cached(target, prop, - () => _resolveWithContext(target, prop, receiver)); - }, - getOwnPropertyDescriptor(target, prop) { - return target._descriptors.allKeys - ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined - : Reflect.getOwnPropertyDescriptor(proxy, prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(proxy); - }, - has(target, prop) { - return Reflect.has(proxy, prop); - }, - ownKeys() { - return Reflect.ownKeys(proxy); - }, - set(target, prop, value) { - proxy[prop] = value; - delete target[prop]; - return true; - } - }); -} -function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) { - const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy; - return { - allKeys: _allKeys, - scriptable: _scriptable, - indexable: _indexable, - isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable, - isIndexable: isFunction(_indexable) ? _indexable : () => _indexable - }; -} -const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name; -const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' && - (Object.getPrototypeOf(value) === null || value.constructor === Object); -function _cached(target, prop, resolve) { - if (Object.prototype.hasOwnProperty.call(target, prop)) { - return target[prop]; - } - const value = resolve(); - target[prop] = value; - return value; -} -function _resolveWithContext(target, prop, receiver) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - let value = _proxy[prop]; - if (isFunction(value) && descriptors.isScriptable(prop)) { - value = _resolveScriptable(prop, value, target, receiver); - } - if (isArray(value) && value.length) { - value = _resolveArray(prop, value, target, descriptors.isIndexable); - } - if (needsSubResolver(prop, value)) { - value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); - } - return value; -} -function _resolveScriptable(prop, value, target, receiver) { - const {_proxy, _context, _subProxy, _stack} = target; - if (_stack.has(prop)) { - throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); - } - _stack.add(prop); - value = value(_context, _subProxy || receiver); - _stack.delete(prop); - if (needsSubResolver(prop, value)) { - value = createSubResolver(_proxy._scopes, _proxy, prop, value); - } - return value; -} -function _resolveArray(prop, value, target, isIndexable) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - if (defined(_context.index) && isIndexable(prop)) { - value = value[_context.index % value.length]; - } else if (isObject(value[0])) { - const arr = value; - const scopes = _proxy._scopes.filter(s => s !== arr); - value = []; - for (const item of arr) { - const resolver = createSubResolver(scopes, _proxy, prop, item); - value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); - } - } - return value; -} -function resolveFallback(fallback, prop, value) { - return isFunction(fallback) ? fallback(prop, value) : fallback; -} -const getScope = (key, parent) => key === true ? parent - : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; -function addScopes(set, parentScopes, key, parentFallback, value) { - for (const parent of parentScopes) { - const scope = getScope(key, parent); - if (scope) { - set.add(scope); - const fallback = resolveFallback(scope._fallback, key, value); - if (defined(fallback) && fallback !== key && fallback !== parentFallback) { - return fallback; - } - } else if (scope === false && defined(parentFallback) && key !== parentFallback) { - return null; - } - } - return false; -} -function createSubResolver(parentScopes, resolver, prop, value) { - const rootScopes = resolver._rootScopes; - const fallback = resolveFallback(resolver._fallback, prop, value); - const allScopes = [...parentScopes, ...rootScopes]; - const set = new Set(); - set.add(value); - let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); - if (key === null) { - return false; - } - if (defined(fallback) && fallback !== prop) { - key = addScopesFromKey(set, allScopes, fallback, key, value); - if (key === null) { - return false; - } - } - return _createResolver(Array.from(set), [''], rootScopes, fallback, - () => subGetTarget(resolver, prop, value)); -} -function addScopesFromKey(set, allScopes, key, fallback, item) { - while (key) { - key = addScopes(set, allScopes, key, fallback, item); - } - return key; -} -function subGetTarget(resolver, prop, value) { - const parent = resolver._getTarget(); - if (!(prop in parent)) { - parent[prop] = {}; - } - const target = parent[prop]; - if (isArray(target) && isObject(value)) { - return value; - } - return target; -} -function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { - let value; - for (const prefix of prefixes) { - value = _resolve(readKey(prefix, prop), scopes); - if (defined(value)) { - return needsSubResolver(prop, value) - ? createSubResolver(scopes, proxy, prop, value) - : value; - } - } -} -function _resolve(key, scopes) { - for (const scope of scopes) { - if (!scope) { - continue; - } - const value = scope[key]; - if (defined(value)) { - return value; - } - } -} -function getKeysFromAllScopes(target) { - let keys = target._keys; - if (!keys) { - keys = target._keys = resolveKeysFromAllScopes(target._scopes); - } - return keys; -} -function resolveKeysFromAllScopes(scopes) { - const set = new Set(); - for (const scope of scopes) { - for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) { - set.add(key); - } - } - return Array.from(set); -} - -const EPSILON = Number.EPSILON || 1e-14; -const getPoint = (points, i) => i < points.length && !points[i].skip && points[i]; -const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x'; -function splineCurve(firstPoint, middlePoint, afterPoint, t) { - const previous = firstPoint.skip ? middlePoint : firstPoint; - const current = middlePoint; - const next = afterPoint.skip ? middlePoint : afterPoint; - const d01 = distanceBetweenPoints(current, previous); - const d12 = distanceBetweenPoints(next, current); - let s01 = d01 / (d01 + d12); - let s12 = d12 / (d01 + d12); - s01 = isNaN(s01) ? 0 : s01; - s12 = isNaN(s12) ? 0 : s12; - const fa = t * s01; - const fb = t * s12; - return { - previous: { - x: current.x - fa * (next.x - previous.x), - y: current.y - fa * (next.y - previous.y) - }, - next: { - x: current.x + fb * (next.x - previous.x), - y: current.y + fb * (next.y - previous.y) - } - }; -} -function monotoneAdjust(points, deltaK, mK) { - const pointsLen = points.length; - let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen - 1; ++i) { - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent || !pointAfter) { - continue; - } - if (almostEquals(deltaK[i], 0, EPSILON)) { - mK[i] = mK[i + 1] = 0; - continue; - } - alphaK = mK[i] / deltaK[i]; - betaK = mK[i + 1] / deltaK[i]; - squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); - if (squaredMagnitude <= 9) { - continue; - } - tauK = 3 / Math.sqrt(squaredMagnitude); - mK[i] = alphaK * tauK * deltaK[i]; - mK[i + 1] = betaK * tauK * deltaK[i]; - } -} -function monotoneCompute(points, mK, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - let delta, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - const iPixel = pointCurrent[indexAxis]; - const vPixel = pointCurrent[valueAxis]; - if (pointBefore) { - delta = (iPixel - pointBefore[indexAxis]) / 3; - pointCurrent[`cp1${indexAxis}`] = iPixel - delta; - pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; - } - if (pointAfter) { - delta = (pointAfter[indexAxis] - iPixel) / 3; - pointCurrent[`cp2${indexAxis}`] = iPixel + delta; - pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; - } - } -} -function splineCurveMonotone(points, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - const deltaK = Array(pointsLen).fill(0); - const mK = Array(pointsLen); - let i, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - if (pointAfter) { - const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; - deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; - } - mK[i] = !pointBefore ? deltaK[i] - : !pointAfter ? deltaK[i - 1] - : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0 - : (deltaK[i - 1] + deltaK[i]) / 2; - } - monotoneAdjust(points, deltaK, mK); - monotoneCompute(points, mK, indexAxis); -} -function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); -} -function capBezierPoints(points, area) { - let i, ilen, point, inArea, inAreaPrev; - let inAreaNext = _isPointInArea(points[0], area); - for (i = 0, ilen = points.length; i < ilen; ++i) { - inAreaPrev = inArea; - inArea = inAreaNext; - inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); - if (!inArea) { - continue; - } - point = points[i]; - if (inAreaPrev) { - point.cp1x = capControlPoint(point.cp1x, area.left, area.right); - point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); - } - if (inAreaNext) { - point.cp2x = capControlPoint(point.cp2x, area.left, area.right); - point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); - } - } -} -function _updateBezierControlPoints(points, options, area, loop, indexAxis) { - let i, ilen, point, controlPoints; - if (options.spanGaps) { - points = points.filter((pt) => !pt.skip); - } - if (options.cubicInterpolationMode === 'monotone') { - splineCurveMonotone(points, indexAxis); - } else { - let prev = loop ? points[points.length - 1] : points[0]; - for (i = 0, ilen = points.length; i < ilen; ++i) { - point = points[i]; - controlPoints = splineCurve( - prev, - point, - points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], - options.tension - ); - point.cp1x = controlPoints.previous.x; - point.cp1y = controlPoints.previous.y; - point.cp2x = controlPoints.next.x; - point.cp2y = controlPoints.next.y; - prev = point; - } - } - if (options.capBezierPoints) { - capBezierPoints(points, area); - } -} - -const atEdge = (t) => t === 0 || t === 1; -const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); -const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; -const effects = { - linear: t => t, - easeInQuad: t => t * t, - easeOutQuad: t => -t * (t - 2), - easeInOutQuad: t => ((t /= 0.5) < 1) - ? 0.5 * t * t - : -0.5 * ((--t) * (t - 2) - 1), - easeInCubic: t => t * t * t, - easeOutCubic: t => (t -= 1) * t * t + 1, - easeInOutCubic: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t - : 0.5 * ((t -= 2) * t * t + 2), - easeInQuart: t => t * t * t * t, - easeOutQuart: t => -((t -= 1) * t * t * t - 1), - easeInOutQuart: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t - : -0.5 * ((t -= 2) * t * t * t - 2), - easeInQuint: t => t * t * t * t * t, - easeOutQuint: t => (t -= 1) * t * t * t * t + 1, - easeInOutQuint: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t * t - : 0.5 * ((t -= 2) * t * t * t * t + 2), - easeInSine: t => -Math.cos(t * HALF_PI) + 1, - easeOutSine: t => Math.sin(t * HALF_PI), - easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1), - easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)), - easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1, - easeInOutExpo: t => atEdge(t) ? t : t < 0.5 - ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) - : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), - easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1), - easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t), - easeInOutCirc: t => ((t /= 0.5) < 1) - ? -0.5 * (Math.sqrt(1 - t * t) - 1) - : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), - easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3), - easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3), - easeInOutElastic(t) { - const s = 0.1125; - const p = 0.45; - return atEdge(t) ? t : - t < 0.5 - ? 0.5 * elasticIn(t * 2, s, p) - : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); - }, - easeInBack(t) { - const s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - easeOutBack(t) { - const s = 1.70158; - return (t -= 1) * t * ((s + 1) * t + s) + 1; - }, - easeInOutBack(t) { - let s = 1.70158; - if ((t /= 0.5) < 1) { - return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); - } - return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - easeInBounce: t => 1 - effects.easeOutBounce(1 - t), - easeOutBounce(t) { - const m = 7.5625; - const d = 2.75; - if (t < (1 / d)) { - return m * t * t; - } - if (t < (2 / d)) { - return m * (t -= (1.5 / d)) * t + 0.75; - } - if (t < (2.5 / d)) { - return m * (t -= (2.25 / d)) * t + 0.9375; - } - return m * (t -= (2.625 / d)) * t + 0.984375; - }, - easeInOutBounce: t => (t < 0.5) - ? effects.easeInBounce(t * 2) * 0.5 - : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5, -}; - -function _pointInLine(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: p1.y + t * (p2.y - p1.y) - }; -} -function _steppedInterpolation(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y - : mode === 'after' ? t < 1 ? p1.y : p2.y - : t > 0 ? p2.y : p1.y - }; -} -function _bezierInterpolation(p1, p2, t, mode) { - const cp1 = {x: p1.cp2x, y: p1.cp2y}; - const cp2 = {x: p2.cp1x, y: p2.cp1y}; - const a = _pointInLine(p1, cp1, t); - const b = _pointInLine(cp1, cp2, t); - const c = _pointInLine(cp2, p2, t); - const d = _pointInLine(a, b, t); - const e = _pointInLine(b, c, t); - return _pointInLine(d, e, t); -} - -const intlCache = new Map(); -function getNumberFormat(locale, options) { - options = options || {}; - const cacheKey = locale + JSON.stringify(options); - let formatter = intlCache.get(cacheKey); - if (!formatter) { - formatter = new Intl.NumberFormat(locale, options); - intlCache.set(cacheKey, formatter); - } - return formatter; -} -function formatNumber(num, locale, options) { - return getNumberFormat(locale, options).format(num); -} - -const getRightToLeftAdapter = function(rectX, width) { - return { - x(x) { - return rectX + rectX + width - x; - }, - setWidth(w) { - width = w; - }, - textAlign(align) { - if (align === 'center') { - return align; - } - return align === 'right' ? 'left' : 'right'; - }, - xPlus(x, value) { - return x - value; - }, - leftForLtr(x, itemWidth) { - return x - itemWidth; - }, - }; -}; -const getLeftToRightAdapter = function() { - return { - x(x) { - return x; - }, - setWidth(w) { - }, - textAlign(align) { - return align; - }, - xPlus(x, value) { - return x + value; - }, - leftForLtr(x, _itemWidth) { - return x; - }, - }; -}; -function getRtlAdapter(rtl, rectX, width) { - return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); -} -function overrideTextDirection(ctx, direction) { - let style, original; - if (direction === 'ltr' || direction === 'rtl') { - style = ctx.canvas.style; - original = [ - style.getPropertyValue('direction'), - style.getPropertyPriority('direction'), - ]; - style.setProperty('direction', direction, 'important'); - ctx.prevTextDirection = original; - } -} -function restoreTextDirection(ctx, original) { - if (original !== undefined) { - delete ctx.prevTextDirection; - ctx.canvas.style.setProperty('direction', original[0], original[1]); - } -} - -function propertyFn(property) { - if (property === 'angle') { - return { - between: _angleBetween, - compare: _angleDiff, - normalize: _normalizeAngle, - }; - } - return { - between: _isBetween, - compare: (a, b) => a - b, - normalize: x => x - }; -} -function normalizeSegment({start, end, count, loop, style}) { - return { - start: start % count, - end: end % count, - loop: loop && (end - start + 1) % count === 0, - style - }; -} -function getSegment(segment, points, bounds) { - const {property, start: startBound, end: endBound} = bounds; - const {between, normalize} = propertyFn(property); - const count = points.length; - let {start, end, loop} = segment; - let i, ilen; - if (loop) { - start += count; - end += count; - for (i = 0, ilen = count; i < ilen; ++i) { - if (!between(normalize(points[start % count][property]), startBound, endBound)) { - break; - } - start--; - end--; - } - start %= count; - end %= count; - } - if (end < start) { - end += count; - } - return {start, end, loop, style: segment.style}; -} -function _boundSegment(segment, points, bounds) { - if (!bounds) { - return [segment]; - } - const {property, start: startBound, end: endBound} = bounds; - const count = points.length; - const {compare, between, normalize} = propertyFn(property); - const {start, end, loop, style} = getSegment(segment, points, bounds); - const result = []; - let inside = false; - let subStart = null; - let value, point, prevValue; - const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; - const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value); - const shouldStart = () => inside || startIsBefore(); - const shouldStop = () => !inside || endIsBefore(); - for (let i = start, prev = start; i <= end; ++i) { - point = points[i % count]; - if (point.skip) { - continue; - } - value = normalize(point[property]); - if (value === prevValue) { - continue; - } - inside = between(value, startBound, endBound); - if (subStart === null && shouldStart()) { - subStart = compare(value, startBound) === 0 ? i : prev; - } - if (subStart !== null && shouldStop()) { - result.push(normalizeSegment({start: subStart, end: i, loop, count, style})); - subStart = null; - } - prev = i; - prevValue = value; - } - if (subStart !== null) { - result.push(normalizeSegment({start: subStart, end, loop, count, style})); - } - return result; -} -function _boundSegments(line, bounds) { - const result = []; - const segments = line.segments; - for (let i = 0; i < segments.length; i++) { - const sub = _boundSegment(segments[i], line.points, bounds); - if (sub.length) { - result.push(...sub); - } - } - return result; -} -function findStartAndEnd(points, count, loop, spanGaps) { - let start = 0; - let end = count - 1; - if (loop && !spanGaps) { - while (start < count && !points[start].skip) { - start++; - } - } - while (start < count && points[start].skip) { - start++; - } - start %= count; - if (loop) { - end += start; - } - while (end > start && points[end % count].skip) { - end--; - } - end %= count; - return {start, end}; -} -function solidSegments(points, start, max, loop) { - const count = points.length; - const result = []; - let last = start; - let prev = points[start]; - let end; - for (end = start + 1; end <= max; ++end) { - const cur = points[end % count]; - if (cur.skip || cur.stop) { - if (!prev.skip) { - loop = false; - result.push({start: start % count, end: (end - 1) % count, loop}); - start = last = cur.stop ? end : null; - } - } else { - last = end; - if (prev.skip) { - start = end; - } - } - prev = cur; - } - if (last !== null) { - result.push({start: start % count, end: last % count, loop}); - } - return result; -} -function _computeSegments(line, segmentOptions) { - const points = line.points; - const spanGaps = line.options.spanGaps; - const count = points.length; - if (!count) { - return []; - } - const loop = !!line._loop; - const {start, end} = findStartAndEnd(points, count, loop, spanGaps); - if (spanGaps === true) { - return splitByStyles(line, [{start, end, loop}], points, segmentOptions); - } - const max = end < start ? end + count : end; - const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; - return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); -} -function splitByStyles(line, segments, points, segmentOptions) { - if (!segmentOptions || !segmentOptions.setContext || !points) { - return segments; - } - return doSplitByStyles(line, segments, points, segmentOptions); -} -function doSplitByStyles(line, segments, points, segmentOptions) { - const chartContext = line._chart.getContext(); - const baseStyle = readStyle(line.options); - const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; - const count = points.length; - const result = []; - let prevStyle = baseStyle; - let start = segments[0].start; - let i = start; - function addStyle(s, e, l, st) { - const dir = spanGaps ? -1 : 1; - if (s === e) { - return; - } - s += count; - while (points[s % count].skip) { - s -= dir; - } - while (points[e % count].skip) { - e += dir; - } - if (s % count !== e % count) { - result.push({start: s % count, end: e % count, loop: l, style: st}); - prevStyle = st; - start = e % count; - } - } - for (const segment of segments) { - start = spanGaps ? start : segment.start; - let prev = points[start % count]; - let style; - for (i = start + 1; i <= segment.end; i++) { - const pt = points[i % count]; - style = readStyle(segmentOptions.setContext(createContext(chartContext, { - type: 'segment', - p0: prev, - p1: pt, - p0DataIndex: (i - 1) % count, - p1DataIndex: i % count, - datasetIndex - }))); - if (styleChanged(style, prevStyle)) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - prev = pt; - prevStyle = style; - } - if (start < i - 1) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - } - return result; -} -function readStyle(options) { - return { - backgroundColor: options.backgroundColor, - borderCapStyle: options.borderCapStyle, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderJoinStyle: options.borderJoinStyle, - borderWidth: options.borderWidth, - borderColor: options.borderColor - }; -} -function styleChanged(style, prevStyle) { - return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle); -} - -var helpers = /*#__PURE__*/Object.freeze({ -__proto__: null, -easingEffects: effects, -color: color, -getHoverColor: getHoverColor, -noop: noop, -uid: uid, -isNullOrUndef: isNullOrUndef, -isArray: isArray, -isObject: isObject, -isFinite: isNumberFinite, -finiteOrDefault: finiteOrDefault, -valueOrDefault: valueOrDefault, -toPercentage: toPercentage, -toDimension: toDimension, -callback: callback, -each: each, -_elementsEqual: _elementsEqual, -clone: clone, -_merger: _merger, -merge: merge, -mergeIf: mergeIf, -_mergerIf: _mergerIf, -_deprecated: _deprecated, -resolveObjectKey: resolveObjectKey, -_capitalize: _capitalize, -defined: defined, -isFunction: isFunction, -setsEqual: setsEqual, -_isClickEvent: _isClickEvent, -toFontString: toFontString, -_measureText: _measureText, -_longestText: _longestText, -_alignPixel: _alignPixel, -clearCanvas: clearCanvas, -drawPoint: drawPoint, -_isPointInArea: _isPointInArea, -clipArea: clipArea, -unclipArea: unclipArea, -_steppedLineTo: _steppedLineTo, -_bezierCurveTo: _bezierCurveTo, -renderText: renderText, -addRoundedRectPath: addRoundedRectPath, -_lookup: _lookup, -_lookupByKey: _lookupByKey, -_rlookupByKey: _rlookupByKey, -_filterBetween: _filterBetween, -listenArrayEvents: listenArrayEvents, -unlistenArrayEvents: unlistenArrayEvents, -_arrayUnique: _arrayUnique, -_createResolver: _createResolver, -_attachContext: _attachContext, -_descriptors: _descriptors, -splineCurve: splineCurve, -splineCurveMonotone: splineCurveMonotone, -_updateBezierControlPoints: _updateBezierControlPoints, -_isDomSupported: _isDomSupported, -_getParentNode: _getParentNode, -getStyle: getStyle, -getRelativePosition: getRelativePosition$1, -getMaximumSize: getMaximumSize, -retinaScale: retinaScale, -supportsEventListenerOptions: supportsEventListenerOptions, -readUsedSize: readUsedSize, -fontString: fontString, -requestAnimFrame: requestAnimFrame, -throttled: throttled, -debounce: debounce, -_toLeftRightCenter: _toLeftRightCenter, -_alignStartEnd: _alignStartEnd, -_textX: _textX, -_pointInLine: _pointInLine, -_steppedInterpolation: _steppedInterpolation, -_bezierInterpolation: _bezierInterpolation, -formatNumber: formatNumber, -toLineHeight: toLineHeight, -_readValueToProps: _readValueToProps, -toTRBL: toTRBL, -toTRBLCorners: toTRBLCorners, -toPadding: toPadding, -toFont: toFont, -resolve: resolve, -_addGrace: _addGrace, -createContext: createContext, -PI: PI, -TAU: TAU, -PITAU: PITAU, -INFINITY: INFINITY, -RAD_PER_DEG: RAD_PER_DEG, -HALF_PI: HALF_PI, -QUARTER_PI: QUARTER_PI, -TWO_THIRDS_PI: TWO_THIRDS_PI, -log10: log10, -sign: sign, -niceNum: niceNum, -_factorize: _factorize, -isNumber: isNumber, -almostEquals: almostEquals, -almostWhole: almostWhole, -_setMinAndMaxByKey: _setMinAndMaxByKey, -toRadians: toRadians, -toDegrees: toDegrees, -_decimalPlaces: _decimalPlaces, -getAngleFromPoint: getAngleFromPoint, -distanceBetweenPoints: distanceBetweenPoints, -_angleDiff: _angleDiff, -_normalizeAngle: _normalizeAngle, -_angleBetween: _angleBetween, -_limitValue: _limitValue, -_int16Range: _int16Range, -_isBetween: _isBetween, -getRtlAdapter: getRtlAdapter, -overrideTextDirection: overrideTextDirection, -restoreTextDirection: restoreTextDirection, -_boundSegment: _boundSegment, -_boundSegments: _boundSegments, -_computeSegments: _computeSegments -}); - -class BasePlatform { - acquireContext(canvas, aspectRatio) {} - releaseContext(context) { - return false; - } - addEventListener(chart, type, listener) {} - removeEventListener(chart, type, listener) {} - getDevicePixelRatio() { - return 1; - } - getMaximumSize(element, width, height, aspectRatio) { - width = Math.max(0, width || element.width); - height = height || element.height; - return { - width, - height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) - }; - } - isAttached(canvas) { - return true; - } - updateConfig(config) { - } -} - -class BasicPlatform extends BasePlatform { - acquireContext(item) { - return item && item.getContext && item.getContext('2d') || null; - } - updateConfig(config) { - config.options.animation = false; - } -} - -const EXPANDO_KEY = '$chartjs'; -const EVENT_TYPES = { - touchstart: 'mousedown', - touchmove: 'mousemove', - touchend: 'mouseup', - pointerenter: 'mouseenter', - pointerdown: 'mousedown', - pointermove: 'mousemove', - pointerup: 'mouseup', - pointerleave: 'mouseout', - pointerout: 'mouseout' -}; -const isNullOrEmpty = value => value === null || value === ''; -function initCanvas(canvas, aspectRatio) { - const style = canvas.style; - const renderHeight = canvas.getAttribute('height'); - const renderWidth = canvas.getAttribute('width'); - canvas[EXPANDO_KEY] = { - initial: { - height: renderHeight, - width: renderWidth, - style: { - display: style.display, - height: style.height, - width: style.width - } - } - }; - style.display = style.display || 'block'; - style.boxSizing = style.boxSizing || 'border-box'; - if (isNullOrEmpty(renderWidth)) { - const displayWidth = readUsedSize(canvas, 'width'); - if (displayWidth !== undefined) { - canvas.width = displayWidth; - } - } - if (isNullOrEmpty(renderHeight)) { - if (canvas.style.height === '') { - canvas.height = canvas.width / (aspectRatio || 2); - } else { - const displayHeight = readUsedSize(canvas, 'height'); - if (displayHeight !== undefined) { - canvas.height = displayHeight; - } - } - } - return canvas; -} -const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; -function addListener(node, type, listener) { - node.addEventListener(type, listener, eventListenerOptions); -} -function removeListener(chart, type, listener) { - chart.canvas.removeEventListener(type, listener, eventListenerOptions); -} -function fromNativeEvent(event, chart) { - const type = EVENT_TYPES[event.type] || event.type; - const {x, y} = getRelativePosition$1(event, chart); - return { - type, - chart, - native: event, - x: x !== undefined ? x : null, - y: y !== undefined ? y : null, - }; -} -function nodeListContains(nodeList, canvas) { - for (const node of nodeList) { - if (node === canvas || node.contains(canvas)) { - return true; - } - } -} -function createAttachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.addedNodes, canvas); - trigger = trigger && !nodeListContains(entry.removedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -function createDetachObserver(chart, type, listener) { - const canvas = chart.canvas; - const observer = new MutationObserver(entries => { - let trigger = false; - for (const entry of entries) { - trigger = trigger || nodeListContains(entry.removedNodes, canvas); - trigger = trigger && !nodeListContains(entry.addedNodes, canvas); - } - if (trigger) { - listener(); - } - }); - observer.observe(document, {childList: true, subtree: true}); - return observer; -} -const drpListeningCharts = new Map(); -let oldDevicePixelRatio = 0; -function onWindowResize() { - const dpr = window.devicePixelRatio; - if (dpr === oldDevicePixelRatio) { - return; - } - oldDevicePixelRatio = dpr; - drpListeningCharts.forEach((resize, chart) => { - if (chart.currentDevicePixelRatio !== dpr) { - resize(); - } - }); -} -function listenDevicePixelRatioChanges(chart, resize) { - if (!drpListeningCharts.size) { - window.addEventListener('resize', onWindowResize); - } - drpListeningCharts.set(chart, resize); -} -function unlistenDevicePixelRatioChanges(chart) { - drpListeningCharts.delete(chart); - if (!drpListeningCharts.size) { - window.removeEventListener('resize', onWindowResize); - } -} -function createResizeObserver(chart, type, listener) { - const canvas = chart.canvas; - const container = canvas && _getParentNode(canvas); - if (!container) { - return; - } - const resize = throttled((width, height) => { - const w = container.clientWidth; - listener(width, height); - if (w < container.clientWidth) { - listener(); - } - }, window); - const observer = new ResizeObserver(entries => { - const entry = entries[0]; - const width = entry.contentRect.width; - const height = entry.contentRect.height; - if (width === 0 && height === 0) { - return; - } - resize(width, height); - }); - observer.observe(container); - listenDevicePixelRatioChanges(chart, resize); - return observer; -} -function releaseObserver(chart, type, observer) { - if (observer) { - observer.disconnect(); - } - if (type === 'resize') { - unlistenDevicePixelRatioChanges(chart); - } -} -function createProxyAndListen(chart, type, listener) { - const canvas = chart.canvas; - const proxy = throttled((event) => { - if (chart.ctx !== null) { - listener(fromNativeEvent(event, chart)); - } - }, chart, (args) => { - const event = args[0]; - return [event, event.offsetX, event.offsetY]; - }); - addListener(canvas, type, proxy); - return proxy; -} -class DomPlatform extends BasePlatform { - acquireContext(canvas, aspectRatio) { - const context = canvas && canvas.getContext && canvas.getContext('2d'); - if (context && context.canvas === canvas) { - initCanvas(canvas, aspectRatio); - return context; - } - return null; - } - releaseContext(context) { - const canvas = context.canvas; - if (!canvas[EXPANDO_KEY]) { - return false; - } - const initial = canvas[EXPANDO_KEY].initial; - ['height', 'width'].forEach((prop) => { - const value = initial[prop]; - if (isNullOrUndef(value)) { - canvas.removeAttribute(prop); - } else { - canvas.setAttribute(prop, value); - } - }); - const style = initial.style || {}; - Object.keys(style).forEach((key) => { - canvas.style[key] = style[key]; - }); - canvas.width = canvas.width; - delete canvas[EXPANDO_KEY]; - return true; - } - addEventListener(chart, type, listener) { - this.removeEventListener(chart, type); - const proxies = chart.$proxies || (chart.$proxies = {}); - const handlers = { - attach: createAttachObserver, - detach: createDetachObserver, - resize: createResizeObserver - }; - const handler = handlers[type] || createProxyAndListen; - proxies[type] = handler(chart, type, listener); - } - removeEventListener(chart, type) { - const proxies = chart.$proxies || (chart.$proxies = {}); - const proxy = proxies[type]; - if (!proxy) { - return; - } - const handlers = { - attach: releaseObserver, - detach: releaseObserver, - resize: releaseObserver - }; - const handler = handlers[type] || removeListener; - handler(chart, type, proxy); - proxies[type] = undefined; - } - getDevicePixelRatio() { - return window.devicePixelRatio; - } - getMaximumSize(canvas, width, height, aspectRatio) { - return getMaximumSize(canvas, width, height, aspectRatio); - } - isAttached(canvas) { - const container = _getParentNode(canvas); - return !!(container && container.isConnected); - } -} - -function _detectPlatform(canvas) { - if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { - return BasicPlatform; - } - return DomPlatform; -} - -var platforms = /*#__PURE__*/Object.freeze({ -__proto__: null, -_detectPlatform: _detectPlatform, -BasePlatform: BasePlatform, -BasicPlatform: BasicPlatform, -DomPlatform: DomPlatform -}); - -const transparent = 'transparent'; -const interpolators = { - boolean(from, to, factor) { - return factor > 0.5 ? to : from; - }, - color(from, to, factor) { - const c0 = color(from || transparent); - const c1 = c0.valid && color(to || transparent); - return c1 && c1.valid - ? c1.mix(c0, factor).hexString() - : to; - }, - number(from, to, factor) { - return from + (to - from) * factor; - } -}; -class Animation { - constructor(cfg, target, prop, to) { - const currentValue = target[prop]; - to = resolve([cfg.to, to, currentValue, cfg.from]); - const from = resolve([cfg.from, currentValue, to]); - this._active = true; - this._fn = cfg.fn || interpolators[cfg.type || typeof from]; - this._easing = effects[cfg.easing] || effects.linear; - this._start = Math.floor(Date.now() + (cfg.delay || 0)); - this._duration = this._total = Math.floor(cfg.duration); - this._loop = !!cfg.loop; - this._target = target; - this._prop = prop; - this._from = from; - this._to = to; - this._promises = undefined; - } - active() { - return this._active; - } - update(cfg, to, date) { - if (this._active) { - this._notify(false); - const currentValue = this._target[this._prop]; - const elapsed = date - this._start; - const remain = this._duration - elapsed; - this._start = date; - this._duration = Math.floor(Math.max(remain, cfg.duration)); - this._total += elapsed; - this._loop = !!cfg.loop; - this._to = resolve([cfg.to, to, currentValue, cfg.from]); - this._from = resolve([cfg.from, currentValue, to]); - } - } - cancel() { - if (this._active) { - this.tick(Date.now()); - this._active = false; - this._notify(false); - } - } - tick(date) { - const elapsed = date - this._start; - const duration = this._duration; - const prop = this._prop; - const from = this._from; - const loop = this._loop; - const to = this._to; - let factor; - this._active = from !== to && (loop || (elapsed < duration)); - if (!this._active) { - this._target[prop] = to; - this._notify(true); - return; - } - if (elapsed < 0) { - this._target[prop] = from; - return; - } - factor = (elapsed / duration) % 2; - factor = loop && factor > 1 ? 2 - factor : factor; - factor = this._easing(Math.min(1, Math.max(0, factor))); - this._target[prop] = this._fn(from, to, factor); - } - wait() { - const promises = this._promises || (this._promises = []); - return new Promise((res, rej) => { - promises.push({res, rej}); - }); - } - _notify(resolved) { - const method = resolved ? 'res' : 'rej'; - const promises = this._promises || []; - for (let i = 0; i < promises.length; i++) { - promises[i][method](); - } - } -} - -const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; -const colors = ['color', 'borderColor', 'backgroundColor']; -defaults.set('animation', { - delay: undefined, - duration: 1000, - easing: 'easeOutQuart', - fn: undefined, - from: undefined, - loop: undefined, - to: undefined, - type: undefined, -}); -const animationOptions = Object.keys(defaults.animation); -defaults.describe('animation', { - _fallback: false, - _indexable: false, - _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn', -}); -defaults.set('animations', { - colors: { - type: 'color', - properties: colors - }, - numbers: { - type: 'number', - properties: numbers - }, -}); -defaults.describe('animations', { - _fallback: 'animation', -}); -defaults.set('transitions', { - active: { - animation: { - duration: 400 - } - }, - resize: { - animation: { - duration: 0 - } - }, - show: { - animations: { - colors: { - from: 'transparent' - }, - visible: { - type: 'boolean', - duration: 0 - }, - } - }, - hide: { - animations: { - colors: { - to: 'transparent' - }, - visible: { - type: 'boolean', - easing: 'linear', - fn: v => v | 0 - }, - } - } -}); -class Animations { - constructor(chart, config) { - this._chart = chart; - this._properties = new Map(); - this.configure(config); - } - configure(config) { - if (!isObject(config)) { - return; - } - const animatedProps = this._properties; - Object.getOwnPropertyNames(config).forEach(key => { - const cfg = config[key]; - if (!isObject(cfg)) { - return; - } - const resolved = {}; - for (const option of animationOptions) { - resolved[option] = cfg[option]; - } - (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => { - if (prop === key || !animatedProps.has(prop)) { - animatedProps.set(prop, resolved); - } - }); - }); - } - _animateOptions(target, values) { - const newOptions = values.options; - const options = resolveTargetOptions(target, newOptions); - if (!options) { - return []; - } - const animations = this._createAnimations(options, newOptions); - if (newOptions.$shared) { - awaitAll(target.options.$animations, newOptions).then(() => { - target.options = newOptions; - }, () => { - }); - } - return animations; - } - _createAnimations(target, values) { - const animatedProps = this._properties; - const animations = []; - const running = target.$animations || (target.$animations = {}); - const props = Object.keys(values); - const date = Date.now(); - let i; - for (i = props.length - 1; i >= 0; --i) { - const prop = props[i]; - if (prop.charAt(0) === '$') { - continue; - } - if (prop === 'options') { - animations.push(...this._animateOptions(target, values)); - continue; - } - const value = values[prop]; - let animation = running[prop]; - const cfg = animatedProps.get(prop); - if (animation) { - if (cfg && animation.active()) { - animation.update(cfg, value, date); - continue; - } else { - animation.cancel(); - } - } - if (!cfg || !cfg.duration) { - target[prop] = value; - continue; - } - running[prop] = animation = new Animation(cfg, target, prop, value); - animations.push(animation); - } - return animations; - } - update(target, values) { - if (this._properties.size === 0) { - Object.assign(target, values); - return; - } - const animations = this._createAnimations(target, values); - if (animations.length) { - animator.add(this._chart, animations); - return true; - } - } -} -function awaitAll(animations, properties) { - const running = []; - const keys = Object.keys(properties); - for (let i = 0; i < keys.length; i++) { - const anim = animations[keys[i]]; - if (anim && anim.active()) { - running.push(anim.wait()); - } - } - return Promise.all(running); -} -function resolveTargetOptions(target, newOptions) { - if (!newOptions) { - return; - } - let options = target.options; - if (!options) { - target.options = newOptions; - return; - } - if (options.$shared) { - target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); - } - return options; -} - -function scaleClip(scale, allowedOverflow) { - const opts = scale && scale.options || {}; - const reverse = opts.reverse; - const min = opts.min === undefined ? allowedOverflow : 0; - const max = opts.max === undefined ? allowedOverflow : 0; - return { - start: reverse ? max : min, - end: reverse ? min : max - }; -} -function defaultClip(xScale, yScale, allowedOverflow) { - if (allowedOverflow === false) { - return false; - } - const x = scaleClip(xScale, allowedOverflow); - const y = scaleClip(yScale, allowedOverflow); - return { - top: y.end, - right: x.end, - bottom: y.start, - left: x.start - }; -} -function toClip(value) { - let t, r, b, l; - if (isObject(value)) { - t = value.top; - r = value.right; - b = value.bottom; - l = value.left; - } else { - t = r = b = l = value; - } - return { - top: t, - right: r, - bottom: b, - left: l, - disabled: value === false - }; -} -function getSortedDatasetIndices(chart, filterVisible) { - const keys = []; - const metasets = chart._getSortedDatasetMetas(filterVisible); - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - keys.push(metasets[i].index); - } - return keys; -} -function applyStack(stack, value, dsIndex, options = {}) { - const keys = stack.keys; - const singleMode = options.mode === 'single'; - let i, ilen, datasetIndex, otherValue; - if (value === null) { - return; - } - for (i = 0, ilen = keys.length; i < ilen; ++i) { - datasetIndex = +keys[i]; - if (datasetIndex === dsIndex) { - if (options.all) { - continue; - } - break; - } - otherValue = stack.values[datasetIndex]; - if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) { - value += otherValue; - } - } - return value; -} -function convertObjectDataToArray(data) { - const keys = Object.keys(data); - const adata = new Array(keys.length); - let i, ilen, key; - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - adata[i] = { - x: key, - y: data[key] - }; - } - return adata; -} -function isStacked(scale, meta) { - const stacked = scale && scale.options.stacked; - return stacked || (stacked === undefined && meta.stack !== undefined); -} -function getStackKey(indexScale, valueScale, meta) { - return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; -} -function getUserBounds(scale) { - const {min, max, minDefined, maxDefined} = scale.getUserBounds(); - return { - min: minDefined ? min : Number.NEGATIVE_INFINITY, - max: maxDefined ? max : Number.POSITIVE_INFINITY - }; -} -function getOrCreateStack(stacks, stackKey, indexValue) { - const subStack = stacks[stackKey] || (stacks[stackKey] = {}); - return subStack[indexValue] || (subStack[indexValue] = {}); -} -function getLastIndexInStack(stack, vScale, positive, type) { - for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) { - const value = stack[meta.index]; - if ((positive && value > 0) || (!positive && value < 0)) { - return meta.index; - } - } - return null; -} -function updateStacks(controller, parsed) { - const {chart, _cachedMeta: meta} = controller; - const stacks = chart._stacks || (chart._stacks = {}); - const {iScale, vScale, index: datasetIndex} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const key = getStackKey(iScale, vScale, meta); - const ilen = parsed.length; - let stack; - for (let i = 0; i < ilen; ++i) { - const item = parsed[i]; - const {[iAxis]: index, [vAxis]: value} = item; - const itemStacks = item._stacks || (item._stacks = {}); - stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); - stack[datasetIndex] = value; - stack._top = getLastIndexInStack(stack, vScale, true, meta.type); - stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); - } -} -function getFirstScaleId(chart, axis) { - const scales = chart.scales; - return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); -} -function createDatasetContext(parent, index) { - return createContext(parent, - { - active: false, - dataset: undefined, - datasetIndex: index, - index, - mode: 'default', - type: 'dataset' - } - ); -} -function createDataContext(parent, index, element) { - return createContext(parent, { - active: false, - dataIndex: index, - parsed: undefined, - raw: undefined, - element, - index, - mode: 'default', - type: 'data' - }); -} -function clearStacks(meta, items) { - const datasetIndex = meta.controller.index; - const axis = meta.vScale && meta.vScale.axis; - if (!axis) { - return; - } - items = items || meta._parsed; - for (const parsed of items) { - const stacks = parsed._stacks; - if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { - return; - } - delete stacks[axis][datasetIndex]; - } -} -const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none'; -const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached); -const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked - && {keys: getSortedDatasetIndices(chart, true), values: null}; -class DatasetController { - constructor(chart, datasetIndex) { - this.chart = chart; - this._ctx = chart.ctx; - this.index = datasetIndex; - this._cachedDataOpts = {}; - this._cachedMeta = this.getMeta(); - this._type = this._cachedMeta.type; - this.options = undefined; - this._parsing = false; - this._data = undefined; - this._objectData = undefined; - this._sharedOptions = undefined; - this._drawStart = undefined; - this._drawCount = undefined; - this.enableOptionSharing = false; - this.$context = undefined; - this._syncList = []; - this.initialize(); - } - initialize() { - const meta = this._cachedMeta; - this.configure(); - this.linkScales(); - meta._stacked = isStacked(meta.vScale, meta); - this.addElements(); - } - updateIndex(datasetIndex) { - if (this.index !== datasetIndex) { - clearStacks(this._cachedMeta); - } - this.index = datasetIndex; - } - linkScales() { - const chart = this.chart; - const meta = this._cachedMeta; - const dataset = this.getDataset(); - const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; - const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); - const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); - const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); - const indexAxis = meta.indexAxis; - const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); - const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); - meta.xScale = this.getScaleForId(xid); - meta.yScale = this.getScaleForId(yid); - meta.rScale = this.getScaleForId(rid); - meta.iScale = this.getScaleForId(iid); - meta.vScale = this.getScaleForId(vid); - } - getDataset() { - return this.chart.data.datasets[this.index]; - } - getMeta() { - return this.chart.getDatasetMeta(this.index); - } - getScaleForId(scaleID) { - return this.chart.scales[scaleID]; - } - _getOtherScale(scale) { - const meta = this._cachedMeta; - return scale === meta.iScale - ? meta.vScale - : meta.iScale; - } - reset() { - this._update('reset'); - } - _destroy() { - const meta = this._cachedMeta; - if (this._data) { - unlistenArrayEvents(this._data, this); - } - if (meta._stacked) { - clearStacks(meta); - } - } - _dataCheck() { - const dataset = this.getDataset(); - const data = dataset.data || (dataset.data = []); - const _data = this._data; - if (isObject(data)) { - this._data = convertObjectDataToArray(data); - } else if (_data !== data) { - if (_data) { - unlistenArrayEvents(_data, this); - const meta = this._cachedMeta; - clearStacks(meta); - meta._parsed = []; - } - if (data && Object.isExtensible(data)) { - listenArrayEvents(data, this); - } - this._syncList = []; - this._data = data; - } - } - addElements() { - const meta = this._cachedMeta; - this._dataCheck(); - if (this.datasetElementType) { - meta.dataset = new this.datasetElementType(); - } - } - buildOrUpdateElements(resetNewElements) { - const meta = this._cachedMeta; - const dataset = this.getDataset(); - let stackChanged = false; - this._dataCheck(); - const oldStacked = meta._stacked; - meta._stacked = isStacked(meta.vScale, meta); - if (meta.stack !== dataset.stack) { - stackChanged = true; - clearStacks(meta); - meta.stack = dataset.stack; - } - this._resyncElements(resetNewElements); - if (stackChanged || oldStacked !== meta._stacked) { - updateStacks(this, meta._parsed); - } - } - configure() { - const config = this.chart.config; - const scopeKeys = config.datasetScopeKeys(this._type); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); - this.options = config.createResolver(scopes, this.getContext()); - this._parsing = this.options.parsing; - this._cachedDataOpts = {}; - } - parse(start, count) { - const {_cachedMeta: meta, _data: data} = this; - const {iScale, _stacked} = meta; - const iAxis = iScale.axis; - let sorted = start === 0 && count === data.length ? true : meta._sorted; - let prev = start > 0 && meta._parsed[start - 1]; - let i, cur, parsed; - if (this._parsing === false) { - meta._parsed = data; - meta._sorted = true; - parsed = data; - } else { - if (isArray(data[start])) { - parsed = this.parseArrayData(meta, data, start, count); - } else if (isObject(data[start])) { - parsed = this.parseObjectData(meta, data, start, count); - } else { - parsed = this.parsePrimitiveData(meta, data, start, count); - } - const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]); - for (i = 0; i < count; ++i) { - meta._parsed[i + start] = cur = parsed[i]; - if (sorted) { - if (isNotInOrderComparedToPrev()) { - sorted = false; - } - prev = cur; - } - } - meta._sorted = sorted; - } - if (_stacked) { - updateStacks(this, parsed); - } - } - parsePrimitiveData(meta, data, start, count) { - const {iScale, vScale} = meta; - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = new Array(count); - let i, ilen, index; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - parsed[i] = { - [iAxis]: singleScale || iScale.parse(labels[index], index), - [vAxis]: vScale.parse(data[index], index) - }; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const {xScale, yScale} = meta; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(item[0], index), - y: yScale.parse(item[1], index) - }; - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const {xScale, yScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const parsed = new Array(count); - let i, ilen, index, item; - for (i = 0, ilen = count; i < ilen; ++i) { - index = i + start; - item = data[index]; - parsed[i] = { - x: xScale.parse(resolveObjectKey(item, xAxisKey), index), - y: yScale.parse(resolveObjectKey(item, yAxisKey), index) - }; - } - return parsed; - } - getParsed(index) { - return this._cachedMeta._parsed[index]; - } - getDataElement(index) { - return this._cachedMeta.data[index]; - } - applyStack(scale, parsed, mode) { - const chart = this.chart; - const meta = this._cachedMeta; - const value = parsed[scale.axis]; - const stack = { - keys: getSortedDatasetIndices(chart, true), - values: parsed._stacks[scale.axis] - }; - return applyStack(stack, value, meta.index, {mode}); - } - updateRangeFromParsed(range, scale, parsed, stack) { - const parsedValue = parsed[scale.axis]; - let value = parsedValue === null ? NaN : parsedValue; - const values = stack && parsed._stacks[scale.axis]; - if (stack && values) { - stack.values = values; - value = applyStack(stack, parsedValue, this._cachedMeta.index); - } - range.min = Math.min(range.min, value); - range.max = Math.max(range.max, value); - } - getMinMax(scale, canStack) { - const meta = this._cachedMeta; - const _parsed = meta._parsed; - const sorted = meta._sorted && scale === meta.iScale; - const ilen = _parsed.length; - const otherScale = this._getOtherScale(scale); - const stack = createStack(canStack, meta, this.chart); - const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; - const {min: otherMin, max: otherMax} = getUserBounds(otherScale); - let i, parsed; - function _skip() { - parsed = _parsed[i]; - const otherValue = parsed[otherScale.axis]; - return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; - } - for (i = 0; i < ilen; ++i) { - if (_skip()) { - continue; - } - this.updateRangeFromParsed(range, scale, parsed, stack); - if (sorted) { - break; - } - } - if (sorted) { - for (i = ilen - 1; i >= 0; --i) { - if (_skip()) { - continue; - } - this.updateRangeFromParsed(range, scale, parsed, stack); - break; - } - } - return range; - } - getAllParsedValues(scale) { - const parsed = this._cachedMeta._parsed; - const values = []; - let i, ilen, value; - for (i = 0, ilen = parsed.length; i < ilen; ++i) { - value = parsed[i][scale.axis]; - if (isNumberFinite(value)) { - values.push(value); - } - } - return values; - } - getMaxOverflow() { - return false; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const vScale = meta.vScale; - const parsed = this.getParsed(index); - return { - label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', - value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' - }; - } - _update(mode) { - const meta = this._cachedMeta; - this.update(mode || 'default'); - meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); - } - update(mode) {} - draw() { - const ctx = this._ctx; - const chart = this.chart; - const meta = this._cachedMeta; - const elements = meta.data || []; - const area = chart.chartArea; - const active = []; - const start = this._drawStart || 0; - const count = this._drawCount || (elements.length - start); - const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; - let i; - if (meta.dataset) { - meta.dataset.draw(ctx, area, start, count); - } - for (i = start; i < start + count; ++i) { - const element = elements[i]; - if (element.hidden) { - continue; - } - if (element.active && drawActiveElementsOnTop) { - active.push(element); - } else { - element.draw(ctx, area); - } - } - for (i = 0; i < active.length; ++i) { - active[i].draw(ctx, area); - } - } - getStyle(index, active) { - const mode = active ? 'active' : 'default'; - return index === undefined && this._cachedMeta.dataset - ? this.resolveDatasetElementOptions(mode) - : this.resolveDataElementOptions(index || 0, mode); - } - getContext(index, active, mode) { - const dataset = this.getDataset(); - let context; - if (index >= 0 && index < this._cachedMeta.data.length) { - const element = this._cachedMeta.data[index]; - context = element.$context || - (element.$context = createDataContext(this.getContext(), index, element)); - context.parsed = this.getParsed(index); - context.raw = dataset.data[index]; - context.index = context.dataIndex = index; - } else { - context = this.$context || - (this.$context = createDatasetContext(this.chart.getContext(), this.index)); - context.dataset = dataset; - context.index = context.datasetIndex = this.index; - } - context.active = !!active; - context.mode = mode; - return context; - } - resolveDatasetElementOptions(mode) { - return this._resolveElementOptions(this.datasetElementType.id, mode); - } - resolveDataElementOptions(index, mode) { - return this._resolveElementOptions(this.dataElementType.id, mode, index); - } - _resolveElementOptions(elementType, mode = 'default', index) { - const active = mode === 'active'; - const cache = this._cachedDataOpts; - const cacheKey = elementType + '-' + mode; - const cached = cache[cacheKey]; - const sharing = this.enableOptionSharing && defined(index); - if (cached) { - return cloneIfNotShared(cached, sharing); - } - const config = this.chart.config; - const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); - const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, '']; - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - const names = Object.keys(defaults.elements[elementType]); - const context = () => this.getContext(index, active); - const values = config.resolveNamedOptions(scopes, names, context, prefixes); - if (values.$shared) { - values.$shared = sharing; - cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); - } - return values; - } - _resolveAnimations(index, transition, active) { - const chart = this.chart; - const cache = this._cachedDataOpts; - const cacheKey = `animation-${transition}`; - const cached = cache[cacheKey]; - if (cached) { - return cached; - } - let options; - if (chart.options.animation !== false) { - const config = this.chart.config; - const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); - const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); - options = config.createResolver(scopes, this.getContext(index, active, transition)); - } - const animations = new Animations(chart, options && options.animations); - if (options && options._cacheable) { - cache[cacheKey] = Object.freeze(animations); - } - return animations; - } - getSharedOptions(options) { - if (!options.$shared) { - return; - } - return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); - } - includeOptions(mode, sharedOptions) { - return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; - } - updateElement(element, index, properties, mode) { - if (isDirectUpdateMode(mode)) { - Object.assign(element, properties); - } else { - this._resolveAnimations(index, mode).update(element, properties); - } - } - updateSharedOptions(sharedOptions, mode, newOptions) { - if (sharedOptions && !isDirectUpdateMode(mode)) { - this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); - } - } - _setStyle(element, index, mode, active) { - element.active = active; - const options = this.getStyle(index, active); - this._resolveAnimations(index, mode, active).update(element, { - options: (!active && this.getSharedOptions(options)) || options - }); - } - removeHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', false); - } - setHoverStyle(element, datasetIndex, index) { - this._setStyle(element, index, 'active', true); - } - _removeDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', false); - } - } - _setDatasetHoverStyle() { - const element = this._cachedMeta.dataset; - if (element) { - this._setStyle(element, undefined, 'active', true); - } - } - _resyncElements(resetNewElements) { - const data = this._data; - const elements = this._cachedMeta.data; - for (const [method, arg1, arg2] of this._syncList) { - this[method](arg1, arg2); - } - this._syncList = []; - const numMeta = elements.length; - const numData = data.length; - const count = Math.min(numData, numMeta); - if (count) { - this.parse(0, count); - } - if (numData > numMeta) { - this._insertElements(numMeta, numData - numMeta, resetNewElements); - } else if (numData < numMeta) { - this._removeElements(numData, numMeta - numData); - } - } - _insertElements(start, count, resetNewElements = true) { - const meta = this._cachedMeta; - const data = meta.data; - const end = start + count; - let i; - const move = (arr) => { - arr.length += count; - for (i = arr.length - 1; i >= end; i--) { - arr[i] = arr[i - count]; - } - }; - move(data); - for (i = start; i < end; ++i) { - data[i] = new this.dataElementType(); - } - if (this._parsing) { - move(meta._parsed); - } - this.parse(start, count); - if (resetNewElements) { - this.updateElements(data, start, count, 'reset'); - } - } - updateElements(element, start, count, mode) {} - _removeElements(start, count) { - const meta = this._cachedMeta; - if (this._parsing) { - const removed = meta._parsed.splice(start, count); - if (meta._stacked) { - clearStacks(meta, removed); - } - } - meta.data.splice(start, count); - } - _sync(args) { - if (this._parsing) { - this._syncList.push(args); - } else { - const [method, arg1, arg2] = args; - this[method](arg1, arg2); - } - this.chart._dataChanges.push([this.index, ...args]); - } - _onDataPush() { - const count = arguments.length; - this._sync(['_insertElements', this.getDataset().data.length - count, count]); - } - _onDataPop() { - this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]); - } - _onDataShift() { - this._sync(['_removeElements', 0, 1]); - } - _onDataSplice(start, count) { - if (count) { - this._sync(['_removeElements', start, count]); - } - const newCount = arguments.length - 2; - if (newCount) { - this._sync(['_insertElements', start, newCount]); - } - } - _onDataUnshift() { - this._sync(['_insertElements', 0, arguments.length]); - } -} -DatasetController.defaults = {}; -DatasetController.prototype.datasetElementType = null; -DatasetController.prototype.dataElementType = null; - -class Element { - constructor() { - this.x = undefined; - this.y = undefined; - this.active = false; - this.options = undefined; - this.$animations = undefined; - } - tooltipPosition(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - hasValue() { - return isNumber(this.x) && isNumber(this.y); - } - getProps(props, final) { - const anims = this.$animations; - if (!final || !anims) { - return this; - } - const ret = {}; - props.forEach(prop => { - ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; - }); - return ret; - } -} -Element.defaults = {}; -Element.defaultRoutes = undefined; - -const formatters = { - values(value) { - return isArray(value) ? value : '' + value; - }, - numeric(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const locale = this.chart.options.locale; - let notation; - let delta = tickValue; - if (ticks.length > 1) { - const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); - if (maxTick < 1e-4 || maxTick > 1e+15) { - notation = 'scientific'; - } - delta = calculateDelta(tickValue, ticks); - } - const logDelta = log10(Math.abs(delta)); - const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); - const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; - Object.assign(options, this.options.ticks.format); - return formatNumber(tickValue, locale, options); - }, - logarithmic(tickValue, index, ticks) { - if (tickValue === 0) { - return '0'; - } - const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); - if (remain === 1 || remain === 2 || remain === 5) { - return formatters.numeric.call(this, tickValue, index, ticks); - } - return ''; - } -}; -function calculateDelta(tickValue, ticks) { - let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; - if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { - delta = tickValue - Math.floor(tickValue); - } - return delta; -} -var Ticks = {formatters}; - -defaults.set('scale', { - display: true, - offset: false, - reverse: false, - beginAtZero: false, - bounds: 'ticks', - grace: 0, - grid: { - display: true, - lineWidth: 1, - drawBorder: true, - drawOnChartArea: true, - drawTicks: true, - tickLength: 8, - tickWidth: (_ctx, options) => options.lineWidth, - tickColor: (_ctx, options) => options.color, - offset: false, - borderDash: [], - borderDashOffset: 0.0, - borderWidth: 1 - }, - title: { - display: false, - text: '', - padding: { - top: 4, - bottom: 4 - } - }, - ticks: { - minRotation: 0, - maxRotation: 50, - mirror: false, - textStrokeWidth: 0, - textStrokeColor: '', - padding: 3, - display: true, - autoSkip: true, - autoSkipPadding: 3, - labelOffset: 0, - callback: Ticks.formatters.values, - minor: {}, - major: {}, - align: 'center', - crossAlign: 'near', - showLabelBackdrop: false, - backdropColor: 'rgba(255, 255, 255, 0.75)', - backdropPadding: 2, - } -}); -defaults.route('scale.ticks', 'color', '', 'color'); -defaults.route('scale.grid', 'color', '', 'borderColor'); -defaults.route('scale.grid', 'borderColor', '', 'borderColor'); -defaults.route('scale.title', 'color', '', 'color'); -defaults.describe('scale', { - _fallback: false, - _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', - _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash', -}); -defaults.describe('scales', { - _fallback: 'scale', -}); -defaults.describe('scale.ticks', { - _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback', - _indexable: (name) => name !== 'backdropPadding', -}); - -function autoSkip(scale, ticks) { - const tickOpts = scale.options.ticks; - const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale); - const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; - const numMajorIndices = majorIndices.length; - const first = majorIndices[0]; - const last = majorIndices[numMajorIndices - 1]; - const newTicks = []; - if (numMajorIndices > ticksLimit) { - skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); - return newTicks; - } - const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); - if (numMajorIndices > 0) { - let i, ilen; - const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; - skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); - for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { - skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); - } - skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); - return newTicks; - } - skip(ticks, newTicks, spacing); - return newTicks; -} -function determineMaxTicks(scale) { - const offset = scale.options.offset; - const tickLength = scale._tickSize(); - const maxScale = scale._length / tickLength + (offset ? 0 : 1); - const maxChart = scale._maxLength / tickLength; - return Math.floor(Math.min(maxScale, maxChart)); -} -function calculateSpacing(majorIndices, ticks, ticksLimit) { - const evenMajorSpacing = getEvenSpacing(majorIndices); - const spacing = ticks.length / ticksLimit; - if (!evenMajorSpacing) { - return Math.max(spacing, 1); - } - const factors = _factorize(evenMajorSpacing); - for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { - const factor = factors[i]; - if (factor > spacing) { - return factor; - } - } - return Math.max(spacing, 1); -} -function getMajorIndices(ticks) { - const result = []; - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (ticks[i].major) { - result.push(i); - } - } - return result; -} -function skipMajors(ticks, newTicks, majorIndices, spacing) { - let count = 0; - let next = majorIndices[0]; - let i; - spacing = Math.ceil(spacing); - for (i = 0; i < ticks.length; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = majorIndices[count * spacing]; - } - } -} -function skip(ticks, newTicks, spacing, majorStart, majorEnd) { - const start = valueOrDefault(majorStart, 0); - const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); - let count = 0; - let length, i, next; - spacing = Math.ceil(spacing); - if (majorEnd) { - length = majorEnd - majorStart; - spacing = length / Math.floor(length / spacing); - } - next = start; - while (next < 0) { - count++; - next = Math.round(start + count * spacing); - } - for (i = Math.max(start, 0); i < end; i++) { - if (i === next) { - newTicks.push(ticks[i]); - count++; - next = Math.round(start + count * spacing); - } - } -} -function getEvenSpacing(arr) { - const len = arr.length; - let i, diff; - if (len < 2) { - return false; - } - for (diff = arr[0], i = 1; i < len; ++i) { - if (arr[i] - arr[i - 1] !== diff) { - return false; - } - } - return diff; -} - -const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align; -const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; -function sample(arr, numItems) { - const result = []; - const increment = arr.length / numItems; - const len = arr.length; - let i = 0; - for (; i < len; i += increment) { - result.push(arr[Math.floor(i)]); - } - return result; -} -function getPixelForGridLine(scale, index, offsetGridLines) { - const length = scale.ticks.length; - const validIndex = Math.min(index, length - 1); - const start = scale._startPixel; - const end = scale._endPixel; - const epsilon = 1e-6; - let lineValue = scale.getPixelForTick(validIndex); - let offset; - if (offsetGridLines) { - if (length === 1) { - offset = Math.max(lineValue - start, end - lineValue); - } else if (index === 0) { - offset = (scale.getPixelForTick(1) - lineValue) / 2; - } else { - offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; - } - lineValue += validIndex < index ? offset : -offset; - if (lineValue < start - epsilon || lineValue > end + epsilon) { - return; - } - } - return lineValue; -} -function garbageCollect(caches, length) { - each(caches, (cache) => { - const gc = cache.gc; - const gcLen = gc.length / 2; - let i; - if (gcLen > length) { - for (i = 0; i < gcLen; ++i) { - delete cache.data[gc[i]]; - } - gc.splice(0, gcLen); - } - }); -} -function getTickMarkLength(options) { - return options.drawTicks ? options.tickLength : 0; -} -function getTitleHeight(options, fallback) { - if (!options.display) { - return 0; - } - const font = toFont(options.font, fallback); - const padding = toPadding(options.padding); - const lines = isArray(options.text) ? options.text.length : 1; - return (lines * font.lineHeight) + padding.height; -} -function createScaleContext(parent, scale) { - return createContext(parent, { - scale, - type: 'scale' - }); -} -function createTickContext(parent, index, tick) { - return createContext(parent, { - tick, - index, - type: 'tick' - }); -} -function titleAlign(align, position, reverse) { - let ret = _toLeftRightCenter(align); - if ((reverse && position !== 'right') || (!reverse && position === 'right')) { - ret = reverseAlign(ret); - } - return ret; -} -function titleArgs(scale, offset, position, align) { - const {top, left, bottom, right, chart} = scale; - const {chartArea, scales} = chart; - let rotation = 0; - let maxWidth, titleX, titleY; - const height = bottom - top; - const width = right - left; - if (scale.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; - } else if (position === 'center') { - titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; - } else { - titleY = offsetFromEdge(scale, position, offset); - } - maxWidth = right - left; - } else { - if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; - } else if (position === 'center') { - titleX = (chartArea.left + chartArea.right) / 2 - width + offset; - } else { - titleX = offsetFromEdge(scale, position, offset); - } - titleY = _alignStartEnd(align, bottom, top); - rotation = position === 'left' ? -HALF_PI : HALF_PI; - } - return {titleX, titleY, maxWidth, rotation}; -} -class Scale extends Element { - constructor(cfg) { - super(); - this.id = cfg.id; - this.type = cfg.type; - this.options = undefined; - this.ctx = cfg.ctx; - this.chart = cfg.chart; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this._margins = { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - this.maxWidth = undefined; - this.maxHeight = undefined; - this.paddingTop = undefined; - this.paddingBottom = undefined; - this.paddingLeft = undefined; - this.paddingRight = undefined; - this.axis = undefined; - this.labelRotation = undefined; - this.min = undefined; - this.max = undefined; - this._range = undefined; - this.ticks = []; - this._gridLineItems = null; - this._labelItems = null; - this._labelSizes = null; - this._length = 0; - this._maxLength = 0; - this._longestTextCache = {}; - this._startPixel = undefined; - this._endPixel = undefined; - this._reversePixels = false; - this._userMax = undefined; - this._userMin = undefined; - this._suggestedMax = undefined; - this._suggestedMin = undefined; - this._ticksLength = 0; - this._borderValue = 0; - this._cache = {}; - this._dataLimitsCached = false; - this.$context = undefined; - } - init(options) { - this.options = options.setContext(this.getContext()); - this.axis = options.axis; - this._userMin = this.parse(options.min); - this._userMax = this.parse(options.max); - this._suggestedMin = this.parse(options.suggestedMin); - this._suggestedMax = this.parse(options.suggestedMax); - } - parse(raw, index) { - return raw; - } - getUserBounds() { - let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this; - _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); - _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); - _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); - _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); - return { - min: finiteOrDefault(_userMin, _suggestedMin), - max: finiteOrDefault(_userMax, _suggestedMax), - minDefined: isNumberFinite(_userMin), - maxDefined: isNumberFinite(_userMax) - }; - } - getMinMax(canStack) { - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - let range; - if (minDefined && maxDefined) { - return {min, max}; - } - const metas = this.getMatchingVisibleMetas(); - for (let i = 0, ilen = metas.length; i < ilen; ++i) { - range = metas[i].controller.getMinMax(this, canStack); - if (!minDefined) { - min = Math.min(min, range.min); - } - if (!maxDefined) { - max = Math.max(max, range.max); - } - } - min = maxDefined && min > max ? max : min; - max = minDefined && min > max ? min : max; - return { - min: finiteOrDefault(min, finiteOrDefault(max, min)), - max: finiteOrDefault(max, finiteOrDefault(min, max)) - }; - } - getPadding() { - return { - left: this.paddingLeft || 0, - top: this.paddingTop || 0, - right: this.paddingRight || 0, - bottom: this.paddingBottom || 0 - }; - } - getTicks() { - return this.ticks; - } - getLabels() { - const data = this.chart.data; - return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; - } - beforeLayout() { - this._cache = {}; - this._dataLimitsCached = false; - } - beforeUpdate() { - callback(this.options.beforeUpdate, [this]); - } - update(maxWidth, maxHeight, margins) { - const {beginAtZero, grace, ticks: tickOpts} = this.options; - const sampleSize = tickOpts.sampleSize; - this.beforeUpdate(); - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins = Object.assign({ - left: 0, - right: 0, - top: 0, - bottom: 0 - }, margins); - this.ticks = null; - this._labelSizes = null; - this._gridLineItems = null; - this._labelItems = null; - this.beforeSetDimensions(); - this.setDimensions(); - this.afterSetDimensions(); - this._maxLength = this.isHorizontal() - ? this.width + margins.left + margins.right - : this.height + margins.top + margins.bottom; - if (!this._dataLimitsCached) { - this.beforeDataLimits(); - this.determineDataLimits(); - this.afterDataLimits(); - this._range = _addGrace(this, grace, beginAtZero); - this._dataLimitsCached = true; - } - this.beforeBuildTicks(); - this.ticks = this.buildTicks() || []; - this.afterBuildTicks(); - const samplingEnabled = sampleSize < this.ticks.length; - this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); - this.configure(); - this.beforeCalculateLabelRotation(); - this.calculateLabelRotation(); - this.afterCalculateLabelRotation(); - if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { - this.ticks = autoSkip(this, this.ticks); - this._labelSizes = null; - } - if (samplingEnabled) { - this._convertTicksToLabels(this.ticks); - } - this.beforeFit(); - this.fit(); - this.afterFit(); - this.afterUpdate(); - } - configure() { - let reversePixels = this.options.reverse; - let startPixel, endPixel; - if (this.isHorizontal()) { - startPixel = this.left; - endPixel = this.right; - } else { - startPixel = this.top; - endPixel = this.bottom; - reversePixels = !reversePixels; - } - this._startPixel = startPixel; - this._endPixel = endPixel; - this._reversePixels = reversePixels; - this._length = endPixel - startPixel; - this._alignToPixels = this.options.alignToPixels; - } - afterUpdate() { - callback(this.options.afterUpdate, [this]); - } - beforeSetDimensions() { - callback(this.options.beforeSetDimensions, [this]); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = 0; - this.right = this.width; - } else { - this.height = this.maxHeight; - this.top = 0; - this.bottom = this.height; - } - this.paddingLeft = 0; - this.paddingTop = 0; - this.paddingRight = 0; - this.paddingBottom = 0; - } - afterSetDimensions() { - callback(this.options.afterSetDimensions, [this]); - } - _callHooks(name) { - this.chart.notifyPlugins(name, this.getContext()); - callback(this.options[name], [this]); - } - beforeDataLimits() { - this._callHooks('beforeDataLimits'); - } - determineDataLimits() {} - afterDataLimits() { - this._callHooks('afterDataLimits'); - } - beforeBuildTicks() { - this._callHooks('beforeBuildTicks'); - } - buildTicks() { - return []; - } - afterBuildTicks() { - this._callHooks('afterBuildTicks'); - } - beforeTickToLabelConversion() { - callback(this.options.beforeTickToLabelConversion, [this]); - } - generateTickLabels(ticks) { - const tickOpts = this.options.ticks; - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - tick = ticks[i]; - tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this); - } - } - afterTickToLabelConversion() { - callback(this.options.afterTickToLabelConversion, [this]); - } - beforeCalculateLabelRotation() { - callback(this.options.beforeCalculateLabelRotation, [this]); - } - calculateLabelRotation() { - const options = this.options; - const tickOpts = options.ticks; - const numTicks = this.ticks.length; - const minRotation = tickOpts.minRotation || 0; - const maxRotation = tickOpts.maxRotation; - let labelRotation = minRotation; - let tickWidth, maxHeight, maxLabelDiagonal; - if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { - this.labelRotation = minRotation; - return; - } - const labelSizes = this._getLabelSizes(); - const maxLabelWidth = labelSizes.widest.width; - const maxLabelHeight = labelSizes.highest.height; - const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); - tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); - if (maxLabelWidth + 6 > tickWidth) { - tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); - maxHeight = this.maxHeight - getTickMarkLength(options.grid) - - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); - maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); - labelRotation = toDegrees(Math.min( - Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), - Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)) - )); - labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); - } - this.labelRotation = labelRotation; - } - afterCalculateLabelRotation() { - callback(this.options.afterCalculateLabelRotation, [this]); - } - beforeFit() { - callback(this.options.beforeFit, [this]); - } - fit() { - const minSize = { - width: 0, - height: 0 - }; - const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this; - const display = this._isVisible(); - const isHorizontal = this.isHorizontal(); - if (display) { - const titleHeight = getTitleHeight(titleOpts, chart.options.font); - if (isHorizontal) { - minSize.width = this.maxWidth; - minSize.height = getTickMarkLength(gridOpts) + titleHeight; - } else { - minSize.height = this.maxHeight; - minSize.width = getTickMarkLength(gridOpts) + titleHeight; - } - if (tickOpts.display && this.ticks.length) { - const {first, last, widest, highest} = this._getLabelSizes(); - const tickPadding = tickOpts.padding * 2; - const angleRadians = toRadians(this.labelRotation); - const cos = Math.cos(angleRadians); - const sin = Math.sin(angleRadians); - if (isHorizontal) { - const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; - minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); - } else { - const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; - minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); - } - this._calculatePadding(first, last, sin, cos); - } - } - this._handleMargins(); - if (isHorizontal) { - this.width = this._length = chart.width - this._margins.left - this._margins.right; - this.height = minSize.height; - } else { - this.width = minSize.width; - this.height = this._length = chart.height - this._margins.top - this._margins.bottom; - } - } - _calculatePadding(first, last, sin, cos) { - const {ticks: {align, padding}, position} = this.options; - const isRotated = this.labelRotation !== 0; - const labelsBelowTicks = position !== 'top' && this.axis === 'x'; - if (this.isHorizontal()) { - const offsetLeft = this.getPixelForTick(0) - this.left; - const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); - let paddingLeft = 0; - let paddingRight = 0; - if (isRotated) { - if (labelsBelowTicks) { - paddingLeft = cos * first.width; - paddingRight = sin * last.height; - } else { - paddingLeft = sin * first.height; - paddingRight = cos * last.width; - } - } else if (align === 'start') { - paddingRight = last.width; - } else if (align === 'end') { - paddingLeft = first.width; - } else { - paddingLeft = first.width / 2; - paddingRight = last.width / 2; - } - this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); - this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); - } else { - let paddingTop = last.height / 2; - let paddingBottom = first.height / 2; - if (align === 'start') { - paddingTop = 0; - paddingBottom = first.height; - } else if (align === 'end') { - paddingTop = last.height; - paddingBottom = 0; - } - this.paddingTop = paddingTop + padding; - this.paddingBottom = paddingBottom + padding; - } - } - _handleMargins() { - if (this._margins) { - this._margins.left = Math.max(this.paddingLeft, this._margins.left); - this._margins.top = Math.max(this.paddingTop, this._margins.top); - this._margins.right = Math.max(this.paddingRight, this._margins.right); - this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); - } - } - afterFit() { - callback(this.options.afterFit, [this]); - } - isHorizontal() { - const {axis, position} = this.options; - return position === 'top' || position === 'bottom' || axis === 'x'; - } - isFullSize() { - return this.options.fullSize; - } - _convertTicksToLabels(ticks) { - this.beforeTickToLabelConversion(); - this.generateTickLabels(ticks); - let i, ilen; - for (i = 0, ilen = ticks.length; i < ilen; i++) { - if (isNullOrUndef(ticks[i].label)) { - ticks.splice(i, 1); - ilen--; - i--; - } - } - this.afterTickToLabelConversion(); - } - _getLabelSizes() { - let labelSizes = this._labelSizes; - if (!labelSizes) { - const sampleSize = this.options.ticks.sampleSize; - let ticks = this.ticks; - if (sampleSize < ticks.length) { - ticks = sample(ticks, sampleSize); - } - this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length); - } - return labelSizes; - } - _computeLabelSizes(ticks, length) { - const {ctx, _longestTextCache: caches} = this; - const widths = []; - const heights = []; - let widestLabelSize = 0; - let highestLabelSize = 0; - let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; - for (i = 0; i < length; ++i) { - label = ticks[i].label; - tickFont = this._resolveTickFontOptions(i); - ctx.font = fontString = tickFont.string; - cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; - lineHeight = tickFont.lineHeight; - width = height = 0; - if (!isNullOrUndef(label) && !isArray(label)) { - width = _measureText(ctx, cache.data, cache.gc, width, label); - height = lineHeight; - } else if (isArray(label)) { - for (j = 0, jlen = label.length; j < jlen; ++j) { - nestedLabel = label[j]; - if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { - width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); - height += lineHeight; - } - } - } - widths.push(width); - heights.push(height); - widestLabelSize = Math.max(width, widestLabelSize); - highestLabelSize = Math.max(height, highestLabelSize); - } - garbageCollect(caches, length); - const widest = widths.indexOf(widestLabelSize); - const highest = heights.indexOf(highestLabelSize); - const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0}); - return { - first: valueAt(0), - last: valueAt(length - 1), - widest: valueAt(widest), - highest: valueAt(highest), - widths, - heights, - }; - } - getLabelForValue(value) { - return value; - } - getPixelForValue(value, index) { - return NaN; - } - getValueForPixel(pixel) {} - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getPixelForDecimal(decimal) { - if (this._reversePixels) { - decimal = 1 - decimal; - } - const pixel = this._startPixel + decimal * this._length; - return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); - } - getDecimalForPixel(pixel) { - const decimal = (pixel - this._startPixel) / this._length; - return this._reversePixels ? 1 - decimal : decimal; - } - getBasePixel() { - return this.getPixelForValue(this.getBaseValue()); - } - getBaseValue() { - const {min, max} = this; - return min < 0 && max < 0 ? max : - min > 0 && max > 0 ? min : - 0; - } - getContext(index) { - const ticks = this.ticks || []; - if (index >= 0 && index < ticks.length) { - const tick = ticks[index]; - return tick.$context || - (tick.$context = createTickContext(this.getContext(), index, tick)); - } - return this.$context || - (this.$context = createScaleContext(this.chart.getContext(), this)); - } - _tickSize() { - const optionTicks = this.options.ticks; - const rot = toRadians(this.labelRotation); - const cos = Math.abs(Math.cos(rot)); - const sin = Math.abs(Math.sin(rot)); - const labelSizes = this._getLabelSizes(); - const padding = optionTicks.autoSkipPadding || 0; - const w = labelSizes ? labelSizes.widest.width + padding : 0; - const h = labelSizes ? labelSizes.highest.height + padding : 0; - return this.isHorizontal() - ? h * cos > w * sin ? w / cos : h / sin - : h * sin < w * cos ? h / cos : w / sin; - } - _isVisible() { - const display = this.options.display; - if (display !== 'auto') { - return !!display; - } - return this.getMatchingVisibleMetas().length > 0; - } - _computeGridLineItems(chartArea) { - const axis = this.axis; - const chart = this.chart; - const options = this.options; - const {grid, position} = options; - const offset = grid.offset; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const ticksLength = ticks.length + (offset ? 1 : 0); - const tl = getTickMarkLength(grid); - const items = []; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0; - const axisHalfWidth = axisWidth / 2; - const alignBorderValue = function(pixel) { - return _alignPixel(chart, pixel, axisWidth); - }; - let borderValue, i, lineValue, alignedLineValue; - let tx1, ty1, tx2, ty2, x1, y1, x2, y2; - if (position === 'top') { - borderValue = alignBorderValue(this.bottom); - ty1 = this.bottom - tl; - ty2 = borderValue - axisHalfWidth; - y1 = alignBorderValue(chartArea.top) + axisHalfWidth; - y2 = chartArea.bottom; - } else if (position === 'bottom') { - borderValue = alignBorderValue(this.top); - y1 = chartArea.top; - y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; - ty1 = borderValue + axisHalfWidth; - ty2 = this.top + tl; - } else if (position === 'left') { - borderValue = alignBorderValue(this.right); - tx1 = this.right - tl; - tx2 = borderValue - axisHalfWidth; - x1 = alignBorderValue(chartArea.left) + axisHalfWidth; - x2 = chartArea.right; - } else if (position === 'right') { - borderValue = alignBorderValue(this.left); - x1 = chartArea.left; - x2 = alignBorderValue(chartArea.right) - axisHalfWidth; - tx1 = borderValue + axisHalfWidth; - tx2 = this.left + tl; - } else if (axis === 'x') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - y1 = chartArea.top; - y2 = chartArea.bottom; - ty1 = borderValue + axisHalfWidth; - ty2 = ty1 + tl; - } else if (axis === 'y') { - if (position === 'center') { - borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); - } - tx1 = borderValue - axisHalfWidth; - tx2 = tx1 - tl; - x1 = chartArea.left; - x2 = chartArea.right; - } - const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); - const step = Math.max(1, Math.ceil(ticksLength / limit)); - for (i = 0; i < ticksLength; i += step) { - const optsAtIndex = grid.setContext(this.getContext(i)); - const lineWidth = optsAtIndex.lineWidth; - const lineColor = optsAtIndex.color; - const borderDash = grid.borderDash || []; - const borderDashOffset = optsAtIndex.borderDashOffset; - const tickWidth = optsAtIndex.tickWidth; - const tickColor = optsAtIndex.tickColor; - const tickBorderDash = optsAtIndex.tickBorderDash || []; - const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; - lineValue = getPixelForGridLine(this, i, offset); - if (lineValue === undefined) { - continue; - } - alignedLineValue = _alignPixel(chart, lineValue, lineWidth); - if (isHorizontal) { - tx1 = tx2 = x1 = x2 = alignedLineValue; - } else { - ty1 = ty2 = y1 = y2 = alignedLineValue; - } - items.push({ - tx1, - ty1, - tx2, - ty2, - x1, - y1, - x2, - y2, - width: lineWidth, - color: lineColor, - borderDash, - borderDashOffset, - tickWidth, - tickColor, - tickBorderDash, - tickBorderDashOffset, - }); - } - this._ticksLength = ticksLength; - this._borderValue = borderValue; - return items; - } - _computeLabelItems(chartArea) { - const axis = this.axis; - const options = this.options; - const {position, ticks: optionTicks} = options; - const isHorizontal = this.isHorizontal(); - const ticks = this.ticks; - const {align, crossAlign, padding, mirror} = optionTicks; - const tl = getTickMarkLength(options.grid); - const tickAndPadding = tl + padding; - const hTickAndPadding = mirror ? -padding : tickAndPadding; - const rotation = -toRadians(this.labelRotation); - const items = []; - let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; - let textBaseline = 'middle'; - if (position === 'top') { - y = this.bottom - hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'bottom') { - y = this.top + hTickAndPadding; - textAlign = this._getXAxisLabelAlignment(); - } else if (position === 'left') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (position === 'right') { - const ret = this._getYAxisLabelAlignment(tl); - textAlign = ret.textAlign; - x = ret.x; - } else if (axis === 'x') { - if (position === 'center') { - y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; - } - textAlign = this._getXAxisLabelAlignment(); - } else if (axis === 'y') { - if (position === 'center') { - x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding; - } else if (isObject(position)) { - const positionAxisID = Object.keys(position)[0]; - const value = position[positionAxisID]; - x = this.chart.scales[positionAxisID].getPixelForValue(value); - } - textAlign = this._getYAxisLabelAlignment(tl).textAlign; - } - if (axis === 'y') { - if (align === 'start') { - textBaseline = 'top'; - } else if (align === 'end') { - textBaseline = 'bottom'; - } - } - const labelSizes = this._getLabelSizes(); - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - label = tick.label; - const optsAtIndex = optionTicks.setContext(this.getContext(i)); - pixel = this.getPixelForTick(i) + optionTicks.labelOffset; - font = this._resolveTickFontOptions(i); - lineHeight = font.lineHeight; - lineCount = isArray(label) ? label.length : 1; - const halfCount = lineCount / 2; - const color = optsAtIndex.color; - const strokeColor = optsAtIndex.textStrokeColor; - const strokeWidth = optsAtIndex.textStrokeWidth; - if (isHorizontal) { - x = pixel; - if (position === 'top') { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = -lineCount * lineHeight + lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; - } else { - textOffset = -labelSizes.highest.height + lineHeight / 2; - } - } else { - if (crossAlign === 'near' || rotation !== 0) { - textOffset = lineHeight / 2; - } else if (crossAlign === 'center') { - textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; - } else { - textOffset = labelSizes.highest.height - lineCount * lineHeight; - } - } - if (mirror) { - textOffset *= -1; - } - } else { - y = pixel; - textOffset = (1 - lineCount) * lineHeight / 2; - } - let backdrop; - if (optsAtIndex.showLabelBackdrop) { - const labelPadding = toPadding(optsAtIndex.backdropPadding); - const height = labelSizes.heights[i]; - const width = labelSizes.widths[i]; - let top = y + textOffset - labelPadding.top; - let left = x - labelPadding.left; - switch (textBaseline) { - case 'middle': - top -= height / 2; - break; - case 'bottom': - top -= height; - break; - } - switch (textAlign) { - case 'center': - left -= width / 2; - break; - case 'right': - left -= width; - break; - } - backdrop = { - left, - top, - width: width + labelPadding.width, - height: height + labelPadding.height, - color: optsAtIndex.backdropColor, - }; - } - items.push({ - rotation, - label, - font, - color, - strokeColor, - strokeWidth, - textOffset, - textAlign, - textBaseline, - translation: [x, y], - backdrop, - }); - } - return items; - } - _getXAxisLabelAlignment() { - const {position, ticks} = this.options; - const rotation = -toRadians(this.labelRotation); - if (rotation) { - return position === 'top' ? 'left' : 'right'; - } - let align = 'center'; - if (ticks.align === 'start') { - align = 'left'; - } else if (ticks.align === 'end') { - align = 'right'; - } - return align; - } - _getYAxisLabelAlignment(tl) { - const {position, ticks: {crossAlign, mirror, padding}} = this.options; - const labelSizes = this._getLabelSizes(); - const tickAndPadding = tl + padding; - const widest = labelSizes.widest.width; - let textAlign; - let x; - if (position === 'left') { - if (mirror) { - x = this.right + padding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += (widest / 2); - } else { - textAlign = 'right'; - x += widest; - } - } else { - x = this.right - tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x = this.left; - } - } - } else if (position === 'right') { - if (mirror) { - x = this.left + padding; - if (crossAlign === 'near') { - textAlign = 'right'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x -= (widest / 2); - } else { - textAlign = 'left'; - x -= widest; - } - } else { - x = this.left + tickAndPadding; - if (crossAlign === 'near') { - textAlign = 'left'; - } else if (crossAlign === 'center') { - textAlign = 'center'; - x += widest / 2; - } else { - textAlign = 'right'; - x = this.right; - } - } - } else { - textAlign = 'right'; - } - return {textAlign, x}; - } - _computeLabelArea() { - if (this.options.ticks.mirror) { - return; - } - const chart = this.chart; - const position = this.options.position; - if (position === 'left' || position === 'right') { - return {top: 0, left: this.left, bottom: chart.height, right: this.right}; - } if (position === 'top' || position === 'bottom') { - return {top: this.top, left: 0, bottom: this.bottom, right: chart.width}; - } - } - drawBackground() { - const {ctx, options: {backgroundColor}, left, top, width, height} = this; - if (backgroundColor) { - ctx.save(); - ctx.fillStyle = backgroundColor; - ctx.fillRect(left, top, width, height); - ctx.restore(); - } - } - getLineWidthForValue(value) { - const grid = this.options.grid; - if (!this._isVisible() || !grid.display) { - return 0; - } - const ticks = this.ticks; - const index = ticks.findIndex(t => t.value === value); - if (index >= 0) { - const opts = grid.setContext(this.getContext(index)); - return opts.lineWidth; - } - return 0; - } - drawGrid(chartArea) { - const grid = this.options.grid; - const ctx = this.ctx; - const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); - let i, ilen; - const drawLine = (p1, p2, style) => { - if (!style.width || !style.color) { - return; - } - ctx.save(); - ctx.lineWidth = style.width; - ctx.strokeStyle = style.color; - ctx.setLineDash(style.borderDash || []); - ctx.lineDashOffset = style.borderDashOffset; - ctx.beginPath(); - ctx.moveTo(p1.x, p1.y); - ctx.lineTo(p2.x, p2.y); - ctx.stroke(); - ctx.restore(); - }; - if (grid.display) { - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - if (grid.drawOnChartArea) { - drawLine( - {x: item.x1, y: item.y1}, - {x: item.x2, y: item.y2}, - item - ); - } - if (grid.drawTicks) { - drawLine( - {x: item.tx1, y: item.ty1}, - {x: item.tx2, y: item.ty2}, - { - color: item.tickColor, - width: item.tickWidth, - borderDash: item.tickBorderDash, - borderDashOffset: item.tickBorderDashOffset - } - ); - } - } - } - } - drawBorder() { - const {chart, ctx, options: {grid}} = this; - const borderOpts = grid.setContext(this.getContext()); - const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0; - if (!axisWidth) { - return; - } - const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; - const borderValue = this._borderValue; - let x1, x2, y1, y2; - if (this.isHorizontal()) { - x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; - x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; - y1 = y2 = borderValue; - } else { - y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; - y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; - x1 = x2 = borderValue; - } - ctx.save(); - ctx.lineWidth = borderOpts.borderWidth; - ctx.strokeStyle = borderOpts.borderColor; - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); - ctx.restore(); - } - drawLabels(chartArea) { - const optionTicks = this.options.ticks; - if (!optionTicks.display) { - return; - } - const ctx = this.ctx; - const area = this._computeLabelArea(); - if (area) { - clipArea(ctx, area); - } - const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - const item = items[i]; - const tickFont = item.font; - const label = item.label; - if (item.backdrop) { - ctx.fillStyle = item.backdrop.color; - ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); - } - let y = item.textOffset; - renderText(ctx, label, 0, y, tickFont, item); - } - if (area) { - unclipArea(ctx); - } - } - drawTitle() { - const {ctx, options: {position, title, reverse}} = this; - if (!title.display) { - return; - } - const font = toFont(title.font); - const padding = toPadding(title.padding); - const align = title.align; - let offset = font.lineHeight / 2; - if (position === 'bottom' || position === 'center' || isObject(position)) { - offset += padding.bottom; - if (isArray(title.text)) { - offset += font.lineHeight * (title.text.length - 1); - } - } else { - offset += padding.top; - } - const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align); - renderText(ctx, title.text, 0, 0, font, { - color: title.color, - maxWidth, - rotation, - textAlign: titleAlign(align, position, reverse), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } - draw(chartArea) { - if (!this._isVisible()) { - return; - } - this.drawBackground(); - this.drawGrid(chartArea); - this.drawBorder(); - this.drawTitle(); - this.drawLabels(chartArea); - } - _layers() { - const opts = this.options; - const tz = opts.ticks && opts.ticks.z || 0; - const gz = valueOrDefault(opts.grid && opts.grid.z, -1); - if (!this._isVisible() || this.draw !== Scale.prototype.draw) { - return [{ - z: tz, - draw: (chartArea) => { - this.draw(chartArea); - } - }]; - } - return [{ - z: gz, - draw: (chartArea) => { - this.drawBackground(); - this.drawGrid(chartArea); - this.drawTitle(); - } - }, { - z: gz + 1, - draw: () => { - this.drawBorder(); - } - }, { - z: tz, - draw: (chartArea) => { - this.drawLabels(chartArea); - } - }]; - } - getMatchingVisibleMetas(type) { - const metas = this.chart.getSortedVisibleDatasetMetas(); - const axisID = this.axis + 'AxisID'; - const result = []; - let i, ilen; - for (i = 0, ilen = metas.length; i < ilen; ++i) { - const meta = metas[i]; - if (meta[axisID] === this.id && (!type || meta.type === type)) { - result.push(meta); - } - } - return result; - } - _resolveTickFontOptions(index) { - const opts = this.options.ticks.setContext(this.getContext(index)); - return toFont(opts.font); - } - _maxDigits() { - const fontSize = this._resolveTickFontOptions(0).lineHeight; - return (this.isHorizontal() ? this.width : this.height) / fontSize; - } -} - -class TypedRegistry { - constructor(type, scope, override) { - this.type = type; - this.scope = scope; - this.override = override; - this.items = Object.create(null); - } - isForType(type) { - return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); - } - register(item) { - const proto = Object.getPrototypeOf(item); - let parentScope; - if (isIChartComponent(proto)) { - parentScope = this.register(proto); - } - const items = this.items; - const id = item.id; - const scope = this.scope + '.' + id; - if (!id) { - throw new Error('class does not have id: ' + item); - } - if (id in items) { - return scope; - } - items[id] = item; - registerDefaults(item, scope, parentScope); - if (this.override) { - defaults.override(item.id, item.overrides); - } - return scope; - } - get(id) { - return this.items[id]; - } - unregister(item) { - const items = this.items; - const id = item.id; - const scope = this.scope; - if (id in items) { - delete items[id]; - } - if (scope && id in defaults[scope]) { - delete defaults[scope][id]; - if (this.override) { - delete overrides[id]; - } - } - } -} -function registerDefaults(item, scope, parentScope) { - const itemDefaults = merge(Object.create(null), [ - parentScope ? defaults.get(parentScope) : {}, - defaults.get(scope), - item.defaults - ]); - defaults.set(scope, itemDefaults); - if (item.defaultRoutes) { - routeDefaults(scope, item.defaultRoutes); - } - if (item.descriptors) { - defaults.describe(scope, item.descriptors); - } -} -function routeDefaults(scope, routes) { - Object.keys(routes).forEach(property => { - const propertyParts = property.split('.'); - const sourceName = propertyParts.pop(); - const sourceScope = [scope].concat(propertyParts).join('.'); - const parts = routes[property].split('.'); - const targetName = parts.pop(); - const targetScope = parts.join('.'); - defaults.route(sourceScope, sourceName, targetScope, targetName); - }); -} -function isIChartComponent(proto) { - return 'id' in proto && 'defaults' in proto; -} - -class Registry { - constructor() { - this.controllers = new TypedRegistry(DatasetController, 'datasets', true); - this.elements = new TypedRegistry(Element, 'elements'); - this.plugins = new TypedRegistry(Object, 'plugins'); - this.scales = new TypedRegistry(Scale, 'scales'); - this._typedRegistries = [this.controllers, this.scales, this.elements]; - } - add(...args) { - this._each('register', args); - } - remove(...args) { - this._each('unregister', args); - } - addControllers(...args) { - this._each('register', args, this.controllers); - } - addElements(...args) { - this._each('register', args, this.elements); - } - addPlugins(...args) { - this._each('register', args, this.plugins); - } - addScales(...args) { - this._each('register', args, this.scales); - } - getController(id) { - return this._get(id, this.controllers, 'controller'); - } - getElement(id) { - return this._get(id, this.elements, 'element'); - } - getPlugin(id) { - return this._get(id, this.plugins, 'plugin'); - } - getScale(id) { - return this._get(id, this.scales, 'scale'); - } - removeControllers(...args) { - this._each('unregister', args, this.controllers); - } - removeElements(...args) { - this._each('unregister', args, this.elements); - } - removePlugins(...args) { - this._each('unregister', args, this.plugins); - } - removeScales(...args) { - this._each('unregister', args, this.scales); - } - _each(method, args, typedRegistry) { - [...args].forEach(arg => { - const reg = typedRegistry || this._getRegistryForType(arg); - if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) { - this._exec(method, reg, arg); - } else { - each(arg, item => { - const itemReg = typedRegistry || this._getRegistryForType(item); - this._exec(method, itemReg, item); - }); - } - }); - } - _exec(method, registry, component) { - const camelMethod = _capitalize(method); - callback(component['before' + camelMethod], [], component); - registry[method](component); - callback(component['after' + camelMethod], [], component); - } - _getRegistryForType(type) { - for (let i = 0; i < this._typedRegistries.length; i++) { - const reg = this._typedRegistries[i]; - if (reg.isForType(type)) { - return reg; - } - } - return this.plugins; - } - _get(id, typedRegistry, type) { - const item = typedRegistry.get(id); - if (item === undefined) { - throw new Error('"' + id + '" is not a registered ' + type + '.'); - } - return item; - } -} -var registry = new Registry(); - -class PluginService { - constructor() { - this._init = []; - } - notify(chart, hook, args, filter) { - if (hook === 'beforeInit') { - this._init = this._createDescriptors(chart, true); - this._notify(this._init, chart, 'install'); - } - const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); - const result = this._notify(descriptors, chart, hook, args); - if (hook === 'afterDestroy') { - this._notify(descriptors, chart, 'stop'); - this._notify(this._init, chart, 'uninstall'); - } - return result; - } - _notify(descriptors, chart, hook, args) { - args = args || {}; - for (const descriptor of descriptors) { - const plugin = descriptor.plugin; - const method = plugin[hook]; - const params = [chart, args, descriptor.options]; - if (callback(method, params, plugin) === false && args.cancelable) { - return false; - } - } - return true; - } - invalidate() { - if (!isNullOrUndef(this._cache)) { - this._oldCache = this._cache; - this._cache = undefined; - } - } - _descriptors(chart) { - if (this._cache) { - return this._cache; - } - const descriptors = this._cache = this._createDescriptors(chart); - this._notifyStateChanges(chart); - return descriptors; - } - _createDescriptors(chart, all) { - const config = chart && chart.config; - const options = valueOrDefault(config.options && config.options.plugins, {}); - const plugins = allPlugins(config); - return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); - } - _notifyStateChanges(chart) { - const previousDescriptors = this._oldCache || []; - const descriptors = this._cache; - const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id)); - this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); - this._notify(diff(descriptors, previousDescriptors), chart, 'start'); - } -} -function allPlugins(config) { - const plugins = []; - const keys = Object.keys(registry.plugins.items); - for (let i = 0; i < keys.length; i++) { - plugins.push(registry.getPlugin(keys[i])); - } - const local = config.plugins || []; - for (let i = 0; i < local.length; i++) { - const plugin = local[i]; - if (plugins.indexOf(plugin) === -1) { - plugins.push(plugin); - } - } - return plugins; -} -function getOpts(options, all) { - if (!all && options === false) { - return null; - } - if (options === true) { - return {}; - } - return options; -} -function createDescriptors(chart, plugins, options, all) { - const result = []; - const context = chart.getContext(); - for (let i = 0; i < plugins.length; i++) { - const plugin = plugins[i]; - const id = plugin.id; - const opts = getOpts(options[id], all); - if (opts === null) { - continue; - } - result.push({ - plugin, - options: pluginOpts(chart.config, plugin, opts, context) - }); - } - return result; -} -function pluginOpts(config, plugin, opts, context) { - const keys = config.pluginScopeKeys(plugin); - const scopes = config.getOptionScopes(opts, keys); - return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true}); -} - -function getIndexAxis(type, options) { - const datasetDefaults = defaults.datasets[type] || {}; - const datasetOptions = (options.datasets || {})[type] || {}; - return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; -} -function getAxisFromDefaultScaleID(id, indexAxis) { - let axis = id; - if (id === '_index_') { - axis = indexAxis; - } else if (id === '_value_') { - axis = indexAxis === 'x' ? 'y' : 'x'; - } - return axis; -} -function getDefaultScaleIDFromAxis(axis, indexAxis) { - return axis === indexAxis ? '_index_' : '_value_'; -} -function axisFromPosition(position) { - if (position === 'top' || position === 'bottom') { - return 'x'; - } - if (position === 'left' || position === 'right') { - return 'y'; - } -} -function determineAxis(id, scaleOptions) { - if (id === 'x' || id === 'y') { - return id; - } - return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); -} -function mergeScaleConfig(config, options) { - const chartDefaults = overrides[config.type] || {scales: {}}; - const configScales = options.scales || {}; - const chartIndexAxis = getIndexAxis(config.type, options); - const firstIDs = Object.create(null); - const scales = Object.create(null); - Object.keys(configScales).forEach(id => { - const scaleConf = configScales[id]; - if (!isObject(scaleConf)) { - return console.error(`Invalid scale configuration for scale: ${id}`); - } - if (scaleConf._proxy) { - return console.warn(`Ignoring resolver passed as options for scale: ${id}`); - } - const axis = determineAxis(id, scaleConf); - const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); - const defaultScaleOptions = chartDefaults.scales || {}; - firstIDs[axis] = firstIDs[axis] || id; - scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]); - }); - config.data.datasets.forEach(dataset => { - const type = dataset.type || config.type; - const indexAxis = dataset.indexAxis || getIndexAxis(type, options); - const datasetDefaults = overrides[type] || {}; - const defaultScaleOptions = datasetDefaults.scales || {}; - Object.keys(defaultScaleOptions).forEach(defaultID => { - const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); - const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; - scales[id] = scales[id] || Object.create(null); - mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); - }); - }); - Object.keys(scales).forEach(key => { - const scale = scales[key]; - mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); - }); - return scales; -} -function initOptions(config) { - const options = config.options || (config.options = {}); - options.plugins = valueOrDefault(options.plugins, {}); - options.scales = mergeScaleConfig(config, options); -} -function initData(data) { - data = data || {}; - data.datasets = data.datasets || []; - data.labels = data.labels || []; - return data; -} -function initConfig(config) { - config = config || {}; - config.data = initData(config.data); - initOptions(config); - return config; -} -const keyCache = new Map(); -const keysCached = new Set(); -function cachedKeys(cacheKey, generate) { - let keys = keyCache.get(cacheKey); - if (!keys) { - keys = generate(); - keyCache.set(cacheKey, keys); - keysCached.add(keys); - } - return keys; -} -const addIfFound = (set, obj, key) => { - const opts = resolveObjectKey(obj, key); - if (opts !== undefined) { - set.add(opts); - } -}; -class Config { - constructor(config) { - this._config = initConfig(config); - this._scopeCache = new Map(); - this._resolverCache = new Map(); - } - get platform() { - return this._config.platform; - } - get type() { - return this._config.type; - } - set type(type) { - this._config.type = type; - } - get data() { - return this._config.data; - } - set data(data) { - this._config.data = initData(data); - } - get options() { - return this._config.options; - } - set options(options) { - this._config.options = options; - } - get plugins() { - return this._config.plugins; - } - update() { - const config = this._config; - this.clearCache(); - initOptions(config); - } - clearCache() { - this._scopeCache.clear(); - this._resolverCache.clear(); - } - datasetScopeKeys(datasetType) { - return cachedKeys(datasetType, - () => [[ - `datasets.${datasetType}`, - '' - ]]); - } - datasetAnimationScopeKeys(datasetType, transition) { - return cachedKeys(`${datasetType}.transition.${transition}`, - () => [ - [ - `datasets.${datasetType}.transitions.${transition}`, - `transitions.${transition}`, - ], - [ - `datasets.${datasetType}`, - '' - ] - ]); - } - datasetElementScopeKeys(datasetType, elementType) { - return cachedKeys(`${datasetType}-${elementType}`, - () => [[ - `datasets.${datasetType}.elements.${elementType}`, - `datasets.${datasetType}`, - `elements.${elementType}`, - '' - ]]); - } - pluginScopeKeys(plugin) { - const id = plugin.id; - const type = this.type; - return cachedKeys(`${type}-plugin-${id}`, - () => [[ - `plugins.${id}`, - ...plugin.additionalOptionScopes || [], - ]]); - } - _cachedScopes(mainScope, resetCache) { - const _scopeCache = this._scopeCache; - let cache = _scopeCache.get(mainScope); - if (!cache || resetCache) { - cache = new Map(); - _scopeCache.set(mainScope, cache); - } - return cache; - } - getOptionScopes(mainScope, keyLists, resetCache) { - const {options, type} = this; - const cache = this._cachedScopes(mainScope, resetCache); - const cached = cache.get(keyLists); - if (cached) { - return cached; - } - const scopes = new Set(); - keyLists.forEach(keys => { - if (mainScope) { - scopes.add(mainScope); - keys.forEach(key => addIfFound(scopes, mainScope, key)); - } - keys.forEach(key => addIfFound(scopes, options, key)); - keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key)); - keys.forEach(key => addIfFound(scopes, defaults, key)); - keys.forEach(key => addIfFound(scopes, descriptors, key)); - }); - const array = Array.from(scopes); - if (array.length === 0) { - array.push(Object.create(null)); - } - if (keysCached.has(keyLists)) { - cache.set(keyLists, array); - } - return array; - } - chartOptionScopes() { - const {options, type} = this; - return [ - options, - overrides[type] || {}, - defaults.datasets[type] || {}, - {type}, - defaults, - descriptors - ]; - } - resolveNamedOptions(scopes, names, context, prefixes = ['']) { - const result = {$shared: true}; - const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes); - let options = resolver; - if (needContext(resolver, names)) { - result.$shared = false; - context = isFunction(context) ? context() : context; - const subResolver = this.createResolver(scopes, context, subPrefixes); - options = _attachContext(resolver, context, subResolver); - } - for (const prop of names) { - result[prop] = options[prop]; - } - return result; - } - createResolver(scopes, context, prefixes = [''], descriptorDefaults) { - const {resolver} = getResolver(this._resolverCache, scopes, prefixes); - return isObject(context) - ? _attachContext(resolver, context, undefined, descriptorDefaults) - : resolver; - } -} -function getResolver(resolverCache, scopes, prefixes) { - let cache = resolverCache.get(scopes); - if (!cache) { - cache = new Map(); - resolverCache.set(scopes, cache); - } - const cacheKey = prefixes.join(); - let cached = cache.get(cacheKey); - if (!cached) { - const resolver = _createResolver(scopes, prefixes); - cached = { - resolver, - subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover')) - }; - cache.set(cacheKey, cached); - } - return cached; -} -const hasFunction = value => isObject(value) - && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false); -function needContext(proxy, names) { - const {isScriptable, isIndexable} = _descriptors(proxy); - for (const prop of names) { - const scriptable = isScriptable(prop); - const indexable = isIndexable(prop); - const value = (indexable || scriptable) && proxy[prop]; - if ((scriptable && (isFunction(value) || hasFunction(value))) - || (indexable && isArray(value))) { - return true; - } - } - return false; -} - -var version = "3.7.1"; - -const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; -function positionIsHorizontal(position, axis) { - return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); -} -function compare2Level(l1, l2) { - return function(a, b) { - return a[l1] === b[l1] - ? a[l2] - b[l2] - : a[l1] - b[l1]; - }; -} -function onAnimationsComplete(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - chart.notifyPlugins('afterRender'); - callback(animationOptions && animationOptions.onComplete, [context], chart); -} -function onAnimationProgress(context) { - const chart = context.chart; - const animationOptions = chart.options.animation; - callback(animationOptions && animationOptions.onProgress, [context], chart); -} -function getCanvas(item) { - if (_isDomSupported() && typeof item === 'string') { - item = document.getElementById(item); - } else if (item && item.length) { - item = item[0]; - } - if (item && item.canvas) { - item = item.canvas; - } - return item; -} -const instances = {}; -const getChart = (key) => { - const canvas = getCanvas(key); - return Object.values(instances).filter((c) => c.canvas === canvas).pop(); -}; -function moveNumericKeys(obj, start, move) { - const keys = Object.keys(obj); - for (const key of keys) { - const intKey = +key; - if (intKey >= start) { - const value = obj[key]; - delete obj[key]; - if (move > 0 || intKey > start) { - obj[intKey + move] = value; - } - } - } -} -function determineLastEvent(e, lastEvent, inChartArea, isClick) { - if (!inChartArea || e.type === 'mouseout') { - return null; - } - if (isClick) { - return lastEvent; - } - return e; -} -class Chart { - constructor(item, userConfig) { - const config = this.config = new Config(userConfig); - const initialCanvas = getCanvas(item); - const existingChart = getChart(initialCanvas); - if (existingChart) { - throw new Error( - 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + - ' must be destroyed before the canvas can be reused.' - ); - } - const options = config.createResolver(config.chartOptionScopes(), this.getContext()); - this.platform = new (config.platform || _detectPlatform(initialCanvas))(); - this.platform.updateConfig(config); - const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); - const canvas = context && context.canvas; - const height = canvas && canvas.height; - const width = canvas && canvas.width; - this.id = uid(); - this.ctx = context; - this.canvas = canvas; - this.width = width; - this.height = height; - this._options = options; - this._aspectRatio = this.aspectRatio; - this._layers = []; - this._metasets = []; - this._stacks = undefined; - this.boxes = []; - this.currentDevicePixelRatio = undefined; - this.chartArea = undefined; - this._active = []; - this._lastEvent = undefined; - this._listeners = {}; - this._responsiveListeners = undefined; - this._sortedMetasets = []; - this.scales = {}; - this._plugins = new PluginService(); - this.$proxies = {}; - this._hiddenIndices = {}; - this.attached = false; - this._animationsDisabled = undefined; - this.$context = undefined; - this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0); - this._dataChanges = []; - instances[this.id] = this; - if (!context || !canvas) { - console.error("Failed to create chart: can't acquire context from the given item"); - return; - } - animator.listen(this, 'complete', onAnimationsComplete); - animator.listen(this, 'progress', onAnimationProgress); - this._initialize(); - if (this.attached) { - this.update(); - } - } - get aspectRatio() { - const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this; - if (!isNullOrUndef(aspectRatio)) { - return aspectRatio; - } - if (maintainAspectRatio && _aspectRatio) { - return _aspectRatio; - } - return height ? width / height : null; - } - get data() { - return this.config.data; - } - set data(data) { - this.config.data = data; - } - get options() { - return this._options; - } - set options(options) { - this.config.options = options; - } - _initialize() { - this.notifyPlugins('beforeInit'); - if (this.options.responsive) { - this.resize(); - } else { - retinaScale(this, this.options.devicePixelRatio); - } - this.bindEvents(); - this.notifyPlugins('afterInit'); - return this; - } - clear() { - clearCanvas(this.canvas, this.ctx); - return this; - } - stop() { - animator.stop(this); - return this; - } - resize(width, height) { - if (!animator.running(this)) { - this._resize(width, height); - } else { - this._resizeBeforeDraw = {width, height}; - } - } - _resize(width, height) { - const options = this.options; - const canvas = this.canvas; - const aspectRatio = options.maintainAspectRatio && this.aspectRatio; - const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); - const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); - const mode = this.width ? 'resize' : 'attach'; - this.width = newSize.width; - this.height = newSize.height; - this._aspectRatio = this.aspectRatio; - if (!retinaScale(this, newRatio, true)) { - return; - } - this.notifyPlugins('resize', {size: newSize}); - callback(options.onResize, [this, newSize], this); - if (this.attached) { - if (this._doResize(mode)) { - this.render(); - } - } - } - ensureScalesHaveIDs() { - const options = this.options; - const scalesOptions = options.scales || {}; - each(scalesOptions, (axisOptions, axisID) => { - axisOptions.id = axisID; - }); - } - buildOrUpdateScales() { - const options = this.options; - const scaleOpts = options.scales; - const scales = this.scales; - const updated = Object.keys(scales).reduce((obj, id) => { - obj[id] = false; - return obj; - }, {}); - let items = []; - if (scaleOpts) { - items = items.concat( - Object.keys(scaleOpts).map((id) => { - const scaleOptions = scaleOpts[id]; - const axis = determineAxis(id, scaleOptions); - const isRadial = axis === 'r'; - const isHorizontal = axis === 'x'; - return { - options: scaleOptions, - dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', - dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' - }; - }) - ); - } - each(items, (item) => { - const scaleOptions = item.options; - const id = scaleOptions.id; - const axis = determineAxis(id, scaleOptions); - const scaleType = valueOrDefault(scaleOptions.type, item.dtype); - if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { - scaleOptions.position = item.dposition; - } - updated[id] = true; - let scale = null; - if (id in scales && scales[id].type === scaleType) { - scale = scales[id]; - } else { - const scaleClass = registry.getScale(scaleType); - scale = new scaleClass({ - id, - type: scaleType, - ctx: this.ctx, - chart: this - }); - scales[scale.id] = scale; - } - scale.init(scaleOptions, options); - }); - each(updated, (hasUpdated, id) => { - if (!hasUpdated) { - delete scales[id]; - } - }); - each(scales, (scale) => { - layouts.configure(this, scale, scale.options); - layouts.addBox(this, scale); - }); - } - _updateMetasets() { - const metasets = this._metasets; - const numData = this.data.datasets.length; - const numMeta = metasets.length; - metasets.sort((a, b) => a.index - b.index); - if (numMeta > numData) { - for (let i = numData; i < numMeta; ++i) { - this._destroyDatasetMeta(i); - } - metasets.splice(numData, numMeta - numData); - } - this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); - } - _removeUnreferencedMetasets() { - const {_metasets: metasets, data: {datasets}} = this; - if (metasets.length > datasets.length) { - delete this._stacks; - } - metasets.forEach((meta, index) => { - if (datasets.filter(x => x === meta._dataset).length === 0) { - this._destroyDatasetMeta(index); - } - }); - } - buildOrUpdateControllers() { - const newControllers = []; - const datasets = this.data.datasets; - let i, ilen; - this._removeUnreferencedMetasets(); - for (i = 0, ilen = datasets.length; i < ilen; i++) { - const dataset = datasets[i]; - let meta = this.getDatasetMeta(i); - const type = dataset.type || this.config.type; - if (meta.type && meta.type !== type) { - this._destroyDatasetMeta(i); - meta = this.getDatasetMeta(i); - } - meta.type = type; - meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); - meta.order = dataset.order || 0; - meta.index = i; - meta.label = '' + dataset.label; - meta.visible = this.isDatasetVisible(i); - if (meta.controller) { - meta.controller.updateIndex(i); - meta.controller.linkScales(); - } else { - const ControllerClass = registry.getController(type); - const {datasetElementType, dataElementType} = defaults.datasets[type]; - Object.assign(ControllerClass.prototype, { - dataElementType: registry.getElement(dataElementType), - datasetElementType: datasetElementType && registry.getElement(datasetElementType) - }); - meta.controller = new ControllerClass(this, i); - newControllers.push(meta.controller); - } - } - this._updateMetasets(); - return newControllers; - } - _resetElements() { - each(this.data.datasets, (dataset, datasetIndex) => { - this.getDatasetMeta(datasetIndex).controller.reset(); - }, this); - } - reset() { - this._resetElements(); - this.notifyPlugins('reset'); - } - update(mode) { - const config = this.config; - config.update(); - const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); - const animsDisabled = this._animationsDisabled = !options.animation; - this._updateScales(); - this._checkEventBindings(); - this._updateHiddenIndices(); - this._plugins.invalidate(); - if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) { - return; - } - const newControllers = this.buildOrUpdateControllers(); - this.notifyPlugins('beforeElementsUpdate'); - let minPadding = 0; - for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) { - const {controller} = this.getDatasetMeta(i); - const reset = !animsDisabled && newControllers.indexOf(controller) === -1; - controller.buildOrUpdateElements(reset); - minPadding = Math.max(+controller.getMaxOverflow(), minPadding); - } - minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; - this._updateLayout(minPadding); - if (!animsDisabled) { - each(newControllers, (controller) => { - controller.reset(); - }); - } - this._updateDatasets(mode); - this.notifyPlugins('afterUpdate', {mode}); - this._layers.sort(compare2Level('z', '_idx')); - const {_active, _lastEvent} = this; - if (_lastEvent) { - this._eventHandler(_lastEvent, true); - } else if (_active.length) { - this._updateHoverStyles(_active, _active, true); - } - this.render(); - } - _updateScales() { - each(this.scales, (scale) => { - layouts.removeBox(this, scale); - }); - this.ensureScalesHaveIDs(); - this.buildOrUpdateScales(); - } - _checkEventBindings() { - const options = this.options; - const existingEvents = new Set(Object.keys(this._listeners)); - const newEvents = new Set(options.events); - if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { - this.unbindEvents(); - this.bindEvents(); - } - } - _updateHiddenIndices() { - const {_hiddenIndices} = this; - const changes = this._getUniformDataChanges() || []; - for (const {method, start, count} of changes) { - const move = method === '_removeElements' ? -count : count; - moveNumericKeys(_hiddenIndices, start, move); - } - } - _getUniformDataChanges() { - const _dataChanges = this._dataChanges; - if (!_dataChanges || !_dataChanges.length) { - return; - } - this._dataChanges = []; - const datasetCount = this.data.datasets.length; - const makeSet = (idx) => new Set( - _dataChanges - .filter(c => c[0] === idx) - .map((c, i) => i + ',' + c.splice(1).join(',')) - ); - const changeSet = makeSet(0); - for (let i = 1; i < datasetCount; i++) { - if (!setsEqual(changeSet, makeSet(i))) { - return; - } - } - return Array.from(changeSet) - .map(c => c.split(',')) - .map(a => ({method: a[1], start: +a[2], count: +a[3]})); - } - _updateLayout(minPadding) { - if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) { - return; - } - layouts.update(this, this.width, this.height, minPadding); - const area = this.chartArea; - const noArea = area.width <= 0 || area.height <= 0; - this._layers = []; - each(this.boxes, (box) => { - if (noArea && box.position === 'chartArea') { - return; - } - if (box.configure) { - box.configure(); - } - this._layers.push(...box._layers()); - }, this); - this._layers.forEach((item, index) => { - item._idx = index; - }); - this.notifyPlugins('afterLayout'); - } - _updateDatasets(mode) { - if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { - return; - } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this.getDatasetMeta(i).controller.configure(); - } - for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); - } - this.notifyPlugins('afterDatasetsUpdate', {mode}); - } - _updateDataset(index, mode) { - const meta = this.getDatasetMeta(index); - const args = {meta, index, mode, cancelable: true}; - if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { - return; - } - meta.controller._update(mode); - args.cancelable = false; - this.notifyPlugins('afterDatasetUpdate', args); - } - render() { - if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) { - return; - } - if (animator.has(this)) { - if (this.attached && !animator.running(this)) { - animator.start(this); - } - } else { - this.draw(); - onAnimationsComplete({chart: this}); - } - } - draw() { - let i; - if (this._resizeBeforeDraw) { - const {width, height} = this._resizeBeforeDraw; - this._resize(width, height); - this._resizeBeforeDraw = null; - } - this.clear(); - if (this.width <= 0 || this.height <= 0) { - return; - } - if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) { - return; - } - const layers = this._layers; - for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { - layers[i].draw(this.chartArea); - } - this._drawDatasets(); - for (; i < layers.length; ++i) { - layers[i].draw(this.chartArea); - } - this.notifyPlugins('afterDraw'); - } - _getSortedDatasetMetas(filterVisible) { - const metasets = this._sortedMetasets; - const result = []; - let i, ilen; - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - const meta = metasets[i]; - if (!filterVisible || meta.visible) { - result.push(meta); - } - } - return result; - } - getSortedVisibleDatasetMetas() { - return this._getSortedDatasetMetas(true); - } - _drawDatasets() { - if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) { - return; - } - const metasets = this.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - this._drawDataset(metasets[i]); - } - this.notifyPlugins('afterDatasetsDraw'); - } - _drawDataset(meta) { - const ctx = this.ctx; - const clip = meta._clip; - const useClip = !clip.disabled; - const area = this.chartArea; - const args = { - meta, - index: meta.index, - cancelable: true - }; - if (this.notifyPlugins('beforeDatasetDraw', args) === false) { - return; - } - if (useClip) { - clipArea(ctx, { - left: clip.left === false ? 0 : area.left - clip.left, - right: clip.right === false ? this.width : area.right + clip.right, - top: clip.top === false ? 0 : area.top - clip.top, - bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom - }); - } - meta.controller.draw(); - if (useClip) { - unclipArea(ctx); - } - args.cancelable = false; - this.notifyPlugins('afterDatasetDraw', args); - } - getElementsAtEventForMode(e, mode, options, useFinalPosition) { - const method = Interaction.modes[mode]; - if (typeof method === 'function') { - return method(this, e, options, useFinalPosition); - } - return []; - } - getDatasetMeta(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - const metasets = this._metasets; - let meta = metasets.filter(x => x && x._dataset === dataset).pop(); - if (!meta) { - meta = { - type: null, - data: [], - dataset: null, - controller: null, - hidden: null, - xAxisID: null, - yAxisID: null, - order: dataset && dataset.order || 0, - index: datasetIndex, - _dataset: dataset, - _parsed: [], - _sorted: false - }; - metasets.push(meta); - } - return meta; - } - getContext() { - return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'})); - } - getVisibleDatasetCount() { - return this.getSortedVisibleDatasetMetas().length; - } - isDatasetVisible(datasetIndex) { - const dataset = this.data.datasets[datasetIndex]; - if (!dataset) { - return false; - } - const meta = this.getDatasetMeta(datasetIndex); - return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; - } - setDatasetVisibility(datasetIndex, visible) { - const meta = this.getDatasetMeta(datasetIndex); - meta.hidden = !visible; - } - toggleDataVisibility(index) { - this._hiddenIndices[index] = !this._hiddenIndices[index]; - } - getDataVisibility(index) { - return !this._hiddenIndices[index]; - } - _updateVisibility(datasetIndex, dataIndex, visible) { - const mode = visible ? 'show' : 'hide'; - const meta = this.getDatasetMeta(datasetIndex); - const anims = meta.controller._resolveAnimations(undefined, mode); - if (defined(dataIndex)) { - meta.data[dataIndex].hidden = !visible; - this.update(); - } else { - this.setDatasetVisibility(datasetIndex, visible); - anims.update(meta, {visible}); - this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); - } - } - hide(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, false); - } - show(datasetIndex, dataIndex) { - this._updateVisibility(datasetIndex, dataIndex, true); - } - _destroyDatasetMeta(datasetIndex) { - const meta = this._metasets[datasetIndex]; - if (meta && meta.controller) { - meta.controller._destroy(); - } - delete this._metasets[datasetIndex]; - } - _stop() { - let i, ilen; - this.stop(); - animator.remove(this); - for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._destroyDatasetMeta(i); - } - } - destroy() { - this.notifyPlugins('beforeDestroy'); - const {canvas, ctx} = this; - this._stop(); - this.config.clearCache(); - if (canvas) { - this.unbindEvents(); - clearCanvas(canvas, ctx); - this.platform.releaseContext(ctx); - this.canvas = null; - this.ctx = null; - } - this.notifyPlugins('destroy'); - delete instances[this.id]; - this.notifyPlugins('afterDestroy'); - } - toBase64Image(...args) { - return this.canvas.toDataURL(...args); - } - bindEvents() { - this.bindUserEvents(); - if (this.options.responsive) { - this.bindResponsiveEvents(); - } else { - this.attached = true; - } - } - bindUserEvents() { - const listeners = this._listeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const listener = (e, x, y) => { - e.offsetX = x; - e.offsetY = y; - this._eventHandler(e); - }; - each(this.options.events, (type) => _add(type, listener)); - } - bindResponsiveEvents() { - if (!this._responsiveListeners) { - this._responsiveListeners = {}; - } - const listeners = this._responsiveListeners; - const platform = this.platform; - const _add = (type, listener) => { - platform.addEventListener(this, type, listener); - listeners[type] = listener; - }; - const _remove = (type, listener) => { - if (listeners[type]) { - platform.removeEventListener(this, type, listener); - delete listeners[type]; - } - }; - const listener = (width, height) => { - if (this.canvas) { - this.resize(width, height); - } - }; - let detached; - const attached = () => { - _remove('attach', attached); - this.attached = true; - this.resize(); - _add('resize', listener); - _add('detach', detached); - }; - detached = () => { - this.attached = false; - _remove('resize', listener); - this._stop(); - this._resize(0, 0); - _add('attach', attached); - }; - if (platform.isAttached(this.canvas)) { - attached(); - } else { - detached(); - } - } - unbindEvents() { - each(this._listeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._listeners = {}; - each(this._responsiveListeners, (listener, type) => { - this.platform.removeEventListener(this, type, listener); - }); - this._responsiveListeners = undefined; - } - updateHoverStyle(items, mode, enabled) { - const prefix = enabled ? 'set' : 'remove'; - let meta, item, i, ilen; - if (mode === 'dataset') { - meta = this.getDatasetMeta(items[0].datasetIndex); - meta.controller['_' + prefix + 'DatasetHoverStyle'](); - } - for (i = 0, ilen = items.length; i < ilen; ++i) { - item = items[i]; - const controller = item && this.getDatasetMeta(item.datasetIndex).controller; - if (controller) { - controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); - } - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements) { - const lastActive = this._active || []; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('No dataset found at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(active, lastActive); - if (changed) { - this._active = active; - this._lastEvent = null; - this._updateHoverStyles(active, lastActive); - } - } - notifyPlugins(hook, args, filter) { - return this._plugins.notify(this, hook, args, filter); - } - _updateHoverStyles(active, lastActive, replay) { - const hoverOptions = this.options.hover; - const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index)); - const deactivated = diff(lastActive, active); - const activated = replay ? active : diff(active, lastActive); - if (deactivated.length) { - this.updateHoverStyle(deactivated, hoverOptions.mode, false); - } - if (activated.length && hoverOptions.mode) { - this.updateHoverStyle(activated, hoverOptions.mode, true); - } - } - _eventHandler(e, replay) { - const args = { - event: e, - replay, - cancelable: true, - inChartArea: _isPointInArea(e, this.chartArea, this._minPadding) - }; - const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type); - if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { - return; - } - const changed = this._handleEvent(e, replay, args.inChartArea); - args.cancelable = false; - this.notifyPlugins('afterEvent', args, eventFilter); - if (changed || args.changed) { - this.render(); - } - return this; - } - _handleEvent(e, replay, inChartArea) { - const {_active: lastActive = [], options} = this; - const useFinalPosition = replay; - const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); - const isClick = _isClickEvent(e); - const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); - if (inChartArea) { - this._lastEvent = null; - callback(options.onHover, [e, active, this], this); - if (isClick) { - callback(options.onClick, [e, active, this], this); - } - } - const changed = !_elementsEqual(active, lastActive); - if (changed || replay) { - this._active = active; - this._updateHoverStyles(active, lastActive, replay); - } - this._lastEvent = lastEvent; - return changed; - } - _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const hoverOptions = this.options.hover; - return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); - } -} -const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); -const enumerable = true; -Object.defineProperties(Chart, { - defaults: { - enumerable, - value: defaults - }, - instances: { - enumerable, - value: instances - }, - overrides: { - enumerable, - value: overrides - }, - registry: { - enumerable, - value: registry - }, - version: { - enumerable, - value: version - }, - getChart: { - enumerable, - value: getChart - }, - register: { - enumerable, - value: (...items) => { - registry.add(...items); - invalidatePlugins(); - } - }, - unregister: { - enumerable, - value: (...items) => { - registry.remove(...items); - invalidatePlugins(); - } - } -}); - -function abstract() { - throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); -} -class DateAdapter { - constructor(options) { - this.options = options || {}; - } - formats() { - return abstract(); - } - parse(value, format) { - return abstract(); - } - format(timestamp, format) { - return abstract(); - } - add(timestamp, amount, unit) { - return abstract(); - } - diff(a, b, unit) { - return abstract(); - } - startOf(timestamp, unit, weekday) { - return abstract(); - } - endOf(timestamp, unit) { - return abstract(); - } -} -DateAdapter.override = function(members) { - Object.assign(DateAdapter.prototype, members); -}; -var _adapters = { - _date: DateAdapter -}; - -function getAllScaleValues(scale, type) { - if (!scale._cache.$bar) { - const visibleMetas = scale.getMatchingVisibleMetas(type); - let values = []; - for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) { - values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); - } - scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b)); - } - return scale._cache.$bar; -} -function computeMinSampleSize(meta) { - const scale = meta.iScale; - const values = getAllScaleValues(scale, meta.type); - let min = scale._length; - let i, ilen, curr, prev; - const updateMinAndPrev = () => { - if (curr === 32767 || curr === -32768) { - return; - } - if (defined(prev)) { - min = Math.min(min, Math.abs(curr - prev) || min); - } - prev = curr; - }; - for (i = 0, ilen = values.length; i < ilen; ++i) { - curr = scale.getPixelForValue(values[i]); - updateMinAndPrev(); - } - prev = undefined; - for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { - curr = scale.getPixelForTick(i); - updateMinAndPrev(); - } - return min; -} -function computeFitCategoryTraits(index, ruler, options, stackCount) { - const thickness = options.barThickness; - let size, ratio; - if (isNullOrUndef(thickness)) { - size = ruler.min * options.categoryPercentage; - ratio = options.barPercentage; - } else { - size = thickness * stackCount; - ratio = 1; - } - return { - chunk: size / stackCount, - ratio, - start: ruler.pixels[index] - (size / 2) - }; -} -function computeFlexCategoryTraits(index, ruler, options, stackCount) { - const pixels = ruler.pixels; - const curr = pixels[index]; - let prev = index > 0 ? pixels[index - 1] : null; - let next = index < pixels.length - 1 ? pixels[index + 1] : null; - const percent = options.categoryPercentage; - if (prev === null) { - prev = curr - (next === null ? ruler.end - ruler.start : next - curr); - } - if (next === null) { - next = curr + curr - prev; - } - const start = curr - (curr - Math.min(prev, next)) / 2 * percent; - const size = Math.abs(next - prev) / 2 * percent; - return { - chunk: size / stackCount, - ratio: options.barPercentage, - start - }; -} -function parseFloatBar(entry, item, vScale, i) { - const startValue = vScale.parse(entry[0], i); - const endValue = vScale.parse(entry[1], i); - const min = Math.min(startValue, endValue); - const max = Math.max(startValue, endValue); - let barStart = min; - let barEnd = max; - if (Math.abs(min) > Math.abs(max)) { - barStart = max; - barEnd = min; - } - item[vScale.axis] = barEnd; - item._custom = { - barStart, - barEnd, - start: startValue, - end: endValue, - min, - max - }; -} -function parseValue(entry, item, vScale, i) { - if (isArray(entry)) { - parseFloatBar(entry, item, vScale, i); - } else { - item[vScale.axis] = vScale.parse(entry, i); - } - return item; -} -function parseArrayOrPrimitive(meta, data, start, count) { - const iScale = meta.iScale; - const vScale = meta.vScale; - const labels = iScale.getLabels(); - const singleScale = iScale === vScale; - const parsed = []; - let i, ilen, item, entry; - for (i = start, ilen = start + count; i < ilen; ++i) { - entry = data[i]; - item = {}; - item[iScale.axis] = singleScale || iScale.parse(labels[i], i); - parsed.push(parseValue(entry, item, vScale, i)); - } - return parsed; -} -function isFloatBar(custom) { - return custom && custom.barStart !== undefined && custom.barEnd !== undefined; -} -function barSign(size, vScale, actualBase) { - if (size !== 0) { - return sign(size); - } - return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); -} -function borderProps(properties) { - let reverse, start, end, top, bottom; - if (properties.horizontal) { - reverse = properties.base > properties.x; - start = 'left'; - end = 'right'; - } else { - reverse = properties.base < properties.y; - start = 'bottom'; - end = 'top'; - } - if (reverse) { - top = 'end'; - bottom = 'start'; - } else { - top = 'start'; - bottom = 'end'; - } - return {start, end, reverse, top, bottom}; -} -function setBorderSkipped(properties, options, stack, index) { - let edge = options.borderSkipped; - const res = {}; - if (!edge) { - properties.borderSkipped = res; - return; - } - const {start, end, reverse, top, bottom} = borderProps(properties); - if (edge === 'middle' && stack) { - properties.enableBorderRadius = true; - if ((stack._top || 0) === index) { - edge = top; - } else if ((stack._bottom || 0) === index) { - edge = bottom; - } else { - res[parseEdge(bottom, start, end, reverse)] = true; - edge = top; - } - } - res[parseEdge(edge, start, end, reverse)] = true; - properties.borderSkipped = res; -} -function parseEdge(edge, a, b, reverse) { - if (reverse) { - edge = swap(edge, a, b); - edge = startEnd(edge, b, a); - } else { - edge = startEnd(edge, a, b); - } - return edge; -} -function swap(orig, v1, v2) { - return orig === v1 ? v2 : orig === v2 ? v1 : orig; -} -function startEnd(v, start, end) { - return v === 'start' ? start : v === 'end' ? end : v; -} -function setInflateAmount(properties, {inflateAmount}, ratio) { - properties.inflateAmount = inflateAmount === 'auto' - ? ratio === 1 ? 0.33 : 0 - : inflateAmount; -} -class BarController extends DatasetController { - parsePrimitiveData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseArrayData(meta, data, start, count) { - return parseArrayOrPrimitive(meta, data, start, count); - } - parseObjectData(meta, data, start, count) { - const {iScale, vScale} = meta; - const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; - const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; - const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; - const parsed = []; - let i, ilen, item, obj; - for (i = start, ilen = start + count; i < ilen; ++i) { - obj = data[i]; - item = {}; - item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); - parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); - } - return parsed; - } - updateRangeFromParsed(range, scale, parsed, stack) { - super.updateRangeFromParsed(range, scale, parsed, stack); - const custom = parsed._custom; - if (custom && scale === this._cachedMeta.vScale) { - range.min = Math.min(range.min, custom.min); - range.max = Math.max(range.max, custom.max); - } - } - getMaxOverflow() { - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {iScale, vScale} = meta; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const value = isFloatBar(custom) - ? '[' + custom.start + ', ' + custom.end + ']' - : '' + vScale.getLabelForValue(parsed[vScale.axis]); - return { - label: '' + iScale.getLabelForValue(parsed[iScale.axis]), - value - }; - } - initialize() { - this.enableOptionSharing = true; - super.initialize(); - const meta = this._cachedMeta; - meta.stack = this.getDataset().stack; - } - update(mode) { - const meta = this._cachedMeta; - this.updateElements(meta.data, 0, meta.data.length, mode); - } - updateElements(bars, start, count, mode) { - const reset = mode === 'reset'; - const {index, _cachedMeta: {vScale}} = this; - const base = vScale.getBasePixel(); - const horizontal = vScale.isHorizontal(); - const ruler = this._getRuler(); - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - this.updateSharedOptions(sharedOptions, mode, firstOpts); - for (let i = start; i < start + count; i++) { - const parsed = this.getParsed(i); - const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i); - const ipixels = this._calculateBarIndexPixels(i, ruler); - const stack = (parsed._stacks || {})[vScale.axis]; - const properties = { - horizontal, - base: vpixels.base, - enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom), - x: horizontal ? vpixels.head : ipixels.center, - y: horizontal ? ipixels.center : vpixels.head, - height: horizontal ? ipixels.size : Math.abs(vpixels.size), - width: horizontal ? Math.abs(vpixels.size) : ipixels.size - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); - } - const options = properties.options || bars[i].options; - setBorderSkipped(properties, options, stack, index); - setInflateAmount(properties, options, ruler.ratio); - this.updateElement(bars[i], i, properties, mode); - } - } - _getStacks(last, dataIndex) { - const meta = this._cachedMeta; - const iScale = meta.iScale; - const metasets = iScale.getMatchingVisibleMetas(this._type); - const stacked = iScale.options.stacked; - const ilen = metasets.length; - const stacks = []; - let i, item; - for (i = 0; i < ilen; ++i) { - item = metasets[i]; - if (!item.controller.options.grouped) { - continue; - } - if (typeof dataIndex !== 'undefined') { - const val = item.controller.getParsed(dataIndex)[ - item.controller._cachedMeta.vScale.axis - ]; - if (isNullOrUndef(val) || isNaN(val)) { - continue; - } - } - if (stacked === false || stacks.indexOf(item.stack) === -1 || - (stacked === undefined && item.stack === undefined)) { - stacks.push(item.stack); - } - if (item.index === last) { - break; - } - } - if (!stacks.length) { - stacks.push(undefined); - } - return stacks; - } - _getStackCount(index) { - return this._getStacks(undefined, index).length; - } - _getStackIndex(datasetIndex, name, dataIndex) { - const stacks = this._getStacks(datasetIndex, dataIndex); - const index = (name !== undefined) - ? stacks.indexOf(name) - : -1; - return (index === -1) - ? stacks.length - 1 - : index; - } - _getRuler() { - const opts = this.options; - const meta = this._cachedMeta; - const iScale = meta.iScale; - const pixels = []; - let i, ilen; - for (i = 0, ilen = meta.data.length; i < ilen; ++i) { - pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); - } - const barThickness = opts.barThickness; - const min = barThickness || computeMinSampleSize(meta); - return { - min, - pixels, - start: iScale._startPixel, - end: iScale._endPixel, - stackCount: this._getStackCount(), - scale: iScale, - grouped: opts.grouped, - ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage - }; - } - _calculateBarValuePixels(index) { - const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; - const actualBase = baseValue || 0; - const parsed = this.getParsed(index); - const custom = parsed._custom; - const floating = isFloatBar(custom); - let value = parsed[vScale.axis]; - let start = 0; - let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; - let head, size; - if (length !== value) { - start = length - value; - length = value; - } - if (floating) { - value = custom.barStart; - length = custom.barEnd - custom.barStart; - if (value !== 0 && sign(value) !== sign(custom.barEnd)) { - start = 0; - } - start += value; - } - const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; - let base = vScale.getPixelForValue(startValue); - if (this.chart.getDataVisibility(index)) { - head = vScale.getPixelForValue(start + length); - } else { - head = base; - } - size = head - base; - if (Math.abs(size) < minBarLength) { - size = barSign(size, vScale, actualBase) * minBarLength; - if (value === actualBase) { - base -= size / 2; - } - head = base + size; - } - if (base === vScale.getPixelForValue(actualBase)) { - const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; - base += halfGrid; - size -= halfGrid; - } - return { - size, - base, - head, - center: head + size / 2 - }; - } - _calculateBarIndexPixels(index, ruler) { - const scale = ruler.scale; - const options = this.options; - const skipNull = options.skipNull; - const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); - let center, size; - if (ruler.grouped) { - const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; - const range = options.barThickness === 'flex' - ? computeFlexCategoryTraits(index, ruler, options, stackCount) - : computeFitCategoryTraits(index, ruler, options, stackCount); - const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined); - center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); - size = Math.min(maxBarThickness, range.chunk * range.ratio); - } else { - center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); - size = Math.min(maxBarThickness, ruler.min * ruler.ratio); - } - return { - base: center - size / 2, - head: center + size / 2, - center, - size - }; - } - draw() { - const meta = this._cachedMeta; - const vScale = meta.vScale; - const rects = meta.data; - const ilen = rects.length; - let i = 0; - for (; i < ilen; ++i) { - if (this.getParsed(i)[vScale.axis] !== null) { - rects[i].draw(this._ctx); - } - } - } -} -BarController.id = 'bar'; -BarController.defaults = { - datasetElementType: false, - dataElementType: 'bar', - categoryPercentage: 0.8, - barPercentage: 0.9, - grouped: true, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'base', 'width', 'height'] - } - } -}; -BarController.overrides = { - scales: { - _index_: { - type: 'category', - offset: true, - grid: { - offset: true - } - }, - _value_: { - type: 'linear', - beginAtZero: true, - } - } -}; - -class BubbleController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - parsePrimitiveData(meta, data, start, count) { - const parsed = super.parsePrimitiveData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; - } - return parsed; - } - parseArrayData(meta, data, start, count) { - const parsed = super.parseArrayData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - parseObjectData(meta, data, start, count) { - const parsed = super.parseObjectData(meta, data, start, count); - for (let i = 0; i < parsed.length; i++) { - const item = data[start + i]; - parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); - } - return parsed; - } - getMaxOverflow() { - const data = this._cachedMeta.data; - let max = 0; - for (let i = data.length - 1; i >= 0; --i) { - max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); - } - return max > 0 && max; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const {xScale, yScale} = meta; - const parsed = this.getParsed(index); - const x = xScale.getLabelForValue(parsed.x); - const y = yScale.getLabelForValue(parsed.y); - const r = parsed._custom; - return { - label: meta.label, - value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' - }; - } - update(mode) { - const points = this._cachedMeta.data; - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const parsed = !reset && this.getParsed(i); - const properties = {}; - const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); - const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); - properties.skip = isNaN(iPixel) || isNaN(vPixel); - if (includeOptions) { - properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - if (reset) { - properties.options.radius = 0; - } - } - this.updateElement(point, i, properties, mode); - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - resolveDataElementOptions(index, mode) { - const parsed = this.getParsed(index); - let values = super.resolveDataElementOptions(index, mode); - if (values.$shared) { - values = Object.assign({}, values, {$shared: false}); - } - const radius = values.radius; - if (mode !== 'active') { - values.radius = 0; - } - values.radius += valueOrDefault(parsed && parsed._custom, radius); - return values; - } -} -BubbleController.id = 'bubble'; -BubbleController.defaults = { - datasetElementType: false, - dataElementType: 'point', - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'borderWidth', 'radius'] - } - } -}; -BubbleController.overrides = { - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' - } - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - } - } - } - } -}; - -function getRatioAndOffset(rotation, circumference, cutout) { - let ratioX = 1; - let ratioY = 1; - let offsetX = 0; - let offsetY = 0; - if (circumference < TAU) { - const startAngle = rotation; - const endAngle = startAngle + circumference; - const startX = Math.cos(startAngle); - const startY = Math.sin(startAngle); - const endX = Math.cos(endAngle); - const endY = Math.sin(endAngle); - const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); - const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); - const maxX = calcMax(0, startX, endX); - const maxY = calcMax(HALF_PI, startY, endY); - const minX = calcMin(PI, startX, endX); - const minY = calcMin(PI + HALF_PI, startY, endY); - ratioX = (maxX - minX) / 2; - ratioY = (maxY - minY) / 2; - offsetX = -(maxX + minX) / 2; - offsetY = -(maxY + minY) / 2; - } - return {ratioX, ratioY, offsetX, offsetY}; -} -class DoughnutController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.enableOptionSharing = true; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.offsetX = undefined; - this.offsetY = undefined; - } - linkScales() {} - parse(start, count) { - const data = this.getDataset().data; - const meta = this._cachedMeta; - if (this._parsing === false) { - meta._parsed = data; - } else { - let getter = (i) => +data[i]; - if (isObject(data[start])) { - const {key = 'value'} = this._parsing; - getter = (i) => +resolveObjectKey(data[i], key); - } - let i, ilen; - for (i = start, ilen = start + count; i < ilen; ++i) { - meta._parsed[i] = getter(i); - } - } - } - _getRotation() { - return toRadians(this.options.rotation - 90); - } - _getCircumference() { - return toRadians(this.options.circumference); - } - _getRotationExtents() { - let min = TAU; - let max = -TAU; - for (let i = 0; i < this.chart.data.datasets.length; ++i) { - if (this.chart.isDatasetVisible(i)) { - const controller = this.chart.getDatasetMeta(i).controller; - const rotation = controller._getRotation(); - const circumference = controller._getCircumference(); - min = Math.min(min, rotation); - max = Math.max(max, rotation + circumference); - } - } - return { - rotation: min, - circumference: max - min, - }; - } - update(mode) { - const chart = this.chart; - const {chartArea} = chart; - const meta = this._cachedMeta; - const arcs = meta.data; - const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; - const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); - const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); - const chartWeight = this._getRingWeight(this.index); - const {circumference, rotation} = this._getRotationExtents(); - const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout); - const maxWidth = (chartArea.width - spacing) / ratioX; - const maxHeight = (chartArea.height - spacing) / ratioY; - const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); - const outerRadius = toDimension(this.options.radius, maxRadius); - const innerRadius = Math.max(outerRadius * cutout, 0); - const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); - this.offsetX = offsetX * outerRadius; - this.offsetY = offsetY * outerRadius; - meta.total = this.calculateTotal(); - this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); - this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); - this.updateElements(arcs, 0, arcs.length, mode); - } - _circumference(i, reset) { - const opts = this.options; - const meta = this._cachedMeta; - const circumference = this._getCircumference(); - if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { - return 0; - } - return this.calculateCircumference(meta._parsed[i] * circumference / TAU); - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const animationOpts = opts.animation; - const centerX = (chartArea.left + chartArea.right) / 2; - const centerY = (chartArea.top + chartArea.bottom) / 2; - const animateScale = reset && animationOpts.animateScale; - const innerRadius = animateScale ? 0 : this.innerRadius; - const outerRadius = animateScale ? 0 : this.outerRadius; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - let startAngle = this._getRotation(); - let i; - for (i = 0; i < start; ++i) { - startAngle += this._circumference(i, reset); - } - for (i = start; i < start + count; ++i) { - const circumference = this._circumference(i, reset); - const arc = arcs[i]; - const properties = { - x: centerX + this.offsetX, - y: centerY + this.offsetY, - startAngle, - endAngle: startAngle + circumference, - circumference, - outerRadius, - innerRadius - }; - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); - } - startAngle += circumference; - this.updateElement(arc, i, properties, mode); - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - calculateTotal() { - const meta = this._cachedMeta; - const metaData = meta.data; - let total = 0; - let i; - for (i = 0; i < metaData.length; i++) { - const value = meta._parsed[i]; - if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { - total += Math.abs(value); - } - } - return total; - } - calculateCircumference(value) { - const total = this._cachedMeta.total; - if (total > 0 && !isNaN(value)) { - return TAU * (Math.abs(value) / total); - } - return 0; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index], chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - getMaxBorderWidth(arcs) { - let max = 0; - const chart = this.chart; - let i, ilen, meta, controller, options; - if (!arcs) { - for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { - if (chart.isDatasetVisible(i)) { - meta = chart.getDatasetMeta(i); - arcs = meta.data; - controller = meta.controller; - break; - } - } - } - if (!arcs) { - return 0; - } - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - options = controller.resolveDataElementOptions(i); - if (options.borderAlign !== 'inner') { - max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); - } - } - return max; - } - getMaxOffset(arcs) { - let max = 0; - for (let i = 0, ilen = arcs.length; i < ilen; ++i) { - const options = this.resolveDataElementOptions(i); - max = Math.max(max, options.offset || 0, options.hoverOffset || 0); - } - return max; - } - _getRingWeightOffset(datasetIndex) { - let ringWeightOffset = 0; - for (let i = 0; i < datasetIndex; ++i) { - if (this.chart.isDatasetVisible(i)) { - ringWeightOffset += this._getRingWeight(i); - } - } - return ringWeightOffset; - } - _getRingWeight(datasetIndex) { - return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); - } - _getVisibleDatasetWeightTotal() { - return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; - } -} -DoughnutController.id = 'doughnut'; -DoughnutController.defaults = { - datasetElementType: false, - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: false - }, - animations: { - numbers: { - type: 'number', - properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing'] - }, - }, - cutout: '50%', - rotation: 0, - circumference: 360, - radius: '100%', - spacing: 0, - indexAxis: 'r', -}; -DoughnutController.descriptors = { - _scriptable: (name) => name !== 'spacing', - _indexable: (name) => name !== 'spacing', -}; -DoughnutController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; - }, - label(tooltipItem) { - let dataLabel = tooltipItem.label; - const value = ': ' + tooltipItem.formattedValue; - if (isArray(dataLabel)) { - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - return dataLabel; - } - } - } - } -}; - -class LineController extends DatasetController { - initialize() { - this.enableOptionSharing = true; - super.initialize(); - } - update(mode) { - const meta = this._cachedMeta; - const {dataset: line, data: points = [], _dataset} = meta; - const animationsDisabled = this.chart._animationsDisabled; - let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); - this._drawStart = start; - this._drawCount = count; - if (scaleRangesChanged(meta)) { - start = 0; - count = points.length; - } - line._chart = this.chart; - line._datasetIndex = this.index; - line._decimated = !!_dataset._decimated; - line.points = points; - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; - } - options.segment = this.options.segment; - this.updateElement(line, undefined, { - animated: !animationsDisabled, - options - }, mode); - this.updateElements(points, start, count, mode); - } - updateElements(points, start, count, mode) { - const reset = mode === 'reset'; - const {iScale, vScale, _stacked, _dataset} = this._cachedMeta; - const firstOpts = this.resolveDataElementOptions(start, mode); - const sharedOptions = this.getSharedOptions(firstOpts); - const includeOptions = this.includeOptions(mode, sharedOptions); - const iAxis = iScale.axis; - const vAxis = vScale.axis; - const {spanGaps, segment} = this.options; - const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; - const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; - let prevParsed = start > 0 && this.getParsed(start - 1); - for (let i = start; i < start + count; ++i) { - const point = points[i]; - const parsed = this.getParsed(i); - const properties = directUpdate ? point : {}; - const nullData = isNullOrUndef(parsed[vAxis]); - const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); - const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); - properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; - properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; - if (segment) { - properties.parsed = parsed; - properties.raw = _dataset.data[i]; - } - if (includeOptions) { - properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); - } - if (!directUpdate) { - this.updateElement(point, i, properties, mode); - } - prevParsed = parsed; - } - this.updateSharedOptions(sharedOptions, mode, firstOpts); - } - getMaxOverflow() { - const meta = this._cachedMeta; - const dataset = meta.dataset; - const border = dataset.options && dataset.options.borderWidth || 0; - const data = meta.data || []; - if (!data.length) { - return border; - } - const firstPoint = data[0].size(this.resolveDataElementOptions(0)); - const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); - return Math.max(border, firstPoint, lastPoint) / 2; - } - draw() { - const meta = this._cachedMeta; - meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); - super.draw(); - } -} -LineController.id = 'line'; -LineController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - showLine: true, - spanGaps: false, -}; -LineController.overrides = { - scales: { - _index_: { - type: 'category', - }, - _value_: { - type: 'linear', - }, - } -}; -function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { - const pointCount = points.length; - let start = 0; - let count = pointCount; - if (meta._sorted) { - const {iScale, _parsed} = meta; - const axis = iScale.axis; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(Math.min( - _lookupByKey(_parsed, iScale.axis, min).lo, - animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), - 0, pointCount - 1); - } - if (maxDefined) { - count = _limitValue(Math.max( - _lookupByKey(_parsed, iScale.axis, max).hi + 1, - animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), - start, pointCount) - start; - } else { - count = pointCount - start; - } - } - return {start, count}; -} -function scaleRangesChanged(meta) { - const {xScale, yScale, _scaleRanges} = meta; - const newRanges = { - xmin: xScale.min, - xmax: xScale.max, - ymin: yScale.min, - ymax: yScale.max - }; - if (!_scaleRanges) { - meta._scaleRanges = newRanges; - return true; - } - const changed = _scaleRanges.xmin !== xScale.min - || _scaleRanges.xmax !== xScale.max - || _scaleRanges.ymin !== yScale.min - || _scaleRanges.ymax !== yScale.max; - Object.assign(_scaleRanges, newRanges); - return changed; -} - -class PolarAreaController extends DatasetController { - constructor(chart, datasetIndex) { - super(chart, datasetIndex); - this.innerRadius = undefined; - this.outerRadius = undefined; - } - getLabelAndValue(index) { - const meta = this._cachedMeta; - const chart = this.chart; - const labels = chart.data.labels || []; - const value = formatNumber(meta._parsed[index].r, chart.options.locale); - return { - label: labels[index] || '', - value, - }; - } - update(mode) { - const arcs = this._cachedMeta.data; - this._updateRadius(); - this.updateElements(arcs, 0, arcs.length, mode); - } - _updateRadius() { - const chart = this.chart; - const chartArea = chart.chartArea; - const opts = chart.options; - const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); - const outerRadius = Math.max(minSize / 2, 0); - const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); - const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); - this.outerRadius = outerRadius - (radiusLength * this.index); - this.innerRadius = this.outerRadius - radiusLength; - } - updateElements(arcs, start, count, mode) { - const reset = mode === 'reset'; - const chart = this.chart; - const dataset = this.getDataset(); - const opts = chart.options; - const animationOpts = opts.animation; - const scale = this._cachedMeta.rScale; - const centerX = scale.xCenter; - const centerY = scale.yCenter; - const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; - let angle = datasetStartAngle; - let i; - const defaultAngle = 360 / this.countVisibleElements(); - for (i = 0; i < start; ++i) { - angle += this._computeAngle(i, mode, defaultAngle); - } - for (i = start; i < start + count; i++) { - const arc = arcs[i]; - let startAngle = angle; - let endAngle = angle + this._computeAngle(i, mode, defaultAngle); - let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; - angle = endAngle; - if (reset) { - if (animationOpts.animateScale) { - outerRadius = 0; - } - if (animationOpts.animateRotate) { - startAngle = endAngle = datasetStartAngle; - } - } - const properties = { - x: centerX, - y: centerY, - innerRadius: 0, - outerRadius, - startAngle, - endAngle, - options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) - }; - this.updateElement(arc, i, properties, mode); - } - } - countVisibleElements() { - const dataset = this.getDataset(); - const meta = this._cachedMeta; - let count = 0; - meta.data.forEach((element, index) => { - if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { - count++; - } - }); - return count; - } - _computeAngle(index, mode, defaultAngle) { - return this.chart.getDataVisibility(index) - ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) - : 0; - } -} -PolarAreaController.id = 'polarArea'; -PolarAreaController.defaults = { - dataElementType: 'arc', - animation: { - animateRotate: true, - animateScale: true - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] - }, - }, - indexAxis: 'r', - startAngle: 0, -}; -PolarAreaController.overrides = { - aspectRatio: 1, - plugins: { - legend: { - labels: { - generateLabels(chart) { - const data = chart.data; - if (data.labels.length && data.datasets.length) { - const {labels: {pointStyle}} = chart.legend.options; - return data.labels.map((label, i) => { - const meta = chart.getDatasetMeta(0); - const style = meta.controller.getStyle(i); - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - pointStyle: pointStyle, - hidden: !chart.getDataVisibility(i), - index: i - }; - }); - } - return []; - } - }, - onClick(e, legendItem, legend) { - legend.chart.toggleDataVisibility(legendItem.index); - legend.chart.update(); - } - }, - tooltip: { - callbacks: { - title() { - return ''; - }, - label(context) { - return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; - } - } - } - }, - scales: { - r: { - type: 'radialLinear', - angleLines: { - display: false - }, - beginAtZero: true, - grid: { - circular: true - }, - pointLabels: { - display: false - }, - startAngle: 0 - } - } -}; - -class PieController extends DoughnutController { -} -PieController.id = 'pie'; -PieController.defaults = { - cutout: 0, - rotation: 0, - circumference: 360, - radius: '100%' -}; - -class RadarController extends DatasetController { - getLabelAndValue(index) { - const vScale = this._cachedMeta.vScale; - const parsed = this.getParsed(index); - return { - label: vScale.getLabels()[index], - value: '' + vScale.getLabelForValue(parsed[vScale.axis]) - }; - } - update(mode) { - const meta = this._cachedMeta; - const line = meta.dataset; - const points = meta.data || []; - const labels = meta.iScale.getLabels(); - line.points = points; - if (mode !== 'resize') { - const options = this.resolveDatasetElementOptions(mode); - if (!this.options.showLine) { - options.borderWidth = 0; - } - const properties = { - _loop: true, - _fullLoop: labels.length === points.length, - options - }; - this.updateElement(line, undefined, properties, mode); - } - this.updateElements(points, 0, points.length, mode); - } - updateElements(points, start, count, mode) { - const dataset = this.getDataset(); - const scale = this._cachedMeta.rScale; - const reset = mode === 'reset'; - for (let i = start; i < start + count; i++) { - const point = points[i]; - const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); - const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); - const x = reset ? scale.xCenter : pointPosition.x; - const y = reset ? scale.yCenter : pointPosition.y; - const properties = { - x, - y, - angle: pointPosition.angle, - skip: isNaN(x) || isNaN(y), - options - }; - this.updateElement(point, i, properties, mode); - } - } -} -RadarController.id = 'radar'; -RadarController.defaults = { - datasetElementType: 'line', - dataElementType: 'point', - indexAxis: 'r', - showLine: true, - elements: { - line: { - fill: 'start' - } - }, -}; -RadarController.overrides = { - aspectRatio: 1, - scales: { - r: { - type: 'radialLinear', - } - } -}; - -class ScatterController extends LineController { -} -ScatterController.id = 'scatter'; -ScatterController.defaults = { - showLine: false, - fill: false -}; -ScatterController.overrides = { - interaction: { - mode: 'point' - }, - plugins: { - tooltip: { - callbacks: { - title() { - return ''; - }, - label(item) { - return '(' + item.label + ', ' + item.formattedValue + ')'; - } - } - } - }, - scales: { - x: { - type: 'linear' - }, - y: { - type: 'linear' - } - } -}; - -var controllers = /*#__PURE__*/Object.freeze({ -__proto__: null, -BarController: BarController, -BubbleController: BubbleController, -DoughnutController: DoughnutController, -LineController: LineController, -PolarAreaController: PolarAreaController, -PieController: PieController, -RadarController: RadarController, -ScatterController: ScatterController -}); - -function clipArc(ctx, element, endAngle) { - const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; - let angleMargin = pixelMargin / outerRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); - if (innerRadius > pixelMargin) { - angleMargin = pixelMargin / innerRadius; - ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); - } else { - ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); - } - ctx.closePath(); - ctx.clip(); -} -function toRadiusCorners(value) { - return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']); -} -function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { - const o = toRadiusCorners(arc.options.borderRadius); - const halfThickness = (outerRadius - innerRadius) / 2; - const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); - const computeOuterLimit = (val) => { - const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; - return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); - }; - return { - outerStart: computeOuterLimit(o.outerStart), - outerEnd: computeOuterLimit(o.outerEnd), - innerStart: _limitValue(o.innerStart, 0, innerLimit), - innerEnd: _limitValue(o.innerEnd, 0, innerLimit), - }; -} -function rThetaToXY(r, theta, x, y) { - return { - x: x + r * Math.cos(theta), - y: y + r * Math.sin(theta), - }; -} -function pathArc(ctx, element, offset, spacing, end) { - const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element; - const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); - const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; - let spacingOffset = 0; - const alpha = end - start; - if (spacing) { - const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; - const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; - const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; - const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha; - spacingOffset = (alpha - adjustedAngle) / 2; - } - const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; - const angleOffset = (alpha - beta) / 2; - const startAngle = start + angleOffset + spacingOffset; - const endAngle = end - angleOffset - spacingOffset; - const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); - const outerStartAdjustedRadius = outerRadius - outerStart; - const outerEndAdjustedRadius = outerRadius - outerEnd; - const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; - const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; - const innerStartAdjustedRadius = innerRadius + innerStart; - const innerEndAdjustedRadius = innerRadius + innerEnd; - const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; - const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; - ctx.beginPath(); - ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle); - if (outerEnd > 0) { - const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); - } - const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); - ctx.lineTo(p4.x, p4.y); - if (innerEnd > 0) { - const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); - } - ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true); - if (innerStart > 0) { - const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); - } - const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); - ctx.lineTo(p8.x, p8.y); - if (outerStart > 0) { - const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); - ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); - } - ctx.closePath(); -} -function drawArc(ctx, element, offset, spacing) { - const {fullCircles, startAngle, circumference} = element; - let endAngle = element.endAngle; - if (fullCircles) { - pathArc(ctx, element, offset, spacing, startAngle + TAU); - for (let i = 0; i < fullCircles; ++i) { - ctx.fill(); - } - if (!isNaN(circumference)) { - endAngle = startAngle + circumference % TAU; - if (circumference % TAU === 0) { - endAngle += TAU; - } - } - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.fill(); - return endAngle; -} -function drawFullCircleBorders(ctx, element, inner) { - const {x, y, startAngle, pixelMargin, fullCircles} = element; - const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); - const innerRadius = element.innerRadius + pixelMargin; - let i; - if (inner) { - clipArc(ctx, element, startAngle + TAU); - } - ctx.beginPath(); - ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } - ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); - for (i = 0; i < fullCircles; ++i) { - ctx.stroke(); - } -} -function drawBorder(ctx, element, offset, spacing, endAngle) { - const {options} = element; - const {borderWidth, borderJoinStyle} = options; - const inner = options.borderAlign === 'inner'; - if (!borderWidth) { - return; - } - if (inner) { - ctx.lineWidth = borderWidth * 2; - ctx.lineJoin = borderJoinStyle || 'round'; - } else { - ctx.lineWidth = borderWidth; - ctx.lineJoin = borderJoinStyle || 'bevel'; - } - if (element.fullCircles) { - drawFullCircleBorders(ctx, element, inner); - } - if (inner) { - clipArc(ctx, element, endAngle); - } - pathArc(ctx, element, offset, spacing, endAngle); - ctx.stroke(); -} -class ArcElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.circumference = undefined; - this.startAngle = undefined; - this.endAngle = undefined; - this.innerRadius = undefined; - this.outerRadius = undefined; - this.pixelMargin = 0; - this.fullCircles = 0; - if (cfg) { - Object.assign(this, cfg); - } - } - inRange(chartX, chartY, useFinalPosition) { - const point = this.getProps(['x', 'y'], useFinalPosition); - const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); - const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference' - ], useFinalPosition); - const rAdjust = this.options.spacing / 2; - const _circumference = valueOrDefault(circumference, endAngle - startAngle); - const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); - const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); - return (betweenAngles && withinRadius); - } - getCenterPoint(useFinalPosition) { - const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ - 'x', - 'y', - 'startAngle', - 'endAngle', - 'innerRadius', - 'outerRadius', - 'circumference', - ], useFinalPosition); - const {offset, spacing} = this.options; - const halfAngle = (startAngle + endAngle) / 2; - const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; - return { - x: x + Math.cos(halfAngle) * halfRadius, - y: y + Math.sin(halfAngle) * halfRadius - }; - } - tooltipPosition(useFinalPosition) { - return this.getCenterPoint(useFinalPosition); - } - draw(ctx) { - const {options, circumference} = this; - const offset = (options.offset || 0) / 2; - const spacing = (options.spacing || 0) / 2; - this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; - this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; - if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { - return; - } - ctx.save(); - let radiusOffset = 0; - if (offset) { - radiusOffset = offset / 2; - const halfAngle = (this.startAngle + this.endAngle) / 2; - ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset); - if (this.circumference >= PI) { - radiusOffset = offset; - } - } - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - const endAngle = drawArc(ctx, this, radiusOffset, spacing); - drawBorder(ctx, this, radiusOffset, spacing, endAngle); - ctx.restore(); - } -} -ArcElement.id = 'arc'; -ArcElement.defaults = { - borderAlign: 'center', - borderColor: '#fff', - borderJoinStyle: undefined, - borderRadius: 0, - borderWidth: 2, - offset: 0, - spacing: 0, - angle: undefined, -}; -ArcElement.defaultRoutes = { - backgroundColor: 'backgroundColor' -}; - -function setStyle(ctx, options, style = options) { - ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); - ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); - ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); - ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); - ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); - ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); -} -function lineTo(ctx, previous, target) { - ctx.lineTo(target.x, target.y); -} -function getLineMethod(options) { - if (options.stepped) { - return _steppedLineTo; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierCurveTo; - } - return lineTo; -} -function pathVars(points, segment, params = {}) { - const count = points.length; - const {start: paramsStart = 0, end: paramsEnd = count - 1} = params; - const {start: segmentStart, end: segmentEnd} = segment; - const start = Math.max(paramsStart, segmentStart); - const end = Math.min(paramsEnd, segmentEnd); - const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; - return { - count, - start, - loop: segment.loop, - ilen: end < start && !outside ? count + end - start : end - start - }; -} -function pathSegment(ctx, line, segment, params) { - const {points, options} = line; - const {count, start, loop, ilen} = pathVars(points, segment, params); - const lineMethod = getLineMethod(options); - let {move = true, reverse} = params || {}; - let i, point, prev; - for (i = 0; i <= ilen; ++i) { - point = points[(start + (reverse ? ilen - i : i)) % count]; - if (point.skip) { - continue; - } else if (move) { - ctx.moveTo(point.x, point.y); - move = false; - } else { - lineMethod(ctx, prev, point, reverse, options.stepped); - } - prev = point; - } - if (loop) { - point = points[(start + (reverse ? ilen : 0)) % count]; - lineMethod(ctx, prev, point, reverse, options.stepped); - } - return !!loop; -} -function fastPathSegment(ctx, line, segment, params) { - const points = line.points; - const {count, start, ilen} = pathVars(points, segment, params); - const {move = true, reverse} = params || {}; - let avgX = 0; - let countX = 0; - let i, point, prevX, minY, maxY, lastY; - const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; - const drawX = () => { - if (minY !== maxY) { - ctx.lineTo(avgX, maxY); - ctx.lineTo(avgX, minY); - ctx.lineTo(avgX, lastY); - } - }; - if (move) { - point = points[pointIndex(0)]; - ctx.moveTo(point.x, point.y); - } - for (i = 0; i <= ilen; ++i) { - point = points[pointIndex(i)]; - if (point.skip) { - continue; - } - const x = point.x; - const y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - } else if (y > maxY) { - maxY = y; - } - avgX = (countX * avgX + x) / ++countX; - } else { - drawX(); - ctx.lineTo(x, y); - prevX = truncX; - countX = 0; - minY = maxY = y; - } - lastY = y; - } - drawX(); -} -function _getSegmentMethod(line) { - const opts = line.options; - const borderDash = opts.borderDash && opts.borderDash.length; - const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; - return useFastPath ? fastPathSegment : pathSegment; -} -function _getInterpolationMethod(options) { - if (options.stepped) { - return _steppedInterpolation; - } - if (options.tension || options.cubicInterpolationMode === 'monotone') { - return _bezierInterpolation; - } - return _pointInLine; -} -function strokePathWithCache(ctx, line, start, count) { - let path = line._path; - if (!path) { - path = line._path = new Path2D(); - if (line.path(path, start, count)) { - path.closePath(); - } - } - setStyle(ctx, line.options); - ctx.stroke(path); -} -function strokePathDirect(ctx, line, start, count) { - const {segments, options} = line; - const segmentMethod = _getSegmentMethod(line); - for (const segment of segments) { - setStyle(ctx, options, segment.style); - ctx.beginPath(); - if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) { - ctx.closePath(); - } - ctx.stroke(); - } -} -const usePath2D = typeof Path2D === 'function'; -function draw(ctx, line, start, count) { - if (usePath2D && !line.options.segment) { - strokePathWithCache(ctx, line, start, count); - } else { - strokePathDirect(ctx, line, start, count); - } -} -class LineElement extends Element { - constructor(cfg) { - super(); - this.animated = true; - this.options = undefined; - this._chart = undefined; - this._loop = undefined; - this._fullLoop = undefined; - this._path = undefined; - this._points = undefined; - this._segments = undefined; - this._decimated = false; - this._pointsUpdated = false; - this._datasetIndex = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - updateControlPoints(chartArea, indexAxis) { - const options = this.options; - if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { - const loop = options.spanGaps ? this._loop : this._fullLoop; - _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); - this._pointsUpdated = true; - } - } - set points(points) { - this._points = points; - delete this._segments; - delete this._path; - this._pointsUpdated = false; - } - get points() { - return this._points; - } - get segments() { - return this._segments || (this._segments = _computeSegments(this, this.options.segment)); - } - first() { - const segments = this.segments; - const points = this.points; - return segments.length && points[segments[0].start]; - } - last() { - const segments = this.segments; - const points = this.points; - const count = segments.length; - return count && points[segments[count - 1].end]; - } - interpolate(point, property) { - const options = this.options; - const value = point[property]; - const points = this.points; - const segments = _boundSegments(this, {property, start: value, end: value}); - if (!segments.length) { - return; - } - const result = []; - const _interpolate = _getInterpolationMethod(options); - let i, ilen; - for (i = 0, ilen = segments.length; i < ilen; ++i) { - const {start, end} = segments[i]; - const p1 = points[start]; - const p2 = points[end]; - if (p1 === p2) { - result.push(p1); - continue; - } - const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); - const interpolated = _interpolate(p1, p2, t, options.stepped); - interpolated[property] = point[property]; - result.push(interpolated); - } - return result.length === 1 ? result[0] : result; - } - pathSegment(ctx, segment, params) { - const segmentMethod = _getSegmentMethod(this); - return segmentMethod(ctx, this, segment, params); - } - path(ctx, start, count) { - const segments = this.segments; - const segmentMethod = _getSegmentMethod(this); - let loop = this._loop; - start = start || 0; - count = count || (this.points.length - start); - for (const segment of segments) { - loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1}); - } - return !!loop; - } - draw(ctx, chartArea, start, count) { - const options = this.options || {}; - const points = this.points || []; - if (points.length && options.borderWidth) { - ctx.save(); - draw(ctx, this, start, count); - ctx.restore(); - } - if (this.animated) { - this._pointsUpdated = false; - this._path = undefined; - } - } -} -LineElement.id = 'line'; -LineElement.defaults = { - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0, - borderJoinStyle: 'miter', - borderWidth: 3, - capBezierPoints: true, - cubicInterpolationMode: 'default', - fill: false, - spanGaps: false, - stepped: false, - tension: 0, -}; -LineElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; -LineElement.descriptors = { - _scriptable: true, - _indexable: (name) => name !== 'borderDash' && name !== 'fill', -}; - -function inRange$1(el, pos, axis, useFinalPosition) { - const options = el.options; - const {[axis]: value} = el.getProps([axis], useFinalPosition); - return (Math.abs(pos - value) < options.radius + options.hitRadius); -} -class PointElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.parsed = undefined; - this.skip = undefined; - this.stop = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - inRange(mouseX, mouseY, useFinalPosition) { - const options = this.options; - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); - } - inXRange(mouseX, useFinalPosition) { - return inRange$1(this, mouseX, 'x', useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange$1(this, mouseY, 'y', useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y} = this.getProps(['x', 'y'], useFinalPosition); - return {x, y}; - } - size(options) { - options = options || this.options || {}; - let radius = options.radius || 0; - radius = Math.max(radius, radius && options.hoverRadius || 0); - const borderWidth = radius && options.borderWidth || 0; - return (radius + borderWidth) * 2; - } - draw(ctx, area) { - const options = this.options; - if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { - return; - } - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.fillStyle = options.backgroundColor; - drawPoint(ctx, options, this.x, this.y); - } - getRange() { - const options = this.options || {}; - return options.radius + options.hitRadius; - } -} -PointElement.id = 'point'; -PointElement.defaults = { - borderWidth: 1, - hitRadius: 1, - hoverBorderWidth: 1, - hoverRadius: 4, - pointStyle: 'circle', - radius: 3, - rotation: 0 -}; -PointElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; - -function getBarBounds(bar, useFinalPosition) { - const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); - let left, right, top, bottom, half; - if (bar.horizontal) { - half = height / 2; - left = Math.min(x, base); - right = Math.max(x, base); - top = y - half; - bottom = y + half; - } else { - half = width / 2; - left = x - half; - right = x + half; - top = Math.min(y, base); - bottom = Math.max(y, base); - } - return {left, top, right, bottom}; -} -function skipOrLimit(skip, value, min, max) { - return skip ? 0 : _limitValue(value, min, max); -} -function parseBorderWidth(bar, maxW, maxH) { - const value = bar.options.borderWidth; - const skip = bar.borderSkipped; - const o = toTRBL(value); - return { - t: skipOrLimit(skip.top, o.top, 0, maxH), - r: skipOrLimit(skip.right, o.right, 0, maxW), - b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), - l: skipOrLimit(skip.left, o.left, 0, maxW) - }; -} -function parseBorderRadius(bar, maxW, maxH) { - const {enableBorderRadius} = bar.getProps(['enableBorderRadius']); - const value = bar.options.borderRadius; - const o = toTRBLCorners(value); - const maxR = Math.min(maxW, maxH); - const skip = bar.borderSkipped; - const enableBorder = enableBorderRadius || isObject(value); - return { - topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), - topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), - bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), - bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) - }; -} -function boundingRects(bar) { - const bounds = getBarBounds(bar); - const width = bounds.right - bounds.left; - const height = bounds.bottom - bounds.top; - const border = parseBorderWidth(bar, width / 2, height / 2); - const radius = parseBorderRadius(bar, width / 2, height / 2); - return { - outer: { - x: bounds.left, - y: bounds.top, - w: width, - h: height, - radius - }, - inner: { - x: bounds.left + border.l, - y: bounds.top + border.t, - w: width - border.l - border.r, - h: height - border.t - border.b, - radius: { - topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), - topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), - bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), - bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)), - } - } - }; -} -function inRange(bar, x, y, useFinalPosition) { - const skipX = x === null; - const skipY = y === null; - const skipBoth = skipX && skipY; - const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); - return bounds - && (skipX || _isBetween(x, bounds.left, bounds.right)) - && (skipY || _isBetween(y, bounds.top, bounds.bottom)); -} -function hasRadius(radius) { - return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; -} -function addNormalRectPath(ctx, rect) { - ctx.rect(rect.x, rect.y, rect.w, rect.h); -} -function inflateRect(rect, amount, refRect = {}) { - const x = rect.x !== refRect.x ? -amount : 0; - const y = rect.y !== refRect.y ? -amount : 0; - const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; - const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; - return { - x: rect.x + x, - y: rect.y + y, - w: rect.w + w, - h: rect.h + h, - radius: rect.radius - }; -} -class BarElement extends Element { - constructor(cfg) { - super(); - this.options = undefined; - this.horizontal = undefined; - this.base = undefined; - this.width = undefined; - this.height = undefined; - this.inflateAmount = undefined; - if (cfg) { - Object.assign(this, cfg); - } - } - draw(ctx) { - const {inflateAmount, options: {borderColor, backgroundColor}} = this; - const {inner, outer} = boundingRects(this); - const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; - ctx.save(); - if (outer.w !== inner.w || outer.h !== inner.h) { - ctx.beginPath(); - addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); - ctx.clip(); - addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); - ctx.fillStyle = borderColor; - ctx.fill('evenodd'); - } - ctx.beginPath(); - addRectPath(ctx, inflateRect(inner, inflateAmount)); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - inRange(mouseX, mouseY, useFinalPosition) { - return inRange(this, mouseX, mouseY, useFinalPosition); - } - inXRange(mouseX, useFinalPosition) { - return inRange(this, mouseX, null, useFinalPosition); - } - inYRange(mouseY, useFinalPosition) { - return inRange(this, null, mouseY, useFinalPosition); - } - getCenterPoint(useFinalPosition) { - const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); - return { - x: horizontal ? (x + base) / 2 : x, - y: horizontal ? y : (y + base) / 2 - }; - } - getRange(axis) { - return axis === 'x' ? this.width / 2 : this.height / 2; - } -} -BarElement.id = 'bar'; -BarElement.defaults = { - borderSkipped: 'start', - borderWidth: 0, - borderRadius: 0, - inflateAmount: 'auto', - pointStyle: undefined -}; -BarElement.defaultRoutes = { - backgroundColor: 'backgroundColor', - borderColor: 'borderColor' -}; - -var elements = /*#__PURE__*/Object.freeze({ -__proto__: null, -ArcElement: ArcElement, -LineElement: LineElement, -PointElement: PointElement, -BarElement: BarElement -}); - -function lttbDecimation(data, start, count, availableWidth, options) { - const samples = options.samples || availableWidth; - if (samples >= count) { - return data.slice(start, start + count); - } - const decimated = []; - const bucketWidth = (count - 2) / (samples - 2); - let sampledIndex = 0; - const endIndex = start + count - 1; - let a = start; - let i, maxAreaPoint, maxArea, area, nextA; - decimated[sampledIndex++] = data[a]; - for (i = 0; i < samples - 2; i++) { - let avgX = 0; - let avgY = 0; - let j; - const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; - const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; - const avgRangeLength = avgRangeEnd - avgRangeStart; - for (j = avgRangeStart; j < avgRangeEnd; j++) { - avgX += data[j].x; - avgY += data[j].y; - } - avgX /= avgRangeLength; - avgY /= avgRangeLength; - const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; - const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; - const {x: pointAx, y: pointAy} = data[a]; - maxArea = area = -1; - for (j = rangeOffs; j < rangeTo; j++) { - area = 0.5 * Math.abs( - (pointAx - avgX) * (data[j].y - pointAy) - - (pointAx - data[j].x) * (avgY - pointAy) - ); - if (area > maxArea) { - maxArea = area; - maxAreaPoint = data[j]; - nextA = j; - } - } - decimated[sampledIndex++] = maxAreaPoint; - a = nextA; - } - decimated[sampledIndex++] = data[endIndex]; - return decimated; -} -function minMaxDecimation(data, start, count, availableWidth) { - let avgX = 0; - let countX = 0; - let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; - const decimated = []; - const endIndex = start + count - 1; - const xMin = data[start].x; - const xMax = data[endIndex].x; - const dx = xMax - xMin; - for (i = start; i < start + count; ++i) { - point = data[i]; - x = (point.x - xMin) / dx * availableWidth; - y = point.y; - const truncX = x | 0; - if (truncX === prevX) { - if (y < minY) { - minY = y; - minIndex = i; - } else if (y > maxY) { - maxY = y; - maxIndex = i; - } - avgX = (countX * avgX + point.x) / ++countX; - } else { - const lastIndex = i - 1; - if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { - const intermediateIndex1 = Math.min(minIndex, maxIndex); - const intermediateIndex2 = Math.max(minIndex, maxIndex); - if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex1], - x: avgX, - }); - } - if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { - decimated.push({ - ...data[intermediateIndex2], - x: avgX - }); - } - } - if (i > 0 && lastIndex !== startIndex) { - decimated.push(data[lastIndex]); - } - decimated.push(point); - prevX = truncX; - countX = 0; - minY = maxY = y; - minIndex = maxIndex = startIndex = i; - } - } - return decimated; -} -function cleanDecimatedDataset(dataset) { - if (dataset._decimated) { - const data = dataset._data; - delete dataset._decimated; - delete dataset._data; - Object.defineProperty(dataset, 'data', {value: data}); - } -} -function cleanDecimatedData(chart) { - chart.data.datasets.forEach((dataset) => { - cleanDecimatedDataset(dataset); - }); -} -function getStartAndCountOfVisiblePointsSimplified(meta, points) { - const pointCount = points.length; - let start = 0; - let count; - const {iScale} = meta; - const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); - if (minDefined) { - start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); - } - if (maxDefined) { - count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; - } else { - count = pointCount - start; - } - return {start, count}; -} -var plugin_decimation = { - id: 'decimation', - defaults: { - algorithm: 'min-max', - enabled: false, - }, - beforeElementsUpdate: (chart, args, options) => { - if (!options.enabled) { - cleanDecimatedData(chart); - return; - } - const availableWidth = chart.width; - chart.data.datasets.forEach((dataset, datasetIndex) => { - const {_data, indexAxis} = dataset; - const meta = chart.getDatasetMeta(datasetIndex); - const data = _data || dataset.data; - if (resolve([indexAxis, chart.options.indexAxis]) === 'y') { - return; - } - if (meta.type !== 'line') { - return; - } - const xAxis = chart.scales[meta.xAxisID]; - if (xAxis.type !== 'linear' && xAxis.type !== 'time') { - return; - } - if (chart.options.parsing) { - return; - } - let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data); - const threshold = options.threshold || 4 * availableWidth; - if (count <= threshold) { - cleanDecimatedDataset(dataset); - return; - } - if (isNullOrUndef(_data)) { - dataset._data = data; - delete dataset.data; - Object.defineProperty(dataset, 'data', { - configurable: true, - enumerable: true, - get: function() { - return this._decimated; - }, - set: function(d) { - this._data = d; - } - }); - } - let decimated; - switch (options.algorithm) { - case 'lttb': - decimated = lttbDecimation(data, start, count, availableWidth, options); - break; - case 'min-max': - decimated = minMaxDecimation(data, start, count, availableWidth); - break; - default: - throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); - } - dataset._decimated = decimated; - }); - }, - destroy(chart) { - cleanDecimatedData(chart); - } -}; - -function getLineByIndex(chart, index) { - const meta = chart.getDatasetMeta(index); - const visible = meta && chart.isDatasetVisible(index); - return visible ? meta.dataset : null; -} -function parseFillOption(line) { - const options = line.options; - const fillOption = options.fill; - let fill = valueOrDefault(fillOption && fillOption.target, fillOption); - if (fill === undefined) { - fill = !!options.backgroundColor; - } - if (fill === false || fill === null) { - return false; - } - if (fill === true) { - return 'origin'; - } - return fill; -} -function decodeFill(line, index, count) { - const fill = parseFillOption(line); - if (isObject(fill)) { - return isNaN(fill.value) ? false : fill; - } - let target = parseFloat(fill); - if (isNumberFinite(target) && Math.floor(target) === target) { - if (fill[0] === '-' || fill[0] === '+') { - target = index + target; - } - if (target === index || target < 0 || target >= count) { - return false; - } - return target; - } - return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill; -} -function computeLinearBoundary(source) { - const {scale = {}, fill} = source; - let target = null; - let horizontal; - if (fill === 'start') { - target = scale.bottom; - } else if (fill === 'end') { - target = scale.top; - } else if (isObject(fill)) { - target = scale.getPixelForValue(fill.value); - } else if (scale.getBasePixel) { - target = scale.getBasePixel(); - } - if (isNumberFinite(target)) { - horizontal = scale.isHorizontal(); - return { - x: horizontal ? target : null, - y: horizontal ? null : target - }; - } - return null; -} -class simpleArc { - constructor(opts) { - this.x = opts.x; - this.y = opts.y; - this.radius = opts.radius; - } - pathSegment(ctx, bounds, opts) { - const {x, y, radius} = this; - bounds = bounds || {start: 0, end: TAU}; - ctx.arc(x, y, radius, bounds.end, bounds.start, true); - return !opts.bounds; - } - interpolate(point) { - const {x, y, radius} = this; - const angle = point.angle; - return { - x: x + Math.cos(angle) * radius, - y: y + Math.sin(angle) * radius, - angle - }; - } -} -function computeCircularBoundary(source) { - const {scale, fill} = source; - const options = scale.options; - const length = scale.getLabels().length; - const target = []; - const start = options.reverse ? scale.max : scale.min; - const end = options.reverse ? scale.min : scale.max; - let i, center, value; - if (fill === 'start') { - value = start; - } else if (fill === 'end') { - value = end; - } else if (isObject(fill)) { - value = fill.value; - } else { - value = scale.getBaseValue(); - } - if (options.grid.circular) { - center = scale.getPointPositionForValue(0, start); - return new simpleArc({ - x: center.x, - y: center.y, - radius: scale.getDistanceFromCenterForValue(value) - }); - } - for (i = 0; i < length; ++i) { - target.push(scale.getPointPositionForValue(i, value)); - } - return target; -} -function computeBoundary(source) { - const scale = source.scale || {}; - if (scale.getPointPositionForValue) { - return computeCircularBoundary(source); - } - return computeLinearBoundary(source); -} -function findSegmentEnd(start, end, points) { - for (;end > start; end--) { - const point = points[end]; - if (!isNaN(point.x) && !isNaN(point.y)) { - break; - } - } - return end; -} -function pointsFromSegments(boundary, line) { - const {x = null, y = null} = boundary || {}; - const linePoints = line.points; - const points = []; - line.segments.forEach(({start, end}) => { - end = findSegmentEnd(start, end, linePoints); - const first = linePoints[start]; - const last = linePoints[end]; - if (y !== null) { - points.push({x: first.x, y}); - points.push({x: last.x, y}); - } else if (x !== null) { - points.push({x, y: first.y}); - points.push({x, y: last.y}); - } - }); - return points; -} -function buildStackLine(source) { - const {scale, index, line} = source; - const points = []; - const segments = line.segments; - const sourcePoints = line.points; - const linesBelow = getLinesBelow(scale, index); - linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - for (let j = segment.start; j <= segment.end; j++) { - addPointsBelow(points, sourcePoints[j], linesBelow); - } - } - return new LineElement({points, options: {}}); -} -function getLinesBelow(scale, index) { - const below = []; - const metas = scale.getMatchingVisibleMetas('line'); - for (let i = 0; i < metas.length; i++) { - const meta = metas[i]; - if (meta.index === index) { - break; - } - if (!meta.hidden) { - below.unshift(meta.dataset); - } - } - return below; -} -function addPointsBelow(points, sourcePoint, linesBelow) { - const postponed = []; - for (let j = 0; j < linesBelow.length; j++) { - const line = linesBelow[j]; - const {first, last, point} = findPoint(line, sourcePoint, 'x'); - if (!point || (first && last)) { - continue; - } - if (first) { - postponed.unshift(point); - } else { - points.push(point); - if (!last) { - break; - } - } - } - points.push(...postponed); -} -function findPoint(line, sourcePoint, property) { - const point = line.interpolate(sourcePoint, property); - if (!point) { - return {}; - } - const pointValue = point[property]; - const segments = line.segments; - const linePoints = line.points; - let first = false; - let last = false; - for (let i = 0; i < segments.length; i++) { - const segment = segments[i]; - const firstValue = linePoints[segment.start][property]; - const lastValue = linePoints[segment.end][property]; - if (_isBetween(pointValue, firstValue, lastValue)) { - first = pointValue === firstValue; - last = pointValue === lastValue; - break; - } - } - return {first, last, point}; -} -function getTarget(source) { - const {chart, fill, line} = source; - if (isNumberFinite(fill)) { - return getLineByIndex(chart, fill); - } - if (fill === 'stack') { - return buildStackLine(source); - } - if (fill === 'shape') { - return true; - } - const boundary = computeBoundary(source); - if (boundary instanceof simpleArc) { - return boundary; - } - return createBoundaryLine(boundary, line); -} -function createBoundaryLine(boundary, line) { - let points = []; - let _loop = false; - if (isArray(boundary)) { - _loop = true; - points = boundary; - } else { - points = pointsFromSegments(boundary, line); - } - return points.length ? new LineElement({ - points, - options: {tension: 0}, - _loop, - _fullLoop: _loop - }) : null; -} -function resolveTarget(sources, index, propagate) { - const source = sources[index]; - let fill = source.fill; - const visited = [index]; - let target; - if (!propagate) { - return fill; - } - while (fill !== false && visited.indexOf(fill) === -1) { - if (!isNumberFinite(fill)) { - return fill; - } - target = sources[fill]; - if (!target) { - return false; - } - if (target.visible) { - return fill; - } - visited.push(fill); - fill = target.fill; - } - return false; -} -function _clip(ctx, target, clipY) { - const {segments, points} = target; - let first = true; - let lineLoop = false; - ctx.beginPath(); - for (const segment of segments) { - const {start, end} = segment; - const firstPoint = points[start]; - const lastPoint = points[findSegmentEnd(start, end, points)]; - if (first) { - ctx.moveTo(firstPoint.x, firstPoint.y); - first = false; - } else { - ctx.lineTo(firstPoint.x, clipY); - ctx.lineTo(firstPoint.x, firstPoint.y); - } - lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop}); - if (lineLoop) { - ctx.closePath(); - } else { - ctx.lineTo(lastPoint.x, clipY); - } - } - ctx.lineTo(target.first().x, clipY); - ctx.closePath(); - ctx.clip(); -} -function getBounds(property, first, last, loop) { - if (loop) { - return; - } - let start = first[property]; - let end = last[property]; - if (property === 'angle') { - start = _normalizeAngle(start); - end = _normalizeAngle(end); - } - return {property, start, end}; -} -function _getEdge(a, b, prop, fn) { - if (a && b) { - return fn(a[prop], b[prop]); - } - return a ? a[prop] : b ? b[prop] : 0; -} -function _segments(line, target, property) { - const segments = line.segments; - const points = line.points; - const tpoints = target.points; - const parts = []; - for (const segment of segments) { - let {start, end} = segment; - end = findSegmentEnd(start, end, points); - const bounds = getBounds(property, points[start], points[end], segment.loop); - if (!target.segments) { - parts.push({ - source: segment, - target: bounds, - start: points[start], - end: points[end] - }); - continue; - } - const targetSegments = _boundSegments(target, bounds); - for (const tgt of targetSegments) { - const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); - const fillSources = _boundSegment(segment, points, subBounds); - for (const fillSource of fillSources) { - parts.push({ - source: fillSource, - target: tgt, - start: { - [property]: _getEdge(bounds, subBounds, 'start', Math.max) - }, - end: { - [property]: _getEdge(bounds, subBounds, 'end', Math.min) - } - }); - } - } - } - return parts; -} -function clipBounds(ctx, scale, bounds) { - const {top, bottom} = scale.chart.chartArea; - const {property, start, end} = bounds || {}; - if (property === 'x') { - ctx.beginPath(); - ctx.rect(start, top, end - start, bottom - top); - ctx.clip(); - } -} -function interpolatedLineTo(ctx, target, point, property) { - const interpolatedPoint = target.interpolate(point, property); - if (interpolatedPoint) { - ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); - } -} -function _fill(ctx, cfg) { - const {line, target, property, color, scale} = cfg; - const segments = _segments(line, target, property); - for (const {source: src, target: tgt, start, end} of segments) { - const {style: {backgroundColor = color} = {}} = src; - const notShape = target !== true; - ctx.save(); - ctx.fillStyle = backgroundColor; - clipBounds(ctx, scale, notShape && getBounds(property, start, end)); - ctx.beginPath(); - const lineLoop = !!line.pathSegment(ctx, src); - let loop; - if (notShape) { - if (lineLoop) { - ctx.closePath(); - } else { - interpolatedLineTo(ctx, target, end, property); - } - const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); - loop = lineLoop && targetLoop; - if (!loop) { - interpolatedLineTo(ctx, target, start, property); - } - } - ctx.closePath(); - ctx.fill(loop ? 'evenodd' : 'nonzero'); - ctx.restore(); - } -} -function doFill(ctx, cfg) { - const {line, target, above, below, area, scale} = cfg; - const property = line._loop ? 'angle' : cfg.axis; - ctx.save(); - if (property === 'x' && below !== above) { - _clip(ctx, target, area.top); - _fill(ctx, {line, target, color: above, scale, property}); - ctx.restore(); - ctx.save(); - _clip(ctx, target, area.bottom); - } - _fill(ctx, {line, target, color: below, scale, property}); - ctx.restore(); -} -function drawfill(ctx, source, area) { - const target = getTarget(source); - const {line, scale, axis} = source; - const lineOpts = line.options; - const fillOption = lineOpts.fill; - const color = lineOpts.backgroundColor; - const {above = color, below = color} = fillOption || {}; - if (target && line.points.length) { - clipArea(ctx, area); - doFill(ctx, {line, target, above, below, area, scale, axis}); - unclipArea(ctx); - } -} -var plugin_filler = { - id: 'filler', - afterDatasetsUpdate(chart, _args, options) { - const count = (chart.data.datasets || []).length; - const sources = []; - let meta, i, line, source; - for (i = 0; i < count; ++i) { - meta = chart.getDatasetMeta(i); - line = meta.dataset; - source = null; - if (line && line.options && line instanceof LineElement) { - source = { - visible: chart.isDatasetVisible(i), - index: i, - fill: decodeFill(line, i, count), - chart, - axis: meta.controller.options.indexAxis, - scale: meta.vScale, - line, - }; - } - meta.$filler = source; - sources.push(source); - } - for (i = 0; i < count; ++i) { - source = sources[i]; - if (!source || source.fill === false) { - continue; - } - source.fill = resolveTarget(sources, i, options.propagate); - } - }, - beforeDraw(chart, _args, options) { - const draw = options.drawTime === 'beforeDraw'; - const metasets = chart.getSortedVisibleDatasetMetas(); - const area = chart.chartArea; - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (!source) { - continue; - } - source.line.updateControlPoints(area, source.axis); - if (draw) { - drawfill(chart.ctx, source, area); - } - } - }, - beforeDatasetsDraw(chart, _args, options) { - if (options.drawTime !== 'beforeDatasetsDraw') { - return; - } - const metasets = chart.getSortedVisibleDatasetMetas(); - for (let i = metasets.length - 1; i >= 0; --i) { - const source = metasets[i].$filler; - if (source) { - drawfill(chart.ctx, source, chart.chartArea); - } - } - }, - beforeDatasetDraw(chart, args, options) { - const source = args.meta.$filler; - if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') { - return; - } - drawfill(chart.ctx, source, chart.chartArea); - }, - defaults: { - propagate: true, - drawTime: 'beforeDatasetDraw' - } -}; - -const getBoxSize = (labelOpts, fontSize) => { - let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts; - if (labelOpts.usePointStyle) { - boxHeight = Math.min(boxHeight, fontSize); - boxWidth = Math.min(boxWidth, fontSize); - } - return { - boxWidth, - boxHeight, - itemHeight: Math.max(fontSize, boxHeight) - }; -}; -const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; -class Legend extends Element { - constructor(config) { - super(); - this._added = false; - this.legendHitBoxes = []; - this._hoveredItem = null; - this.doughnutMode = false; - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this.legendItems = undefined; - this.columnSizes = undefined; - this.lineWidths = undefined; - this.maxHeight = undefined; - this.maxWidth = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.height = undefined; - this.width = undefined; - this._margins = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight, margins) { - this.maxWidth = maxWidth; - this.maxHeight = maxHeight; - this._margins = margins; - this.setDimensions(); - this.buildLabels(); - this.fit(); - } - setDimensions() { - if (this.isHorizontal()) { - this.width = this.maxWidth; - this.left = this._margins.left; - this.right = this.width; - } else { - this.height = this.maxHeight; - this.top = this._margins.top; - this.bottom = this.height; - } - } - buildLabels() { - const labelOpts = this.options.labels || {}; - let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || []; - if (labelOpts.filter) { - legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data)); - } - if (labelOpts.sort) { - legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data)); - } - if (this.options.reverse) { - legendItems.reverse(); - } - this.legendItems = legendItems; - } - fit() { - const {options, ctx} = this; - if (!options.display) { - this.width = this.height = 0; - return; - } - const labelOpts = options.labels; - const labelFont = toFont(labelOpts.font); - const fontSize = labelFont.size; - const titleHeight = this._computeTitleHeight(); - const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize); - let width, height; - ctx.font = labelFont.string; - if (this.isHorizontal()) { - width = this.maxWidth; - height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } else { - height = this.maxHeight; - width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10; - } - this.width = Math.min(width, options.maxWidth || this.maxWidth); - this.height = Math.min(height, options.maxHeight || this.maxHeight); - } - _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxWidth, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const lineWidths = this.lineWidths = [0]; - const lineHeight = itemHeight + padding; - let totalHeight = titleHeight; - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - let row = -1; - let top = -lineHeight; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { - totalHeight += lineHeight; - lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; - top += lineHeight; - row++; - } - hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight}; - lineWidths[lineWidths.length - 1] += itemWidth + padding; - }); - return totalHeight; - } - _fitCols(titleHeight, fontSize, boxWidth, itemHeight) { - const {ctx, maxHeight, options: {labels: {padding}}} = this; - const hitboxes = this.legendHitBoxes = []; - const columnSizes = this.columnSizes = []; - const heightLimit = maxHeight - titleHeight; - let totalWidth = padding; - let currentColWidth = 0; - let currentColHeight = 0; - let left = 0; - let col = 0; - this.legendItems.forEach((legendItem, i) => { - const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { - totalWidth += currentColWidth + padding; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - left += currentColWidth + padding; - col++; - currentColWidth = currentColHeight = 0; - } - hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight}; - currentColWidth = Math.max(currentColWidth, itemWidth); - currentColHeight += itemHeight + padding; - }); - totalWidth += currentColWidth; - columnSizes.push({width: currentColWidth, height: currentColHeight}); - return totalWidth; - } - adjustHitBoxes() { - if (!this.options.display) { - return; - } - const titleHeight = this._computeTitleHeight(); - const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this; - const rtlHelper = getRtlAdapter(rtl, this.left, this.width); - if (this.isHorizontal()) { - let row = 0; - let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); - for (const hitbox of hitboxes) { - if (row !== hitbox.row) { - row = hitbox.row; - left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); - } - hitbox.top += this.top + titleHeight + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); - left += hitbox.width + padding; - } - } else { - let col = 0; - let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); - for (const hitbox of hitboxes) { - if (hitbox.col !== col) { - col = hitbox.col; - top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); - } - hitbox.top = top; - hitbox.left += this.left + padding; - hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); - top += hitbox.height + padding; - } - } - } - isHorizontal() { - return this.options.position === 'top' || this.options.position === 'bottom'; - } - draw() { - if (this.options.display) { - const ctx = this.ctx; - clipArea(ctx, this); - this._draw(); - unclipArea(ctx); - } - } - _draw() { - const {options: opts, columnSizes, lineWidths, ctx} = this; - const {align, labels: labelOpts} = opts; - const defaultColor = defaults.color; - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const labelFont = toFont(labelOpts.font); - const {color: fontColor, padding} = labelOpts; - const fontSize = labelFont.size; - const halfFontSize = fontSize / 2; - let cursor; - this.drawTitle(); - ctx.textAlign = rtlHelper.textAlign('left'); - ctx.textBaseline = 'middle'; - ctx.lineWidth = 0.5; - ctx.font = labelFont.string; - const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize); - const drawLegendBox = function(x, y, legendItem) { - if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { - return; - } - ctx.save(); - const lineWidth = valueOrDefault(legendItem.lineWidth, 1); - ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); - ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); - ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); - ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); - ctx.lineWidth = lineWidth; - ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); - ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); - if (labelOpts.usePointStyle) { - const drawOptions = { - radius: boxWidth * Math.SQRT2 / 2, - pointStyle: legendItem.pointStyle, - rotation: legendItem.rotation, - borderWidth: lineWidth - }; - const centerX = rtlHelper.xPlus(x, boxWidth / 2); - const centerY = y + halfFontSize; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); - const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); - const borderRadius = toTRBLCorners(legendItem.borderRadius); - ctx.beginPath(); - if (Object.values(borderRadius).some(v => v !== 0)) { - addRoundedRectPath(ctx, { - x: xBoxLeft, - y: yBoxTop, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); - } else { - ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); - } - ctx.fill(); - if (lineWidth !== 0) { - ctx.stroke(); - } - } - ctx.restore(); - }; - const fillText = function(x, y, legendItem) { - renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, { - strikethrough: legendItem.hidden, - textAlign: rtlHelper.textAlign(legendItem.textAlign) - }); - }; - const isHorizontal = this.isHorizontal(); - const titleHeight = this._computeTitleHeight(); - if (isHorizontal) { - cursor = { - x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), - y: this.top + padding + titleHeight, - line: 0 - }; - } else { - cursor = { - x: this.left + padding, - y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), - line: 0 - }; - } - overrideTextDirection(this.ctx, opts.textDirection); - const lineHeight = itemHeight + padding; - this.legendItems.forEach((legendItem, i) => { - ctx.strokeStyle = legendItem.fontColor || fontColor; - ctx.fillStyle = legendItem.fontColor || fontColor; - const textWidth = ctx.measureText(legendItem.text).width; - const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); - const width = boxWidth + halfFontSize + textWidth; - let x = cursor.x; - let y = cursor.y; - rtlHelper.setWidth(this.width); - if (isHorizontal) { - if (i > 0 && x + width + padding > this.right) { - y = cursor.y += lineHeight; - cursor.line++; - x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); - } - } else if (i > 0 && y + lineHeight > this.bottom) { - x = cursor.x = x + columnSizes[cursor.line].width + padding; - cursor.line++; - y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); - } - const realX = rtlHelper.x(x); - drawLegendBox(realX, y, legendItem); - x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); - fillText(rtlHelper.x(x), y, legendItem); - if (isHorizontal) { - cursor.x += width + padding; - } else { - cursor.y += lineHeight; - } - }); - restoreTextDirection(this.ctx, opts.textDirection); - } - drawTitle() { - const opts = this.options; - const titleOpts = opts.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - if (!titleOpts.display) { - return; - } - const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); - const ctx = this.ctx; - const position = titleOpts.position; - const halfFontSize = titleFont.size / 2; - const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; - let y; - let left = this.left; - let maxWidth = this.width; - if (this.isHorizontal()) { - maxWidth = Math.max(...this.lineWidths); - y = this.top + topPaddingPlusHalfFontSize; - left = _alignStartEnd(opts.align, left, this.right - maxWidth); - } else { - const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0); - y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); - } - const x = _alignStartEnd(position, left, left + maxWidth); - ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); - ctx.textBaseline = 'middle'; - ctx.strokeStyle = titleOpts.color; - ctx.fillStyle = titleOpts.color; - ctx.font = titleFont.string; - renderText(ctx, titleOpts.text, x, y, titleFont); - } - _computeTitleHeight() { - const titleOpts = this.options.title; - const titleFont = toFont(titleOpts.font); - const titlePadding = toPadding(titleOpts.padding); - return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; - } - _getLegendItemAt(x, y) { - let i, hitBox, lh; - if (_isBetween(x, this.left, this.right) - && _isBetween(y, this.top, this.bottom)) { - lh = this.legendHitBoxes; - for (i = 0; i < lh.length; ++i) { - hitBox = lh[i]; - if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) - && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { - return this.legendItems[i]; - } - } - } - return null; - } - handleEvent(e) { - const opts = this.options; - if (!isListened(e.type, opts)) { - return; - } - const hoveredItem = this._getLegendItemAt(e.x, e.y); - if (e.type === 'mousemove') { - const previous = this._hoveredItem; - const sameItem = itemsEqual(previous, hoveredItem); - if (previous && !sameItem) { - callback(opts.onLeave, [e, previous, this], this); - } - this._hoveredItem = hoveredItem; - if (hoveredItem && !sameItem) { - callback(opts.onHover, [e, hoveredItem, this], this); - } - } else if (hoveredItem) { - callback(opts.onClick, [e, hoveredItem, this], this); - } - } -} -function isListened(type, opts) { - if (type === 'mousemove' && (opts.onHover || opts.onLeave)) { - return true; - } - if (opts.onClick && (type === 'click' || type === 'mouseup')) { - return true; - } - return false; -} -var plugin_legend = { - id: 'legend', - _element: Legend, - start(chart, _args, options) { - const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart}); - layouts.configure(chart, legend, options); - layouts.addBox(chart, legend); - }, - stop(chart) { - layouts.removeBox(chart, chart.legend); - delete chart.legend; - }, - beforeUpdate(chart, _args, options) { - const legend = chart.legend; - layouts.configure(chart, legend, options); - legend.options = options; - }, - afterUpdate(chart) { - const legend = chart.legend; - legend.buildLabels(); - legend.adjustHitBoxes(); - }, - afterEvent(chart, args) { - if (!args.replay) { - chart.legend.handleEvent(args.event); - } - }, - defaults: { - display: true, - position: 'top', - align: 'center', - fullSize: true, - reverse: false, - weight: 1000, - onClick(e, legendItem, legend) { - const index = legendItem.datasetIndex; - const ci = legend.chart; - if (ci.isDatasetVisible(index)) { - ci.hide(index); - legendItem.hidden = true; - } else { - ci.show(index); - legendItem.hidden = false; - } - }, - onHover: null, - onLeave: null, - labels: { - color: (ctx) => ctx.chart.options.color, - boxWidth: 40, - padding: 10, - generateLabels(chart) { - const datasets = chart.data.datasets; - const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options; - return chart._getSortedDatasetMetas().map((meta) => { - const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); - const borderWidth = toPadding(style.borderWidth); - return { - text: datasets[meta.index].label, - fillStyle: style.backgroundColor, - fontColor: color, - hidden: !meta.visible, - lineCap: style.borderCapStyle, - lineDash: style.borderDash, - lineDashOffset: style.borderDashOffset, - lineJoin: style.borderJoinStyle, - lineWidth: (borderWidth.width + borderWidth.height) / 4, - strokeStyle: style.borderColor, - pointStyle: pointStyle || style.pointStyle, - rotation: style.rotation, - textAlign: textAlign || style.textAlign, - borderRadius: 0, - datasetIndex: meta.index - }; - }, this); - } - }, - title: { - color: (ctx) => ctx.chart.options.color, - display: false, - position: 'center', - text: '', - } - }, - descriptors: { - _scriptable: (name) => !name.startsWith('on'), - labels: { - _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name), - } - }, -}; - -class Title extends Element { - constructor(config) { - super(); - this.chart = config.chart; - this.options = config.options; - this.ctx = config.ctx; - this._padding = undefined; - this.top = undefined; - this.bottom = undefined; - this.left = undefined; - this.right = undefined; - this.width = undefined; - this.height = undefined; - this.position = undefined; - this.weight = undefined; - this.fullSize = undefined; - } - update(maxWidth, maxHeight) { - const opts = this.options; - this.left = 0; - this.top = 0; - if (!opts.display) { - this.width = this.height = this.right = this.bottom = 0; - return; - } - this.width = this.right = maxWidth; - this.height = this.bottom = maxHeight; - const lineCount = isArray(opts.text) ? opts.text.length : 1; - this._padding = toPadding(opts.padding); - const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; - if (this.isHorizontal()) { - this.height = textSize; - } else { - this.width = textSize; - } - } - isHorizontal() { - const pos = this.options.position; - return pos === 'top' || pos === 'bottom'; - } - _drawArgs(offset) { - const {top, left, bottom, right, options} = this; - const align = options.align; - let rotation = 0; - let maxWidth, titleX, titleY; - if (this.isHorizontal()) { - titleX = _alignStartEnd(align, left, right); - titleY = top + offset; - maxWidth = right - left; - } else { - if (options.position === 'left') { - titleX = left + offset; - titleY = _alignStartEnd(align, bottom, top); - rotation = PI * -0.5; - } else { - titleX = right - offset; - titleY = _alignStartEnd(align, top, bottom); - rotation = PI * 0.5; - } - maxWidth = bottom - top; - } - return {titleX, titleY, maxWidth, rotation}; - } - draw() { - const ctx = this.ctx; - const opts = this.options; - if (!opts.display) { - return; - } - const fontOpts = toFont(opts.font); - const lineHeight = fontOpts.lineHeight; - const offset = lineHeight / 2 + this._padding.top; - const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset); - renderText(ctx, opts.text, 0, 0, fontOpts, { - color: opts.color, - maxWidth, - rotation, - textAlign: _toLeftRightCenter(opts.align), - textBaseline: 'middle', - translation: [titleX, titleY], - }); - } -} -function createTitle(chart, titleOpts) { - const title = new Title({ - ctx: chart.ctx, - options: titleOpts, - chart - }); - layouts.configure(chart, title, titleOpts); - layouts.addBox(chart, title); - chart.titleBlock = title; -} -var plugin_title = { - id: 'title', - _element: Title, - start(chart, _args, options) { - createTitle(chart, options); - }, - stop(chart) { - const titleBlock = chart.titleBlock; - layouts.removeBox(chart, titleBlock); - delete chart.titleBlock; - }, - beforeUpdate(chart, _args, options) { - const title = chart.titleBlock; - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'bold', - }, - fullSize: true, - padding: 10, - position: 'top', - text: '', - weight: 2000 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, -}; - -const map = new WeakMap(); -var plugin_subtitle = { - id: 'subtitle', - start(chart, _args, options) { - const title = new Title({ - ctx: chart.ctx, - options, - chart - }); - layouts.configure(chart, title, options); - layouts.addBox(chart, title); - map.set(chart, title); - }, - stop(chart) { - layouts.removeBox(chart, map.get(chart)); - map.delete(chart); - }, - beforeUpdate(chart, _args, options) { - const title = map.get(chart); - layouts.configure(chart, title, options); - title.options = options; - }, - defaults: { - align: 'center', - display: false, - font: { - weight: 'normal', - }, - fullSize: true, - padding: 0, - position: 'top', - text: '', - weight: 1500 - }, - defaultRoutes: { - color: 'color' - }, - descriptors: { - _scriptable: true, - _indexable: false, - }, -}; - -const positioners = { - average(items) { - if (!items.length) { - return false; - } - let i, len; - let x = 0; - let y = 0; - let count = 0; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const pos = el.tooltipPosition(); - x += pos.x; - y += pos.y; - ++count; - } - } - return { - x: x / count, - y: y / count - }; - }, - nearest(items, eventPosition) { - if (!items.length) { - return false; - } - let x = eventPosition.x; - let y = eventPosition.y; - let minDistance = Number.POSITIVE_INFINITY; - let i, len, nearestElement; - for (i = 0, len = items.length; i < len; ++i) { - const el = items[i].element; - if (el && el.hasValue()) { - const center = el.getCenterPoint(); - const d = distanceBetweenPoints(eventPosition, center); - if (d < minDistance) { - minDistance = d; - nearestElement = el; - } - } - } - if (nearestElement) { - const tp = nearestElement.tooltipPosition(); - x = tp.x; - y = tp.y; - } - return { - x, - y - }; - } -}; -function pushOrConcat(base, toPush) { - if (toPush) { - if (isArray(toPush)) { - Array.prototype.push.apply(base, toPush); - } else { - base.push(toPush); - } - } - return base; -} -function splitNewlines(str) { - if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { - return str.split('\n'); - } - return str; -} -function createTooltipItem(chart, item) { - const {element, datasetIndex, index} = item; - const controller = chart.getDatasetMeta(datasetIndex).controller; - const {label, value} = controller.getLabelAndValue(index); - return { - chart, - label, - parsed: controller.getParsed(index), - raw: chart.data.datasets[datasetIndex].data[index], - formattedValue: value, - dataset: controller.getDataset(), - dataIndex: index, - datasetIndex, - element - }; -} -function getTooltipSize(tooltip, options) { - const ctx = tooltip.chart.ctx; - const {body, footer, title} = tooltip; - const {boxWidth, boxHeight} = options; - const bodyFont = toFont(options.bodyFont); - const titleFont = toFont(options.titleFont); - const footerFont = toFont(options.footerFont); - const titleLineCount = title.length; - const footerLineCount = footer.length; - const bodyLineItemCount = body.length; - const padding = toPadding(options.padding); - let height = padding.height; - let width = 0; - let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); - combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; - if (titleLineCount) { - height += titleLineCount * titleFont.lineHeight - + (titleLineCount - 1) * options.titleSpacing - + options.titleMarginBottom; - } - if (combinedBodyLength) { - const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; - height += bodyLineItemCount * bodyLineHeight - + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight - + (combinedBodyLength - 1) * options.bodySpacing; - } - if (footerLineCount) { - height += options.footerMarginTop - + footerLineCount * footerFont.lineHeight - + (footerLineCount - 1) * options.footerSpacing; - } - let widthPadding = 0; - const maxLineWidth = function(line) { - width = Math.max(width, ctx.measureText(line).width + widthPadding); - }; - ctx.save(); - ctx.font = titleFont.string; - each(tooltip.title, maxLineWidth); - ctx.font = bodyFont.string; - each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); - widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0; - each(body, (bodyItem) => { - each(bodyItem.before, maxLineWidth); - each(bodyItem.lines, maxLineWidth); - each(bodyItem.after, maxLineWidth); - }); - widthPadding = 0; - ctx.font = footerFont.string; - each(tooltip.footer, maxLineWidth); - ctx.restore(); - width += padding.width; - return {width, height}; -} -function determineYAlign(chart, size) { - const {y, height} = size; - if (y < height / 2) { - return 'top'; - } else if (y > (chart.height - height / 2)) { - return 'bottom'; - } - return 'center'; -} -function doesNotFitWithAlign(xAlign, chart, options, size) { - const {x, width} = size; - const caret = options.caretSize + options.caretPadding; - if (xAlign === 'left' && x + width + caret > chart.width) { - return true; - } - if (xAlign === 'right' && x - width - caret < 0) { - return true; - } -} -function determineXAlign(chart, options, size, yAlign) { - const {x, width} = size; - const {width: chartWidth, chartArea: {left, right}} = chart; - let xAlign = 'center'; - if (yAlign === 'center') { - xAlign = x <= (left + right) / 2 ? 'left' : 'right'; - } else if (x <= width / 2) { - xAlign = 'left'; - } else if (x >= chartWidth - width / 2) { - xAlign = 'right'; - } - if (doesNotFitWithAlign(xAlign, chart, options, size)) { - xAlign = 'center'; - } - return xAlign; -} -function determineAlignment(chart, options, size) { - const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); - return { - xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), - yAlign - }; -} -function alignX(size, xAlign) { - let {x, width} = size; - if (xAlign === 'right') { - x -= width; - } else if (xAlign === 'center') { - x -= (width / 2); - } - return x; -} -function alignY(size, yAlign, paddingAndSize) { - let {y, height} = size; - if (yAlign === 'top') { - y += paddingAndSize; - } else if (yAlign === 'bottom') { - y -= height + paddingAndSize; - } else { - y -= (height / 2); - } - return y; -} -function getBackgroundPoint(options, size, alignment, chart) { - const {caretSize, caretPadding, cornerRadius} = options; - const {xAlign, yAlign} = alignment; - const paddingAndSize = caretSize + caretPadding; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - let x = alignX(size, xAlign); - const y = alignY(size, yAlign, paddingAndSize); - if (yAlign === 'center') { - if (xAlign === 'left') { - x += paddingAndSize; - } else if (xAlign === 'right') { - x -= paddingAndSize; - } - } else if (xAlign === 'left') { - x -= Math.max(topLeft, bottomLeft) + caretSize; - } else if (xAlign === 'right') { - x += Math.max(topRight, bottomRight) + caretSize; - } - return { - x: _limitValue(x, 0, chart.width - size.width), - y: _limitValue(y, 0, chart.height - size.height) - }; -} -function getAlignedX(tooltip, align, options) { - const padding = toPadding(options.padding); - return align === 'center' - ? tooltip.x + tooltip.width / 2 - : align === 'right' - ? tooltip.x + tooltip.width - padding.right - : tooltip.x + padding.left; -} -function getBeforeAfterBodyLines(callback) { - return pushOrConcat([], splitNewlines(callback)); -} -function createTooltipContext(parent, tooltip, tooltipItems) { - return createContext(parent, { - tooltip, - tooltipItems, - type: 'tooltip' - }); -} -function overrideCallbacks(callbacks, context) { - const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; - return override ? callbacks.override(override) : callbacks; -} -class Tooltip extends Element { - constructor(config) { - super(); - this.opacity = 0; - this._active = []; - this._eventPosition = undefined; - this._size = undefined; - this._cachedAnimations = undefined; - this._tooltipItems = []; - this.$animations = undefined; - this.$context = undefined; - this.chart = config.chart || config._chart; - this._chart = this.chart; - this.options = config.options; - this.dataPoints = undefined; - this.title = undefined; - this.beforeBody = undefined; - this.body = undefined; - this.afterBody = undefined; - this.footer = undefined; - this.xAlign = undefined; - this.yAlign = undefined; - this.x = undefined; - this.y = undefined; - this.height = undefined; - this.width = undefined; - this.caretX = undefined; - this.caretY = undefined; - this.labelColors = undefined; - this.labelPointStyles = undefined; - this.labelTextColors = undefined; - } - initialize(options) { - this.options = options; - this._cachedAnimations = undefined; - this.$context = undefined; - } - _resolveAnimations() { - const cached = this._cachedAnimations; - if (cached) { - return cached; - } - const chart = this.chart; - const options = this.options.setContext(this.getContext()); - const opts = options.enabled && chart.options.animation && options.animations; - const animations = new Animations(this.chart, opts); - if (opts._cacheable) { - this._cachedAnimations = Object.freeze(animations); - } - return animations; - } - getContext() { - return this.$context || - (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); - } - getTitle(context, options) { - const {callbacks} = options; - const beforeTitle = callbacks.beforeTitle.apply(this, [context]); - const title = callbacks.title.apply(this, [context]); - const afterTitle = callbacks.afterTitle.apply(this, [context]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeTitle)); - lines = pushOrConcat(lines, splitNewlines(title)); - lines = pushOrConcat(lines, splitNewlines(afterTitle)); - return lines; - } - getBeforeBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems])); - } - getBody(tooltipItems, options) { - const {callbacks} = options; - const bodyItems = []; - each(tooltipItems, (context) => { - const bodyItem = { - before: [], - lines: [], - after: [] - }; - const scoped = overrideCallbacks(callbacks, context); - pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context))); - pushOrConcat(bodyItem.lines, scoped.label.call(this, context)); - pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context))); - bodyItems.push(bodyItem); - }); - return bodyItems; - } - getAfterBody(tooltipItems, options) { - return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems])); - } - getFooter(tooltipItems, options) { - const {callbacks} = options; - const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]); - const footer = callbacks.footer.apply(this, [tooltipItems]); - const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]); - let lines = []; - lines = pushOrConcat(lines, splitNewlines(beforeFooter)); - lines = pushOrConcat(lines, splitNewlines(footer)); - lines = pushOrConcat(lines, splitNewlines(afterFooter)); - return lines; - } - _createItems(options) { - const active = this._active; - const data = this.chart.data; - const labelColors = []; - const labelPointStyles = []; - const labelTextColors = []; - let tooltipItems = []; - let i, len; - for (i = 0, len = active.length; i < len; ++i) { - tooltipItems.push(createTooltipItem(this.chart, active[i])); - } - if (options.filter) { - tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); - } - if (options.itemSort) { - tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); - } - each(tooltipItems, (context) => { - const scoped = overrideCallbacks(options.callbacks, context); - labelColors.push(scoped.labelColor.call(this, context)); - labelPointStyles.push(scoped.labelPointStyle.call(this, context)); - labelTextColors.push(scoped.labelTextColor.call(this, context)); - }); - this.labelColors = labelColors; - this.labelPointStyles = labelPointStyles; - this.labelTextColors = labelTextColors; - this.dataPoints = tooltipItems; - return tooltipItems; - } - update(changed, replay) { - const options = this.options.setContext(this.getContext()); - const active = this._active; - let properties; - let tooltipItems = []; - if (!active.length) { - if (this.opacity !== 0) { - properties = { - opacity: 0 - }; - } - } else { - const position = positioners[options.position].call(this, active, this._eventPosition); - tooltipItems = this._createItems(options); - this.title = this.getTitle(tooltipItems, options); - this.beforeBody = this.getBeforeBody(tooltipItems, options); - this.body = this.getBody(tooltipItems, options); - this.afterBody = this.getAfterBody(tooltipItems, options); - this.footer = this.getFooter(tooltipItems, options); - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, size); - const alignment = determineAlignment(this.chart, options, positionAndSize); - const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - properties = { - opacity: 1, - x: backgroundPoint.x, - y: backgroundPoint.y, - width: size.width, - height: size.height, - caretX: position.x, - caretY: position.y - }; - } - this._tooltipItems = tooltipItems; - this.$context = undefined; - if (properties) { - this._resolveAnimations().update(this, properties); - } - if (changed && options.external) { - options.external.call(this, {chart: this.chart, tooltip: this, replay}); - } - } - drawCaret(tooltipPoint, ctx, size, options) { - const caretPosition = this.getCaretPosition(tooltipPoint, size, options); - ctx.lineTo(caretPosition.x1, caretPosition.y1); - ctx.lineTo(caretPosition.x2, caretPosition.y2); - ctx.lineTo(caretPosition.x3, caretPosition.y3); - } - getCaretPosition(tooltipPoint, size, options) { - const {xAlign, yAlign} = this; - const {caretSize, cornerRadius} = options; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius); - const {x: ptX, y: ptY} = tooltipPoint; - const {width, height} = size; - let x1, x2, x3, y1, y2, y3; - if (yAlign === 'center') { - y2 = ptY + (height / 2); - if (xAlign === 'left') { - x1 = ptX; - x2 = x1 - caretSize; - y1 = y2 + caretSize; - y3 = y2 - caretSize; - } else { - x1 = ptX + width; - x2 = x1 + caretSize; - y1 = y2 - caretSize; - y3 = y2 + caretSize; - } - x3 = x1; - } else { - if (xAlign === 'left') { - x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize); - } else if (xAlign === 'right') { - x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; - } else { - x2 = this.caretX; - } - if (yAlign === 'top') { - y1 = ptY; - y2 = y1 - caretSize; - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } else { - y1 = ptY + height; - y2 = y1 + caretSize; - x1 = x2 + caretSize; - x3 = x2 - caretSize; - } - y3 = y1; - } - return {x1, x2, x3, y1, y2, y3}; - } - drawTitle(pt, ctx, options) { - const title = this.title; - const length = title.length; - let titleFont, titleSpacing, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.titleAlign, options); - ctx.textAlign = rtlHelper.textAlign(options.titleAlign); - ctx.textBaseline = 'middle'; - titleFont = toFont(options.titleFont); - titleSpacing = options.titleSpacing; - ctx.fillStyle = options.titleColor; - ctx.font = titleFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); - pt.y += titleFont.lineHeight + titleSpacing; - if (i + 1 === length) { - pt.y += options.titleMarginBottom - titleSpacing; - } - } - } - } - _drawColorBox(ctx, pt, i, rtlHelper, options) { - const labelColors = this.labelColors[i]; - const labelPointStyle = this.labelPointStyles[i]; - const {boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - const colorX = getAlignedX(this, 'left', options); - const rtlColorX = rtlHelper.x(colorX); - const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; - const colorY = pt.y + yOffSet; - if (options.usePointStyle) { - const drawOptions = { - radius: Math.min(boxWidth, boxHeight) / 2, - pointStyle: labelPointStyle.pointStyle, - rotation: labelPointStyle.rotation, - borderWidth: 1 - }; - const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; - const centerY = colorY + boxHeight / 2; - ctx.strokeStyle = options.multiKeyBackground; - ctx.fillStyle = options.multiKeyBackground; - drawPoint(ctx, drawOptions, centerX, centerY); - ctx.strokeStyle = labelColors.borderColor; - ctx.fillStyle = labelColors.backgroundColor; - drawPoint(ctx, drawOptions, centerX, centerY); - } else { - ctx.lineWidth = labelColors.borderWidth || 1; - ctx.strokeStyle = labelColors.borderColor; - ctx.setLineDash(labelColors.borderDash || []); - ctx.lineDashOffset = labelColors.borderDashOffset || 0; - const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding); - const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2); - const borderRadius = toTRBLCorners(labelColors.borderRadius); - if (Object.values(borderRadius).some(v => v !== 0)) { - ctx.beginPath(); - ctx.fillStyle = options.multiKeyBackground; - addRoundedRectPath(ctx, { - x: outerX, - y: colorY, - w: boxWidth, - h: boxHeight, - radius: borderRadius, - }); - ctx.fill(); - ctx.stroke(); - ctx.fillStyle = labelColors.backgroundColor; - ctx.beginPath(); - addRoundedRectPath(ctx, { - x: innerX, - y: colorY + 1, - w: boxWidth - 2, - h: boxHeight - 2, - radius: borderRadius, - }); - ctx.fill(); - } else { - ctx.fillStyle = options.multiKeyBackground; - ctx.fillRect(outerX, colorY, boxWidth, boxHeight); - ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); - ctx.fillStyle = labelColors.backgroundColor; - ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); - } - } - ctx.fillStyle = this.labelTextColors[i]; - } - drawBody(pt, ctx, options) { - const {body} = this; - const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options; - const bodyFont = toFont(options.bodyFont); - let bodyLineHeight = bodyFont.lineHeight; - let xLinePadding = 0; - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - const fillLineOfText = function(line) { - ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); - pt.y += bodyLineHeight + bodySpacing; - }; - const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); - let bodyItem, textColor, lines, i, j, ilen, jlen; - ctx.textAlign = bodyAlign; - ctx.textBaseline = 'middle'; - ctx.font = bodyFont.string; - pt.x = getAlignedX(this, bodyAlignForCalculation, options); - ctx.fillStyle = options.bodyColor; - each(this.beforeBody, fillLineOfText); - xLinePadding = displayColors && bodyAlignForCalculation !== 'right' - ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding) - : 0; - for (i = 0, ilen = body.length; i < ilen; ++i) { - bodyItem = body[i]; - textColor = this.labelTextColors[i]; - ctx.fillStyle = textColor; - each(bodyItem.before, fillLineOfText); - lines = bodyItem.lines; - if (displayColors && lines.length) { - this._drawColorBox(ctx, pt, i, rtlHelper, options); - bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); - } - for (j = 0, jlen = lines.length; j < jlen; ++j) { - fillLineOfText(lines[j]); - bodyLineHeight = bodyFont.lineHeight; - } - each(bodyItem.after, fillLineOfText); - } - xLinePadding = 0; - bodyLineHeight = bodyFont.lineHeight; - each(this.afterBody, fillLineOfText); - pt.y -= bodySpacing; - } - drawFooter(pt, ctx, options) { - const footer = this.footer; - const length = footer.length; - let footerFont, i; - if (length) { - const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); - pt.x = getAlignedX(this, options.footerAlign, options); - pt.y += options.footerMarginTop; - ctx.textAlign = rtlHelper.textAlign(options.footerAlign); - ctx.textBaseline = 'middle'; - footerFont = toFont(options.footerFont); - ctx.fillStyle = options.footerColor; - ctx.font = footerFont.string; - for (i = 0; i < length; ++i) { - ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); - pt.y += footerFont.lineHeight + options.footerSpacing; - } - } - } - drawBackground(pt, ctx, tooltipSize, options) { - const {xAlign, yAlign} = this; - const {x, y} = pt; - const {width, height} = tooltipSize; - const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius); - ctx.fillStyle = options.backgroundColor; - ctx.strokeStyle = options.borderColor; - ctx.lineWidth = options.borderWidth; - ctx.beginPath(); - ctx.moveTo(x + topLeft, y); - if (yAlign === 'top') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width - topRight, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); - if (yAlign === 'center' && xAlign === 'right') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + width, y + height - bottomRight); - ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); - if (yAlign === 'bottom') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x + bottomLeft, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); - if (yAlign === 'center' && xAlign === 'left') { - this.drawCaret(pt, ctx, tooltipSize, options); - } - ctx.lineTo(x, y + topLeft); - ctx.quadraticCurveTo(x, y, x + topLeft, y); - ctx.closePath(); - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } - } - _updateAnimationTarget(options) { - const chart = this.chart; - const anims = this.$animations; - const animX = anims && anims.x; - const animY = anims && anims.y; - if (animX || animY) { - const position = positioners[options.position].call(this, this._active, this._eventPosition); - if (!position) { - return; - } - const size = this._size = getTooltipSize(this, options); - const positionAndSize = Object.assign({}, position, this._size); - const alignment = determineAlignment(chart, options, positionAndSize); - const point = getBackgroundPoint(options, positionAndSize, alignment, chart); - if (animX._to !== point.x || animY._to !== point.y) { - this.xAlign = alignment.xAlign; - this.yAlign = alignment.yAlign; - this.width = size.width; - this.height = size.height; - this.caretX = position.x; - this.caretY = position.y; - this._resolveAnimations().update(this, point); - } - } - } - draw(ctx) { - const options = this.options.setContext(this.getContext()); - let opacity = this.opacity; - if (!opacity) { - return; - } - this._updateAnimationTarget(options); - const tooltipSize = { - width: this.width, - height: this.height - }; - const pt = { - x: this.x, - y: this.y - }; - opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; - const padding = toPadding(options.padding); - const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; - if (options.enabled && hasTooltipContent) { - ctx.save(); - ctx.globalAlpha = opacity; - this.drawBackground(pt, ctx, tooltipSize, options); - overrideTextDirection(ctx, options.textDirection); - pt.y += padding.top; - this.drawTitle(pt, ctx, options); - this.drawBody(pt, ctx, options); - this.drawFooter(pt, ctx, options); - restoreTextDirection(ctx, options.textDirection); - ctx.restore(); - } - } - getActiveElements() { - return this._active || []; - } - setActiveElements(activeElements, eventPosition) { - const lastActive = this._active; - const active = activeElements.map(({datasetIndex, index}) => { - const meta = this.chart.getDatasetMeta(datasetIndex); - if (!meta) { - throw new Error('Cannot find a dataset at index ' + datasetIndex); - } - return { - datasetIndex, - element: meta.data[index], - index, - }; - }); - const changed = !_elementsEqual(lastActive, active); - const positionChanged = this._positionChanged(active, eventPosition); - if (changed || positionChanged) { - this._active = active; - this._eventPosition = eventPosition; - this._ignoreReplayEvents = true; - this.update(true); - } - } - handleEvent(e, replay, inChartArea = true) { - if (replay && this._ignoreReplayEvents) { - return false; - } - this._ignoreReplayEvents = false; - const options = this.options; - const lastActive = this._active || []; - const active = this._getActiveElements(e, lastActive, replay, inChartArea); - const positionChanged = this._positionChanged(active, e); - const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; - if (changed) { - this._active = active; - if (options.enabled || options.external) { - this._eventPosition = { - x: e.x, - y: e.y - }; - this.update(true, replay); - } - } - return changed; - } - _getActiveElements(e, lastActive, replay, inChartArea) { - const options = this.options; - if (e.type === 'mouseout') { - return []; - } - if (!inChartArea) { - return lastActive; - } - const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); - if (options.reverse) { - active.reverse(); - } - return active; - } - _positionChanged(active, e) { - const {caretX, caretY, options} = this; - const position = positioners[options.position].call(this, active, e); - return position !== false && (caretX !== position.x || caretY !== position.y); - } -} -Tooltip.positioners = positioners; -var plugin_tooltip = { - id: 'tooltip', - _element: Tooltip, - positioners, - afterInit(chart, _args, options) { - if (options) { - chart.tooltip = new Tooltip({chart, options}); - } - }, - beforeUpdate(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - reset(chart, _args, options) { - if (chart.tooltip) { - chart.tooltip.initialize(options); - } - }, - afterDraw(chart) { - const tooltip = chart.tooltip; - const args = { - tooltip - }; - if (chart.notifyPlugins('beforeTooltipDraw', args) === false) { - return; - } - if (tooltip) { - tooltip.draw(chart.ctx); - } - chart.notifyPlugins('afterTooltipDraw', args); - }, - afterEvent(chart, args) { - if (chart.tooltip) { - const useFinalPosition = args.replay; - if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { - args.changed = true; - } - } - }, - defaults: { - enabled: true, - external: null, - position: 'average', - backgroundColor: 'rgba(0,0,0,0.8)', - titleColor: '#fff', - titleFont: { - weight: 'bold', - }, - titleSpacing: 2, - titleMarginBottom: 6, - titleAlign: 'left', - bodyColor: '#fff', - bodySpacing: 2, - bodyFont: { - }, - bodyAlign: 'left', - footerColor: '#fff', - footerSpacing: 2, - footerMarginTop: 6, - footerFont: { - weight: 'bold', - }, - footerAlign: 'left', - padding: 6, - caretPadding: 2, - caretSize: 5, - cornerRadius: 6, - boxHeight: (ctx, opts) => opts.bodyFont.size, - boxWidth: (ctx, opts) => opts.bodyFont.size, - multiKeyBackground: '#fff', - displayColors: true, - boxPadding: 0, - borderColor: 'rgba(0,0,0,0)', - borderWidth: 0, - animation: { - duration: 400, - easing: 'easeOutQuart', - }, - animations: { - numbers: { - type: 'number', - properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], - }, - opacity: { - easing: 'linear', - duration: 200 - } - }, - callbacks: { - beforeTitle: noop, - title(tooltipItems) { - if (tooltipItems.length > 0) { - const item = tooltipItems[0]; - const labels = item.chart.data.labels; - const labelCount = labels ? labels.length : 0; - if (this && this.options && this.options.mode === 'dataset') { - return item.dataset.label || ''; - } else if (item.label) { - return item.label; - } else if (labelCount > 0 && item.dataIndex < labelCount) { - return labels[item.dataIndex]; - } - } - return ''; - }, - afterTitle: noop, - beforeBody: noop, - beforeLabel: noop, - label(tooltipItem) { - if (this && this.options && this.options.mode === 'dataset') { - return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; - } - let label = tooltipItem.dataset.label || ''; - if (label) { - label += ': '; - } - const value = tooltipItem.formattedValue; - if (!isNullOrUndef(value)) { - label += value; - } - return label; - }, - labelColor(tooltipItem) { - const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); - const options = meta.controller.getStyle(tooltipItem.dataIndex); - return { - borderColor: options.borderColor, - backgroundColor: options.backgroundColor, - borderWidth: options.borderWidth, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderRadius: 0, - }; - }, - labelTextColor() { - return this.options.bodyColor; - }, - labelPointStyle(tooltipItem) { - const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); - const options = meta.controller.getStyle(tooltipItem.dataIndex); - return { - pointStyle: options.pointStyle, - rotation: options.rotation, - }; - }, - afterLabel: noop, - afterBody: noop, - beforeFooter: noop, - footer: noop, - afterFooter: noop - } - }, - defaultRoutes: { - bodyFont: 'font', - footerFont: 'font', - titleFont: 'font' - }, - descriptors: { - _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external', - _indexable: false, - callbacks: { - _scriptable: false, - _indexable: false, - }, - animation: { - _fallback: false - }, - animations: { - _fallback: 'animation' - } - }, - additionalOptionScopes: ['interaction'] -}; - -var plugins = /*#__PURE__*/Object.freeze({ -__proto__: null, -Decimation: plugin_decimation, -Filler: plugin_filler, -Legend: plugin_legend, -SubTitle: plugin_subtitle, -Title: plugin_title, -Tooltip: plugin_tooltip -}); - -const addIfString = (labels, raw, index, addedLabels) => { - if (typeof raw === 'string') { - index = labels.push(raw) - 1; - addedLabels.unshift({index, label: raw}); - } else if (isNaN(raw)) { - index = null; - } - return index; -}; -function findOrAddLabel(labels, raw, index, addedLabels) { - const first = labels.indexOf(raw); - if (first === -1) { - return addIfString(labels, raw, index, addedLabels); - } - const last = labels.lastIndexOf(raw); - return first !== last ? index : first; -} -const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max); -class CategoryScale extends Scale { - constructor(cfg) { - super(cfg); - this._startValue = undefined; - this._valueRange = 0; - this._addedLabels = []; - } - init(scaleOptions) { - const added = this._addedLabels; - if (added.length) { - const labels = this.getLabels(); - for (const {index, label} of added) { - if (labels[index] === label) { - labels.splice(index, 1); - } - } - this._addedLabels = []; - } - super.init(scaleOptions); - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; - } - const labels = this.getLabels(); - index = isFinite(index) && labels[index] === raw ? index - : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); - return validIndex(index, labels.length - 1); - } - determineDataLimits() { - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this.getMinMax(true); - if (this.options.bounds === 'ticks') { - if (!minDefined) { - min = 0; - } - if (!maxDefined) { - max = this.getLabels().length - 1; - } - } - this.min = min; - this.max = max; - } - buildTicks() { - const min = this.min; - const max = this.max; - const offset = this.options.offset; - const ticks = []; - let labels = this.getLabels(); - labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); - this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); - this._startValue = this.min - (offset ? 0.5 : 0); - for (let value = min; value <= max; value++) { - ticks.push({value}); - } - return ticks; - } - getLabelForValue(value) { - const labels = this.getLabels(); - if (value >= 0 && value < labels.length) { - return labels[value]; - } - return value; - } - configure() { - super.configure(); - if (!this.isHorizontal()) { - this._reversePixels = !this._reversePixels; - } - } - getPixelForValue(value) { - if (typeof value !== 'number') { - value = this.parse(value); - } - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getPixelForTick(index) { - const ticks = this.ticks; - if (index < 0 || index > ticks.length - 1) { - return null; - } - return this.getPixelForValue(ticks[index].value); - } - getValueForPixel(pixel) { - return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); - } - getBasePixel() { - return this.bottom; - } -} -CategoryScale.id = 'category'; -CategoryScale.defaults = { - ticks: { - callback: CategoryScale.prototype.getLabelForValue - } -}; - -function generateTicks$1(generationOptions, dataRange) { - const ticks = []; - const MIN_SPACING = 1e-14; - const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions; - const unit = step || 1; - const maxSpaces = maxTicks - 1; - const {min: rmin, max: rmax} = dataRange; - const minDefined = !isNullOrUndef(min); - const maxDefined = !isNullOrUndef(max); - const countDefined = !isNullOrUndef(count); - const minSpacing = (rmax - rmin) / (maxDigits + 1); - let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; - let factor, niceMin, niceMax, numSpaces; - if (spacing < MIN_SPACING && !minDefined && !maxDefined) { - return [{value: rmin}, {value: rmax}]; - } - numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); - if (numSpaces > maxSpaces) { - spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; - } - if (!isNullOrUndef(precision)) { - factor = Math.pow(10, precision); - spacing = Math.ceil(spacing * factor) / factor; - } - if (bounds === 'ticks') { - niceMin = Math.floor(rmin / spacing) * spacing; - niceMax = Math.ceil(rmax / spacing) * spacing; - } else { - niceMin = rmin; - niceMax = rmax; - } - if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { - numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); - spacing = (max - min) / numSpaces; - niceMin = min; - niceMax = max; - } else if (countDefined) { - niceMin = minDefined ? min : niceMin; - niceMax = maxDefined ? max : niceMax; - numSpaces = count - 1; - spacing = (niceMax - niceMin) / numSpaces; - } else { - numSpaces = (niceMax - niceMin) / spacing; - if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { - numSpaces = Math.round(numSpaces); - } else { - numSpaces = Math.ceil(numSpaces); - } - } - const decimalPlaces = Math.max( - _decimalPlaces(spacing), - _decimalPlaces(niceMin) - ); - factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); - niceMin = Math.round(niceMin * factor) / factor; - niceMax = Math.round(niceMax * factor) / factor; - let j = 0; - if (minDefined) { - if (includeBounds && niceMin !== min) { - ticks.push({value: min}); - if (niceMin < min) { - j++; - } - if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { - j++; - } - } else if (niceMin < min) { - j++; - } - } - for (; j < numSpaces; ++j) { - ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); - } - if (maxDefined && includeBounds && niceMax !== max) { - if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { - ticks[ticks.length - 1].value = max; - } else { - ticks.push({value: max}); - } - } else if (!maxDefined || niceMax === max) { - ticks.push({value: niceMax}); - } - return ticks; -} -function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) { - const rad = toRadians(minRotation); - const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; - const length = 0.75 * minSpacing * ('' + value).length; - return Math.min(minSpacing / ratio, length); -} -class LinearScaleBase extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._endValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - if (isNullOrUndef(raw)) { - return null; - } - if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { - return null; - } - return +raw; - } - handleTickRangeOptions() { - const {beginAtZero} = this.options; - const {minDefined, maxDefined} = this.getUserBounds(); - let {min, max} = this; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - if (beginAtZero) { - const minSign = sign(min); - const maxSign = sign(max); - if (minSign < 0 && maxSign < 0) { - setMax(0); - } else if (minSign > 0 && maxSign > 0) { - setMin(0); - } - } - if (min === max) { - let offset = 1; - if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) { - offset = Math.abs(max * 0.05); - } - setMax(max + offset); - if (!beginAtZero) { - setMin(min - offset); - } - } - this.min = min; - this.max = max; - } - getTickLimit() { - const tickOpts = this.options.ticks; - let {maxTicksLimit, stepSize} = tickOpts; - let maxTicks; - if (stepSize) { - maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; - if (maxTicks > 1000) { - console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); - maxTicks = 1000; - } - } else { - maxTicks = this.computeTickLimit(); - maxTicksLimit = maxTicksLimit || 11; - } - if (maxTicksLimit) { - maxTicks = Math.min(maxTicksLimit, maxTicks); - } - return maxTicks; - } - computeTickLimit() { - return Number.POSITIVE_INFINITY; - } - buildTicks() { - const opts = this.options; - const tickOpts = opts.ticks; - let maxTicks = this.getTickLimit(); - maxTicks = Math.max(2, maxTicks); - const numericGeneratorOptions = { - maxTicks, - bounds: opts.bounds, - min: opts.min, - max: opts.max, - precision: tickOpts.precision, - step: tickOpts.stepSize, - count: tickOpts.count, - maxDigits: this._maxDigits(), - horizontal: this.isHorizontal(), - minRotation: tickOpts.minRotation || 0, - includeBounds: tickOpts.includeBounds !== false - }; - const dataRange = this._range || this; - const ticks = generateTicks$1(numericGeneratorOptions, dataRange); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); - } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; - } - return ticks; - } - configure() { - const ticks = this.ticks; - let start = this.min; - let end = this.max; - super.configure(); - if (this.options.offset && ticks.length) { - const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; - start -= offset; - end += offset; - } - this._startValue = start; - this._endValue = end; - this._valueRange = end - start; - } - getLabelForValue(value) { - return formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } -} - -class LinearScale extends LinearScaleBase { - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? min : 0; - this.max = isNumberFinite(max) ? max : 1; - this.handleTickRangeOptions(); - } - computeTickLimit() { - const horizontal = this.isHorizontal(); - const length = horizontal ? this.width : this.height; - const minRotation = toRadians(this.options.ticks.minRotation); - const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; - const tickFont = this._resolveTickFontOptions(0); - return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); - } - getPixelForValue(value) { - return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; - } -} -LinearScale.id = 'linear'; -LinearScale.defaults = { - ticks: { - callback: Ticks.formatters.numeric - } -}; - -function isMajor(tickVal) { - const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); - return remain === 1; -} -function generateTicks(generationOptions, dataRange) { - const endExp = Math.floor(log10(dataRange.max)); - const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); - const ticks = []; - let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); - let exp = Math.floor(log10(tickVal)); - let significand = Math.floor(tickVal / Math.pow(10, exp)); - let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; - do { - ticks.push({value: tickVal, major: isMajor(tickVal)}); - ++significand; - if (significand === 10) { - significand = 1; - ++exp; - precision = exp >= 0 ? 1 : precision; - } - tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; - } while (exp < endExp || (exp === endExp && significand < endSignificand)); - const lastTick = finiteOrDefault(generationOptions.max, tickVal); - ticks.push({value: lastTick, major: isMajor(tickVal)}); - return ticks; -} -class LogarithmicScale extends Scale { - constructor(cfg) { - super(cfg); - this.start = undefined; - this.end = undefined; - this._startValue = undefined; - this._valueRange = 0; - } - parse(raw, index) { - const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); - if (value === 0) { - this._zero = true; - return undefined; - } - return isNumberFinite(value) && value > 0 ? value : null; - } - determineDataLimits() { - const {min, max} = this.getMinMax(true); - this.min = isNumberFinite(min) ? Math.max(0, min) : null; - this.max = isNumberFinite(max) ? Math.max(0, max) : null; - if (this.options.beginAtZero) { - this._zero = true; - } - this.handleTickRangeOptions(); - } - handleTickRangeOptions() { - const {minDefined, maxDefined} = this.getUserBounds(); - let min = this.min; - let max = this.max; - const setMin = v => (min = minDefined ? min : v); - const setMax = v => (max = maxDefined ? max : v); - const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m); - if (min === max) { - if (min <= 0) { - setMin(1); - setMax(10); - } else { - setMin(exp(min, -1)); - setMax(exp(max, +1)); - } - } - if (min <= 0) { - setMin(exp(max, -1)); - } - if (max <= 0) { - setMax(exp(min, +1)); - } - if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) { - setMin(exp(min, -1)); - } - this.min = min; - this.max = max; - } - buildTicks() { - const opts = this.options; - const generationOptions = { - min: this._userMin, - max: this._userMax - }; - const ticks = generateTicks(generationOptions, this); - if (opts.bounds === 'ticks') { - _setMinAndMaxByKey(ticks, this, 'value'); - } - if (opts.reverse) { - ticks.reverse(); - this.start = this.max; - this.end = this.min; - } else { - this.start = this.min; - this.end = this.max; - } - return ticks; - } - getLabelForValue(value) { - return value === undefined - ? '0' - : formatNumber(value, this.chart.options.locale, this.options.ticks.format); - } - configure() { - const start = this.min; - super.configure(); - this._startValue = log10(start); - this._valueRange = log10(this.max) - log10(start); - } - getPixelForValue(value) { - if (value === undefined || value === 0) { - value = this.min; - } - if (value === null || isNaN(value)) { - return NaN; - } - return this.getPixelForDecimal(value === this.min - ? 0 - : (log10(value) - this._startValue) / this._valueRange); - } - getValueForPixel(pixel) { - const decimal = this.getDecimalForPixel(pixel); - return Math.pow(10, this._startValue + decimal * this._valueRange); - } -} -LogarithmicScale.id = 'logarithmic'; -LogarithmicScale.defaults = { - ticks: { - callback: Ticks.formatters.logarithmic, - major: { - enabled: true - } - } -}; - -function getTickBackdropHeight(opts) { - const tickOpts = opts.ticks; - if (tickOpts.display && opts.display) { - const padding = toPadding(tickOpts.backdropPadding); - return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; - } - return 0; -} -function measureLabelSize(ctx, font, label) { - label = isArray(label) ? label : [label]; - return { - w: _longestText(ctx, font.string, label), - h: label.length * font.lineHeight - }; -} -function determineLimits(angle, pos, size, min, max) { - if (angle === min || angle === max) { - return { - start: pos - (size / 2), - end: pos + (size / 2) - }; - } else if (angle < min || angle > max) { - return { - start: pos - size, - end: pos - }; - } - return { - start: pos, - end: pos + size - }; -} -function fitWithPointLabels(scale) { - const orig = { - l: scale.left + scale._padding.left, - r: scale.right - scale._padding.right, - t: scale.top + scale._padding.top, - b: scale.bottom - scale._padding.bottom - }; - const limits = Object.assign({}, orig); - const labelSizes = []; - const padding = []; - const valueCount = scale._pointLabels.length; - const pointLabelOpts = scale.options.pointLabels; - const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); - padding[i] = opts.padding; - const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); - const plFont = toFont(opts.font); - const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); - labelSizes[i] = textSize; - const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); - const angle = Math.round(toDegrees(angleRadians)); - const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); - const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); - updateLimits(limits, orig, angleRadians, hLimits, vLimits); - } - scale.setCenterPoint( - orig.l - limits.l, - limits.r - orig.r, - orig.t - limits.t, - limits.b - orig.b - ); - scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); -} -function updateLimits(limits, orig, angle, hLimits, vLimits) { - const sin = Math.abs(Math.sin(angle)); - const cos = Math.abs(Math.cos(angle)); - let x = 0; - let y = 0; - if (hLimits.start < orig.l) { - x = (orig.l - hLimits.start) / sin; - limits.l = Math.min(limits.l, orig.l - x); - } else if (hLimits.end > orig.r) { - x = (hLimits.end - orig.r) / sin; - limits.r = Math.max(limits.r, orig.r + x); - } - if (vLimits.start < orig.t) { - y = (orig.t - vLimits.start) / cos; - limits.t = Math.min(limits.t, orig.t - y); - } else if (vLimits.end > orig.b) { - y = (vLimits.end - orig.b) / cos; - limits.b = Math.max(limits.b, orig.b + y); - } -} -function buildPointLabelItems(scale, labelSizes, padding) { - const items = []; - const valueCount = scale._pointLabels.length; - const opts = scale.options; - const extra = getTickBackdropHeight(opts) / 2; - const outerDistance = scale.drawingArea; - const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0; - for (let i = 0; i < valueCount; i++) { - const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle); - const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); - const size = labelSizes[i]; - const y = yForAngle(pointLabelPosition.y, size.h, angle); - const textAlign = getTextAlignForAngle(angle); - const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); - items.push({ - x: pointLabelPosition.x, - y, - textAlign, - left, - top: y, - right: left + size.w, - bottom: y + size.h - }); - } - return items; -} -function getTextAlignForAngle(angle) { - if (angle === 0 || angle === 180) { - return 'center'; - } else if (angle < 180) { - return 'left'; - } - return 'right'; -} -function leftForTextAlign(x, w, align) { - if (align === 'right') { - x -= w; - } else if (align === 'center') { - x -= (w / 2); - } - return x; -} -function yForAngle(y, h, angle) { - if (angle === 90 || angle === 270) { - y -= (h / 2); - } else if (angle > 270 || angle < 90) { - y -= h; - } - return y; -} -function drawPointLabels(scale, labelCount) { - const {ctx, options: {pointLabels}} = scale; - for (let i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); - const plFont = toFont(optsAtIndex.font); - const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i]; - const {backdropColor} = optsAtIndex; - if (!isNullOrUndef(backdropColor)) { - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillStyle = backdropColor; - ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height); - } - renderText( - ctx, - scale._pointLabels[i], - x, - y + (plFont.lineHeight / 2), - plFont, - { - color: optsAtIndex.color, - textAlign: textAlign, - textBaseline: 'middle' - } - ); - } -} -function pathRadiusLine(scale, radius, circular, labelCount) { - const {ctx} = scale; - if (circular) { - ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); - } else { - let pointPosition = scale.getPointPosition(0, radius); - ctx.moveTo(pointPosition.x, pointPosition.y); - for (let i = 1; i < labelCount; i++) { - pointPosition = scale.getPointPosition(i, radius); - ctx.lineTo(pointPosition.x, pointPosition.y); - } - } -} -function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { - const ctx = scale.ctx; - const circular = gridLineOpts.circular; - const {color, lineWidth} = gridLineOpts; - if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { - return; - } - ctx.save(); - ctx.strokeStyle = color; - ctx.lineWidth = lineWidth; - ctx.setLineDash(gridLineOpts.borderDash); - ctx.lineDashOffset = gridLineOpts.borderDashOffset; - ctx.beginPath(); - pathRadiusLine(scale, radius, circular, labelCount); - ctx.closePath(); - ctx.stroke(); - ctx.restore(); -} -function createPointLabelContext(parent, index, label) { - return createContext(parent, { - label, - index, - type: 'pointLabel' - }); -} -class RadialLinearScale extends LinearScaleBase { - constructor(cfg) { - super(cfg); - this.xCenter = undefined; - this.yCenter = undefined; - this.drawingArea = undefined; - this._pointLabels = []; - this._pointLabelItems = []; - } - setDimensions() { - const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); - const w = this.width = this.maxWidth - padding.width; - const h = this.height = this.maxHeight - padding.height; - this.xCenter = Math.floor(this.left + w / 2 + padding.left); - this.yCenter = Math.floor(this.top + h / 2 + padding.top); - this.drawingArea = Math.floor(Math.min(w, h) / 2); - } - determineDataLimits() { - const {min, max} = this.getMinMax(false); - this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; - this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; - this.handleTickRangeOptions(); - } - computeTickLimit() { - return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); - } - generateTickLabels(ticks) { - LinearScaleBase.prototype.generateTickLabels.call(this, ticks); - this._pointLabels = this.getLabels() - .map((value, index) => { - const label = callback(this.options.pointLabels.callback, [value, index], this); - return label || label === 0 ? label : ''; - }) - .filter((v, i) => this.chart.getDataVisibility(i)); - } - fit() { - const opts = this.options; - if (opts.display && opts.pointLabels.display) { - fitWithPointLabels(this); - } else { - this.setCenterPoint(0, 0, 0, 0); - } - } - setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { - this.xCenter += Math.floor((leftMovement - rightMovement) / 2); - this.yCenter += Math.floor((topMovement - bottomMovement) / 2); - this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); - } - getIndexAngle(index) { - const angleMultiplier = TAU / (this._pointLabels.length || 1); - const startAngle = this.options.startAngle || 0; - return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); - } - getDistanceFromCenterForValue(value) { - if (isNullOrUndef(value)) { - return NaN; - } - const scalingFactor = this.drawingArea / (this.max - this.min); - if (this.options.reverse) { - return (this.max - value) * scalingFactor; - } - return (value - this.min) * scalingFactor; - } - getValueForDistanceFromCenter(distance) { - if (isNullOrUndef(distance)) { - return NaN; - } - const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); - return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; - } - getPointLabelContext(index) { - const pointLabels = this._pointLabels || []; - if (index >= 0 && index < pointLabels.length) { - const pointLabel = pointLabels[index]; - return createPointLabelContext(this.getContext(), index, pointLabel); - } - } - getPointPosition(index, distanceFromCenter, additionalAngle = 0) { - const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; - return { - x: Math.cos(angle) * distanceFromCenter + this.xCenter, - y: Math.sin(angle) * distanceFromCenter + this.yCenter, - angle - }; - } - getPointPositionForValue(index, value) { - return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); - } - getBasePosition(index) { - return this.getPointPositionForValue(index || 0, this.getBaseValue()); - } - getPointLabelPosition(index) { - const {left, top, right, bottom} = this._pointLabelItems[index]; - return { - left, - top, - right, - bottom, - }; - } - drawBackground() { - const {backgroundColor, grid: {circular}} = this.options; - if (backgroundColor) { - const ctx = this.ctx; - ctx.save(); - ctx.beginPath(); - pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); - ctx.closePath(); - ctx.fillStyle = backgroundColor; - ctx.fill(); - ctx.restore(); - } - } - drawGrid() { - const ctx = this.ctx; - const opts = this.options; - const {angleLines, grid} = opts; - const labelCount = this._pointLabels.length; - let i, offset, position; - if (opts.pointLabels.display) { - drawPointLabels(this, labelCount); - } - if (grid.display) { - this.ticks.forEach((tick, index) => { - if (index !== 0) { - offset = this.getDistanceFromCenterForValue(tick.value); - const optsAtIndex = grid.setContext(this.getContext(index - 1)); - drawRadiusLine(this, optsAtIndex, offset, labelCount); - } - }); - } - if (angleLines.display) { - ctx.save(); - for (i = labelCount - 1; i >= 0; i--) { - const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); - const {color, lineWidth} = optsAtIndex; - if (!lineWidth || !color) { - continue; - } - ctx.lineWidth = lineWidth; - ctx.strokeStyle = color; - ctx.setLineDash(optsAtIndex.borderDash); - ctx.lineDashOffset = optsAtIndex.borderDashOffset; - offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max); - position = this.getPointPosition(i, offset); - ctx.beginPath(); - ctx.moveTo(this.xCenter, this.yCenter); - ctx.lineTo(position.x, position.y); - ctx.stroke(); - } - ctx.restore(); - } - } - drawBorder() {} - drawLabels() { - const ctx = this.ctx; - const opts = this.options; - const tickOpts = opts.ticks; - if (!tickOpts.display) { - return; - } - const startAngle = this.getIndexAngle(0); - let offset, width; - ctx.save(); - ctx.translate(this.xCenter, this.yCenter); - ctx.rotate(startAngle); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - this.ticks.forEach((tick, index) => { - if (index === 0 && !opts.reverse) { - return; - } - const optsAtIndex = tickOpts.setContext(this.getContext(index)); - const tickFont = toFont(optsAtIndex.font); - offset = this.getDistanceFromCenterForValue(this.ticks[index].value); - if (optsAtIndex.showLabelBackdrop) { - ctx.font = tickFont.string; - width = ctx.measureText(tick.label).width; - ctx.fillStyle = optsAtIndex.backdropColor; - const padding = toPadding(optsAtIndex.backdropPadding); - ctx.fillRect( - -width / 2 - padding.left, - -offset - tickFont.size / 2 - padding.top, - width + padding.width, - tickFont.size + padding.height - ); - } - renderText(ctx, tick.label, 0, -offset, tickFont, { - color: optsAtIndex.color, - }); - }); - ctx.restore(); - } - drawTitle() {} -} -RadialLinearScale.id = 'radialLinear'; -RadialLinearScale.defaults = { - display: true, - animate: true, - position: 'chartArea', - angleLines: { - display: true, - lineWidth: 1, - borderDash: [], - borderDashOffset: 0.0 - }, - grid: { - circular: false - }, - startAngle: 0, - ticks: { - showLabelBackdrop: true, - callback: Ticks.formatters.numeric - }, - pointLabels: { - backdropColor: undefined, - backdropPadding: 2, - display: true, - font: { - size: 10 - }, - callback(label) { - return label; - }, - padding: 5, - centerPointLabels: false - } -}; -RadialLinearScale.defaultRoutes = { - 'angleLines.color': 'borderColor', - 'pointLabels.color': 'color', - 'ticks.color': 'color' -}; -RadialLinearScale.descriptors = { - angleLines: { - _fallback: 'grid' - } -}; - -const INTERVALS = { - millisecond: {common: true, size: 1, steps: 1000}, - second: {common: true, size: 1000, steps: 60}, - minute: {common: true, size: 60000, steps: 60}, - hour: {common: true, size: 3600000, steps: 24}, - day: {common: true, size: 86400000, steps: 30}, - week: {common: false, size: 604800000, steps: 4}, - month: {common: true, size: 2.628e9, steps: 12}, - quarter: {common: false, size: 7.884e9, steps: 4}, - year: {common: true, size: 3.154e10} -}; -const UNITS = (Object.keys(INTERVALS)); -function sorter(a, b) { - return a - b; -} -function parse(scale, input) { - if (isNullOrUndef(input)) { - return null; - } - const adapter = scale._adapter; - const {parser, round, isoWeekday} = scale._parseOpts; - let value = input; - if (typeof parser === 'function') { - value = parser(value); - } - if (!isNumberFinite(value)) { - value = typeof parser === 'string' - ? adapter.parse(value, parser) - : adapter.parse(value); - } - if (value === null) { - return null; - } - if (round) { - value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) - ? adapter.startOf(value, 'isoWeek', isoWeekday) - : adapter.startOf(value, round); - } - return +value; -} -function determineUnitForAutoTicks(minUnit, min, max, capacity) { - const ilen = UNITS.length; - for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { - const interval = INTERVALS[UNITS[i]]; - const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; - if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { - return UNITS[i]; - } - } - return UNITS[ilen - 1]; -} -function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { - for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { - const unit = UNITS[i]; - if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { - return unit; - } - } - return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; -} -function determineMajorUnit(unit) { - for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { - if (INTERVALS[UNITS[i]].common) { - return UNITS[i]; - } - } -} -function addTick(ticks, time, timestamps) { - if (!timestamps) { - ticks[time] = true; - } else if (timestamps.length) { - const {lo, hi} = _lookup(timestamps, time); - const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; - ticks[timestamp] = true; - } -} -function setMajorTicks(scale, ticks, map, majorUnit) { - const adapter = scale._adapter; - const first = +adapter.startOf(ticks[0].value, majorUnit); - const last = ticks[ticks.length - 1].value; - let major, index; - for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { - index = map[major]; - if (index >= 0) { - ticks[index].major = true; - } - } - return ticks; -} -function ticksFromTimestamps(scale, values, majorUnit) { - const ticks = []; - const map = {}; - const ilen = values.length; - let i, value; - for (i = 0; i < ilen; ++i) { - value = values[i]; - map[value] = i; - ticks.push({ - value, - major: false - }); - } - return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); -} -class TimeScale extends Scale { - constructor(props) { - super(props); - this._cache = { - data: [], - labels: [], - all: [] - }; - this._unit = 'day'; - this._majorUnit = undefined; - this._offsets = {}; - this._normalized = false; - this._parseOpts = undefined; - } - init(scaleOpts, opts) { - const time = scaleOpts.time || (scaleOpts.time = {}); - const adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date); - mergeIf(time.displayFormats, adapter.formats()); - this._parseOpts = { - parser: time.parser, - round: time.round, - isoWeekday: time.isoWeekday - }; - super.init(scaleOpts); - this._normalized = opts.normalized; - } - parse(raw, index) { - if (raw === undefined) { - return null; - } - return parse(this, raw); - } - beforeLayout() { - super.beforeLayout(); - this._cache = { - data: [], - labels: [], - all: [] - }; - } - determineDataLimits() { - const options = this.options; - const adapter = this._adapter; - const unit = options.time.unit || 'day'; - let {min, max, minDefined, maxDefined} = this.getUserBounds(); - function _applyBounds(bounds) { - if (!minDefined && !isNaN(bounds.min)) { - min = Math.min(min, bounds.min); - } - if (!maxDefined && !isNaN(bounds.max)) { - max = Math.max(max, bounds.max); - } - } - if (!minDefined || !maxDefined) { - _applyBounds(this._getLabelBounds()); - if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { - _applyBounds(this.getMinMax(false)); - } - } - min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); - max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; - this.min = Math.min(min, max - 1); - this.max = Math.max(min + 1, max); - } - _getLabelBounds() { - const arr = this.getLabelTimestamps(); - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - if (arr.length) { - min = arr[0]; - max = arr[arr.length - 1]; - } - return {min, max}; - } - buildTicks() { - const options = this.options; - const timeOpts = options.time; - const tickOpts = options.ticks; - const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); - if (options.bounds === 'ticks' && timestamps.length) { - this.min = this._userMin || timestamps[0]; - this.max = this._userMax || timestamps[timestamps.length - 1]; - } - const min = this.min; - const max = this.max; - const ticks = _filterBetween(timestamps, min, max); - this._unit = timeOpts.unit || (tickOpts.autoSkip - ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) - : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); - this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined - : determineMajorUnit(this._unit); - this.initOffsets(timestamps); - if (options.reverse) { - ticks.reverse(); - } - return ticksFromTimestamps(this, ticks, this._majorUnit); - } - initOffsets(timestamps) { - let start = 0; - let end = 0; - let first, last; - if (this.options.offset && timestamps.length) { - first = this.getDecimalForValue(timestamps[0]); - if (timestamps.length === 1) { - start = 1 - first; - } else { - start = (this.getDecimalForValue(timestamps[1]) - first) / 2; - } - last = this.getDecimalForValue(timestamps[timestamps.length - 1]); - if (timestamps.length === 1) { - end = last; - } else { - end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; - } - } - const limit = timestamps.length < 3 ? 0.5 : 0.25; - start = _limitValue(start, 0, limit); - end = _limitValue(end, 0, limit); - this._offsets = {start, end, factor: 1 / (start + 1 + end)}; - } - _generate() { - const adapter = this._adapter; - const min = this.min; - const max = this.max; - const options = this.options; - const timeOpts = options.time; - const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); - const stepSize = valueOrDefault(timeOpts.stepSize, 1); - const weekday = minor === 'week' ? timeOpts.isoWeekday : false; - const hasWeekday = isNumber(weekday) || weekday === true; - const ticks = {}; - let first = min; - let time, count; - if (hasWeekday) { - first = +adapter.startOf(first, 'isoWeek', weekday); - } - first = +adapter.startOf(first, hasWeekday ? 'day' : minor); - if (adapter.diff(max, min, minor) > 100000 * stepSize) { - throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); - } - const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); - for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) { - addTick(ticks, time, timestamps); - } - if (time === max || options.bounds === 'ticks' || count === 1) { - addTick(ticks, time, timestamps); - } - return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); - } - getLabelForValue(value) { - const adapter = this._adapter; - const timeOpts = this.options.time; - if (timeOpts.tooltipFormat) { - return adapter.format(value, timeOpts.tooltipFormat); - } - return adapter.format(value, timeOpts.displayFormats.datetime); - } - _tickFormatFunction(time, index, ticks, format) { - const options = this.options; - const formats = options.time.displayFormats; - const unit = this._unit; - const majorUnit = this._majorUnit; - const minorFormat = unit && formats[unit]; - const majorFormat = majorUnit && formats[majorUnit]; - const tick = ticks[index]; - const major = majorUnit && majorFormat && tick && tick.major; - const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat)); - const formatter = options.ticks.callback; - return formatter ? callback(formatter, [label, index, ticks], this) : label; - } - generateTickLabels(ticks) { - let i, ilen, tick; - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - tick = ticks[i]; - tick.label = this._tickFormatFunction(tick.value, i, ticks); - } - } - getDecimalForValue(value) { - return value === null ? NaN : (value - this.min) / (this.max - this.min); - } - getPixelForValue(value) { - const offsets = this._offsets; - const pos = this.getDecimalForValue(value); - return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return this.min + pos * (this.max - this.min); - } - _getLabelSize(label) { - const ticksOpts = this.options.ticks; - const tickLabelWidth = this.ctx.measureText(label).width; - const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); - const cosRotation = Math.cos(angle); - const sinRotation = Math.sin(angle); - const tickFontSize = this._resolveTickFontOptions(0).size; - return { - w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), - h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) - }; - } - _getLabelCapacity(exampleTime) { - const timeOpts = this.options.time; - const displayFormats = timeOpts.displayFormats; - const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; - const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format); - const size = this._getLabelSize(exampleLabel); - const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; - return capacity > 0 ? capacity : 1; - } - getDataTimestamps() { - let timestamps = this._cache.data || []; - let i, ilen; - if (timestamps.length) { - return timestamps; - } - const metas = this.getMatchingVisibleMetas(); - if (this._normalized && metas.length) { - return (this._cache.data = metas[0].controller.getAllParsedValues(this)); - } - for (i = 0, ilen = metas.length; i < ilen; ++i) { - timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); - } - return (this._cache.data = this.normalize(timestamps)); - } - getLabelTimestamps() { - const timestamps = this._cache.labels || []; - let i, ilen; - if (timestamps.length) { - return timestamps; - } - const labels = this.getLabels(); - for (i = 0, ilen = labels.length; i < ilen; ++i) { - timestamps.push(parse(this, labels[i])); - } - return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps)); - } - normalize(values) { - return _arrayUnique(values.sort(sorter)); - } -} -TimeScale.id = 'time'; -TimeScale.defaults = { - bounds: 'data', - adapters: {}, - time: { - parser: false, - unit: false, - round: false, - isoWeekday: false, - minUnit: 'millisecond', - displayFormats: {} - }, - ticks: { - source: 'auto', - major: { - enabled: false - } - } -}; - -function interpolate(table, val, reverse) { - let lo = 0; - let hi = table.length - 1; - let prevSource, nextSource, prevTarget, nextTarget; - if (reverse) { - if (val >= table[lo].pos && val <= table[hi].pos) { - ({lo, hi} = _lookupByKey(table, 'pos', val)); - } - ({pos: prevSource, time: prevTarget} = table[lo]); - ({pos: nextSource, time: nextTarget} = table[hi]); - } else { - if (val >= table[lo].time && val <= table[hi].time) { - ({lo, hi} = _lookupByKey(table, 'time', val)); - } - ({time: prevSource, pos: prevTarget} = table[lo]); - ({time: nextSource, pos: nextTarget} = table[hi]); - } - const span = nextSource - prevSource; - return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; -} -class TimeSeriesScale extends TimeScale { - constructor(props) { - super(props); - this._table = []; - this._minPos = undefined; - this._tableRange = undefined; - } - initOffsets() { - const timestamps = this._getTimestampsForTable(); - const table = this._table = this.buildLookupTable(timestamps); - this._minPos = interpolate(table, this.min); - this._tableRange = interpolate(table, this.max) - this._minPos; - super.initOffsets(timestamps); - } - buildLookupTable(timestamps) { - const {min, max} = this; - const items = []; - const table = []; - let i, ilen, prev, curr, next; - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - curr = timestamps[i]; - if (curr >= min && curr <= max) { - items.push(curr); - } - } - if (items.length < 2) { - return [ - {time: min, pos: 0}, - {time: max, pos: 1} - ]; - } - for (i = 0, ilen = items.length; i < ilen; ++i) { - next = items[i + 1]; - prev = items[i - 1]; - curr = items[i]; - if (Math.round((next + prev) / 2) !== curr) { - table.push({time: curr, pos: i / (ilen - 1)}); - } - } - return table; - } - _getTimestampsForTable() { - let timestamps = this._cache.all || []; - if (timestamps.length) { - return timestamps; - } - const data = this.getDataTimestamps(); - const label = this.getLabelTimestamps(); - if (data.length && label.length) { - timestamps = this.normalize(data.concat(label)); - } else { - timestamps = data.length ? data : label; - } - timestamps = this._cache.all = timestamps; - return timestamps; - } - getDecimalForValue(value) { - return (interpolate(this._table, value) - this._minPos) / this._tableRange; - } - getValueForPixel(pixel) { - const offsets = this._offsets; - const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; - return interpolate(this._table, decimal * this._tableRange + this._minPos, true); - } -} -TimeSeriesScale.id = 'timeseries'; -TimeSeriesScale.defaults = TimeScale.defaults; - -var scales = /*#__PURE__*/Object.freeze({ -__proto__: null, -CategoryScale: CategoryScale, -LinearScale: LinearScale, -LogarithmicScale: LogarithmicScale, -RadialLinearScale: RadialLinearScale, -TimeScale: TimeScale, -TimeSeriesScale: TimeSeriesScale -}); - -Chart.register(controllers, scales, elements, plugins); -Chart.helpers = {...helpers}; -Chart._adapters = _adapters; -Chart.Animation = Animation; -Chart.Animations = Animations; -Chart.animator = animator; -Chart.controllers = registry.controllers.items; -Chart.DatasetController = DatasetController; -Chart.Element = Element; -Chart.elements = elements; -Chart.Interaction = Interaction; -Chart.layouts = layouts; -Chart.platforms = platforms; -Chart.Scale = Scale; -Chart.Ticks = Ticks; -Object.assign(Chart, controllers, scales, elements, plugins, platforms); -Chart.Chart = Chart; -if (typeof window !== 'undefined') { - window.Chart = Chart; -} - -return Chart; - -})); diff --git a/node_modules/chart.js/dist/chart.min.js b/node_modules/chart.js/dist/chart.min.js deleted file mode 100644 index 2b3e9984..00000000 --- a/node_modules/chart.js/dist/chart.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! - * Chart.js v3.7.1 - * https://www.chartjs.org - * (c) 2022 Chart.js Contributors - * Released under the MIT License - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";const t="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function e(e,i,s){const n=s||(t=>Array.prototype.slice.call(t));let o=!1,a=[];return function(...s){a=n(s),o||(o=!0,t.call(window,(()=>{o=!1,e.apply(i,a)})))}}function i(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const s=t=>"start"===t?"left":"end"===t?"right":"center",n=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,o=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;var a=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=t.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}; -/*! - * @kurkle/color v0.1.9 - * https://github.com/kurkle/color#readme - * (c) 2020 Jukka Kurkela - * Released under the MIT License - */const r={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},l="0123456789ABCDEF",h=t=>l[15&t],c=t=>l[(240&t)>>4]+l[15&t],d=t=>(240&t)>>4==(15&t);function u(t){var e=function(t){return d(t.r)&&d(t.g)&&d(t.b)&&d(t.a)}(t)?h:c;return t?"#"+e(t.r)+e(t.g)+e(t.b)+(t.a<255?e(t.a):""):t}function f(t){return t+.5|0}const g=(t,e,i)=>Math.max(Math.min(t,i),e);function p(t){return g(f(2.55*t),0,255)}function m(t){return g(f(255*t),0,255)}function x(t){return g(f(t/2.55)/100,0,1)}function b(t){return g(f(100*t),0,100)}const _=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const y=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function v(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function w(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function M(t,e,i){const s=v(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function k(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=n===e?(i-s)/h+(i>16&255,o>>8&255,255&o]}return t}(),T.transparent=[0,0,0,0]);const e=T[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}function R(t,e,i){if(t){let s=k(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=P(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function E(t,e){return t?Object.assign(e||{},t):t}function I(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=m(t[3]))):(e=E(t,{r:0,g:0,b:0,a:1})).a=m(e.a),e}function z(t){return"r"===t.charAt(0)?function(t){const e=_.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=255&(e[8]?p(t):255*t)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?p(i):i),s=255&(e[4]?p(s):s),n=255&(e[6]?p(n):n),{r:i,g:s,b:n,a:o}}}(t):C(t)}class F{constructor(t){if(t instanceof F)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=I(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*r[s[1]],g:255&17*r[s[2]],b:255&17*r[s[3]],a:5===o?17*r[s[4]]:255}:7!==o&&9!==o||(n={r:r[s[1]]<<4|r[s[2]],g:r[s[3]]<<4|r[s[4]],b:r[s[5]]<<4|r[s[6]],a:9===o?r[s[7]]<<4|r[s[8]]:255})),i=n||L(t)||z(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=E(this._rgb);return t&&(t.a=x(t.a)),t}set rgb(t){this._rgb=I(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${x(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):this._rgb;var t}hexString(){return this._valid?u(this._rgb):this._rgb}hslString(){return this._valid?function(t){if(!t)return;const e=k(t),i=e[0],s=b(e[1]),n=b(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${x(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):this._rgb}mix(t,e){const i=this;if(t){const s=i.rgb,n=t.rgb;let o;const a=e===o?.5:e,r=2*a-1,l=s.a-n.a,h=((r*l==-1?r:(r+l)/(1+r*l))+1)/2;o=1-h,s.r=255&h*s.r+o*n.r+.5,s.g=255&h*s.g+o*n.g+.5,s.b=255&h*s.b+o*n.b+.5,s.a=a*s.a+(1-a)*n.a,i.rgb=s}return i}clone(){return new F(this.rgb)}alpha(t){return this._rgb.a=m(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=f(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return R(this._rgb,2,t),this}darken(t){return R(this._rgb,2,-t),this}saturate(t){return R(this._rgb,1,t),this}desaturate(t){return R(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=k(t);i[0]=D(i[0]+e),i=P(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function B(t){return new F(t)}const V=t=>t instanceof CanvasGradient||t instanceof CanvasPattern;function W(t){return V(t)?t:B(t)}function N(t){return V(t)?t:B(t).saturate(.5).darken(.1).hexString()}function H(){}const j=function(){let t=0;return function(){return t++}}();function $(t){return null==t}function Y(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)}function U(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}const X=t=>("number"==typeof t||t instanceof Number)&&isFinite(+t);function q(t,e){return X(t)?t:e}function K(t,e){return void 0===t?e:t}const G=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:t/e,Z=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function J(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function Q(t,e,i,s){let n,o,a;if(Y(t))if(o=t.length,s)for(n=o-1;n>=0;n--)e.call(i,t[n],n);else for(n=0;ni;)t=t[e.substr(i,s-i)],i=s+1,s=rt(e,i);return t}function ht(t){return t.charAt(0).toUpperCase()+t.slice(1)}const ct=t=>void 0!==t,dt=t=>"function"==typeof t,ut=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function ft(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const gt=Object.create(null),pt=Object.create(null);function mt(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>N(e.backgroundColor),this.hoverBorderColor=(t,e)=>N(e.borderColor),this.hoverColor=(t,e)=>N(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t)}set(t,e){return xt(this,t,e)}get(t){return mt(this,t)}describe(t,e){return xt(pt,t,e)}override(t,e){return xt(gt,t,e)}route(t,e,i,s){const n=mt(this,t),o=mt(this,i),a="_"+e;Object.defineProperties(n,{[a]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[a],e=o[s];return U(t)?Object.assign({},e,t):K(t,e)},set(t){this[a]=t}}})}}({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}});const _t=Math.PI,yt=2*_t,vt=yt+_t,wt=Number.POSITIVE_INFINITY,Mt=_t/180,kt=_t/2,St=_t/4,Pt=2*_t/3,Dt=Math.log10,Ct=Math.sign;function Ot(t){const e=Math.round(t);t=Lt(t,e,t/1e3)?e:t;const i=Math.pow(10,Math.floor(Dt(t))),s=t/i;return(s<=1?1:s<=2?2:s<=5?5:10)*i}function At(t){const e=[],i=Math.sqrt(t);let s;for(s=1;st-e)).pop(),e}function Tt(t){return!isNaN(parseFloat(t))&&isFinite(t)}function Lt(t,e,i){return Math.abs(t-e)=t}function Et(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function Ut(t){return!t||$(t.size)||$(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Xt(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function qt(t,e,i,s){let n=(s=s||{}).data=s.data||{},o=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(n=s.data={},o=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let a=0;const r=i.length;let l,h,c,d,u;for(l=0;li.length){for(l=0;l0&&t.stroke()}}function Jt(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==o.strokeColor;let l,h;for(t.save(),t.font=n.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]);$(e.rotation)||t.rotate(e.rotation);e.color&&(t.fillStyle=e.color);e.textAlign&&(t.textAlign=e.textAlign);e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,o),l=0;lt[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const re=(t,e,i)=>ae(t,i,(s=>t[s][e]ae(t,i,(s=>t[s][e]>=i));function he(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+ht(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function ue(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ce.forEach((e=>{delete t[e]})),delete t._chartjs)}function fe(t){const e=new Set;let i,s;for(i=0,s=t.length;iwindow.getComputedStyle(t,null);function be(t,e){return xe(t).getPropertyValue(e)}const _e=["top","right","bottom","left"];function ye(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=_e[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}function ve(t,e){const{canvas:i,currentDevicePixelRatio:s}=e,n=xe(i),o="border-box"===n.boxSizing,a=ye(n,"padding"),r=ye(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.native||t,s=i.touches,n=s&&s.length?s[0]:i,{offsetX:o,offsetY:a}=n;let r,l,h=!1;if(((t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot))(o,a,i.target))r=o,l=a;else{const t=e.getBoundingClientRect();r=n.clientX-t.left,l=n.clientY-t.top,h=!0}return{x:r,y:l,box:h}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const we=t=>Math.round(10*t)/10;function Me(t,e,i,s){const n=xe(t),o=ye(n,"margin"),a=me(n.maxWidth,t,"clientWidth")||wt,r=me(n.maxHeight,t,"clientHeight")||wt,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=pe(t);if(o){const t=o.getBoundingClientRect(),a=xe(o),r=ye(a,"border","width"),l=ye(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=me(a.maxWidth,o,"clientWidth"),n=me(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||wt,maxHeight:n||wt}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=ye(n,"border","width"),e=ye(n,"padding");h-=e.width+t.width,c-=e.height+t.height}return h=Math.max(0,h-o.width),c=Math.max(0,s?Math.floor(h/s):c-o.height),h=we(Math.min(h,a,l.maxWidth)),c=we(Math.min(c,r,l.maxHeight)),h&&!c&&(c=we(h/2)),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=n/s,t.width=o/s;const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function Pe(t,e){const i=be(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t,e){return"native"in t?{x:t.x,y:t.y}:ve(t,e)}function Ce(t,e,i,s){const{controller:n,data:o,_sorted:a}=t,r=n._cachedMeta.iScale;if(r&&e===r.axis&&"r"!==e&&a&&o.length){const t=r._reversePixels?le:re;if(!s)return t(o,e,i);if(n._sharedOptions){const s=o[0],n="function"==typeof s.getRange&&s.getRange(e);if(n){const s=t(o,e,i-n),a=t(o,e,i+n);return{lo:s.lo,hi:a.hi}}}}return{lo:0,hi:o.length-1}}function Oe(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t{t[r](n[a],s)&&o.push({element:t,datasetIndex:e,index:i}),t.inRange(n.x,n.y,s)&&(l=!0)})),i.intersect&&!l?[]:o}var Ee={modes:{index(t,e,i,s){const n=De(e,t),o=i.axis||"x",a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s),r=[];return a.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=a[0].index,i=t.data[e];i&&!i.skip&&r.push({element:i,datasetIndex:t.index,index:e})})),r):[]},dataset(t,e,i,s){const n=De(e,t),o=i.axis||"xy";let a=i.intersect?Ae(t,n,o,s):Le(t,n,o,!1,s);if(a.length>0){const e=a[0].datasetIndex,i=t.getDatasetMeta(e).data;a=[];for(let t=0;tAe(t,De(e,t),i.axis||"xy",s),nearest:(t,e,i,s)=>Le(t,De(e,t),i.axis||"xy",i.intersect,s),x:(t,e,i,s)=>Re(t,e,{axis:"x",intersect:i.intersect},s),y:(t,e,i,s)=>Re(t,e,{axis:"y",intersect:i.intersect},s)}};const Ie=new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/),ze=new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/);function Fe(t,e){const i=(""+t).match(Ie);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}function Be(t,e){const i={},s=U(e),n=s?Object.keys(e):e,o=U(t)?s?i=>K(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=+o(t)||0;return i}function Ve(t){return Be(t,{top:"y",right:"x",bottom:"y",left:"x"})}function We(t){return Be(t,["topLeft","topRight","bottomLeft","bottomRight"])}function Ne(t){const e=Ve(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function He(t,e){t=t||{},e=e||bt.font;let i=K(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=K(t.style,e.style);s&&!(""+s).match(ze)&&(console.warn('Invalid font style specified: "'+s+'"'),s="");const n={family:K(t.family,e.family),lineHeight:Fe(K(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:K(t.weight,e.weight),string:""};return n.string=Ut(n),n}function je(t,e,i,s){let n,o,a,r=!0;for(n=0,o=t.length;ni&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ye(t,e){return Object.assign(Object.create(t),e)}const Ue=["left","top","right","bottom"];function Xe(t,e){return t.filter((t=>t.pos===e))}function qe(t,e){return t.filter((t=>-1===Ue.indexOf(t.pos)&&t.box.axis===e))}function Ke(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function Ge(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Ue.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function ei(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Ke(Xe(e,"left"),!0),n=Ke(Xe(e,"right")),o=Ke(Xe(e,"top"),!0),a=Ke(Xe(e,"bottom")),r=qe(e,"x"),l=qe(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Xe(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;Q(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),u=Object.assign({},n);Je(u,Ne(s));const f=Object.assign({maxPadding:u,w:o,h:a,x:n.left,y:n.top},n),g=Ge(l.concat(h),d);ei(r.fullSize,f,d,g),ei(l,f,d,g),ei(h,f,d,g)&&ei(l,f,d,g),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(f),si(r.leftAndTop,f,d,g),f.x+=f.w,f.y+=f.h,si(r.rightAndBottom,f,d,g),t.chartArea={left:f.left,top:f.top,right:f.left+f.w,bottom:f.top+f.h,height:f.h,width:f.w},Q(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})}))}};function oi(t,e=[""],i=t,s,n=(()=>t[0])){ct(s)||(s=mi("_fallback",t));const o={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:i,_fallback:s,_getTarget:n,override:n=>oi([n,...t],e,i,s)};return new Proxy(o,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>ci(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=mi(li(o,t),i),ct(n))return hi(t,n)?gi(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>xi(t).includes(e),ownKeys:t=>xi(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function ai(t,e,i,s){const n={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:ri(t,s),setContext:e=>ai(t,e,i,s),override:n=>ai(t.override(n),e,i,s)};return new Proxy(n,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>ci(t,e,(()=>function(t,e,i){const{_proxy:s,_context:n,_subProxy:o,_descriptors:a}=t;let r=s[e];dt(r)&&a.isScriptable(e)&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t),e=e(o,a||s),r.delete(t),hi(t,e)&&(e=gi(n._scopes,n,t,e));return e}(e,r,t,i));Y(r)&&r.length&&(r=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_descriptors:r}=i;if(ct(o.index)&&s(t))e=e[o.index%e.length];else if(U(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const l of i){const i=gi(s,n,t,l);e.push(ai(i,o,a&&a[t],r))}}return e}(e,r,t,a.isIndexable));hi(e,r)&&(r=ai(r,n,o&&o[e],a));return r}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function ri(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:dt(i)?i:()=>i,isIndexable:dt(s)?s:()=>s}}const li=(t,e)=>t?t+ht(e):e,hi=(t,e)=>U(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function ci(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const s=i();return t[e]=s,s}function di(t,e,i){return dt(t)?t(e,i):t}const ui=(t,e)=>!0===t?e:"string"==typeof t?lt(e,t):void 0;function fi(t,e,i,s,n){for(const o of e){const e=ui(i,o);if(e){t.add(e);const o=di(e._fallback,i,n);if(ct(o)&&o!==i&&o!==s)return o}else if(!1===e&&ct(s)&&i!==s)return null}return!1}function gi(t,e,i,s){const n=e._rootScopes,o=di(e._fallback,i,s),a=[...t,...n],r=new Set;r.add(s);let l=pi(r,a,i,o||i,s);return null!==l&&((!ct(o)||o===i||(l=pi(r,a,o,l,s),null!==l))&&oi(Array.from(r),[""],n,o,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const n=s[e];if(Y(n)&&U(i))return i;return n}(e,i,s))))}function pi(t,e,i,s,n){for(;i;)i=fi(t,e,i,s,n);return i}function mi(t,e){for(const i of e){if(!i)continue;const e=i[t];if(ct(e))return e}}function xi(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}const bi=Number.EPSILON||1e-14,_i=(t,e)=>e"x"===t?"y":"x";function vi(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=Vt(o,n),l=Vt(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function wi(t,e="x"){const i=yi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=_i(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)wi(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,Pi=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*yt/i),Di=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*yt/i)+1,Ci={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*kt),easeOutSine:t=>Math.sin(t*kt),easeInOutSine:t=>-.5*(Math.cos(_t*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>Si(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>Si(t)?t:Pi(t,.075,.3),easeOutElastic:t=>Si(t)?t:Di(t,.075,.3),easeInOutElastic(t){const e=.1125;return Si(t)?t:t<.5?.5*Pi(2*t,e,.45):.5+.5*Di(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-Ci.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*Ci.easeInBounce(2*t):.5*Ci.easeOutBounce(2*t-1)+.5};function Oi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function Ai(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function Ti(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=Oi(t,n,i),r=Oi(n,o,i),l=Oi(o,e,i),h=Oi(a,r,i),c=Oi(r,l,i);return Oi(h,c,i)}const Li=new Map;function Ri(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=Li.get(i);return s||(s=new Intl.NumberFormat(t,e),Li.set(i,s)),s}(e,i).format(t)}function Ei(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ii(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function zi(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Fi(t){return"angle"===t?{between:Ht,compare:Wt,normalize:Nt}:{between:Yt,compare:(t,e)=>t-e,normalize:t=>t}}function Bi({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Vi(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Fi(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Fi(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hb||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Bi({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Bi({start:_,end:d,loop:u,count:a,style:f})),g}function Wi(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Hi(t,[{start:a,end:r,loop:o}],i,e);return Hi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,rnull===t||""===t;const Gi=!!Se&&{passive:!0};function Zi(t,e,i){t.canvas.removeEventListener(e,i,Gi)}function Ji(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function Qi(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.addedNodes,s),e=e&&!Ji(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function ts(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||Ji(i.removedNodes,s),e=e&&!Ji(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const es=new Map;let is=0;function ss(){const t=window.devicePixelRatio;t!==is&&(is=t,es.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function ns(t,i,s){const n=t.canvas,o=n&&pe(n);if(!o)return;const a=e(((t,e)=>{const i=o.clientWidth;s(t,e),i{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||a(i,s)}));return r.observe(o),function(t,e){es.size||window.addEventListener("resize",ss),es.set(t,e)}(t,a),r}function os(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){es.delete(t),es.size||window.removeEventListener("resize",ss)}(t)}function as(t,i,s){const n=t.canvas,o=e((e=>{null!==t.ctx&&s(function(t,e){const i=qi[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t,(t=>{const e=t[0];return[e,e.offsetX,e.offsetY]}));return function(t,e,i){t.addEventListener(e,i,Gi)}(n,i,o),o}class rs extends Ui{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t.$chartjs={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",Ki(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(Ki(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e.$chartjs)return!1;const i=e.$chartjs.initial;["height","width"].forEach((t=>{const s=i[t];$(s)?e.removeAttribute(t):e.setAttribute(t,s)}));const s=i.style||{};return Object.keys(s).forEach((t=>{e.style[t]=s[t]})),e.width=e.width,delete e.$chartjs,!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:Qi,detach:ts,resize:ns}[e]||as;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:os,detach:os,resize:os}[e]||Zi)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return Me(t,e,i,s)}isAttached(t){const e=pe(t);return!(!e||!e.isConnected)}}function ls(t){return!ge()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?Xi:rs}var hs=Object.freeze({__proto__:null,_detectPlatform:ls,BasePlatform:Ui,BasicPlatform:Xi,DomPlatform:rs});const cs="transparent",ds={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=W(t||cs),n=s.valid&&W(e||cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class us{constructor(t,e,i,s){const n=e[i];s=je([t.to,s,n,t.from]);const o=je([t.from,n,s]);this._active=!0,this._fn=t.fn||ds[t.type||typeof o],this._easing=Ci[t.easing]||Ci.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=je([t.to,e,s,t.from]),this._from=je([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),bt.set("animations",{colors:{type:"color",properties:["color","borderColor","backgroundColor"]},numbers:{type:"number",properties:["x","y","borderWidth","radius","tension"]}}),bt.describe("animations",{_fallback:"animation"}),bt.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}});class gs{constructor(t,e){this._chart=t,this._properties=new Map,this.configure(e)}configure(t){if(!U(t))return;const e=this._properties;Object.getOwnPropertyNames(t).forEach((i=>{const s=t[i];if(!U(s))return;const n={};for(const t of fs)n[t]=s[t];(Y(s.properties)&&s.properties||[i]).forEach((t=>{t!==i&&e.has(t)||e.set(t,n)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new us(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(a.add(this._chart,i),!0):void 0}}function ps(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function ms(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Ms(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i]}}}const ks=t=>"reset"===t||"none"===t,Ss=(t,e)=>e?t:Object.assign({},t);class Ps{constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.$context=void 0,this._syncList=[],this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=bs(t.vScale,t),this.addElements()}updateIndex(t){this.index!==t&&Ms(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=K(i.xAxisID,ws(t,"x")),o=e.yAxisID=K(i.yAxisID,ws(t,"y")),a=e.rAxisID=K(i.rAxisID,ws(t,"r")),r=e.indexAxis,l=e.iAxisID=s(r,n,o,a),h=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(l),e.vScale=this.getScaleForId(h)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&ue(this._data,this),t._stacked&&Ms(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(U(e))this._data=function(t){const e=Object.keys(t),i=new Array(e.length);let s,n,o;for(s=0,n=e.length;s0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,h=s;else{h=Y(s[t])?this.parseArrayData(i,s,t,e):U(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const n=()=>null===l[a]||d&&l[a]t&&!e.hidden&&e._stacked&&{keys:ms(i,!0),values:null})(e,i,this.chart),l={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:h,max:c}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(a);let d,u;function f(){u=s[d];const e=u[a.axis];return!X(u[t.axis])||h>e||c=0;--d)if(!f()){this.updateRangeFromParsed(l,t,u,r);break}return l}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Ss(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new gs(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||ks(t)||this.chart._animationsDisabled}updateElement(t,e,i,s){ks(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!ks(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}Ds.defaults={},Ds.defaultRoutes=void 0;const Cs={values:t=>Y(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=Dt(Math.abs(o)),r=Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),Ri(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=t/Math.pow(10,Math.floor(Dt(t)));return 1===s||2===s||5===s?Cs.numeric.call(this,t,e,i):""}};var Os={formatters:Cs};function As(t,e){const i=t.options.ticks,s=i.maxTicksLimit||function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),n=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;is)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(n,e,s);if(o>0){let t,i;const s=o>1?Math.round((r-a)/(o-1)):null;for(Ts(e,l,h,$(s)?0:a-s,a),t=0,i=o-1;te.lineWidth,tickColor:(t,e)=>e.color,offset:!1,borderDash:[],borderDashOffset:0,borderWidth:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:Os.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),bt.route("scale.ticks","color","","color"),bt.route("scale.grid","color","","borderColor"),bt.route("scale.grid","borderColor","","borderColor"),bt.route("scale.title","color","","color"),bt.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t}),bt.describe("scales",{_fallback:"scale"}),bt.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t});const Ls=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i;function Rs(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Is(t){return t.drawTicks?t.tickLength:0}function zs(t,e){if(!t.display)return 0;const i=He(t.font,e),s=Ne(t.padding);return(Y(t.text)?t.text.length:1)*i.lineHeight+s.height}function Fs(t,e,i){let n=s(t);return(i&&"right"!==e||!i&&"right"===e)&&(n=(t=>"left"===t?"right":"right"===t?"left":t)(n)),n}class Bs extends Ds{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=q(t,Number.POSITIVE_INFINITY),e=q(e,Number.NEGATIVE_INFINITY),i=q(i,Number.POSITIVE_INFINITY),s=q(s,Number.NEGATIVE_INFINITY),{min:q(t,i),max:q(e,s),minDefined:X(t),maxDefined:X(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:q(i,q(s,i)),max:q(s,q(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){J(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=$e(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=jt(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Is(t.grid)-e.padding-zs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=zt(Math.min(Math.asin(jt((h.highest.height+6)/o,-1,1)),Math.asin(jt(a/r,-1,1))-Math.asin(jt(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){J(this.options.afterCalculateLabelRotation,[this])}beforeFit(){J(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=zs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Is(n)+o):(t.height=this.maxHeight,t.width=Is(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=It(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){J(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:n[t]||0,height:o[t]||0});return{first:v(0),last:v(e-1),widest:v(_),highest:v(y),widths:n,heights:o}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return $t(this._alignToPixels?Kt(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:o}=s,a=n.offset,r=this.isHorizontal(),l=this.ticks.length+(a?1:0),h=Is(n),c=[],d=n.setContext(this.getContext()),u=d.drawBorder?d.borderWidth:0,f=u/2,g=function(t){return Kt(i,t,u)};let p,m,x,b,_,y,v,w,M,k,S,P;if("top"===o)p=g(this.bottom),y=this.bottom-h,w=p-f,k=g(t.top)+f,P=t.bottom;else if("bottom"===o)p=g(this.top),k=t.top,P=g(t.bottom)-f,y=p+f,w=this.top+h;else if("left"===o)p=g(this.right),_=this.right-h,v=p-f,M=g(t.left)+f,S=t.right;else if("right"===o)p=g(this.left),M=t.left,S=g(t.right)-f,_=p+f,v=this.left+h;else if("x"===e){if("center"===o)p=g((t.top+t.bottom)/2+.5);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}k=t.top,P=t.bottom,y=p+f,w=y+h}else if("y"===e){if("center"===o)p=g((t.left+t.right)/2);else if(U(o)){const t=Object.keys(o)[0],e=o[t];p=g(this.chart.scales[t].getPixelForValue(e))}_=p-f,v=_-h,M=t.left,S=t.right}const D=K(s.ticks.maxTicksLimit,l),C=Math.max(1,Math.ceil(l/D));for(m=0;me.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:i+1,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");bt.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&bt.describe(e,t.descriptors)}(t,o,i),this.override&&bt.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in bt[s]&&(delete bt[s][i],this.override&&delete gt[i])}}var Ws=new class{constructor(){this.controllers=new Vs(Ps,"datasets",!0),this.elements=new Vs(Ds,"elements"),this.plugins=new Vs(Object,"plugins"),this.scales=new Vs(Bs,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):Q(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=ht(t);J(i["before"+s],[],i),e[t](i),J(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function Hs(t,e){return e||!1!==t?!0===t?{}:t:null}function js(t,e,i,s){const n=t.pluginScopeKeys(e),o=t.getOptionScopes(i,n);return t.createResolver(o,s,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function $s(t,e){const i=bt.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function Ys(t,e){return"x"===t||"y"===t?t:e.axis||("top"===(i=e.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.charAt(0).toLowerCase();var i}function Us(t){const e=t.options||(t.options={});e.plugins=K(e.plugins,{}),e.scales=function(t,e){const i=gt[t.type]||{scales:{}},s=e.scales||{},n=$s(t.type,e),o=Object.create(null),a=Object.create(null);return Object.keys(s).forEach((t=>{const e=s[t];if(!U(e))return console.error(`Invalid scale configuration for scale: ${t}`);if(e._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);const r=Ys(t,e),l=function(t,e){return t===e?"_index_":"_value_"}(r,n),h=i.scales||{};o[r]=o[r]||t,a[t]=ot(Object.create(null),[{axis:r},e,h[r],h[l]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,r=i.indexAxis||$s(n,e),l=(gt[n]||{}).scales||{};Object.keys(l).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,r),n=i[e+"AxisID"]||o[e]||e;a[n]=a[n]||Object.create(null),ot(a[n],[{axis:e},s[n],l[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];ot(e,[bt.scales[e.type],bt.scale])})),a}(t,e)}function Xs(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const qs=new Map,Ks=new Set;function Gs(t,e){let i=qs.get(t);return i||(i=e(),qs.set(t,i),Ks.add(i)),i}const Zs=(t,e,i)=>{const s=lt(e,i);void 0!==s&&t.add(s)};class Js{constructor(t){this._config=function(t){return(t=t||{}).data=Xs(t.data),Us(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=Xs(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),Us(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return Gs(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return Gs(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return Gs(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return Gs(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>Zs(r,t,e)))),e.forEach((t=>Zs(r,s,t))),e.forEach((t=>Zs(r,gt[n]||{},t))),e.forEach((t=>Zs(r,bt,t))),e.forEach((t=>Zs(r,pt,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),Ks.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,gt[e]||{},bt.datasets[e]||{},{type:e},bt,pt]}resolveNamedOptions(t,e,i,s=[""]){const n={$shared:!0},{resolver:o,subPrefixes:a}=Qs(this._resolverCache,t,s);let r=o;if(function(t,e){const{isScriptable:i,isIndexable:s}=ri(t);for(const n of e){const e=i(n),o=s(n),a=(o||e)&&t[n];if(e&&(dt(a)||tn(a))||o&&Y(a))return!0}return!1}(o,e)){n.$shared=!1;r=ai(o,i=dt(i)?i():i,this.createResolver(t,i,a))}for(const t of e)n[t]=r[t];return n}createResolver(t,e,i=[""],s){const{resolver:n}=Qs(this._resolverCache,t,i);return U(e)?ai(n,e,void 0,s):n}}function Qs(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:oi(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const tn=t=>U(t)&&Object.getOwnPropertyNames(t).reduce(((e,i)=>e||dt(t[i])),!1);const en=["top","bottom","left","right","chartArea"];function sn(t,e){return"top"===t||"bottom"===t||-1===en.indexOf(t)&&"x"===e}function nn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function on(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),J(i&&i.onComplete,[t],e)}function an(t){const e=t.chart,i=e.options.animation;J(i&&i.onProgress,[t],e)}function rn(t){return ge()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const ln={},hn=t=>{const e=rn(t);return Object.values(ln).filter((t=>t.canvas===e)).pop()};function cn(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class dn{constructor(t,e){const s=this.config=new Js(e),n=rn(t),o=hn(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas can be reused.");const r=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||ls(n)),this.platform.updateConfig(s);const l=this.platform.acquireContext(n,r.aspectRatio),h=l&&l.canvas,c=h&&h.height,d=h&&h.width;this.id=j(),this.ctx=l,this.canvas=h,this.width=d,this.height=c,this._options=r,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Ns,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=i((t=>this.update(t)),r.resizeDelay||0),this._dataChanges=[],ln[this.id]=this,l&&h?(a.listen(this,"complete",on),a.listen(this,"progress",an),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:s,_aspectRatio:n}=this;return $(t)?e&&n?n:s?i/s:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Gt(this.canvas,this.ctx),this}stop(){return a.stop(this),this}resize(t,e){a.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),J(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){Q(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=Ys(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),Q(n,(e=>{const n=e.options,o=n.id,a=Ys(o,n),r=K(n.type,e.dtype);void 0!==n.position&&sn(n.position,a)===sn(e.dposition)||(n.position=e.dposition),s[o]=!0;let l=null;if(o in i&&i[o].type===r)l=i[o];else{l=new(Ws.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[l.id]=l}l.init(n,t)})),Q(s,((t,e)=>{t||delete i[e]})),Q(i,(t=>{ni.configure(this,t,t.options),ni.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(nn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){Q(this.scales,(t=>{ni.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);ut(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){cn(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ni.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],Q(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i=t._clip,s=!i.disabled,n=this.chartArea,o={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",o)&&(s&&Qt(e,{left:!1===i.left?0:n.left-i.left,right:!1===i.right?this.width:n.right+i.right,top:!1===i.top?0:n.top-i.top,bottom:!1===i.bottom?this.height:n.bottom+i.bottom}),t.controller.draw(),s&&te(e),o.cancelable=!1,this.notifyPlugins("afterDatasetDraw",o))}getElementsAtEventForMode(t,e,i,s){const n=Ee.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ye(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);ct(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),a.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};Q(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){Q(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},Q(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!tt(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:Jt(t,this.chartArea,this._minPadding)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=ft(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,J(n.onHover,[t,a,this],this),r&&J(n.onClick,[t,a,this],this));const h=!tt(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}const un=()=>Q(dn.instances,(t=>t._plugins.invalidate())),fn=!0;function gn(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}Object.defineProperties(dn,{defaults:{enumerable:fn,value:bt},instances:{enumerable:fn,value:ln},overrides:{enumerable:fn,value:gt},registry:{enumerable:fn,value:Ws},version:{enumerable:fn,value:"3.7.1"},getChart:{enumerable:fn,value:hn},register:{enumerable:fn,value:(...t)=>{Ws.add(...t),un()}},unregister:{enumerable:fn,value:(...t)=>{Ws.remove(...t),un()}}});class pn{constructor(t){this.options=t||{}}formats(){return gn()}parse(t,e){return gn()}format(t,e){return gn()}add(t,e,i){return gn()}diff(t,e,i){return gn()}startOf(t,e,i){return gn()}endOf(t,e){return gn()}}pn.override=function(t){Object.assign(pn.prototype,t)};var mn={_date:pn};function xn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(ct(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function _n(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base=i?1:-1)}(c,e,o)*n,d===o&&(p-=c/2),h=p+c),p===e.getPixelForValue(o)){const t=Ct(c)*e.getLineWidthForValue(o)/2;p+=t,c-=t}return{size:c,base:p,head:h,center:h+c/2}}_calculateBarIndexPixels(t,e){const i=e.scale,s=this.options,n=s.skipNull,o=K(s.maxBarThickness,1/0);let a,r;if(e.grouped){const i=n?this._getStackCount(t):e.stackCount,l="flex"===s.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,{xScale:i,yScale:s}=e,n=this.getParsed(t),o=i.getLabelForValue(n.x),a=s.getLabelForValue(n.y),r=n._custom;return{label:e.label,value:"("+o+", "+a+(r?", "+r:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,r=this.resolveDataElementOptions(e,s),l=this.getSharedOptions(r),h=this.includeOptions(s,l),c=o.axis,d=a.axis;for(let r=e;r""}}}};class Dn extends Ps{constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,o,a=t=>+i[t];if(U(i[t])){const{key:t="value"}=this._parsing;a=e=>+lt(i[e],t)}for(n=t,o=t+e;nHt(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Ht(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(kt,c,u),x=g(_t,h,d),b=g(_t+kt,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(c,h,r),p=(i.width-o)/d,m=(i.height-o)/u,x=Math.max(Math.min(p,m)/2,0),b=Z(this.options.radius,x),_=(b-Math.max(b*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=f*b,this.offsetY=g*b,s.total=this.calculateTotal(),this.outerRadius=b-_*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-_*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/yt)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,f=this.resolveDataElementOptions(e,s),g=this.getSharedOptions(f),p=this.includeOptions(s,g);let m,x=this._getRotation();for(m=0;m0&&!isNaN(t)?yt*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s"spacing"!==t,_indexable:t=>"spacing"!==t},Dn.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label(t){let e=t.label;const i=": "+t.formattedValue;return Y(e)?(e=e.slice(),e[0]+=i):e+=i,e}}}}};class Cn extends Ps{initialize(){this.enableOptionSharing=!0,super.initialize()}update(t){const e=this._cachedMeta,{dataset:i,data:s=[],_dataset:n}=e,o=this.chart._animationsDisabled;let{start:a,count:r}=function(t,e,i){const s=e.length;let n=0,o=s;if(t._sorted){const{iScale:a,_parsed:r}=t,l=a.axis,{min:h,max:c,minDefined:d,maxDefined:u}=a.getUserBounds();d&&(n=jt(Math.min(re(r,a.axis,h).lo,i?s:re(e,l,a.getPixelForValue(h)).lo),0,s-1)),o=u?jt(Math.max(re(r,a.axis,c).hi+1,i?0:re(e,l,a.getPixelForValue(c)).hi+1),n,s)-n:s-n}return{start:n,count:o}}(e,s,o);this._drawStart=a,this._drawCount=r,function(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}(e)&&(a=0,r=s.length),i._chart=this.chart,i._datasetIndex=this.index,i._decimated=!!n._decimated,i.points=s;const l=this.resolveDatasetElementOptions(t);this.options.showLine||(l.borderWidth=0),l.segment=this.options.segment,this.updateElement(i,void 0,{animated:!o,options:l},t),this.updateElements(s,a,r,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a,_stacked:r,_dataset:l}=this._cachedMeta,h=this.resolveDataElementOptions(e,s),c=this.getSharedOptions(h),d=this.includeOptions(s,c),u=o.axis,f=a.axis,{spanGaps:g,segment:p}=this.options,m=Tt(g)?g:Number.POSITIVE_INFINITY,x=this.chart._animationsDisabled||n||"none"===s;let b=e>0&&this.getParsed(e-1);for(let h=e;h0&&i[u]-b[u]>m,p&&(g.parsed=i,g.raw=l.data[h]),d&&(g.options=c||this.resolveDataElementOptions(h,e.active?"active":s)),x||this.updateElement(e,h,g,s),b=i}this.updateSharedOptions(c,s,h)}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}}Cn.id="line",Cn.defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1},Cn.overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};class On extends Ps{constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=Ri(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=this.getDataset(),r=o.options.animation,l=this._cachedMeta.rScale,h=l.xCenter,c=l.yCenter,d=l.getIndexAngle(0)-.5*_t;let u,f=d;const g=360/this.countVisibleElements();for(u=0;u{!isNaN(t.data[s])&&this.chart.getDataVisibility(s)&&i++})),i}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?It(this.resolveDataElementOptions(t,e).angle||i):0}}On.id="polarArea",On.defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0},On.overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i}}=t.legend.options;return e.labels.map(((e,s)=>{const n=t.getDatasetMeta(0).controller.getStyle(s);return{text:e,fillStyle:n.backgroundColor,strokeStyle:n.borderColor,lineWidth:n.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(s),index:s}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}},tooltip:{callbacks:{title:()=>"",label:t=>t.chart.data.labels[t.dataIndex]+": "+t.formattedValue}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};class An extends Dn{}An.id="pie",An.defaults={cutout:0,rotation:0,circumference:360,radius:"100%"};class Tn extends Ps{getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this.getDataset(),o=this._cachedMeta.rScale,a="reset"===s;for(let r=e;r"",label:t=>"("+t.label+", "+t.formattedValue+")"}}},scales:{x:{type:"linear"},y:{type:"linear"}}};var Rn=Object.freeze({__proto__:null,BarController:Sn,BubbleController:Pn,DoughnutController:Dn,LineController:Cn,PolarAreaController:On,PieController:An,RadarController:Tn,ScatterController:Ln});function En(t,e,i){const{startAngle:s,pixelMargin:n,x:o,y:a,outerRadius:r,innerRadius:l}=e;let h=n/r;t.beginPath(),t.arc(o,a,r,s-h,i+h),l>n?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+kt,s-kt),t.closePath(),t.clip()}function In(t,e,i,s){const n=Be(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return jt(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:jt(n.innerStart,0,a),innerEnd:jt(n.innerEnd,0,a)}}function zn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Fn(t,e,i,s,n){const{x:o,y:a,startAngle:r,pixelMargin:l,innerRadius:h}=e,c=Math.max(e.outerRadius+s+i-l,0),d=h>0?h+s+i+l:0;let u=0;const f=n-r;if(s){const t=((h>0?h-s:0)+(c>0?c-s:0))/2;u=(f-(0!==t?f*t/(t+s):f))/2}const g=(f-Math.max(.001,f*c-i/_t)/c)/2,p=r+g+u,m=n-g-u,{outerStart:x,outerEnd:b,innerStart:_,innerEnd:y}=In(e,d,c,m-p),v=c-x,w=c-b,M=p+x/v,k=m-b/w,S=d+_,P=d+y,D=p+_/S,C=m-y/P;if(t.beginPath(),t.arc(o,a,c,M,k),b>0){const e=zn(w,k,o,a);t.arc(e.x,e.y,b,k,m+kt)}const O=zn(P,m,o,a);if(t.lineTo(O.x,O.y),y>0){const e=zn(P,C,o,a);t.arc(e.x,e.y,y,m+kt,C+Math.PI)}if(t.arc(o,a,d,m-y/d,p+_/d,!0),_>0){const e=zn(S,D,o,a);t.arc(e.x,e.y,_,D+Math.PI,p-kt)}const A=zn(v,p,o,a);if(t.lineTo(A.x,A.y),x>0){const e=zn(v,M,o,a);t.arc(e.x,e.y,x,p-kt,M)}t.closePath()}function Bn(t,e,i,s,n){const{options:o}=e,{borderWidth:a,borderJoinStyle:r}=o,l="inner"===o.borderAlign;a&&(l?(t.lineWidth=2*a,t.lineJoin=r||"round"):(t.lineWidth=a,t.lineJoin=r||"bevel"),e.fullCircles&&function(t,e,i){const{x:s,y:n,startAngle:o,pixelMargin:a,fullCircles:r}=e,l=Math.max(e.outerRadius-a,0),h=e.innerRadius+a;let c;for(i&&En(t,e,o+yt),t.beginPath(),t.arc(s,n,h,o+yt,o,!0),c=0;c=yt||Ht(n,a,r),f=Yt(o,l+d,h+d);return u&&f}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius","circumference"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/2,n=(e.spacing||0)/2;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>yt?Math.floor(i/yt):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();let o=0;if(s){o=s/2;const e=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(e)*o,Math.sin(e)*o),this.circumference>=_t&&(o=s)}t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor;const a=function(t,e,i,s){const{fullCircles:n,startAngle:o,circumference:a}=e;let r=e.endAngle;if(n){Fn(t,e,i,s,o+yt);for(let e=0;er&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function Yn(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?$n:jn}Vn.id="arc",Vn.defaults={borderAlign:"center",borderColor:"#fff",borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0},Vn.defaultRoutes={backgroundColor:"backgroundColor"};const Un="function"==typeof Path2D;function Xn(t,e,i,s){Un&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Wn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=Yn(e);for(const r of n)Wn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class qn extends Ds{constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;ki(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Ni(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Wi(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?Ai:t.tension||"monotone"===t.cubicInterpolationMode?Ti:Oi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t&&"fill"!==t};class Gn extends Ds{constructor(t){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.options,{x:n,y:o}=this.getProps(["x","y"],i);return Math.pow(t-n,2)+Math.pow(e-o,2){oo(t)}))}var ro={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void ao(t);const s=t.width;t.data.datasets.forEach(((e,n)=>{const{_data:o,indexAxis:a}=e,r=t.getDatasetMeta(n),l=o||e.data;if("y"===je([a,t.options.indexAxis]))return;if("line"!==r.type)return;const h=t.scales[r.xAxisID];if("linear"!==h.type&&"time"!==h.type)return;if(t.options.parsing)return;let{start:c,count:d}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=jt(re(e,o.axis,a).lo,0,i-1)),s=h?jt(re(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(r,l);if(d<=(i.threshold||4*s))return void oo(e);let u;switch($(o)&&(e._data=l,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":u=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(l,c,d,s,i);break;case"min-max":u=function(t,e,i,s){let n,o,a,r,l,h,c,d,u,f,g=0,p=0;const m=[],x=e+i-1,b=t[e].x,_=t[x].x-b;for(n=e;nf&&(f=r,c=n),g=(p*g+o.x)/++p;else{const i=n-1;if(!$(h)&&!$(c)){const e=Math.min(h,c),s=Math.max(h,c);e!==d&&e!==i&&m.push({...t[e],x:g}),s!==d&&s!==i&&m.push({...t[s],x:g})}n>0&&i!==d&&m.push(t[i]),m.push(o),l=e,p=0,u=f=r,h=c=d=n}}return m}(l,c,d,s);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=u}))},destroy(t){ao(t)}};function lo(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=K(i&&i.target,i);return void 0===s&&(s=!!e.backgroundColor),!1!==s&&null!==s&&(!0===s?"origin":s)}(t);if(U(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return X(n)&&Math.floor(n)===n?("-"!==s[0]&&"+"!==s[0]||(n=e+n),!(n===e||n<0||n>=i)&&n):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}class ho{constructor(t){this.x=t.x,this.y=t.y,this.radius=t.radius}pathSegment(t,e,i){const{x:s,y:n,radius:o}=this;return e=e||{start:0,end:yt},t.arc(s,n,o,e.end,e.start,!0),!i.bounds}interpolate(t){const{x:e,y:i,radius:s}=this,n=t.angle;return{x:e+Math.cos(n)*s,y:i+Math.sin(n)*s,angle:n}}}function co(t){return(t.scale||{}).getPointPositionForValue?function(t){const{scale:e,fill:i}=t,s=e.options,n=e.getLabels().length,o=[],a=s.reverse?e.max:e.min,r=s.reverse?e.min:e.max;let l,h,c;if(c="start"===i?a:"end"===i?r:U(i)?i.value:e.getBaseValue(),s.grid.circular)return h=e.getPointPositionForValue(0,a),new ho({x:h.x,y:h.y,radius:e.getDistanceFromCenterForValue(c)});for(l=0;lt;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function fo(t,e,i){const s=[];for(let n=0;n{e=uo(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new qn({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function xo(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!X(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function bo(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[uo(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(h.x,i),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(c.x,i)}t.lineTo(e.first().x,i),t.closePath(),t.clip()}function _o(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=Nt(n),o=Nt(o)),{property:t,start:n,end:o}}function yo(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function vo(t,e,i){const{top:s,bottom:n}=e.chart.chartArea,{property:o,start:a,end:r}=i||{};"x"===o&&(t.beginPath(),t.rect(a,s,r-a,n-s),t.clip())}function wo(t,e,i,s){const n=e.interpolate(i,s);n&&t.lineTo(n.x,n.y)}function Mo(t,e){const{line:i,target:s,property:n,color:o,scale:a}=e,r=function(t,e,i){const s=t.segments,n=t.points,o=e.points,a=[];for(const t of s){let{start:s,end:r}=t;r=uo(s,r,n);const l=_o(i,n[s],n[r],t.loop);if(!e.segments){a.push({source:t,target:l,start:n[s],end:n[r]});continue}const h=Wi(e,l);for(const e of h){const s=_o(i,o[e.start],o[e.end],e.loop),r=Vi(t,n,s);for(const t of r)a.push({source:t,target:e,start:{[i]:yo(l,s,"start",Math.max)},end:{[i]:yo(l,s,"end",Math.min)}})}}return a}(i,s,n);for(const{source:e,target:l,start:h,end:c}of r){const{style:{backgroundColor:r=o}={}}=e,d=!0!==s;t.save(),t.fillStyle=r,vo(t,a,d&&_o(n,h,c)),t.beginPath();const u=!!i.pathSegment(t,e);let f;if(d){u?t.closePath():wo(t,s,c,n);const e=!!s.pathSegment(t,l,{move:u,reverse:!0});f=u&&e,f||wo(t,s,h,n)}t.closePath(),t.fill(f?"evenodd":"nonzero"),t.restore()}}function ko(t,e,i){const s=po(e),{line:n,scale:o,axis:a}=e,r=n.options,l=r.fill,h=r.backgroundColor,{above:c=h,below:d=h}=l||{};s&&n.points.length&&(Qt(t,i),function(t,e){const{line:i,target:s,above:n,below:o,area:a,scale:r}=e,l=i._loop?"angle":e.axis;t.save(),"x"===l&&o!==n&&(bo(t,s,a.top),Mo(t,{line:i,target:s,color:n,scale:r,property:l}),t.restore(),t.save(),bo(t,s,a.bottom)),Mo(t,{line:i,target:s,color:o,scale:r,property:l}),t.restore()}(t,{line:n,target:s,above:c,below:d,area:i,scale:o,axis:a}),te(t))}var So={id:"filler",afterDatasetsUpdate(t,e,i){const s=(t.data.datasets||[]).length,n=[];let o,a,r,l;for(a=0;a=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&ko(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;i&&ko(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;s&&!1!==s.fill&&"beforeDatasetDraw"===i.drawTime&&ko(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const Po=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class Do extends Ds{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=J(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=He(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=Po(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,n,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const p=i+e/2+n.measureText(t.text).width;o>0&&u+s+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:s},d=Math.max(d,p),u+=s+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:o}}=this,a=Ei(o,this.left,this.width);if(this.isHorizontal()){let o=0,r=n(i,this.left+s,this.right-this.lineWidths[o]);for(const l of e)o!==l.row&&(o=l.row,r=n(i,this.left+s,this.right-this.lineWidths[o])),l.top+=this.top+t+s,l.left=a.leftForLtr(a.x(r),l.width),r+=l.width+s}else{let o=0,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height);for(const l of e)l.col!==o&&(o=l.col,r=n(i,this.top+t+s,this.bottom-this.columnSizes[o].height)),l.top=r,l.left+=this.left+s,l.left=a.leftForLtr(a.x(l.left),l.width),r+=l.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Qt(t,this),this._draw(),te(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:a,labels:r}=t,l=bt.color,h=Ei(t.rtl,this.left,this.width),c=He(r.font),{color:d,padding:u}=r,f=c.size,g=f/2;let p;this.drawTitle(),s.textAlign=h.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=c.string;const{boxWidth:m,boxHeight:x,itemHeight:b}=Po(r,f),_=this.isHorizontal(),y=this._computeTitleHeight();p=_?{x:n(a,this.left+u,this.right-i[0]),y:this.top+u+y,line:0}:{x:this.left+u,y:n(a,this.top+y+u,this.bottom-e[0].height),line:0},Ii(this.ctx,t.textDirection);const v=b+u;this.legendItems.forEach(((w,M)=>{s.strokeStyle=w.fontColor||d,s.fillStyle=w.fontColor||d;const k=s.measureText(w.text).width,S=h.textAlign(w.textAlign||(w.textAlign=r.textAlign)),P=m+g+k;let D=p.x,C=p.y;h.setWidth(this.width),_?M>0&&D+P+u>this.right&&(C=p.y+=v,p.line++,D=p.x=n(a,this.left+u,this.right-i[p.line])):M>0&&C+v>this.bottom&&(D=p.x=D+e[p.line].width+u,p.line++,C=p.y=n(a,this.top+y+u,this.bottom-e[p.line].height));!function(t,e,i){if(isNaN(m)||m<=0||isNaN(x)||x<0)return;s.save();const n=K(i.lineWidth,1);if(s.fillStyle=K(i.fillStyle,l),s.lineCap=K(i.lineCap,"butt"),s.lineDashOffset=K(i.lineDashOffset,0),s.lineJoin=K(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=K(i.strokeStyle,l),s.setLineDash(K(i.lineDash,[])),r.usePointStyle){const o={radius:m*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},a=h.xPlus(t,m/2);Zt(s,o,a,e+g)}else{const o=e+Math.max((f-x)/2,0),a=h.leftForLtr(t,m),r=We(i.borderRadius);s.beginPath(),Object.values(r).some((t=>0!==t))?oe(s,{x:a,y:o,w:m,h:x,radius:r}):s.rect(a,o,m,x),s.fill(),0!==n&&s.stroke()}s.restore()}(h.x(D),C,w),D=o(S,D+m+g,_?D+P:this.right,t.rtl),function(t,e,i){se(s,i.text,t,e+b/2,c,{strikethrough:i.hidden,textAlign:h.textAlign(i.textAlign)})}(h.x(D),C,w),_?p.x+=P+u:p.y+=v})),zi(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=He(e.font),o=Ne(e.padding);if(!e.display)return;const a=Ei(t.rtl,this.left,this.width),r=this.ctx,l=e.position,h=i.size/2,c=o.top+h;let d,u=this.left,f=this.width;if(this.isHorizontal())f=Math.max(...this.lineWidths),d=this.top+c,u=n(t.align,u,this.right-f);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);d=c+n(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const g=n(l,u,u+f);r.textAlign=a.textAlign(s(l)),r.textBaseline="middle",r.strokeStyle=e.color,r.fillStyle=e.color,r.font=i.string,se(r,e.text,g,d,i)}_computeTitleHeight(){const t=this.options.title,e=He(t.font),i=Ne(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(Yt(t,this.left,this.right)&&Yt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const a=t.controller.getStyle(i?0:void 0),r=Ne(a.borderWidth);return{text:e[t.index].label,fillStyle:a.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:a.borderCapStyle,lineDash:a.borderDash,lineDashOffset:a.borderDashOffset,lineJoin:a.borderJoinStyle,lineWidth:(r.width+r.height)/4,strokeStyle:a.borderColor,pointStyle:s||a.pointStyle,rotation:a.rotation,textAlign:n||a.textAlign,borderRadius:0,datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Oo extends Ds{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=Y(i.text)?i.text.length:1;this._padding=Ne(i.padding);const n=s*He(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=n:this.width=n}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:o,options:a}=this,r=a.align;let l,h,c,d=0;return this.isHorizontal()?(h=n(r,i,o),c=e+t,l=o-i):("left"===a.position?(h=i+t,c=n(r,s,e),d=-.5*_t):(h=o-t,c=n(r,e,s),d=.5*_t),l=s-e),{titleX:h,titleY:c,maxWidth:l,rotation:d}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=He(e.font),n=i.lineHeight/2+this._padding.top,{titleX:o,titleY:a,maxWidth:r,rotation:l}=this._drawArgs(n);se(t,e.text,0,0,i,{color:e.color,maxWidth:r,rotation:l,textAlign:s(e.align),textBaseline:"middle",translation:[o,a]})}}var Ao={id:"title",_element:Oo,start(t,e,i){!function(t,e){const i=new Oo({ctx:t.ctx,options:e,chart:t});ni.configure(t,i,e),ni.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ni.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const To=new WeakMap;var Lo={id:"subtitle",start(t,e,i){const s=new Oo({ctx:t.ctx,options:i,chart:t});ni.configure(t,s,i),ni.addBox(t,s),To.set(t,s)},stop(t){ni.removeBox(t,To.get(t)),To.delete(t)},beforeUpdate(t,e,i){const s=To.get(t);ni.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Ro={average(t){if(!t.length)return!1;let e,i,s=0,n=0,o=0;for(e=0,i=t.length;e-1?t.split("\n"):t}function zo(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Fo(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=He(e.bodyFont),h=He(e.titleFont),c=He(e.footerFont),d=o.length,u=n.length,f=s.length,g=Ne(e.padding);let p=g.height,m=0,x=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(x+=t.beforeBody.length+t.afterBody.length,d&&(p+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),x){p+=f*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(x-f)*l.lineHeight+(x-1)*e.bodySpacing}u&&(p+=e.footerMarginTop+u*c.lineHeight+(u-1)*e.footerSpacing);let b=0;const _=function(t){m=Math.max(m,i.measureText(t).width+b)};return i.save(),i.font=h.string,Q(t.title,_),i.font=l.string,Q(t.beforeBody.concat(t.afterBody),_),b=e.displayColors?a+2+e.boxPadding:0,Q(s,(t=>{Q(t.before,_),Q(t.lines,_),Q(t.after,_)})),b=0,i.font=c.string,Q(t.footer,_),i.restore(),m+=g.width,{width:m,height:p}}function Bo(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Vo(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Bo(t,e,i,s),yAlign:s}}function Wo(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=We(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:jt(g,0,s.width-e.width),y:jt(p,0,s.height-e.height)}}function No(t,e,i){const s=Ne(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ho(t){return Eo([],Io(t))}function jo(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}class $o extends Ds{constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart||t._chart,this._chart=this.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const e=this.chart,i=this.options.setContext(this.getContext()),s=i.enabled&&e.options.animation&&i.animations,n=new gs(this.chart,s);return s._cacheable&&(this._cachedAnimations=Object.freeze(n)),n}getContext(){return this.$context||(this.$context=(t=this.chart.getContext(),e=this,i=this._tooltipItems,Ye(t,{tooltip:e,tooltipItems:i,type:"tooltip"})));var t,e,i}getTitle(t,e){const{callbacks:i}=e,s=i.beforeTitle.apply(this,[t]),n=i.title.apply(this,[t]),o=i.afterTitle.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}getBeforeBody(t,e){return Ho(e.callbacks.beforeBody.apply(this,[t]))}getBody(t,e){const{callbacks:i}=e,s=[];return Q(t,(t=>{const e={before:[],lines:[],after:[]},n=jo(i,t);Eo(e.before,Io(n.beforeLabel.call(this,t))),Eo(e.lines,n.label.call(this,t)),Eo(e.after,Io(n.afterLabel.call(this,t))),s.push(e)})),s}getAfterBody(t,e){return Ho(e.callbacks.afterBody.apply(this,[t]))}getFooter(t,e){const{callbacks:i}=e,s=i.beforeFooter.apply(this,[t]),n=i.footer.apply(this,[t]),o=i.afterFooter.apply(this,[t]);let a=[];return a=Eo(a,Io(s)),a=Eo(a,Io(n)),a=Eo(a,Io(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),Q(l,(e=>{const i=jo(t.callbacks,e);s.push(i.labelColor.call(this,e)),n.push(i.labelPointStyle.call(this,e)),o.push(i.labelTextColor.call(this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Ro[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Fo(this,i),a=Object.assign({},t,e),r=Vo(this.chart,i,a),l=Wo(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=We(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Ei(i.rtl,this.x,this.width);for(t.x=No(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=He(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,oe(t,{x:e,y:g,w:l,h:r,radius:a}),t.fill(),t.stroke(),t.fillStyle=o.backgroundColor,t.beginPath(),oe(t,{x:i,y:g+1,w:l-2,h:r-2,radius:a}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,l,r),t.strokeRect(e,g,l,r),t.fillStyle=o.backgroundColor,t.fillRect(i,g+1,l-2,r-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=He(i.bodyFont);let d=c.lineHeight,u=0;const f=Ei(i.rtl,this.x,this.width),g=function(i){e.fillText(i,f.x(t.x+u),t.y+d/2),t.y+=d+n},p=f.textAlign(o);let m,x,b,_,y,v,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=No(this,p,i),e.fillStyle=i.bodyColor,Q(this.beforeBody,g),u=a&&"right"!==p?"center"===o?l/2+h:l+2+h:0,_=0,v=s.length;_0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Ro[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Fo(this,t),a=Object.assign({},i,this._size),r=Vo(e,t,a),l=Wo(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=Ne(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ii(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),zi(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!tt(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!tt(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e;const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Ro[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}$o.positioners=Ro;var Yo={id:"tooltip",_element:$o,positioners:Ro,afterInit(t,e,i){i&&(t.tooltip=new $o({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip,i={tooltip:e};!1!==t.notifyPlugins("beforeTooltipDraw",i)&&(e&&e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i))},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:{beforeTitle:H,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]},Uo=Object.freeze({__proto__:null,Decimation:ro,Filler:So,Legend:Co,SubTitle:Lo,Title:Ao,Tooltip:Yo});function Xo(t,e,i,s){const n=t.indexOf(e);if(-1===n)return((t,e,i,s)=>("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}class qo extends Bs{constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if($(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:jt(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:Xo(i,t,K(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){const e=this.getLabels();return t>=0&&te.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}}function Ko(t,e,{horizontal:i,minRotation:s}){const n=It(s),o=(i?Math.sin(n):Math.cos(n))||.001,a=.75*e*(""+t).length;return Math.min(e/o,a)}qo.id="category",qo.defaults={ticks:{callback:qo.prototype.getLabelForValue}};class Go extends Bs{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,e){return $(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:e,maxDefined:i}=this.getUserBounds();let{min:s,max:n}=this;const o=t=>s=e?s:t,a=t=>n=i?n:t;if(t){const t=Ct(s),e=Ct(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=1;(n>=Number.MAX_SAFE_INTEGER||s<=Number.MIN_SAFE_INTEGER)&&(e=Math.abs(.05*n)),a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const s=function(t,e){const i=[],{bounds:s,step:n,min:o,max:a,precision:r,count:l,maxTicks:h,maxDigits:c,includeBounds:d}=t,u=n||1,f=h-1,{min:g,max:p}=e,m=!$(o),x=!$(a),b=!$(l),_=(p-g)/(c+1);let y,v,w,M,k=Ot((p-g)/f/u)*u;if(k<1e-14&&!m&&!x)return[{value:g},{value:p}];M=Math.ceil(p/k)-Math.floor(g/k),M>f&&(k=Ot(M*k/f/u)*u),$(r)||(y=Math.pow(10,r),k=Math.ceil(k*y)/y),"ticks"===s?(v=Math.floor(g/k)*k,w=Math.ceil(p/k)*k):(v=g,w=p),m&&x&&n&&Rt((a-o)/n,k/1e3)?(M=Math.round(Math.min((a-o)/k,h)),k=(a-o)/M,v=o,w=a):b?(v=m?o:v,w=x?a:w,M=l-1,k=(w-v)/M):(M=(w-v)/k,M=Lt(M,Math.round(M),k/1e3)?Math.round(M):Math.ceil(M));const S=Math.max(Ft(k),Ft(v));y=Math.pow(10,$(r)?S:r),v=Math.round(v*y)/y,w=Math.round(w*y)/y;let P=0;for(m&&(d&&v!==o?(i.push({value:o}),v0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=X(t)?Math.max(0,t):null,this.max=X(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t,a=(t,e)=>Math.pow(10,Math.floor(Dt(t))+e);i===s&&(i<=0?(n(1),o(10)):(n(a(i,-1)),o(a(s,1)))),i<=0&&n(a(s,-1)),s<=0&&o(a(i,1)),this._zero&&this.min!==this._suggestedMin&&i===a(this.min,0)&&n(a(i,-1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=function(t,e){const i=Math.floor(Dt(e.max)),s=Math.ceil(e.max/Math.pow(10,i)),n=[];let o=q(t.min,Math.pow(10,Math.floor(Dt(e.min)))),a=Math.floor(Dt(o)),r=Math.floor(o/Math.pow(10,a)),l=a<0?Math.pow(10,Math.abs(a)):1;do{n.push({value:o,major:Jo(o)}),++r,10===r&&(r=1,++a,l=a>=0?1:l),o=Math.round(r*Math.pow(10,a)*l)/l}while(an?{start:e-i,end:e}:{start:e,end:e+i}}function ia(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],n=[],o=t._pointLabels.length,a=t.options.pointLabels,r=a.centerPointLabels?_t/o:0;for(let d=0;de.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function na(t){return 0===t||180===t?"center":t<180?"left":"right"}function oa(t,e,i){return"right"===i?t-=e:"center"===i&&(t-=e/2),t}function aa(t,e,i){return 90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e),t}function ra(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,yt);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;o{const i=J(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?ia(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return Nt(t*(yt/(this._pointLabels.length||1))+It(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if($(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if($(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=s.setContext(t.getPointLabelContext(n)),o=He(e.font),{x:a,y:r,textAlign:l,left:h,top:c,right:d,bottom:u}=t._pointLabelItems[n],{backdropColor:f}=e;if(!$(f)){const t=Ne(e.backdropPadding);i.fillStyle=f,i.fillRect(h-t.left,c-t.top,d-h+t.width,u-c+t.height)}se(i,t._pointLabels[n],a,r+o.lineHeight/2,o,{color:e.color,textAlign:l,textBaseline:"middle"})}}(this,n),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e){a=this.getDistanceFromCenterForValue(t.value);!function(t,e,i,s){const n=t.ctx,o=e.circular,{color:a,lineWidth:r}=e;!o&&!s||!a||!r||i<0||(n.save(),n.strokeStyle=a,n.lineWidth=r,n.setLineDash(e.borderDash),n.lineDashOffset=e.borderDashOffset,n.beginPath(),ra(t,i,o,s),n.closePath(),n.stroke(),n.restore())}(this,s.setContext(this.getContext(e-1)),a,n)}})),i.display){for(t.save(),o=n-1;o>=0;o--){const s=i.setContext(this.getPointLabelContext(o)),{color:n,lineWidth:l}=s;l&&n&&(t.lineWidth=l,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,a=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),r=this.getPointPosition(o,a),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(r.x,r.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=He(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=Ne(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}se(t,s.label,0,-n,l,{color:r.color})})),t.restore()}drawTitle(){}}la.id="radialLinear",la.defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Os.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:t=>t,padding:5,centerPointLabels:!1}},la.defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"},la.descriptors={angleLines:{_fallback:"grid"}};const ha={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ca=Object.keys(ha);function da(t,e){return t-e}function ua(t,e){if($(e))return null;const i=t._adapter,{parser:s,round:n,isoWeekday:o}=t._parseOpts;let a=e;return"function"==typeof s&&(a=s(a)),X(a)||(a="string"==typeof s?i.parse(a,s):i.parse(a)),null===a?null:(n&&(a="week"!==n||!Tt(o)&&!0!==o?i.startOf(a,n):i.startOf(a,"isoWeek",o)),+a)}function fa(t,e,i,s){const n=ca.length;for(let o=ca.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function pa(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class ma extends Bs{constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e){const i=t.time||(t.time={}),s=this._adapter=new mn._date(t.adapters.date);ot(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:ua(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:a}=this.getUserBounds();function r(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),a||isNaN(t.max)||(n=Math.max(n,t.max))}o&&a||(r(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||r(this.getMinMax(!1))),s=X(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=X(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=he(s,n,this.max);return this._unit=e.unit||(i.autoSkip?fa(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=ca.length-1;o>=ca.indexOf(i);o--){const i=ca[o];if(ha[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return ca[i?ca.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=ca.indexOf(t)+1,i=ca.length;e1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const f="data"===s.ticks.source&&this.getDataTimestamps();for(c=u,d=0;ct-e)).map((t=>+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.time.displayFormats,a=this._unit,r=this._majorUnit,l=a&&o[a],h=r&&o[r],c=i[e],d=r&&h&&c&&c.major,u=this._adapter.format(t,s||(d?h:l)),f=n.ticks.callback;return f?J(f,[u,e,i],this):u}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=re(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=re(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}ma.id="time",ma.defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",major:{enabled:!1}}};class ba extends ma{constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=xa(e,this.min),this._tableRange=xa(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;o Array.prototype.slice.call(args)); - let ticking = false; - let args = []; - return function(...rest) { - args = updateArgs(rest); - if (!ticking) { - ticking = true; - requestAnimFrame.call(window, () => { - ticking = false; - fn.apply(thisArg, args); - }); - } - }; -} -function debounce(fn, delay) { - let timeout; - return function(...args) { - if (delay) { - clearTimeout(timeout); - timeout = setTimeout(fn, delay, args); - } else { - fn.apply(this, args); - } - return delay; - }; -} -const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; -const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; -const _textX = (align, left, right, rtl) => { - const check = rtl ? 'left' : 'right'; - return align === check ? right : align === 'center' ? (left + right) / 2 : left; -}; - -function noop() {} -const uid = (function() { - let id = 0; - return function() { - return id++; - }; -}()); -function isNullOrUndef(value) { - return value === null || typeof value === 'undefined'; -} -function isArray(value) { - if (Array.isArray && Array.isArray(value)) { - return true; - } - const type = Object.prototype.toString.call(value); - if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { - return true; - } - return false; -} -function isObject(value) { - return value !== null && Object.prototype.toString.call(value) === '[object Object]'; -} -const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value); -function finiteOrDefault(value, defaultValue) { - return isNumberFinite(value) ? value : defaultValue; -} -function valueOrDefault(value, defaultValue) { - return typeof value === 'undefined' ? defaultValue : value; -} -const toPercentage = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 - : value / dimension; -const toDimension = (value, dimension) => - typeof value === 'string' && value.endsWith('%') ? - parseFloat(value) / 100 * dimension - : +value; -function callback(fn, args, thisArg) { - if (fn && typeof fn.call === 'function') { - return fn.apply(thisArg, args); - } -} -function each(loopable, fn, thisArg, reverse) { - let i, len, keys; - if (isArray(loopable)) { - len = loopable.length; - if (reverse) { - for (i = len - 1; i >= 0; i--) { - fn.call(thisArg, loopable[i], i); - } - } else { - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[i], i); - } - } - } else if (isObject(loopable)) { - keys = Object.keys(loopable); - len = keys.length; - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[keys[i]], keys[i]); - } - } -} -function _elementsEqual(a0, a1) { - let i, ilen, v0, v1; - if (!a0 || !a1 || a0.length !== a1.length) { - return false; - } - for (i = 0, ilen = a0.length; i < ilen; ++i) { - v0 = a0[i]; - v1 = a1[i]; - if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { - return false; - } - } - return true; -} -function clone$1(source) { - if (isArray(source)) { - return source.map(clone$1); - } - if (isObject(source)) { - const target = Object.create(null); - const keys = Object.keys(source); - const klen = keys.length; - let k = 0; - for (; k < klen; ++k) { - target[keys[k]] = clone$1(source[keys[k]]); - } - return target; - } - return source; -} -function isValidKey(key) { - return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; -} -function _merger(key, target, source, options) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - merge(tval, sval, options); - } else { - target[key] = clone$1(sval); - } -} -function merge(target, source, options) { - const sources = isArray(source) ? source : [source]; - const ilen = sources.length; - if (!isObject(target)) { - return target; - } - options = options || {}; - const merger = options.merger || _merger; - for (let i = 0; i < ilen; ++i) { - source = sources[i]; - if (!isObject(source)) { - continue; - } - const keys = Object.keys(source); - for (let k = 0, klen = keys.length; k < klen; ++k) { - merger(keys[k], target, source, options); - } - } - return target; -} -function mergeIf(target, source) { - return merge(target, source, {merger: _mergerIf}); -} -function _mergerIf(key, target, source) { - if (!isValidKey(key)) { - return; - } - const tval = target[key]; - const sval = source[key]; - if (isObject(tval) && isObject(sval)) { - mergeIf(tval, sval); - } else if (!Object.prototype.hasOwnProperty.call(target, key)) { - target[key] = clone$1(sval); - } -} -function _deprecated(scope, value, previous, current) { - if (value !== undefined) { - console.warn(scope + ': "' + previous + - '" is deprecated. Please use "' + current + '" instead'); - } -} -const emptyString = ''; -const dot = '.'; -function indexOfDotOrLength(key, start) { - const idx = key.indexOf(dot, start); - return idx === -1 ? key.length : idx; -} -function resolveObjectKey(obj, key) { - if (key === emptyString) { - return obj; - } - let pos = 0; - let idx = indexOfDotOrLength(key, pos); - while (obj && idx > pos) { - obj = obj[key.substr(pos, idx - pos)]; - pos = idx + 1; - idx = indexOfDotOrLength(key, pos); - } - return obj; -} -function _capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); -} -const defined = (value) => typeof value !== 'undefined'; -const isFunction = (value) => typeof value === 'function'; -const setsEqual = (a, b) => { - if (a.size !== b.size) { - return false; - } - for (const item of a) { - if (!b.has(item)) { - return false; - } - } - return true; -}; -function _isClickEvent(e) { - return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; -} - -const PI = Math.PI; -const TAU = 2 * PI; -const PITAU = TAU + PI; -const INFINITY = Number.POSITIVE_INFINITY; -const RAD_PER_DEG = PI / 180; -const HALF_PI = PI / 2; -const QUARTER_PI = PI / 4; -const TWO_THIRDS_PI = PI * 2 / 3; -const log10 = Math.log10; -const sign = Math.sign; -function niceNum(range) { - const roundedRange = Math.round(range); - range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; - const niceRange = Math.pow(10, Math.floor(log10(range))); - const fraction = range / niceRange; - const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; - return niceFraction * niceRange; -} -function _factorize(value) { - const result = []; - const sqrt = Math.sqrt(value); - let i; - for (i = 1; i < sqrt; i++) { - if (value % i === 0) { - result.push(i); - result.push(value / i); - } - } - if (sqrt === (sqrt | 0)) { - result.push(sqrt); - } - result.sort((a, b) => a - b).pop(); - return result; -} -function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); -} -function almostEquals(x, y, epsilon) { - return Math.abs(x - y) < epsilon; -} -function almostWhole(x, epsilon) { - const rounded = Math.round(x); - return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x); -} -function _setMinAndMaxByKey(array, target, property) { - let i, ilen, value; - for (i = 0, ilen = array.length; i < ilen; i++) { - value = array[i][property]; - if (!isNaN(value)) { - target.min = Math.min(target.min, value); - target.max = Math.max(target.max, value); - } - } -} -function toRadians(degrees) { - return degrees * (PI / 180); -} -function toDegrees(radians) { - return radians * (180 / PI); -} -function _decimalPlaces(x) { - if (!isNumberFinite(x)) { - return; - } - let e = 1; - let p = 0; - while (Math.round(x * e) / e !== x) { - e *= 10; - p++; - } - return p; -} -function getAngleFromPoint(centrePoint, anglePoint) { - const distanceFromXCenter = anglePoint.x - centrePoint.x; - const distanceFromYCenter = anglePoint.y - centrePoint.y; - const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); - let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); - if (angle < (-0.5 * PI)) { - angle += TAU; - } - return { - angle, - distance: radialDistanceFromCenter - }; -} -function distanceBetweenPoints(pt1, pt2) { - return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); -} -function _angleDiff(a, b) { - return (a - b + PITAU) % TAU - PI; -} -function _normalizeAngle(a) { - return (a % TAU + TAU) % TAU; -} -function _angleBetween(angle, start, end, sameAngleIsFullCircle) { - const a = _normalizeAngle(angle); - const s = _normalizeAngle(start); - const e = _normalizeAngle(end); - const angleToStart = _normalizeAngle(s - a); - const angleToEnd = _normalizeAngle(e - a); - const startToAngle = _normalizeAngle(a - s); - const endToAngle = _normalizeAngle(a - e); - return a === s || a === e || (sameAngleIsFullCircle && s === e) - || (angleToStart > angleToEnd && startToAngle < endToAngle); -} -function _limitValue(value, min, max) { - return Math.max(min, Math.min(max, value)); -} -function _int16Range(value) { - return _limitValue(value, -32768, 32767); -} -function _isBetween(value, start, end, epsilon = 1e-6) { - return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; -} - -const atEdge = (t) => t === 0 || t === 1; -const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); -const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; -const effects = { - linear: t => t, - easeInQuad: t => t * t, - easeOutQuad: t => -t * (t - 2), - easeInOutQuad: t => ((t /= 0.5) < 1) - ? 0.5 * t * t - : -0.5 * ((--t) * (t - 2) - 1), - easeInCubic: t => t * t * t, - easeOutCubic: t => (t -= 1) * t * t + 1, - easeInOutCubic: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t - : 0.5 * ((t -= 2) * t * t + 2), - easeInQuart: t => t * t * t * t, - easeOutQuart: t => -((t -= 1) * t * t * t - 1), - easeInOutQuart: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t - : -0.5 * ((t -= 2) * t * t * t - 2), - easeInQuint: t => t * t * t * t * t, - easeOutQuint: t => (t -= 1) * t * t * t * t + 1, - easeInOutQuint: t => ((t /= 0.5) < 1) - ? 0.5 * t * t * t * t * t - : 0.5 * ((t -= 2) * t * t * t * t + 2), - easeInSine: t => -Math.cos(t * HALF_PI) + 1, - easeOutSine: t => Math.sin(t * HALF_PI), - easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1), - easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)), - easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1, - easeInOutExpo: t => atEdge(t) ? t : t < 0.5 - ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) - : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), - easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1), - easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t), - easeInOutCirc: t => ((t /= 0.5) < 1) - ? -0.5 * (Math.sqrt(1 - t * t) - 1) - : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), - easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3), - easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3), - easeInOutElastic(t) { - const s = 0.1125; - const p = 0.45; - return atEdge(t) ? t : - t < 0.5 - ? 0.5 * elasticIn(t * 2, s, p) - : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); - }, - easeInBack(t) { - const s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - easeOutBack(t) { - const s = 1.70158; - return (t -= 1) * t * ((s + 1) * t + s) + 1; - }, - easeInOutBack(t) { - let s = 1.70158; - if ((t /= 0.5) < 1) { - return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); - } - return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - easeInBounce: t => 1 - effects.easeOutBounce(1 - t), - easeOutBounce(t) { - const m = 7.5625; - const d = 2.75; - if (t < (1 / d)) { - return m * t * t; - } - if (t < (2 / d)) { - return m * (t -= (1.5 / d)) * t + 0.75; - } - if (t < (2.5 / d)) { - return m * (t -= (2.25 / d)) * t + 0.9375; - } - return m * (t -= (2.625 / d)) * t + 0.984375; - }, - easeInOutBounce: t => (t < 0.5) - ? effects.easeInBounce(t * 2) * 0.5 - : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5, -}; - -/*! - * @kurkle/color v0.1.9 - * https://github.com/kurkle/color#readme - * (c) 2020 Jukka Kurkela - * Released under the MIT License - */ -const map = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; -const hex = '0123456789ABCDEF'; -const h1 = (b) => hex[b & 0xF]; -const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; -const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF)); -function isShort(v) { - return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); -} -function hexParse(str) { - var len = str.length; - var ret; - if (str[0] === '#') { - if (len === 4 || len === 5) { - ret = { - r: 255 & map[str[1]] * 17, - g: 255 & map[str[2]] * 17, - b: 255 & map[str[3]] * 17, - a: len === 5 ? map[str[4]] * 17 : 255 - }; - } else if (len === 7 || len === 9) { - ret = { - r: map[str[1]] << 4 | map[str[2]], - g: map[str[3]] << 4 | map[str[4]], - b: map[str[5]] << 4 | map[str[6]], - a: len === 9 ? (map[str[7]] << 4 | map[str[8]]) : 255 - }; - } - } - return ret; -} -function hexString(v) { - var f = isShort(v) ? h1 : h2; - return v - ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') - : v; -} -function round(v) { - return v + 0.5 | 0; -} -const lim = (v, l, h) => Math.max(Math.min(v, h), l); -function p2b(v) { - return lim(round(v * 2.55), 0, 255); -} -function n2b(v) { - return lim(round(v * 255), 0, 255); -} -function b2n(v) { - return lim(round(v / 2.55) / 100, 0, 1); -} -function n2p(v) { - return lim(round(v * 100), 0, 100); -} -const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; -function rgbParse(str) { - const m = RGB_RE.exec(str); - let a = 255; - let r, g, b; - if (!m) { - return; - } - if (m[7] !== r) { - const v = +m[7]; - a = 255 & (m[8] ? p2b(v) : v * 255); - } - r = +m[1]; - g = +m[3]; - b = +m[5]; - r = 255 & (m[2] ? p2b(r) : r); - g = 255 & (m[4] ? p2b(g) : g); - b = 255 & (m[6] ? p2b(b) : b); - return { - r: r, - g: g, - b: b, - a: a - }; -} -function rgbString(v) { - return v && ( - v.a < 255 - ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` - : `rgb(${v.r}, ${v.g}, ${v.b})` - ); -} -const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; -function hsl2rgbn(h, s, l) { - const a = s * Math.min(l, 1 - l); - const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return [f(0), f(8), f(4)]; -} -function hsv2rgbn(h, s, v) { - const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); - return [f(5), f(3), f(1)]; -} -function hwb2rgbn(h, w, b) { - const rgb = hsl2rgbn(h, 1, 0.5); - let i; - if (w + b > 1) { - i = 1 / (w + b); - w *= i; - b *= i; - } - for (i = 0; i < 3; i++) { - rgb[i] *= 1 - w - b; - rgb[i] += w; - } - return rgb; -} -function rgb2hsl(v) { - const range = 255; - const r = v.r / range; - const g = v.g / range; - const b = v.b / range; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const l = (max + min) / 2; - let h, s, d; - if (max !== min) { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - h = max === r - ? ((g - b) / d) + (g < b ? 6 : 0) - : max === g - ? (b - r) / d + 2 - : (r - g) / d + 4; - h = h * 60 + 0.5; - } - return [h | 0, s || 0, l]; -} -function calln(f, a, b, c) { - return ( - Array.isArray(a) - ? f(a[0], a[1], a[2]) - : f(a, b, c) - ).map(n2b); -} -function hsl2rgb(h, s, l) { - return calln(hsl2rgbn, h, s, l); -} -function hwb2rgb(h, w, b) { - return calln(hwb2rgbn, h, w, b); -} -function hsv2rgb(h, s, v) { - return calln(hsv2rgbn, h, s, v); -} -function hue(h) { - return (h % 360 + 360) % 360; -} -function hueParse(str) { - const m = HUE_RE.exec(str); - let a = 255; - let v; - if (!m) { - return; - } - if (m[5] !== v) { - a = m[6] ? p2b(+m[5]) : n2b(+m[5]); - } - const h = hue(+m[2]); - const p1 = +m[3] / 100; - const p2 = +m[4] / 100; - if (m[1] === 'hwb') { - v = hwb2rgb(h, p1, p2); - } else if (m[1] === 'hsv') { - v = hsv2rgb(h, p1, p2); - } else { - v = hsl2rgb(h, p1, p2); - } - return { - r: v[0], - g: v[1], - b: v[2], - a: a - }; -} -function rotate(v, deg) { - var h = rgb2hsl(v); - h[0] = hue(h[0] + deg); - h = hsl2rgb(h); - v.r = h[0]; - v.g = h[1]; - v.b = h[2]; -} -function hslString(v) { - if (!v) { - return; - } - const a = rgb2hsl(v); - const h = a[0]; - const s = n2p(a[1]); - const l = n2p(a[2]); - return v.a < 255 - ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` - : `hsl(${h}, ${s}%, ${l}%)`; -} -const map$1 = { - x: 'dark', - Z: 'light', - Y: 're', - X: 'blu', - W: 'gr', - V: 'medium', - U: 'slate', - A: 'ee', - T: 'ol', - S: 'or', - B: 'ra', - C: 'lateg', - D: 'ights', - R: 'in', - Q: 'turquois', - E: 'hi', - P: 'ro', - O: 'al', - N: 'le', - M: 'de', - L: 'yello', - F: 'en', - K: 'ch', - G: 'arks', - H: 'ea', - I: 'ightg', - J: 'wh' -}; -const names = { - OiceXe: 'f0f8ff', - antiquewEte: 'faebd7', - aqua: 'ffff', - aquamarRe: '7fffd4', - azuY: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '0', - blanKedOmond: 'ffebcd', - Xe: 'ff', - XeviTet: '8a2be2', - bPwn: 'a52a2a', - burlywood: 'deb887', - caMtXe: '5f9ea0', - KartYuse: '7fff00', - KocTate: 'd2691e', - cSO: 'ff7f50', - cSnflowerXe: '6495ed', - cSnsilk: 'fff8dc', - crimson: 'dc143c', - cyan: 'ffff', - xXe: '8b', - xcyan: '8b8b', - xgTMnPd: 'b8860b', - xWay: 'a9a9a9', - xgYF: '6400', - xgYy: 'a9a9a9', - xkhaki: 'bdb76b', - xmagFta: '8b008b', - xTivegYF: '556b2f', - xSange: 'ff8c00', - xScEd: '9932cc', - xYd: '8b0000', - xsOmon: 'e9967a', - xsHgYF: '8fbc8f', - xUXe: '483d8b', - xUWay: '2f4f4f', - xUgYy: '2f4f4f', - xQe: 'ced1', - xviTet: '9400d3', - dAppRk: 'ff1493', - dApskyXe: 'bfff', - dimWay: '696969', - dimgYy: '696969', - dodgerXe: '1e90ff', - fiYbrick: 'b22222', - flSOwEte: 'fffaf0', - foYstWAn: '228b22', - fuKsia: 'ff00ff', - gaRsbSo: 'dcdcdc', - ghostwEte: 'f8f8ff', - gTd: 'ffd700', - gTMnPd: 'daa520', - Way: '808080', - gYF: '8000', - gYFLw: 'adff2f', - gYy: '808080', - honeyMw: 'f0fff0', - hotpRk: 'ff69b4', - RdianYd: 'cd5c5c', - Rdigo: '4b0082', - ivSy: 'fffff0', - khaki: 'f0e68c', - lavFMr: 'e6e6fa', - lavFMrXsh: 'fff0f5', - lawngYF: '7cfc00', - NmoncEffon: 'fffacd', - ZXe: 'add8e6', - ZcSO: 'f08080', - Zcyan: 'e0ffff', - ZgTMnPdLw: 'fafad2', - ZWay: 'd3d3d3', - ZgYF: '90ee90', - ZgYy: 'd3d3d3', - ZpRk: 'ffb6c1', - ZsOmon: 'ffa07a', - ZsHgYF: '20b2aa', - ZskyXe: '87cefa', - ZUWay: '778899', - ZUgYy: '778899', - ZstAlXe: 'b0c4de', - ZLw: 'ffffe0', - lime: 'ff00', - limegYF: '32cd32', - lRF: 'faf0e6', - magFta: 'ff00ff', - maPon: '800000', - VaquamarRe: '66cdaa', - VXe: 'cd', - VScEd: 'ba55d3', - VpurpN: '9370db', - VsHgYF: '3cb371', - VUXe: '7b68ee', - VsprRggYF: 'fa9a', - VQe: '48d1cc', - VviTetYd: 'c71585', - midnightXe: '191970', - mRtcYam: 'f5fffa', - mistyPse: 'ffe4e1', - moccasR: 'ffe4b5', - navajowEte: 'ffdead', - navy: '80', - Tdlace: 'fdf5e6', - Tive: '808000', - TivedBb: '6b8e23', - Sange: 'ffa500', - SangeYd: 'ff4500', - ScEd: 'da70d6', - pOegTMnPd: 'eee8aa', - pOegYF: '98fb98', - pOeQe: 'afeeee', - pOeviTetYd: 'db7093', - papayawEp: 'ffefd5', - pHKpuff: 'ffdab9', - peru: 'cd853f', - pRk: 'ffc0cb', - plum: 'dda0dd', - powMrXe: 'b0e0e6', - purpN: '800080', - YbeccapurpN: '663399', - Yd: 'ff0000', - Psybrown: 'bc8f8f', - PyOXe: '4169e1', - saddNbPwn: '8b4513', - sOmon: 'fa8072', - sandybPwn: 'f4a460', - sHgYF: '2e8b57', - sHshell: 'fff5ee', - siFna: 'a0522d', - silver: 'c0c0c0', - skyXe: '87ceeb', - UXe: '6a5acd', - UWay: '708090', - UgYy: '708090', - snow: 'fffafa', - sprRggYF: 'ff7f', - stAlXe: '4682b4', - tan: 'd2b48c', - teO: '8080', - tEstN: 'd8bfd8', - tomato: 'ff6347', - Qe: '40e0d0', - viTet: 'ee82ee', - JHt: 'f5deb3', - wEte: 'ffffff', - wEtesmoke: 'f5f5f5', - Lw: 'ffff00', - LwgYF: '9acd32' -}; -function unpack() { - const unpacked = {}; - const keys = Object.keys(names); - const tkeys = Object.keys(map$1); - let i, j, k, ok, nk; - for (i = 0; i < keys.length; i++) { - ok = nk = keys[i]; - for (j = 0; j < tkeys.length; j++) { - k = tkeys[j]; - nk = nk.replace(k, map$1[k]); - } - k = parseInt(names[ok], 16); - unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; - } - return unpacked; -} -let names$1; -function nameParse(str) { - if (!names$1) { - names$1 = unpack(); - names$1.transparent = [0, 0, 0, 0]; - } - const a = names$1[str.toLowerCase()]; - return a && { - r: a[0], - g: a[1], - b: a[2], - a: a.length === 4 ? a[3] : 255 - }; -} -function modHSL(v, i, ratio) { - if (v) { - let tmp = rgb2hsl(v); - tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); - tmp = hsl2rgb(tmp); - v.r = tmp[0]; - v.g = tmp[1]; - v.b = tmp[2]; - } -} -function clone(v, proto) { - return v ? Object.assign(proto || {}, v) : v; -} -function fromObject(input) { - var v = {r: 0, g: 0, b: 0, a: 255}; - if (Array.isArray(input)) { - if (input.length >= 3) { - v = {r: input[0], g: input[1], b: input[2], a: 255}; - if (input.length > 3) { - v.a = n2b(input[3]); - } - } - } else { - v = clone(input, {r: 0, g: 0, b: 0, a: 1}); - v.a = n2b(v.a); - } - return v; -} -function functionParse(str) { - if (str.charAt(0) === 'r') { - return rgbParse(str); - } - return hueParse(str); -} -class Color { - constructor(input) { - if (input instanceof Color) { - return input; - } - const type = typeof input; - let v; - if (type === 'object') { - v = fromObject(input); - } else if (type === 'string') { - v = hexParse(input) || nameParse(input) || functionParse(input); - } - this._rgb = v; - this._valid = !!v; - } - get valid() { - return this._valid; - } - get rgb() { - var v = clone(this._rgb); - if (v) { - v.a = b2n(v.a); - } - return v; - } - set rgb(obj) { - this._rgb = fromObject(obj); - } - rgbString() { - return this._valid ? rgbString(this._rgb) : this._rgb; - } - hexString() { - return this._valid ? hexString(this._rgb) : this._rgb; - } - hslString() { - return this._valid ? hslString(this._rgb) : this._rgb; - } - mix(color, weight) { - const me = this; - if (color) { - const c1 = me.rgb; - const c2 = color.rgb; - let w2; - const p = weight === w2 ? 0.5 : weight; - const w = 2 * p - 1; - const a = c1.a - c2.a; - const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - w2 = 1 - w1; - c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; - c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; - c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; - c1.a = p * c1.a + (1 - p) * c2.a; - me.rgb = c1; - } - return me; - } - clone() { - return new Color(this.rgb); - } - alpha(a) { - this._rgb.a = n2b(a); - return this; - } - clearer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 - ratio; - return this; - } - greyscale() { - const rgb = this._rgb; - const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); - rgb.r = rgb.g = rgb.b = val; - return this; - } - opaquer(ratio) { - const rgb = this._rgb; - rgb.a *= 1 + ratio; - return this; - } - negate() { - const v = this._rgb; - v.r = 255 - v.r; - v.g = 255 - v.g; - v.b = 255 - v.b; - return this; - } - lighten(ratio) { - modHSL(this._rgb, 2, ratio); - return this; - } - darken(ratio) { - modHSL(this._rgb, 2, -ratio); - return this; - } - saturate(ratio) { - modHSL(this._rgb, 1, ratio); - return this; - } - desaturate(ratio) { - modHSL(this._rgb, 1, -ratio); - return this; - } - rotate(deg) { - rotate(this._rgb, deg); - return this; - } -} -function index_esm(input) { - return new Color(input); -} - -const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern; -function color(value) { - return isPatternOrGradient(value) ? value : index_esm(value); -} -function getHoverColor(value) { - return isPatternOrGradient(value) - ? value - : index_esm(value).saturate(0.5).darken(0.1).hexString(); -} - -const overrides = Object.create(null); -const descriptors = Object.create(null); -function getScope$1(node, key) { - if (!key) { - return node; - } - const keys = key.split('.'); - for (let i = 0, n = keys.length; i < n; ++i) { - const k = keys[i]; - node = node[k] || (node[k] = Object.create(null)); - } - return node; -} -function set(root, scope, values) { - if (typeof scope === 'string') { - return merge(getScope$1(root, scope), values); - } - return merge(getScope$1(root, ''), scope); -} -class Defaults { - constructor(_descriptors) { - this.animation = undefined; - this.backgroundColor = 'rgba(0,0,0,0.1)'; - this.borderColor = 'rgba(0,0,0,0.1)'; - this.color = '#666'; - this.datasets = {}; - this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio(); - this.elements = {}; - this.events = [ - 'mousemove', - 'mouseout', - 'click', - 'touchstart', - 'touchmove' - ]; - this.font = { - family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - size: 12, - style: 'normal', - lineHeight: 1.2, - weight: null - }; - this.hover = {}; - this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor); - this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor); - this.hoverColor = (ctx, options) => getHoverColor(options.color); - this.indexAxis = 'x'; - this.interaction = { - mode: 'nearest', - intersect: true - }; - this.maintainAspectRatio = true; - this.onHover = null; - this.onClick = null; - this.parsing = true; - this.plugins = {}; - this.responsive = true; - this.scale = undefined; - this.scales = {}; - this.showLine = true; - this.drawActiveElementsOnTop = true; - this.describe(_descriptors); - } - set(scope, values) { - return set(this, scope, values); - } - get(scope) { - return getScope$1(this, scope); - } - describe(scope, values) { - return set(descriptors, scope, values); - } - override(scope, values) { - return set(overrides, scope, values); - } - route(scope, name, targetScope, targetName) { - const scopeObject = getScope$1(this, scope); - const targetScopeObject = getScope$1(this, targetScope); - const privateName = '_' + name; - Object.defineProperties(scopeObject, { - [privateName]: { - value: scopeObject[name], - writable: true - }, - [name]: { - enumerable: true, - get() { - const local = this[privateName]; - const target = targetScopeObject[targetName]; - if (isObject(local)) { - return Object.assign({}, target, local); - } - return valueOrDefault(local, target); - }, - set(value) { - this[privateName] = value; - } - } - }); - } -} -var defaults = new Defaults({ - _scriptable: (name) => !name.startsWith('on'), - _indexable: (name) => name !== 'events', - hover: { - _fallback: 'interaction' - }, - interaction: { - _scriptable: false, - _indexable: false, - } -}); - -function toFontString(font) { - if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { - return null; - } - return (font.style ? font.style + ' ' : '') - + (font.weight ? font.weight + ' ' : '') - + font.size + 'px ' - + font.family; -} -function _measureText(ctx, data, gc, longest, string) { - let textWidth = data[string]; - if (!textWidth) { - textWidth = data[string] = ctx.measureText(string).width; - gc.push(string); - } - if (textWidth > longest) { - longest = textWidth; - } - return longest; -} -function _longestText(ctx, font, arrayOfThings, cache) { - cache = cache || {}; - let data = cache.data = cache.data || {}; - let gc = cache.garbageCollect = cache.garbageCollect || []; - if (cache.font !== font) { - data = cache.data = {}; - gc = cache.garbageCollect = []; - cache.font = font; - } - ctx.save(); - ctx.font = font; - let longest = 0; - const ilen = arrayOfThings.length; - let i, j, jlen, thing, nestedThing; - for (i = 0; i < ilen; i++) { - thing = arrayOfThings[i]; - if (thing !== undefined && thing !== null && isArray(thing) !== true) { - longest = _measureText(ctx, data, gc, longest, thing); - } else if (isArray(thing)) { - for (j = 0, jlen = thing.length; j < jlen; j++) { - nestedThing = thing[j]; - if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { - longest = _measureText(ctx, data, gc, longest, nestedThing); - } - } - } - } - ctx.restore(); - const gcLen = gc.length / 2; - if (gcLen > arrayOfThings.length) { - for (i = 0; i < gcLen; i++) { - delete data[gc[i]]; - } - gc.splice(0, gcLen); - } - return longest; -} -function _alignPixel(chart, pixel, width) { - const devicePixelRatio = chart.currentDevicePixelRatio; - const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; - return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; -} -function clearCanvas(canvas, ctx) { - ctx = ctx || canvas.getContext('2d'); - ctx.save(); - ctx.resetTransform(); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.restore(); -} -function drawPoint(ctx, options, x, y) { - let type, xOffset, yOffset, size, cornerRadius; - const style = options.pointStyle; - const rotation = options.rotation; - const radius = options.radius; - let rad = (rotation || 0) * RAD_PER_DEG; - if (style && typeof style === 'object') { - type = style.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.save(); - ctx.translate(x, y); - ctx.rotate(rad); - ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); - ctx.restore(); - return; - } - } - if (isNaN(radius) || radius <= 0) { - return; - } - ctx.beginPath(); - switch (style) { - default: - ctx.arc(x, y, radius, 0, TAU); - ctx.closePath(); - break; - case 'triangle': - ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - ctx.closePath(); - break; - case 'rectRounded': - cornerRadius = radius * 0.516; - size = radius - cornerRadius; - xOffset = Math.cos(rad + QUARTER_PI) * size; - yOffset = Math.sin(rad + QUARTER_PI) * size; - ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); - ctx.closePath(); - break; - case 'rect': - if (!rotation) { - size = Math.SQRT1_2 * radius; - ctx.rect(x - size, y - size, 2 * size, 2 * size); - break; - } - rad += QUARTER_PI; - case 'rectRot': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + yOffset, y - xOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.lineTo(x - yOffset, y + xOffset); - ctx.closePath(); - break; - case 'crossRot': - rad += QUARTER_PI; - case 'cross': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'star': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - rad += QUARTER_PI; - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'line': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - break; - case 'dash': - ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); - break; - } - ctx.fill(); - if (options.borderWidth > 0) { - ctx.stroke(); - } -} -function _isPointInArea(point, area, margin) { - margin = margin || 0.5; - return !area || (point && point.x > area.left - margin && point.x < area.right + margin && - point.y > area.top - margin && point.y < area.bottom + margin); -} -function clipArea(ctx, area) { - ctx.save(); - ctx.beginPath(); - ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); - ctx.clip(); -} -function unclipArea(ctx) { - ctx.restore(); -} -function _steppedLineTo(ctx, previous, target, flip, mode) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - if (mode === 'middle') { - const midpoint = (previous.x + target.x) / 2.0; - ctx.lineTo(midpoint, previous.y); - ctx.lineTo(midpoint, target.y); - } else if (mode === 'after' !== !!flip) { - ctx.lineTo(previous.x, target.y); - } else { - ctx.lineTo(target.x, previous.y); - } - ctx.lineTo(target.x, target.y); -} -function _bezierCurveTo(ctx, previous, target, flip) { - if (!previous) { - return ctx.lineTo(target.x, target.y); - } - ctx.bezierCurveTo( - flip ? previous.cp1x : previous.cp2x, - flip ? previous.cp1y : previous.cp2y, - flip ? target.cp2x : target.cp1x, - flip ? target.cp2y : target.cp1y, - target.x, - target.y); -} -function renderText(ctx, text, x, y, font, opts = {}) { - const lines = isArray(text) ? text : [text]; - const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; - let i, line; - ctx.save(); - ctx.font = font.string; - setRenderOpts(ctx, opts); - for (i = 0; i < lines.length; ++i) { - line = lines[i]; - if (stroke) { - if (opts.strokeColor) { - ctx.strokeStyle = opts.strokeColor; - } - if (!isNullOrUndef(opts.strokeWidth)) { - ctx.lineWidth = opts.strokeWidth; - } - ctx.strokeText(line, x, y, opts.maxWidth); - } - ctx.fillText(line, x, y, opts.maxWidth); - decorateText(ctx, x, y, line, opts); - y += font.lineHeight; - } - ctx.restore(); -} -function setRenderOpts(ctx, opts) { - if (opts.translation) { - ctx.translate(opts.translation[0], opts.translation[1]); - } - if (!isNullOrUndef(opts.rotation)) { - ctx.rotate(opts.rotation); - } - if (opts.color) { - ctx.fillStyle = opts.color; - } - if (opts.textAlign) { - ctx.textAlign = opts.textAlign; - } - if (opts.textBaseline) { - ctx.textBaseline = opts.textBaseline; - } -} -function decorateText(ctx, x, y, line, opts) { - if (opts.strikethrough || opts.underline) { - const metrics = ctx.measureText(line); - const left = x - metrics.actualBoundingBoxLeft; - const right = x + metrics.actualBoundingBoxRight; - const top = y - metrics.actualBoundingBoxAscent; - const bottom = y + metrics.actualBoundingBoxDescent; - const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; - ctx.strokeStyle = ctx.fillStyle; - ctx.beginPath(); - ctx.lineWidth = opts.decorationWidth || 2; - ctx.moveTo(left, yDecoration); - ctx.lineTo(right, yDecoration); - ctx.stroke(); - } -} -function addRoundedRectPath(ctx, rect) { - const {x, y, w, h, radius} = rect; - ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true); - ctx.lineTo(x, y + h - radius.bottomLeft); - ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); - ctx.lineTo(x + w - radius.bottomRight, y + h); - ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); - ctx.lineTo(x + w, y + radius.topRight); - ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); - ctx.lineTo(x + radius.topLeft, y); -} - -const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); -const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/); -function toLineHeight(value, size) { - const matches = ('' + value).match(LINE_HEIGHT); - if (!matches || matches[1] === 'normal') { - return size * 1.2; - } - value = +matches[2]; - switch (matches[3]) { - case 'px': - return value; - case '%': - value /= 100; - break; - } - return size * value; -} -const numberOrZero = v => +v || 0; -function _readValueToProps(value, props) { - const ret = {}; - const objProps = isObject(props); - const keys = objProps ? Object.keys(props) : props; - const read = isObject(value) - ? objProps - ? prop => valueOrDefault(value[prop], value[props[prop]]) - : prop => value[prop] - : () => value; - for (const prop of keys) { - ret[prop] = numberOrZero(read(prop)); - } - return ret; -} -function toTRBL(value) { - return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'}); -} -function toTRBLCorners(value) { - return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']); -} -function toPadding(value) { - const obj = toTRBL(value); - obj.width = obj.left + obj.right; - obj.height = obj.top + obj.bottom; - return obj; -} -function toFont(options, fallback) { - options = options || {}; - fallback = fallback || defaults.font; - let size = valueOrDefault(options.size, fallback.size); - if (typeof size === 'string') { - size = parseInt(size, 10); - } - let style = valueOrDefault(options.style, fallback.style); - if (style && !('' + style).match(FONT_STYLE)) { - console.warn('Invalid font style specified: "' + style + '"'); - style = ''; - } - const font = { - family: valueOrDefault(options.family, fallback.family), - lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), - size, - style, - weight: valueOrDefault(options.weight, fallback.weight), - string: '' - }; - font.string = toFontString(font); - return font; -} -function resolve(inputs, context, index, info) { - let cacheable = true; - let i, ilen, value; - for (i = 0, ilen = inputs.length; i < ilen; ++i) { - value = inputs[i]; - if (value === undefined) { - continue; - } - if (context !== undefined && typeof value === 'function') { - value = value(context); - cacheable = false; - } - if (index !== undefined && isArray(value)) { - value = value[index % value.length]; - cacheable = false; - } - if (value !== undefined) { - if (info && !cacheable) { - info.cacheable = false; - } - return value; - } - } -} -function _addGrace(minmax, grace, beginAtZero) { - const {min, max} = minmax; - const change = toDimension(grace, (max - min) / 2); - const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; - return { - min: keepZero(min, -Math.abs(change)), - max: keepZero(max, change) - }; -} -function createContext(parentContext, context) { - return Object.assign(Object.create(parentContext), context); -} - -function _lookup(table, value, cmp) { - cmp = cmp || ((index) => table[index] < value); - let hi = table.length - 1; - let lo = 0; - let mid; - while (hi - lo > 1) { - mid = (lo + hi) >> 1; - if (cmp(mid)) { - lo = mid; - } else { - hi = mid; - } - } - return {lo, hi}; -} -const _lookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] < value); -const _rlookupByKey = (table, key, value) => - _lookup(table, value, index => table[index][key] >= value); -function _filterBetween(values, min, max) { - let start = 0; - let end = values.length; - while (start < end && values[start] < min) { - start++; - } - while (end > start && values[end - 1] > max) { - end--; - } - return start > 0 || end < values.length - ? values.slice(start, end) - : values; -} -const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; -function listenArrayEvents(array, listener) { - if (array._chartjs) { - array._chartjs.listeners.push(listener); - return; - } - Object.defineProperty(array, '_chartjs', { - configurable: true, - enumerable: false, - value: { - listeners: [listener] - } - }); - arrayEvents.forEach((key) => { - const method = '_onData' + _capitalize(key); - const base = array[key]; - Object.defineProperty(array, key, { - configurable: true, - enumerable: false, - value(...args) { - const res = base.apply(this, args); - array._chartjs.listeners.forEach((object) => { - if (typeof object[method] === 'function') { - object[method](...args); - } - }); - return res; - } - }); - }); -} -function unlistenArrayEvents(array, listener) { - const stub = array._chartjs; - if (!stub) { - return; - } - const listeners = stub.listeners; - const index = listeners.indexOf(listener); - if (index !== -1) { - listeners.splice(index, 1); - } - if (listeners.length > 0) { - return; - } - arrayEvents.forEach((key) => { - delete array[key]; - }); - delete array._chartjs; -} -function _arrayUnique(items) { - const set = new Set(); - let i, ilen; - for (i = 0, ilen = items.length; i < ilen; ++i) { - set.add(items[i]); - } - if (set.size === ilen) { - return items; - } - return Array.from(set); -} - -function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) { - if (!defined(fallback)) { - fallback = _resolve('_fallback', scopes); - } - const cache = { - [Symbol.toStringTag]: 'Object', - _cacheable: true, - _scopes: scopes, - _rootScopes: rootScopes, - _fallback: fallback, - _getTarget: getTarget, - override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback), - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete target._keys; - delete scopes[0][prop]; - return true; - }, - get(target, prop) { - return _cached(target, prop, - () => _resolveWithPrefixes(prop, prefixes, scopes, target)); - }, - getOwnPropertyDescriptor(target, prop) { - return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(scopes[0]); - }, - has(target, prop) { - return getKeysFromAllScopes(target).includes(prop); - }, - ownKeys(target) { - return getKeysFromAllScopes(target); - }, - set(target, prop, value) { - const storage = target._storage || (target._storage = getTarget()); - target[prop] = storage[prop] = value; - delete target._keys; - return true; - } - }); -} -function _attachContext(proxy, context, subProxy, descriptorDefaults) { - const cache = { - _cacheable: false, - _proxy: proxy, - _context: context, - _subProxy: subProxy, - _stack: new Set(), - _descriptors: _descriptors(proxy, descriptorDefaults), - setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults), - override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) - }; - return new Proxy(cache, { - deleteProperty(target, prop) { - delete target[prop]; - delete proxy[prop]; - return true; - }, - get(target, prop, receiver) { - return _cached(target, prop, - () => _resolveWithContext(target, prop, receiver)); - }, - getOwnPropertyDescriptor(target, prop) { - return target._descriptors.allKeys - ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined - : Reflect.getOwnPropertyDescriptor(proxy, prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(proxy); - }, - has(target, prop) { - return Reflect.has(proxy, prop); - }, - ownKeys() { - return Reflect.ownKeys(proxy); - }, - set(target, prop, value) { - proxy[prop] = value; - delete target[prop]; - return true; - } - }); -} -function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) { - const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy; - return { - allKeys: _allKeys, - scriptable: _scriptable, - indexable: _indexable, - isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable, - isIndexable: isFunction(_indexable) ? _indexable : () => _indexable - }; -} -const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name; -const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' && - (Object.getPrototypeOf(value) === null || value.constructor === Object); -function _cached(target, prop, resolve) { - if (Object.prototype.hasOwnProperty.call(target, prop)) { - return target[prop]; - } - const value = resolve(); - target[prop] = value; - return value; -} -function _resolveWithContext(target, prop, receiver) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - let value = _proxy[prop]; - if (isFunction(value) && descriptors.isScriptable(prop)) { - value = _resolveScriptable(prop, value, target, receiver); - } - if (isArray(value) && value.length) { - value = _resolveArray(prop, value, target, descriptors.isIndexable); - } - if (needsSubResolver(prop, value)) { - value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); - } - return value; -} -function _resolveScriptable(prop, value, target, receiver) { - const {_proxy, _context, _subProxy, _stack} = target; - if (_stack.has(prop)) { - throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); - } - _stack.add(prop); - value = value(_context, _subProxy || receiver); - _stack.delete(prop); - if (needsSubResolver(prop, value)) { - value = createSubResolver(_proxy._scopes, _proxy, prop, value); - } - return value; -} -function _resolveArray(prop, value, target, isIndexable) { - const {_proxy, _context, _subProxy, _descriptors: descriptors} = target; - if (defined(_context.index) && isIndexable(prop)) { - value = value[_context.index % value.length]; - } else if (isObject(value[0])) { - const arr = value; - const scopes = _proxy._scopes.filter(s => s !== arr); - value = []; - for (const item of arr) { - const resolver = createSubResolver(scopes, _proxy, prop, item); - value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); - } - } - return value; -} -function resolveFallback(fallback, prop, value) { - return isFunction(fallback) ? fallback(prop, value) : fallback; -} -const getScope = (key, parent) => key === true ? parent - : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; -function addScopes(set, parentScopes, key, parentFallback, value) { - for (const parent of parentScopes) { - const scope = getScope(key, parent); - if (scope) { - set.add(scope); - const fallback = resolveFallback(scope._fallback, key, value); - if (defined(fallback) && fallback !== key && fallback !== parentFallback) { - return fallback; - } - } else if (scope === false && defined(parentFallback) && key !== parentFallback) { - return null; - } - } - return false; -} -function createSubResolver(parentScopes, resolver, prop, value) { - const rootScopes = resolver._rootScopes; - const fallback = resolveFallback(resolver._fallback, prop, value); - const allScopes = [...parentScopes, ...rootScopes]; - const set = new Set(); - set.add(value); - let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); - if (key === null) { - return false; - } - if (defined(fallback) && fallback !== prop) { - key = addScopesFromKey(set, allScopes, fallback, key, value); - if (key === null) { - return false; - } - } - return _createResolver(Array.from(set), [''], rootScopes, fallback, - () => subGetTarget(resolver, prop, value)); -} -function addScopesFromKey(set, allScopes, key, fallback, item) { - while (key) { - key = addScopes(set, allScopes, key, fallback, item); - } - return key; -} -function subGetTarget(resolver, prop, value) { - const parent = resolver._getTarget(); - if (!(prop in parent)) { - parent[prop] = {}; - } - const target = parent[prop]; - if (isArray(target) && isObject(value)) { - return value; - } - return target; -} -function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { - let value; - for (const prefix of prefixes) { - value = _resolve(readKey(prefix, prop), scopes); - if (defined(value)) { - return needsSubResolver(prop, value) - ? createSubResolver(scopes, proxy, prop, value) - : value; - } - } -} -function _resolve(key, scopes) { - for (const scope of scopes) { - if (!scope) { - continue; - } - const value = scope[key]; - if (defined(value)) { - return value; - } - } -} -function getKeysFromAllScopes(target) { - let keys = target._keys; - if (!keys) { - keys = target._keys = resolveKeysFromAllScopes(target._scopes); - } - return keys; -} -function resolveKeysFromAllScopes(scopes) { - const set = new Set(); - for (const scope of scopes) { - for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) { - set.add(key); - } - } - return Array.from(set); -} - -const EPSILON = Number.EPSILON || 1e-14; -const getPoint = (points, i) => i < points.length && !points[i].skip && points[i]; -const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x'; -function splineCurve(firstPoint, middlePoint, afterPoint, t) { - const previous = firstPoint.skip ? middlePoint : firstPoint; - const current = middlePoint; - const next = afterPoint.skip ? middlePoint : afterPoint; - const d01 = distanceBetweenPoints(current, previous); - const d12 = distanceBetweenPoints(next, current); - let s01 = d01 / (d01 + d12); - let s12 = d12 / (d01 + d12); - s01 = isNaN(s01) ? 0 : s01; - s12 = isNaN(s12) ? 0 : s12; - const fa = t * s01; - const fb = t * s12; - return { - previous: { - x: current.x - fa * (next.x - previous.x), - y: current.y - fa * (next.y - previous.y) - }, - next: { - x: current.x + fb * (next.x - previous.x), - y: current.y + fb * (next.y - previous.y) - } - }; -} -function monotoneAdjust(points, deltaK, mK) { - const pointsLen = points.length; - let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen - 1; ++i) { - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent || !pointAfter) { - continue; - } - if (almostEquals(deltaK[i], 0, EPSILON)) { - mK[i] = mK[i + 1] = 0; - continue; - } - alphaK = mK[i] / deltaK[i]; - betaK = mK[i + 1] / deltaK[i]; - squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); - if (squaredMagnitude <= 9) { - continue; - } - tauK = 3 / Math.sqrt(squaredMagnitude); - mK[i] = alphaK * tauK * deltaK[i]; - mK[i + 1] = betaK * tauK * deltaK[i]; - } -} -function monotoneCompute(points, mK, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - let delta, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (let i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - const iPixel = pointCurrent[indexAxis]; - const vPixel = pointCurrent[valueAxis]; - if (pointBefore) { - delta = (iPixel - pointBefore[indexAxis]) / 3; - pointCurrent[`cp1${indexAxis}`] = iPixel - delta; - pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; - } - if (pointAfter) { - delta = (pointAfter[indexAxis] - iPixel) / 3; - pointCurrent[`cp2${indexAxis}`] = iPixel + delta; - pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; - } - } -} -function splineCurveMonotone(points, indexAxis = 'x') { - const valueAxis = getValueAxis(indexAxis); - const pointsLen = points.length; - const deltaK = Array(pointsLen).fill(0); - const mK = Array(pointsLen); - let i, pointBefore, pointCurrent; - let pointAfter = getPoint(points, 0); - for (i = 0; i < pointsLen; ++i) { - pointBefore = pointCurrent; - pointCurrent = pointAfter; - pointAfter = getPoint(points, i + 1); - if (!pointCurrent) { - continue; - } - if (pointAfter) { - const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; - deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; - } - mK[i] = !pointBefore ? deltaK[i] - : !pointAfter ? deltaK[i - 1] - : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0 - : (deltaK[i - 1] + deltaK[i]) / 2; - } - monotoneAdjust(points, deltaK, mK); - monotoneCompute(points, mK, indexAxis); -} -function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); -} -function capBezierPoints(points, area) { - let i, ilen, point, inArea, inAreaPrev; - let inAreaNext = _isPointInArea(points[0], area); - for (i = 0, ilen = points.length; i < ilen; ++i) { - inAreaPrev = inArea; - inArea = inAreaNext; - inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); - if (!inArea) { - continue; - } - point = points[i]; - if (inAreaPrev) { - point.cp1x = capControlPoint(point.cp1x, area.left, area.right); - point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); - } - if (inAreaNext) { - point.cp2x = capControlPoint(point.cp2x, area.left, area.right); - point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); - } - } -} -function _updateBezierControlPoints(points, options, area, loop, indexAxis) { - let i, ilen, point, controlPoints; - if (options.spanGaps) { - points = points.filter((pt) => !pt.skip); - } - if (options.cubicInterpolationMode === 'monotone') { - splineCurveMonotone(points, indexAxis); - } else { - let prev = loop ? points[points.length - 1] : points[0]; - for (i = 0, ilen = points.length; i < ilen; ++i) { - point = points[i]; - controlPoints = splineCurve( - prev, - point, - points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], - options.tension - ); - point.cp1x = controlPoints.previous.x; - point.cp1y = controlPoints.previous.y; - point.cp2x = controlPoints.next.x; - point.cp2y = controlPoints.next.y; - prev = point; - } - } - if (options.capBezierPoints) { - capBezierPoints(points, area); - } -} - -function _isDomSupported() { - return typeof window !== 'undefined' && typeof document !== 'undefined'; -} -function _getParentNode(domNode) { - let parent = domNode.parentNode; - if (parent && parent.toString() === '[object ShadowRoot]') { - parent = parent.host; - } - return parent; -} -function parseMaxStyle(styleValue, node, parentProperty) { - let valueInPixels; - if (typeof styleValue === 'string') { - valueInPixels = parseInt(styleValue, 10); - if (styleValue.indexOf('%') !== -1) { - valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; - } - } else { - valueInPixels = styleValue; - } - return valueInPixels; -} -const getComputedStyle = (element) => window.getComputedStyle(element, null); -function getStyle(el, property) { - return getComputedStyle(el).getPropertyValue(property); -} -const positions = ['top', 'right', 'bottom', 'left']; -function getPositionedStyle(styles, style, suffix) { - const result = {}; - suffix = suffix ? '-' + suffix : ''; - for (let i = 0; i < 4; i++) { - const pos = positions[i]; - result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; - } - result.width = result.left + result.right; - result.height = result.top + result.bottom; - return result; -} -const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot); -function getCanvasPosition(evt, canvas) { - const e = evt.native || evt; - const touches = e.touches; - const source = touches && touches.length ? touches[0] : e; - const {offsetX, offsetY} = source; - let box = false; - let x, y; - if (useOffsetPos(offsetX, offsetY, e.target)) { - x = offsetX; - y = offsetY; - } else { - const rect = canvas.getBoundingClientRect(); - x = source.clientX - rect.left; - y = source.clientY - rect.top; - box = true; - } - return {x, y, box}; -} -function getRelativePosition(evt, chart) { - const {canvas, currentDevicePixelRatio} = chart; - const style = getComputedStyle(canvas); - const borderBox = style.boxSizing === 'border-box'; - const paddings = getPositionedStyle(style, 'padding'); - const borders = getPositionedStyle(style, 'border', 'width'); - const {x, y, box} = getCanvasPosition(evt, canvas); - const xOffset = paddings.left + (box && borders.left); - const yOffset = paddings.top + (box && borders.top); - let {width, height} = chart; - if (borderBox) { - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - return { - x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), - y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) - }; -} -function getContainerSize(canvas, width, height) { - let maxWidth, maxHeight; - if (width === undefined || height === undefined) { - const container = _getParentNode(canvas); - if (!container) { - width = canvas.clientWidth; - height = canvas.clientHeight; - } else { - const rect = container.getBoundingClientRect(); - const containerStyle = getComputedStyle(container); - const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); - const containerPadding = getPositionedStyle(containerStyle, 'padding'); - width = rect.width - containerPadding.width - containerBorder.width; - height = rect.height - containerPadding.height - containerBorder.height; - maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); - maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); - } - } - return { - width, - height, - maxWidth: maxWidth || INFINITY, - maxHeight: maxHeight || INFINITY - }; -} -const round1 = v => Math.round(v * 10) / 10; -function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { - const style = getComputedStyle(canvas); - const margins = getPositionedStyle(style, 'margin'); - const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; - const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; - const containerSize = getContainerSize(canvas, bbWidth, bbHeight); - let {width, height} = containerSize; - if (style.boxSizing === 'content-box') { - const borders = getPositionedStyle(style, 'border', 'width'); - const paddings = getPositionedStyle(style, 'padding'); - width -= paddings.width + borders.width; - height -= paddings.height + borders.height; - } - width = Math.max(0, width - margins.width); - height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); - width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); - height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); - if (width && !height) { - height = round1(width / 2); - } - return { - width, - height - }; -} -function retinaScale(chart, forceRatio, forceStyle) { - const pixelRatio = forceRatio || 1; - const deviceHeight = Math.floor(chart.height * pixelRatio); - const deviceWidth = Math.floor(chart.width * pixelRatio); - chart.height = deviceHeight / pixelRatio; - chart.width = deviceWidth / pixelRatio; - const canvas = chart.canvas; - if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) { - canvas.style.height = `${chart.height}px`; - canvas.style.width = `${chart.width}px`; - } - if (chart.currentDevicePixelRatio !== pixelRatio - || canvas.height !== deviceHeight - || canvas.width !== deviceWidth) { - chart.currentDevicePixelRatio = pixelRatio; - canvas.height = deviceHeight; - canvas.width = deviceWidth; - chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - return true; - } - return false; -} -const supportsEventListenerOptions = (function() { - let passiveSupported = false; - try { - const options = { - get passive() { - passiveSupported = true; - return false; - } - }; - window.addEventListener('test', null, options); - window.removeEventListener('test', null, options); - } catch (e) { - } - return passiveSupported; -}()); -function readUsedSize(element, property) { - const value = getStyle(element, property); - const matches = value && value.match(/^(\d+)(\.\d+)?px$/); - return matches ? +matches[1] : undefined; -} - -function _pointInLine(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: p1.y + t * (p2.y - p1.y) - }; -} -function _steppedInterpolation(p1, p2, t, mode) { - return { - x: p1.x + t * (p2.x - p1.x), - y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y - : mode === 'after' ? t < 1 ? p1.y : p2.y - : t > 0 ? p2.y : p1.y - }; -} -function _bezierInterpolation(p1, p2, t, mode) { - const cp1 = {x: p1.cp2x, y: p1.cp2y}; - const cp2 = {x: p2.cp1x, y: p2.cp1y}; - const a = _pointInLine(p1, cp1, t); - const b = _pointInLine(cp1, cp2, t); - const c = _pointInLine(cp2, p2, t); - const d = _pointInLine(a, b, t); - const e = _pointInLine(b, c, t); - return _pointInLine(d, e, t); -} - -const intlCache = new Map(); -function getNumberFormat(locale, options) { - options = options || {}; - const cacheKey = locale + JSON.stringify(options); - let formatter = intlCache.get(cacheKey); - if (!formatter) { - formatter = new Intl.NumberFormat(locale, options); - intlCache.set(cacheKey, formatter); - } - return formatter; -} -function formatNumber(num, locale, options) { - return getNumberFormat(locale, options).format(num); -} - -const getRightToLeftAdapter = function(rectX, width) { - return { - x(x) { - return rectX + rectX + width - x; - }, - setWidth(w) { - width = w; - }, - textAlign(align) { - if (align === 'center') { - return align; - } - return align === 'right' ? 'left' : 'right'; - }, - xPlus(x, value) { - return x - value; - }, - leftForLtr(x, itemWidth) { - return x - itemWidth; - }, - }; -}; -const getLeftToRightAdapter = function() { - return { - x(x) { - return x; - }, - setWidth(w) { - }, - textAlign(align) { - return align; - }, - xPlus(x, value) { - return x + value; - }, - leftForLtr(x, _itemWidth) { - return x; - }, - }; -}; -function getRtlAdapter(rtl, rectX, width) { - return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); -} -function overrideTextDirection(ctx, direction) { - let style, original; - if (direction === 'ltr' || direction === 'rtl') { - style = ctx.canvas.style; - original = [ - style.getPropertyValue('direction'), - style.getPropertyPriority('direction'), - ]; - style.setProperty('direction', direction, 'important'); - ctx.prevTextDirection = original; - } -} -function restoreTextDirection(ctx, original) { - if (original !== undefined) { - delete ctx.prevTextDirection; - ctx.canvas.style.setProperty('direction', original[0], original[1]); - } -} - -function propertyFn(property) { - if (property === 'angle') { - return { - between: _angleBetween, - compare: _angleDiff, - normalize: _normalizeAngle, - }; - } - return { - between: _isBetween, - compare: (a, b) => a - b, - normalize: x => x - }; -} -function normalizeSegment({start, end, count, loop, style}) { - return { - start: start % count, - end: end % count, - loop: loop && (end - start + 1) % count === 0, - style - }; -} -function getSegment(segment, points, bounds) { - const {property, start: startBound, end: endBound} = bounds; - const {between, normalize} = propertyFn(property); - const count = points.length; - let {start, end, loop} = segment; - let i, ilen; - if (loop) { - start += count; - end += count; - for (i = 0, ilen = count; i < ilen; ++i) { - if (!between(normalize(points[start % count][property]), startBound, endBound)) { - break; - } - start--; - end--; - } - start %= count; - end %= count; - } - if (end < start) { - end += count; - } - return {start, end, loop, style: segment.style}; -} -function _boundSegment(segment, points, bounds) { - if (!bounds) { - return [segment]; - } - const {property, start: startBound, end: endBound} = bounds; - const count = points.length; - const {compare, between, normalize} = propertyFn(property); - const {start, end, loop, style} = getSegment(segment, points, bounds); - const result = []; - let inside = false; - let subStart = null; - let value, point, prevValue; - const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; - const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value); - const shouldStart = () => inside || startIsBefore(); - const shouldStop = () => !inside || endIsBefore(); - for (let i = start, prev = start; i <= end; ++i) { - point = points[i % count]; - if (point.skip) { - continue; - } - value = normalize(point[property]); - if (value === prevValue) { - continue; - } - inside = between(value, startBound, endBound); - if (subStart === null && shouldStart()) { - subStart = compare(value, startBound) === 0 ? i : prev; - } - if (subStart !== null && shouldStop()) { - result.push(normalizeSegment({start: subStart, end: i, loop, count, style})); - subStart = null; - } - prev = i; - prevValue = value; - } - if (subStart !== null) { - result.push(normalizeSegment({start: subStart, end, loop, count, style})); - } - return result; -} -function _boundSegments(line, bounds) { - const result = []; - const segments = line.segments; - for (let i = 0; i < segments.length; i++) { - const sub = _boundSegment(segments[i], line.points, bounds); - if (sub.length) { - result.push(...sub); - } - } - return result; -} -function findStartAndEnd(points, count, loop, spanGaps) { - let start = 0; - let end = count - 1; - if (loop && !spanGaps) { - while (start < count && !points[start].skip) { - start++; - } - } - while (start < count && points[start].skip) { - start++; - } - start %= count; - if (loop) { - end += start; - } - while (end > start && points[end % count].skip) { - end--; - } - end %= count; - return {start, end}; -} -function solidSegments(points, start, max, loop) { - const count = points.length; - const result = []; - let last = start; - let prev = points[start]; - let end; - for (end = start + 1; end <= max; ++end) { - const cur = points[end % count]; - if (cur.skip || cur.stop) { - if (!prev.skip) { - loop = false; - result.push({start: start % count, end: (end - 1) % count, loop}); - start = last = cur.stop ? end : null; - } - } else { - last = end; - if (prev.skip) { - start = end; - } - } - prev = cur; - } - if (last !== null) { - result.push({start: start % count, end: last % count, loop}); - } - return result; -} -function _computeSegments(line, segmentOptions) { - const points = line.points; - const spanGaps = line.options.spanGaps; - const count = points.length; - if (!count) { - return []; - } - const loop = !!line._loop; - const {start, end} = findStartAndEnd(points, count, loop, spanGaps); - if (spanGaps === true) { - return splitByStyles(line, [{start, end, loop}], points, segmentOptions); - } - const max = end < start ? end + count : end; - const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; - return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); -} -function splitByStyles(line, segments, points, segmentOptions) { - if (!segmentOptions || !segmentOptions.setContext || !points) { - return segments; - } - return doSplitByStyles(line, segments, points, segmentOptions); -} -function doSplitByStyles(line, segments, points, segmentOptions) { - const chartContext = line._chart.getContext(); - const baseStyle = readStyle(line.options); - const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; - const count = points.length; - const result = []; - let prevStyle = baseStyle; - let start = segments[0].start; - let i = start; - function addStyle(s, e, l, st) { - const dir = spanGaps ? -1 : 1; - if (s === e) { - return; - } - s += count; - while (points[s % count].skip) { - s -= dir; - } - while (points[e % count].skip) { - e += dir; - } - if (s % count !== e % count) { - result.push({start: s % count, end: e % count, loop: l, style: st}); - prevStyle = st; - start = e % count; - } - } - for (const segment of segments) { - start = spanGaps ? start : segment.start; - let prev = points[start % count]; - let style; - for (i = start + 1; i <= segment.end; i++) { - const pt = points[i % count]; - style = readStyle(segmentOptions.setContext(createContext(chartContext, { - type: 'segment', - p0: prev, - p1: pt, - p0DataIndex: (i - 1) % count, - p1DataIndex: i % count, - datasetIndex - }))); - if (styleChanged(style, prevStyle)) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - prev = pt; - prevStyle = style; - } - if (start < i - 1) { - addStyle(start, i - 1, segment.loop, prevStyle); - } - } - return result; -} -function readStyle(options) { - return { - backgroundColor: options.backgroundColor, - borderCapStyle: options.borderCapStyle, - borderDash: options.borderDash, - borderDashOffset: options.borderDashOffset, - borderJoinStyle: options.borderJoinStyle, - borderWidth: options.borderWidth, - borderColor: options.borderColor - }; -} -function styleChanged(style, prevStyle) { - return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle); -} - -export { _toLeftRightCenter as $, _rlookupByKey as A, getAngleFromPoint as B, toPadding as C, each as D, getMaximumSize as E, _getParentNode as F, readUsedSize as G, HALF_PI as H, throttled as I, supportsEventListenerOptions as J, _isDomSupported as K, log10 as L, _factorize as M, finiteOrDefault as N, callback as O, PI as P, _addGrace as Q, toDegrees as R, _measureText as S, TAU as T, _int16Range as U, _alignPixel as V, clipArea as W, renderText as X, unclipArea as Y, toFont as Z, _arrayUnique as _, resolve as a, _angleDiff as a$, _alignStartEnd as a0, overrides as a1, merge as a2, _capitalize as a3, descriptors as a4, isFunction as a5, _attachContext as a6, _createResolver as a7, _descriptors as a8, mergeIf as a9, restoreTextDirection as aA, noop as aB, distanceBetweenPoints as aC, _setMinAndMaxByKey as aD, niceNum as aE, almostWhole as aF, almostEquals as aG, _decimalPlaces as aH, _longestText as aI, _filterBetween as aJ, _lookup as aK, getHoverColor as aL, clone$1 as aM, _merger as aN, _mergerIf as aO, _deprecated as aP, toFontString as aQ, splineCurve as aR, splineCurveMonotone as aS, getStyle as aT, fontString as aU, toLineHeight as aV, PITAU as aW, INFINITY as aX, RAD_PER_DEG as aY, QUARTER_PI as aZ, TWO_THIRDS_PI as a_, uid as aa, debounce as ab, retinaScale as ac, clearCanvas as ad, setsEqual as ae, _elementsEqual as af, _isClickEvent as ag, _isBetween as ah, _readValueToProps as ai, _updateBezierControlPoints as aj, _computeSegments as ak, _boundSegments as al, _steppedInterpolation as am, _bezierInterpolation as an, _pointInLine as ao, _steppedLineTo as ap, _bezierCurveTo as aq, drawPoint as ar, addRoundedRectPath as as, toTRBL as at, toTRBLCorners as au, _boundSegment as av, _normalizeAngle as aw, getRtlAdapter as ax, overrideTextDirection as ay, _textX as az, isArray as b, color as c, defaults as d, effects as e, resolveObjectKey as f, isNumberFinite as g, createContext as h, isObject as i, defined as j, isNullOrUndef as k, listenArrayEvents as l, toPercentage as m, toDimension as n, formatNumber as o, _angleBetween as p, isNumber as q, requestAnimFrame as r, sign as s, toRadians as t, unlistenArrayEvents as u, valueOrDefault as v, _limitValue as w, _lookupByKey as x, getRelativePosition as y, _isPointInArea as z }; diff --git a/node_modules/chart.js/dist/helpers.esm.js b/node_modules/chart.js/dist/helpers.esm.js deleted file mode 100644 index 399496db..00000000 --- a/node_modules/chart.js/dist/helpers.esm.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Chart.js v3.7.1 - * https://www.chartjs.org - * (c) 2022 Chart.js Contributors - * Released under the MIT License - */ -export { H as HALF_PI, aX as INFINITY, P as PI, aW as PITAU, aZ as QUARTER_PI, aY as RAD_PER_DEG, T as TAU, a_ as TWO_THIRDS_PI, Q as _addGrace, V as _alignPixel, a0 as _alignStartEnd, p as _angleBetween, a$ as _angleDiff, _ as _arrayUnique, a6 as _attachContext, aq as _bezierCurveTo, an as _bezierInterpolation, av as _boundSegment, al as _boundSegments, a3 as _capitalize, ak as _computeSegments, a7 as _createResolver, aH as _decimalPlaces, aP as _deprecated, a8 as _descriptors, af as _elementsEqual, M as _factorize, aJ as _filterBetween, F as _getParentNode, U as _int16Range, ah as _isBetween, ag as _isClickEvent, K as _isDomSupported, z as _isPointInArea, w as _limitValue, aI as _longestText, aK as _lookup, x as _lookupByKey, S as _measureText, aN as _merger, aO as _mergerIf, aw as _normalizeAngle, ao as _pointInLine, ai as _readValueToProps, A as _rlookupByKey, aD as _setMinAndMaxByKey, am as _steppedInterpolation, ap as _steppedLineTo, az as _textX, $ as _toLeftRightCenter, aj as _updateBezierControlPoints, as as addRoundedRectPath, aG as almostEquals, aF as almostWhole, O as callback, ad as clearCanvas, W as clipArea, aM as clone, c as color, h as createContext, ab as debounce, j as defined, aC as distanceBetweenPoints, ar as drawPoint, D as each, e as easingEffects, N as finiteOrDefault, aU as fontString, o as formatNumber, B as getAngleFromPoint, aL as getHoverColor, E as getMaximumSize, y as getRelativePosition, ax as getRtlAdapter, aT as getStyle, b as isArray, g as isFinite, a5 as isFunction, k as isNullOrUndef, q as isNumber, i as isObject, l as listenArrayEvents, L as log10, a2 as merge, a9 as mergeIf, aE as niceNum, aB as noop, ay as overrideTextDirection, G as readUsedSize, X as renderText, r as requestAnimFrame, a as resolve, f as resolveObjectKey, aA as restoreTextDirection, ac as retinaScale, ae as setsEqual, s as sign, aR as splineCurve, aS as splineCurveMonotone, J as supportsEventListenerOptions, I as throttled, R as toDegrees, n as toDimension, Z as toFont, aQ as toFontString, aV as toLineHeight, C as toPadding, m as toPercentage, t as toRadians, at as toTRBL, au as toTRBLCorners, aa as uid, Y as unclipArea, u as unlistenArrayEvents, v as valueOrDefault } from './chunks/helpers.segment.js'; diff --git a/node_modules/chart.js/helpers/helpers.esm.d.ts b/node_modules/chart.js/helpers/helpers.esm.d.ts deleted file mode 100644 index 2c3468e7..00000000 --- a/node_modules/chart.js/helpers/helpers.esm.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../types/helpers'; diff --git a/node_modules/chart.js/helpers/helpers.esm.js b/node_modules/chart.js/helpers/helpers.esm.js deleted file mode 100644 index ca4eee52..00000000 --- a/node_modules/chart.js/helpers/helpers.esm.js +++ /dev/null @@ -1 +0,0 @@ -export * from '../dist/helpers.esm'; diff --git a/node_modules/chart.js/helpers/helpers.js b/node_modules/chart.js/helpers/helpers.js deleted file mode 100644 index a762f589..00000000 --- a/node_modules/chart.js/helpers/helpers.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('..').helpers; diff --git a/node_modules/chart.js/helpers/package.json b/node_modules/chart.js/helpers/package.json deleted file mode 100644 index d97b75cb..00000000 --- a/node_modules/chart.js/helpers/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "chart.js-helpers", - "private": true, - "description": "helper package", - "main": "helpers.js", - "module": "helpers.esm.js", - "types": "helpers.esm.d.ts" -} \ No newline at end of file diff --git a/node_modules/chart.js/package.json b/node_modules/chart.js/package.json deleted file mode 100644 index 24c99596..00000000 --- a/node_modules/chart.js/package.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "name": "chart.js", - "homepage": "https://www.chartjs.org", - "description": "Simple HTML5 charts using the canvas element.", - "version": "3.7.1", - "license": "MIT", - "jsdelivr": "dist/chart.min.js", - "unpkg": "dist/chart.min.js", - "main": "dist/chart.js", - "module": "dist/chart.esm.js", - "types": "types/index.esm.d.ts", - "keywords": [ - "canvas", - "charts", - "data", - "graphs", - "html5", - "responsive" - ], - "repository": { - "type": "git", - "url": "https://github.com/chartjs/Chart.js.git" - }, - "bugs": { - "url": "https://github.com/chartjs/Chart.js/issues" - }, - "files": [ - "auto/**/*.js", - "auto/**/*.d.ts", - "dist/*.js", - "dist/chunks/*.js", - "types/*.d.ts", - "types/helpers/*.d.ts", - "helpers/**/*.js", - "helpers/**/*.d.ts" - ], - "scripts": { - "autobuild": "rollup -c -w", - "build": "rollup -c", - "dev": "karma start --auto-watch --no-single-run --browsers chrome --grep", - "dev:ff": "karma start --auto-watch --no-single-run --browsers firefox --grep", - "docs": "npm run build && vuepress build docs --no-cache", - "docs:dev": "npm run build && vuepress dev docs --no-cache", - "lint-js": "eslint \"src/**/*.js\" \"test/**/*.js\" \"docs/**/*.js\"", - "lint-md": "eslint \"**/*.md\"", - "lint-tsc": "tsc", - "lint-types": "eslint \"types/**/*.ts\" && node -r esm types/tests/autogen.js && tsc -p types/tests/", - "lint": "concurrently \"npm:lint-*\"", - "test": "npm run lint && cross-env NODE_ENV=test karma start --auto-watch --single-run --coverage --grep" - }, - "devDependencies": { - "@kurkle/color": "^0.1.9", - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-inject": "^4.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "@simonbrunel/vuepress-plugin-versions": "^0.2.0", - "@types/offscreencanvas": "^2019.6.4", - "@typescript-eslint/eslint-plugin": "^5.8.0", - "@typescript-eslint/parser": "^5.8.0", - "@vuepress/plugin-google-analytics": "^1.8.3", - "@vuepress/plugin-html-redirect": "^0.1.2", - "chartjs-adapter-luxon": "^1.0.0", - "chartjs-adapter-moment": "^1.0.0", - "chartjs-test-utils": "^0.3.1", - "concurrently": "^6.0.1", - "coveralls": "^3.1.0", - "cross-env": "^7.0.3", - "eslint": "^8.5.0", - "eslint-config-chartjs": "^0.3.0", - "eslint-plugin-es": "^4.1.0", - "eslint-plugin-html": "^6.1.2", - "eslint-plugin-markdown": "^2.2.1", - "esm": "^3.2.25", - "glob": "^7.1.6", - "jasmine": "^3.7.0", - "jasmine-core": "^3.7.1", - "karma": "^6.3.2", - "karma-chrome-launcher": "^3.1.0", - "karma-coverage": "^2.0.3", - "karma-edge-launcher": "^0.4.2", - "karma-firefox-launcher": "^2.1.0", - "karma-jasmine": "^4.0.1", - "karma-jasmine-html-reporter": "^1.5.4", - "karma-rollup-preprocessor": "^7.0.7", - "karma-safari-private-launcher": "^1.0.0", - "karma-spec-reporter": "0.0.32", - "luxon": "^2.2.0", - "markdown-it-include": "^2.0.0", - "moment": "^2.29.1", - "moment-timezone": "^0.5.34", - "pixelmatch": "^5.2.1", - "rollup": "^2.44.0", - "rollup-plugin-analyzer": "^4.0.0", - "rollup-plugin-cleanup": "^3.2.1", - "rollup-plugin-istanbul": "^3.0.0", - "rollup-plugin-terser": "^7.0.2", - "typedoc": "^0.22.10", - "typedoc-plugin-markdown": "^3.6.1", - "typescript": "^4.3.5", - "vue-tabs-component": "^1.5.0", - "vuepress": "^1.8.2", - "vuepress-plugin-code-copy": "^1.0.6", - "vuepress-plugin-flexsearch": "^0.3.0", - "vuepress-plugin-redirect": "^1.2.5", - "vuepress-plugin-tabs": "^0.3.0", - "vuepress-plugin-typedoc": "^0.10.0", - "vuepress-theme-chartjs": "^0.2.0", - "yargs": "^17.0.1" - } -} diff --git a/node_modules/chart.js/types/adapters.d.ts b/node_modules/chart.js/types/adapters.d.ts deleted file mode 100644 index f06c41b6..00000000 --- a/node_modules/chart.js/types/adapters.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -export type TimeUnit = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'; - -export interface DateAdapter { - // Override one or multiple of the methods to adjust to the logic of the current date library. - override(members: Partial): void; - readonly options: unknown; - - /** - * Returns a map of time formats for the supported formatting units defined - * in Unit as well as 'datetime' representing a detailed date/time string. - * @returns {{string: string}} - */ - formats(): { [key: string]: string }; - /** - * Parses the given `value` and return the associated timestamp. - * @param {unknown} value - the value to parse (usually comes from the data) - * @param {string} [format] - the expected data format - */ - parse(value: unknown, format?: TimeUnit): number | null; - /** - * Returns the formatted date in the specified `format` for a given `timestamp`. - * @param {number} timestamp - the timestamp to format - * @param {string} format - the date/time token - * @return {string} - */ - format(timestamp: number, format: TimeUnit): string; - /** - * Adds the specified `amount` of `unit` to the given `timestamp`. - * @param {number} timestamp - the input timestamp - * @param {number} amount - the amount to add - * @param {Unit} unit - the unit as string - * @return {number} - */ - add(timestamp: number, amount: number, unit: TimeUnit): number; - /** - * Returns the number of `unit` between the given timestamps. - * @param {number} a - the input timestamp (reference) - * @param {number} b - the timestamp to subtract - * @param {Unit} unit - the unit as string - * @return {number} - */ - diff(a: number, b: number, unit: TimeUnit): number; - /** - * Returns start of `unit` for the given `timestamp`. - * @param {number} timestamp - the input timestamp - * @param {Unit|'isoWeek'} unit - the unit as string - * @param {number} [weekday] - the ISO day of the week with 1 being Monday - * and 7 being Sunday (only needed if param *unit* is `isoWeek`). - * @return {number} - */ - startOf(timestamp: number, unit: TimeUnit | 'isoWeek', weekday?: number): number; - /** - * Returns end of `unit` for the given `timestamp`. - * @param {number} timestamp - the input timestamp - * @param {Unit|'isoWeek'} unit - the unit as string - * @return {number} - */ - endOf(timestamp: number, unit: TimeUnit | 'isoWeek'): number; -} - -export const _adapters: { - _date: DateAdapter; -}; diff --git a/node_modules/chart.js/types/animation.d.ts b/node_modules/chart.js/types/animation.d.ts deleted file mode 100644 index b8320412..00000000 --- a/node_modules/chart.js/types/animation.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Chart } from './index.esm'; -import { AnyObject } from './basic'; - -export class Animation { - constructor(cfg: AnyObject, target: AnyObject, prop: string, to?: unknown); - active(): boolean; - update(cfg: AnyObject, to: unknown, date: number): void; - cancel(): void; - tick(date: number): void; -} - -export interface AnimationEvent { - chart: Chart; - numSteps: number; - initial: boolean; - currentStep: number; -} - -export class Animator { - listen(chart: Chart, event: 'complete' | 'progress', cb: (event: AnimationEvent) => void): void; - add(chart: Chart, items: readonly Animation[]): void; - has(chart: Chart): boolean; - start(chart: Chart): void; - running(chart: Chart): boolean; - stop(chart: Chart): void; - remove(chart: Chart): boolean; -} - -export class Animations { - constructor(chart: Chart, animations: AnyObject); - configure(animations: AnyObject): void; - update(target: AnyObject, values: AnyObject): undefined | boolean; -} diff --git a/node_modules/chart.js/types/basic.d.ts b/node_modules/chart.js/types/basic.d.ts deleted file mode 100644 index 1692c9cb..00000000 --- a/node_modules/chart.js/types/basic.d.ts +++ /dev/null @@ -1,3 +0,0 @@ - -export type AnyObject = Record; -export type EmptyObject = Record; diff --git a/node_modules/chart.js/types/color.d.ts b/node_modules/chart.js/types/color.d.ts deleted file mode 100644 index 4a68f98b..00000000 --- a/node_modules/chart.js/types/color.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type Color = string | CanvasGradient | CanvasPattern; diff --git a/node_modules/chart.js/types/element.d.ts b/node_modules/chart.js/types/element.d.ts deleted file mode 100644 index 3b9359b3..00000000 --- a/node_modules/chart.js/types/element.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { AnyObject } from './basic'; -import { Point } from './geometric'; - -export interface Element { - readonly x: number; - readonly y: number; - readonly active: boolean; - readonly options: O; - - tooltipPosition(useFinalPosition?: boolean): Point; - hasValue(): boolean; - getProps

(props: P, final?: boolean): Pick; -} -export const Element: { - prototype: Element; - new (): Element; -}; diff --git a/node_modules/chart.js/types/geometric.d.ts b/node_modules/chart.js/types/geometric.d.ts deleted file mode 100644 index 0e1affda..00000000 --- a/node_modules/chart.js/types/geometric.d.ts +++ /dev/null @@ -1,37 +0,0 @@ -export interface ChartArea { - top: number; - left: number; - right: number; - bottom: number; - width: number; - height: number; -} - -export interface Point { - x: number; - y: number; -} - -export type TRBL = { - top: number; - right: number; - bottom: number; - left: number; -} - -export type TRBLCorners = { - topLeft: number; - topRight: number; - bottomLeft: number; - bottomRight: number; -}; - -export type CornerRadius = number | Partial; - -export type RoundedRect = { - x: number; - y: number; - w: number; - h: number; - radius?: CornerRadius -} diff --git a/node_modules/chart.js/types/helpers/helpers.canvas.d.ts b/node_modules/chart.js/types/helpers/helpers.canvas.d.ts deleted file mode 100644 index 44e570e6..00000000 --- a/node_modules/chart.js/types/helpers/helpers.canvas.d.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { PointStyle } from '../index.esm'; -import { Color } from '../color'; -import { ChartArea, RoundedRect } from '../geometric'; -import { CanvasFontSpec } from './helpers.options'; - -export function clearCanvas(canvas: HTMLCanvasElement, ctx?: CanvasRenderingContext2D): void; - -export function clipArea(ctx: CanvasRenderingContext2D, area: ChartArea): void; - -export function unclipArea(ctx: CanvasRenderingContext2D): void; - -export interface DrawPointOptions { - pointStyle: PointStyle; - rotation?: number; - radius: number; - borderWidth: number; -} - -export function drawPoint(ctx: CanvasRenderingContext2D, options: DrawPointOptions, x: number, y: number): void; - -/** - * Converts the given font object into a CSS font string. - * @param font a font object - * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font - */ -export function toFontString(font: { size: number; family: string; style?: string; weight?: string }): string | null; - -export interface RenderTextOpts { - /** - * The fill color of the text. If unset, the existing - * fillStyle property of the canvas is unchanged. - */ - color?: Color; - - /** - * The width of the strikethrough / underline - * @default 2 - */ - decorationWidth?: number; - - /** - * The max width of the text in pixels - */ - maxWidth?: number; - - /** - * A rotation to be applied to the canvas - * This is applied after the translation is applied - */ - rotation?: number; - - /** - * Apply a strikethrough effect to the text - */ - strikethrough?: boolean; - - /** - * The color of the text stroke. If unset, the existing - * strokeStyle property of the context is unchanged - */ - strokeColor?: Color; - - /** - * The text stroke width. If unset, the existing - * lineWidth property of the context is unchanged - */ - strokeWidth?: number; - - /** - * The text alignment to use. If unset, the existing - * textAlign property of the context is unchanged - */ - textAlign: CanvasTextAlign; - - /** - * The text baseline to use. If unset, the existing - * textBaseline property of the context is unchanged - */ - textBaseline: CanvasTextBaseline; - - /** - * If specified, a translation to apply to the context - */ - translation?: [number, number]; - - /** - * Underline the text - */ - underline?: boolean; -} - -export function renderText( - ctx: CanvasRenderingContext2D, - text: string | string[], - x: number, - y: number, - font: CanvasFontSpec, - opts?: RenderTextOpts -): void; - -export function addRoundedRectPath(ctx: CanvasRenderingContext2D, rect: RoundedRect): void; diff --git a/node_modules/chart.js/types/helpers/helpers.collection.d.ts b/node_modules/chart.js/types/helpers/helpers.collection.d.ts deleted file mode 100644 index 6a51597c..00000000 --- a/node_modules/chart.js/types/helpers/helpers.collection.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -export interface ArrayListener { - _onDataPush?(...item: T[]): void; - _onDataPop?(): void; - _onDataShift?(): void; - _onDataSplice?(index: number, deleteCount: number, ...items: T[]): void; - _onDataUnshift?(...item: T[]): void; -} - -/** - * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', - * 'unshift') and notify the listener AFTER the array has been altered. Listeners are - * called on the '_onData*' callbacks (e.g. _onDataPush, etc.) with same arguments. - */ -export function listenArrayEvents(array: T[], listener: ArrayListener): void; - -/** - * Removes the given array event listener and cleanup extra attached properties (such as - * the _chartjs stub and overridden methods) if array doesn't have any more listeners. - */ -export function unlistenArrayEvents(array: T[], listener: ArrayListener): void; diff --git a/node_modules/chart.js/types/helpers/helpers.color.d.ts b/node_modules/chart.js/types/helpers/helpers.color.d.ts deleted file mode 100644 index 3cfc20ea..00000000 --- a/node_modules/chart.js/types/helpers/helpers.color.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -export function color(value: CanvasGradient): CanvasGradient; -export function color(value: CanvasPattern): CanvasPattern; -export function color( - value: - | string - | { r: number; g: number; b: number; a: number } - | [number, number, number] - | [number, number, number, number] -): ColorModel; - -export interface ColorModel { - rgbString(): string; - hexString(): string; - hslString(): string; - rgb: { r: number; g: number; b: number; a: number }; - valid: boolean; - mix(color: ColorModel, weight: number): this; - clone(): ColorModel; - alpha(a: number): ColorModel; - clearer(ration: number): ColorModel; - greyscale(): ColorModel; - opaquer(ratio: number): ColorModel; - negate(): ColorModel; - lighten(ratio: number): ColorModel; - darken(ratio: number): ColorModel; - saturate(ratio: number): ColorModel; - desaturate(ratio: number): ColorModel; - rotate(deg: number): this; -} - -export function getHoverColor(value: CanvasGradient): CanvasGradient; -export function getHoverColor(value: CanvasPattern): CanvasPattern; -export function getHoverColor(value: string): string; diff --git a/node_modules/chart.js/types/helpers/helpers.core.d.ts b/node_modules/chart.js/types/helpers/helpers.core.d.ts deleted file mode 100644 index bc376da0..00000000 --- a/node_modules/chart.js/types/helpers/helpers.core.d.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { AnyObject } from '../basic'; - -/** - * An empty function that can be used, for example, for optional callback. - */ -export function noop(): void; - -/** - * Returns a unique id, sequentially generated from a global variable. - * @returns {number} - * @function - */ -export function uid(): number; -/** - * Returns true if `value` is neither null nor undefined, else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @since 2.7.0 - */ -export function isNullOrUndef(value: unknown): value is null | undefined; -/** - * Returns true if `value` is an array (including typed arrays), else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @function - */ -export function isArray(value: unknown): value is ArrayLike; -/** - * Returns true if `value` is an object (excluding null), else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @since 2.7.0 - */ -export function isObject(value: unknown): value is AnyObject; -/** - * Returns true if `value` is a finite number, else returns false - * @param {*} value - The value to test. - * @returns {boolean} - */ -export function isFinite(value: unknown): value is number; - -/** - * Returns `value` if finite, else returns `defaultValue`. - * @param {*} value - The value to return if defined. - * @param {*} defaultValue - The value to return if `value` is not finite. - * @returns {*} - */ -export function finiteOrDefault(value: unknown, defaultValue: number): number; - -/** - * Returns `value` if defined, else returns `defaultValue`. - * @param {*} value - The value to return if defined. - * @param {*} defaultValue - The value to return if `value` is undefined. - * @returns {*} - */ -export function valueOrDefault(value: T | undefined, defaultValue: T): T; - -export function toPercentage(value: number | string, dimesion: number): number; -export function toDimension(value: number | string, dimension: number): number; - -/** - * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the - * value returned by `fn`. If `fn` is not a function, this method returns undefined. - * @param fn - The function to call. - * @param args - The arguments with which `fn` should be called. - * @param [thisArg] - The value of `this` provided for the call to `fn`. - * @returns {*} - */ -export function callback R, TA, R>( - fn: T | undefined, - args: unknown[], - thisArg?: TA -): R | undefined; - -/** - * Note(SB) for performance sake, this method should only be used when loopable type - * is unknown or in none intensive code (not called often and small loopable). Else - * it's preferable to use a regular for() loop and save extra function calls. - * @param loopable - The object or array to be iterated. - * @param fn - The function to call for each item. - * @param [thisArg] - The value of `this` provided for the call to `fn`. - * @param [reverse] - If true, iterates backward on the loopable. - */ -export function each( - loopable: T[], - fn: (this: TA, v: T, i: number) => void, - thisArg?: TA, - reverse?: boolean -): void; -/** - * Note(SB) for performance sake, this method should only be used when loopable type - * is unknown or in none intensive code (not called often and small loopable). Else - * it's preferable to use a regular for() loop and save extra function calls. - * @param loopable - The object or array to be iterated. - * @param fn - The function to call for each item. - * @param [thisArg] - The value of `this` provided for the call to `fn`. - * @param [reverse] - If true, iterates backward on the loopable. - */ -export function each( - loopable: { [key: string]: T }, - fn: (this: TA, v: T, k: string) => void, - thisArg?: TA, - reverse?: boolean -): void; - -/** - * Returns a deep copy of `source` without keeping references on objects and arrays. - * @param source - The value to clone. - */ -export function clone(source: T): T; - -export interface MergeOptions { - merger?: (key: string, target: AnyObject, source: AnyObject, options: AnyObject) => AnyObject; -} -/** - * Recursively deep copies `source` properties into `target` with the given `options`. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param target - The target object in which all sources are merged into. - * @param source - Object(s) to merge into `target`. - * @param {object} [options] - Merging options: - * @param {function} [options.merger] - The merge method (key, target, source, options) - * @returns {object} The `target` object. - */ -export function merge(target: T, source: [], options?: MergeOptions): T; -export function merge(target: T, source: S1, options?: MergeOptions): T & S1; -export function merge(target: T, source: [S1], options?: MergeOptions): T & S1; -export function merge(target: T, source: [S1, S2], options?: MergeOptions): T & S1 & S2; -export function merge(target: T, source: [S1, S2, S3], options?: MergeOptions): T & S1 & S2 & S3; -export function merge( - target: T, - source: [S1, S2, S3, S4], - options?: MergeOptions -): T & S1 & S2 & S3 & S4; -export function merge(target: T, source: AnyObject[], options?: MergeOptions): AnyObject; - -/** - * Recursively deep copies `source` properties into `target` *only* if not defined in target. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param target - The target object in which all sources are merged into. - * @param source - Object(s) to merge into `target`. - * @returns The `target` object. - */ -export function mergeIf(target: T, source: []): T; -export function mergeIf(target: T, source: S1): T & S1; -export function mergeIf(target: T, source: [S1]): T & S1; -export function mergeIf(target: T, source: [S1, S2]): T & S1 & S2; -export function mergeIf(target: T, source: [S1, S2, S3]): T & S1 & S2 & S3; -export function mergeIf(target: T, source: [S1, S2, S3, S4]): T & S1 & S2 & S3 & S4; -export function mergeIf(target: T, source: AnyObject[]): AnyObject; - -export function resolveObjectKey(obj: AnyObject, key: string): AnyObject; - -export function defined(value: unknown): boolean; - -export function isFunction(value: unknown): boolean; - -export function setsEqual(a: Set, b: Set): boolean; diff --git a/node_modules/chart.js/types/helpers/helpers.curve.d.ts b/node_modules/chart.js/types/helpers/helpers.curve.d.ts deleted file mode 100644 index 28d9ee4a..00000000 --- a/node_modules/chart.js/types/helpers/helpers.curve.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -export interface SplinePoint { - x: number; - y: number; -} - -/** - * Props to Rob Spencer at scaled innovation for his post on splining between points - * http://scaledinnovation.com/analytics/splines/aboutSplines.html - */ -export function splineCurve( - firstPoint: SplinePoint & { skip?: boolean }, - middlePoint: SplinePoint, - afterPoint: SplinePoint, - t: number -): { - previous: SplinePoint; - next: SplinePoint; -}; - -export interface MonotoneSplinePoint extends SplinePoint { - skip: boolean; - cp1x?: number; - cp1y?: number; - cp2x?: number; - cp2y?: number; -} - -/** - * This function calculates BΓ©zier control points in a similar way than |splineCurve|, - * but preserves monotonicity of the provided data and ensures no local extremums are added - * between the dataset discrete points due to the interpolation. - * @see https://en.wikipedia.org/wiki/Monotone_cubic_interpolation - */ -export function splineCurveMonotone(points: readonly MonotoneSplinePoint[], indexAxis?: 'x' | 'y'): void; diff --git a/node_modules/chart.js/types/helpers/helpers.dom.d.ts b/node_modules/chart.js/types/helpers/helpers.dom.d.ts deleted file mode 100644 index 73864314..00000000 --- a/node_modules/chart.js/types/helpers/helpers.dom.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ChartEvent } from '../index.esm'; - -export function getMaximumSize(node: HTMLElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number }; -export function getRelativePosition( - evt: MouseEvent | ChartEvent, - chart: { readonly canvas: HTMLCanvasElement } -): { x: number; y: number }; -export function getStyle(el: HTMLElement, property: string): string; -export function retinaScale( - chart: { - currentDevicePixelRatio: number; - readonly canvas: HTMLCanvasElement; - readonly width: number; - readonly height: number; - readonly ctx: CanvasRenderingContext2D; - }, - forceRatio: number, - forceStyle?: boolean -): void; -export function readUsedSize(element: HTMLElement, property: 'width' | 'height'): number | undefined; diff --git a/node_modules/chart.js/types/helpers/helpers.easing.d.ts b/node_modules/chart.js/types/helpers/helpers.easing.d.ts deleted file mode 100644 index b86d6532..00000000 --- a/node_modules/chart.js/types/helpers/helpers.easing.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { EasingFunction } from '../index.esm'; - -export type EasingFunctionSignature = (t: number) => number; - -export const easingEffects: Record; diff --git a/node_modules/chart.js/types/helpers/helpers.extras.d.ts b/node_modules/chart.js/types/helpers/helpers.extras.d.ts deleted file mode 100644 index cb445c32..00000000 --- a/node_modules/chart.js/types/helpers/helpers.extras.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -export function fontString(pixelSize: number, fontStyle: string, fontFamily: string): string; - -/** - * Request animation polyfill - */ -export function requestAnimFrame(cb: () => void): void; - -/** - * Throttles calling `fn` once per animation frame - * Latest arguments are used on the actual call - * @param {function} fn - * @param {*} thisArg - * @param {function} [updateFn] - */ -export function throttled(fn: (...args: unknown[]) => void, thisArg: unknown, updateFn?: (...args: unknown[]) => unknown[]): (...args: unknown[]) => void; - -/** - * Debounces calling `fn` for `delay` ms - * @param {function} fn - Function to call. No arguments are passed. - * @param {number} delay - Delay in ms. 0 = immediate invocation. - * @returns {function} - */ -export function debounce(fn: () => void, delay: number): () => number; diff --git a/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts b/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/node_modules/chart.js/types/helpers/helpers.interpolation.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/node_modules/chart.js/types/helpers/helpers.intl.d.ts b/node_modules/chart.js/types/helpers/helpers.intl.d.ts deleted file mode 100644 index 3a896f4a..00000000 --- a/node_modules/chart.js/types/helpers/helpers.intl.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Format a number using a localized number formatter. - * @param num The number to format - * @param locale The locale to pass to the Intl.NumberFormat constructor - * @param options Number format options - */ -export function formatNumber(num: number, locale: string, options: Intl.NumberFormatOptions): string; diff --git a/node_modules/chart.js/types/helpers/helpers.math.d.ts b/node_modules/chart.js/types/helpers/helpers.math.d.ts deleted file mode 100644 index cc58b30e..00000000 --- a/node_modules/chart.js/types/helpers/helpers.math.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function log10(x: number): number; -export function isNumber(v: unknown): boolean; -export function almostEquals(x: number, y: number, epsilon: number): boolean; -export function almostWhole(x: number, epsilon: number): number; -export function sign(x: number): number; -export function niceNum(range: number): number; -export function toRadians(degrees: number): number; -export function toDegrees(radians: number): number; -/** - * Gets the angle from vertical upright to the point about a centre. - */ -export function getAngleFromPoint( - centrePoint: { x: number; y: number }, - anglePoint: { x: number; y: number } -): { angle: number; distance: number }; - -export function distanceBetweenPoints(pt1: { x: number; y: number }, pt2: { x: number; y: number }): number; diff --git a/node_modules/chart.js/types/helpers/helpers.options.d.ts b/node_modules/chart.js/types/helpers/helpers.options.d.ts deleted file mode 100644 index 0bd783fa..00000000 --- a/node_modules/chart.js/types/helpers/helpers.options.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { TRBL, TRBLCorners } from '../geometric'; -import { FontSpec } from '../index.esm'; - -export interface CanvasFontSpec extends FontSpec { - string: string; -} -/** - * Parses font options and returns the font object. - * @param {object} options - A object that contains font options to be parsed. - * @return {object} The font object. - */ -export function toFont(options: Partial): CanvasFontSpec; - -/** - * Converts the given line height `value` in pixels for a specific font `size`. - * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). - * @param {number} size - The font size (in pixels) used to resolve relative `value`. - * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid). - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height - * @since 2.7.0 - */ -export function toLineHeight(value: string, size: number): number; - -export function toTRBL(value: number | Partial): TRBL; -export function toTRBLCorners(value: number | Partial): TRBLCorners; - -/** - * Converts the given value into a padding object with pre-computed width/height. - * @param {number|object} value - If a number, set the value to all TRBL component; - * else, if an object, use defined properties and sets undefined ones to 0. - * @returns {object} The padding values (top, right, bottom, left, width, height) - * @since 2.7.0 - */ -export function toPadding( - value?: number | { top?: number; left?: number; right?: number; bottom?: number; x?:number, y?: number } -): { top: number; left: number; right: number; bottom: number; width: number; height: number }; - -/** - * Evaluates the given `inputs` sequentially and returns the first defined value. - * @param inputs - An array of values, falling back to the last value. - * @param [context] - If defined and the current value is a function, the value - * is called with `context` as first argument and the result becomes the new input. - * @param [index] - If defined and the current value is an array, the value - * at `index` become the new input. - * @param [info] - object to return information about resolution in - * @param [info.cacheable] - Will be set to `false` if option is not cacheable. - * @since 2.7.0 - */ -export function resolve( - inputs: undefined | T | ((c: C) => T) | readonly T[], - context?: C, - index?: number, - info?: { cacheable?: boolean } -): T | undefined; - - -/** - * Create a context inheriting parentContext - * @since 3.6.0 - */ -export function createContext(parentContext: P, context: T): P extends null ? T : P & T; diff --git a/node_modules/chart.js/types/helpers/helpers.rtl.d.ts b/node_modules/chart.js/types/helpers/helpers.rtl.d.ts deleted file mode 100644 index ed0b9248..00000000 --- a/node_modules/chart.js/types/helpers/helpers.rtl.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface RTLAdapter { - x(x: number): number; - setWidth(w: number): void; - textAlign(align: 'center' | 'left' | 'right'): 'center' | 'left' | 'right'; - xPlus(x: number, value: number): number; - leftForLtr(x: number, itemWidth: number): number; -} -export function getRtlAdapter(rtl: boolean, rectX: number, width: number): RTLAdapter; - -export function overrideTextDirection(ctx: CanvasRenderingContext2D, direction: 'ltr' | 'rtl'): void; - -export function restoreTextDirection(ctx: CanvasRenderingContext2D, original?: [string, string]): void; diff --git a/node_modules/chart.js/types/helpers/helpers.segment.d.ts b/node_modules/chart.js/types/helpers/helpers.segment.d.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/node_modules/chart.js/types/helpers/helpers.segment.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/node_modules/chart.js/types/helpers/index.d.ts b/node_modules/chart.js/types/helpers/index.d.ts deleted file mode 100644 index 01332692..00000000 --- a/node_modules/chart.js/types/helpers/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from './helpers.canvas'; -export * from './helpers.collection'; -export * from './helpers.color'; -export * from './helpers.core'; -export * from './helpers.curve'; -export * from './helpers.dom'; -export * from './helpers.easing'; -export * from './helpers.extras'; -export * from './helpers.interpolation'; -export * from './helpers.intl'; -export * from './helpers.math'; -export * from './helpers.options'; -export * from './helpers.canvas'; -export * from './helpers.rtl'; -export * from './helpers.segment'; diff --git a/node_modules/chart.js/types/index.esm.d.ts b/node_modules/chart.js/types/index.esm.d.ts deleted file mode 100644 index ccea4128..00000000 --- a/node_modules/chart.js/types/index.esm.d.ts +++ /dev/null @@ -1,3601 +0,0 @@ -import { DeepPartial, DistributiveArray, UnionToIntersection } from './utils'; - -import { TimeUnit } from './adapters'; -import { AnimationEvent } from './animation'; -import { AnyObject, EmptyObject } from './basic'; -import { Color } from './color'; -import { Element } from './element'; -import { ChartArea, Point } from './geometric'; -import { LayoutItem, LayoutPosition } from './layout'; - -export { DateAdapter, TimeUnit, _adapters } from './adapters'; -export { Animation, Animations, Animator, AnimationEvent } from './animation'; -export { Color } from './color'; -export { Element } from './element'; -export { ChartArea, Point } from './geometric'; -export { LayoutItem, LayoutPosition } from './layout'; - -export interface ScriptableContext { - active: boolean; - chart: Chart; - dataIndex: number; - dataset: UnionToIntersection>; - datasetIndex: number; - parsed: UnionToIntersection>; - raw: unknown; -} - -export interface ScriptableLineSegmentContext { - type: 'segment', - p0: PointElement, - p1: PointElement, - p0DataIndex: number, - p1DataIndex: number, - datasetIndex: number -} - -export type Scriptable = T | ((ctx: TContext, options: AnyObject) => T | undefined); -export type ScriptableOptions = { [P in keyof T]: Scriptable }; -export type ScriptableAndArray = readonly T[] | Scriptable; -export type ScriptableAndArrayOptions = { [P in keyof T]: ScriptableAndArray }; - -export interface ParsingOptions { - /** - * How to parse the dataset. The parsing can be disabled by specifying parsing: false at chart options or dataset. If parsing is disabled, data must be sorted and in the formats the associated chart type and scales use internally. - */ - parsing: - { - [key: string]: string; - } - | false; - - /** - * Chart.js is fastest if you provide data with indices that are unique, sorted, and consistent across datasets and provide the normalized: true option to let Chart.js know that you have done so. - */ - normalized: boolean; -} - -export interface ControllerDatasetOptions extends ParsingOptions { - /** - * The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts. - * @default 'x' - */ - indexAxis: 'x' | 'y'; - /** - * How to clip relative to chartArea. Positive value allows overflow, negative value clips that many pixels inside chartArea. 0 = clip at chartArea. Clipping can also be configured per side: clip: {left: 5, top: false, right: -2, bottom: 0} - */ - clip: number | ChartArea; - /** - * The label for the dataset which appears in the legend and tooltips. - */ - label: string; - /** - * The drawing order of dataset. Also affects order for stacking, tooltip and legend. - */ - order: number; - - /** - * The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack). - */ - stack: string; - /** - * Configures the visibility state of the dataset. Set it to true, to hide the dataset from the chart. - * @default false - */ - hidden: boolean; -} - -export interface BarControllerDatasetOptions - extends ControllerDatasetOptions, - ScriptableAndArrayOptions>, - ScriptableAndArrayOptions>, - AnimationOptions<'bar'> { - /** - * The ID of the x axis to plot this dataset on. - */ - xAxisID: string; - /** - * The ID of the y axis to plot this dataset on. - */ - yAxisID: string; - - /** - * Percent (0-1) of the available width each bar should be within the category width. 1.0 will take the whole category width and put the bars right next to each other. - * @default 0.9 - */ - barPercentage: number; - /** - * Percent (0-1) of the available width each category should be within the sample width. - * @default 0.8 - */ - categoryPercentage: number; - - /** - * Manually set width of each bar in pixels. If set to 'flex', it computes "optimal" sample widths that globally arrange bars side by side. If not set (default), bars are equally sized based on the smallest interval. - */ - barThickness: number | 'flex'; - - /** - * Set this to ensure that bars are not sized thicker than this. - */ - maxBarThickness: number; - - /** - * Set this to ensure that bars have a minimum length in pixels. - */ - minBarLength: number; - - /** - * Point style for the legend - * @default 'circle; - */ - pointStyle: PointStyle; -} - -export interface BarControllerChartOptions { - /** - * Should null or undefined values be omitted from drawing - */ - skipNull?: boolean; -} - -export type BarController = DatasetController -export const BarController: ChartComponent & { - prototype: BarController; - new (chart: Chart, datasetIndex: number): BarController; -}; - -export interface BubbleControllerDatasetOptions - extends ControllerDatasetOptions, - ScriptableAndArrayOptions>, - ScriptableAndArrayOptions> {} - -export interface BubbleDataPoint { - /** - * X Value - */ - x: number; - - /** - * Y Value - */ - y: number; - - /** - * Bubble radius in pixels (not scaled). - */ - r: number; -} - -export type BubbleController = DatasetController -export const BubbleController: ChartComponent & { - prototype: BubbleController; - new (chart: Chart, datasetIndex: number): BubbleController; -}; - -export interface LineControllerDatasetOptions - extends ControllerDatasetOptions, - ScriptableAndArrayOptions>, - ScriptableAndArrayOptions>, - ScriptableOptions>, - ScriptableOptions>, - AnimationOptions<'line'> { - /** - * The ID of the x axis to plot this dataset on. - */ - xAxisID: string; - /** - * The ID of the y axis to plot this dataset on. - */ - yAxisID: string; - - /** - * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. - * @default false - */ - spanGaps: boolean | number; - - showLine: boolean; -} - -export interface LineControllerChartOptions { - /** - * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. - * @default false - */ - spanGaps: boolean | number; - /** - * If false, the lines between points are not drawn. - * @default true - */ - showLine: boolean; -} - -export type LineController = DatasetController -export const LineController: ChartComponent & { - prototype: LineController; - new (chart: Chart, datasetIndex: number): LineController; -}; - -export type ScatterControllerDatasetOptions = LineControllerDatasetOptions; - -export interface ScatterDataPoint { - x: number; - y: number; -} - -export type ScatterControllerChartOptions = LineControllerChartOptions; - -export type ScatterController = LineController -export const ScatterController: ChartComponent & { - prototype: ScatterController; - new (chart: Chart, datasetIndex: number): ScatterController; -}; - -export interface DoughnutControllerDatasetOptions - extends ControllerDatasetOptions, - ScriptableAndArrayOptions>, - ScriptableAndArrayOptions>, - AnimationOptions<'doughnut'> { - - /** - * Sweep to allow arcs to cover. - * @default 360 - */ - circumference: number; - - /** - * Arc offset (in pixels). - */ - offset: number; - - /** - * Starting angle to draw this dataset from. - * @default 0 - */ - rotation: number; - - /** - * The relative thickness of the dataset. Providing a value for weight will cause the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weight values. - * @default 1 - */ - weight: number; - - /** - * Similar to the `offset` option, but applies to all arcs. This can be used to to add spaces - * between arcs - * @default 0 - */ - spacing: number; -} - -export interface DoughnutAnimationOptions { - /** - * If true, the chart will animate in with a rotation animation. This property is in the options.animation object. - * @default true - */ - animateRotate: boolean; - - /** - * If true, will animate scaling the chart from the center outwards. - * @default false - */ - animateScale: boolean; -} - -export interface DoughnutControllerChartOptions { - /** - * Sweep to allow arcs to cover. - * @default 360 - */ - circumference: number; - - /** - * The portion of the chart that is cut out of the middle. ('50%' - for doughnut, 0 - for pie) - * String ending with '%' means percentage, number means pixels. - * @default 50 - */ - cutout: Scriptable>; - - /** - * Arc offset (in pixels). - */ - offset: number; - - /** - * The outer radius of the chart. String ending with '%' means percentage of maximum radius, number means pixels. - * @default '100%' - */ - radius: Scriptable>; - - /** - * Starting angle to draw arcs from. - * @default 0 - */ - rotation: number; - - /** - * Spacing between the arcs - * @default 0 - */ - spacing: number; - - animation: false | DoughnutAnimationOptions; -} - -export type DoughnutDataPoint = number; - -export interface DoughnutController extends DatasetController { - readonly innerRadius: number; - readonly outerRadius: number; - readonly offsetX: number; - readonly offsetY: number; - - calculateTotal(): number; - calculateCircumference(value: number): number; -} - -export const DoughnutController: ChartComponent & { - prototype: DoughnutController; - new (chart: Chart, datasetIndex: number): DoughnutController; -}; - -export interface DoughnutMetaExtensions { - total: number; -} - -export type PieControllerDatasetOptions = DoughnutControllerDatasetOptions; -export type PieControllerChartOptions = DoughnutControllerChartOptions; -export type PieAnimationOptions = DoughnutAnimationOptions; - -export type PieDataPoint = DoughnutDataPoint; -export type PieMetaExtensions = DoughnutMetaExtensions; - -export type PieController = DoughnutController -export const PieController: ChartComponent & { - prototype: PieController; - new (chart: Chart, datasetIndex: number): PieController; -}; - -export interface PolarAreaControllerDatasetOptions extends DoughnutControllerDatasetOptions { - /** - * Arc angle to cover. - for polar only - * @default circumference / (arc count) - */ - angle: number; -} - -export type PolarAreaAnimationOptions = DoughnutAnimationOptions; - -export interface PolarAreaControllerChartOptions { - /** - * Starting angle to draw arcs for the first item in a dataset. In degrees, 0 is at top. - * @default 0 - */ - startAngle: number; - - animation: false | PolarAreaAnimationOptions; -} - -export interface PolarAreaController extends DoughnutController { - countVisibleElements(): number; -} -export const PolarAreaController: ChartComponent & { - prototype: PolarAreaController; - new (chart: Chart, datasetIndex: number): PolarAreaController; -}; - -export interface RadarControllerDatasetOptions - extends ControllerDatasetOptions, - ScriptableAndArrayOptions>, - ScriptableAndArrayOptions>, - AnimationOptions<'radar'> { - /** - * The ID of the x axis to plot this dataset on. - */ - xAxisID: string; - /** - * The ID of the y axis to plot this dataset on. - */ - yAxisID: string; - - /** - * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. - */ - spanGaps: boolean | number; - - /** - * If false, the line is not drawn for this dataset. - */ - showLine: boolean; -} - -export type RadarControllerChartOptions = LineControllerChartOptions; - -export type RadarController = DatasetController -export const RadarController: ChartComponent & { - prototype: RadarController; - new (chart: Chart, datasetIndex: number): RadarController; -}; -interface ChartMetaCommon { - type: string; - controller: DatasetController; - order: number; - - label: string; - index: number; - visible: boolean; - - stack: number; - - indexAxis: 'x' | 'y'; - - data: TElement[]; - dataset?: TDatasetElement; - - hidden: boolean; - - xAxisID?: string; - yAxisID?: string; - rAxisID?: string; - iAxisID: string; - vAxisID: string; - - xScale?: Scale; - yScale?: Scale; - rScale?: Scale; - iScale?: Scale; - vScale?: Scale; - - _sorted: boolean; - _stacked: boolean | 'single'; - _parsed: unknown[]; -} - -export type ChartMeta< - TElement extends Element = Element, - TDatasetElement extends Element = Element, - // TODO - V4, move this to the first parameter. - // When this was introduced, doing so was a breaking change - TType extends ChartType = ChartType, -> = DeepPartial< -{ [key in ChartType]: ChartTypeRegistry[key]['metaExtensions'] }[TType] -> & ChartMetaCommon; - -export interface ActiveDataPoint { - datasetIndex: number; - index: number; -} - -export interface ActiveElement extends ActiveDataPoint { - element: Element; -} - -export declare class Chart< - TType extends ChartType = ChartType, - TData = DefaultDataPoint, - TLabel = unknown -> { - readonly platform: BasePlatform; - readonly id: string; - readonly canvas: HTMLCanvasElement; - readonly ctx: CanvasRenderingContext2D; - readonly config: ChartConfiguration; - readonly width: number; - readonly height: number; - readonly aspectRatio: number; - readonly boxes: LayoutItem[]; - readonly currentDevicePixelRatio: number; - readonly chartArea: ChartArea; - readonly scales: { [key: string]: Scale }; - readonly attached: boolean; - - readonly legend?: LegendElement; // Only available if legend plugin is registered and enabled - readonly tooltip?: TooltipModel; // Only available if tooltip plugin is registered and enabled - - data: ChartData; - options: ChartOptions; - - constructor(item: ChartItem, config: ChartConfiguration); - - clear(): this; - stop(): this; - - resize(width?: number, height?: number): void; - ensureScalesHaveIDs(): void; - buildOrUpdateScales(): void; - buildOrUpdateControllers(): void; - reset(): void; - update(mode?: UpdateMode): void; - render(): void; - draw(): void; - - getElementsAtEventForMode(e: Event, mode: string, options: InteractionOptions, useFinalPosition: boolean): InteractionItem[]; - - getSortedVisibleDatasetMetas(): ChartMeta[]; - getDatasetMeta(datasetIndex: number): ChartMeta; - getVisibleDatasetCount(): number; - isDatasetVisible(datasetIndex: number): boolean; - setDatasetVisibility(datasetIndex: number, visible: boolean): void; - toggleDataVisibility(index: number): void; - getDataVisibility(index: number): boolean; - hide(datasetIndex: number, dataIndex?: number): void; - show(datasetIndex: number, dataIndex?: number): void; - - getActiveElements(): ActiveElement[]; - setActiveElements(active: ActiveDataPoint[]): void; - - destroy(): void; - toBase64Image(type?: string, quality?: unknown): string; - bindEvents(): void; - unbindEvents(): void; - updateHoverStyle(items: InteractionItem[], mode: 'dataset', enabled: boolean): void; - - notifyPlugins(hook: string, args?: AnyObject): boolean | void; - - static readonly defaults: Defaults; - static readonly overrides: Overrides; - static readonly version: string; - static readonly instances: { [key: string]: Chart }; - static readonly registry: Registry; - static getChart(key: string | CanvasRenderingContext2D | HTMLCanvasElement): Chart | undefined; - static register(...items: ChartComponentLike[]): void; - static unregister(...items: ChartComponentLike[]): void; -} - -export const registerables: readonly ChartComponentLike[]; - -export declare type ChartItem = - | string - | CanvasRenderingContext2D - | HTMLCanvasElement - | { canvas: HTMLCanvasElement } - | ArrayLike; - -export declare enum UpdateModeEnum { - resize = 'resize', - reset = 'reset', - none = 'none', - hide = 'hide', - show = 'show', - normal = 'normal', - active = 'active' -} - -export type UpdateMode = keyof typeof UpdateModeEnum; - -export class DatasetController< - TType extends ChartType = ChartType, - TElement extends Element = Element, - TDatasetElement extends Element = Element, - TParsedData = ParsedDataType, -> { - constructor(chart: Chart, datasetIndex: number); - - readonly chart: Chart; - readonly index: number; - readonly _cachedMeta: ChartMeta; - enableOptionSharing: boolean; - - linkScales(): void; - getAllParsedValues(scale: Scale): number[]; - protected getLabelAndValue(index: number): { label: string; value: string }; - updateElements(elements: TElement[], start: number, count: number, mode: UpdateMode): void; - update(mode: UpdateMode): void; - updateIndex(datasetIndex: number): void; - protected getMaxOverflow(): boolean | number; - draw(): void; - reset(): void; - getDataset(): ChartDataset; - getMeta(): ChartMeta; - getScaleForId(scaleID: string): Scale | undefined; - configure(): void; - initialize(): void; - addElements(): void; - buildOrUpdateElements(resetNewElements?: boolean): void; - - getStyle(index: number, active: boolean): AnyObject; - protected resolveDatasetElementOptions(mode: UpdateMode): AnyObject; - protected resolveDataElementOptions(index: number, mode: UpdateMode): AnyObject; - /** - * Utility for checking if the options are shared and should be animated separately. - * @protected - */ - protected getSharedOptions(options: AnyObject): undefined | AnyObject; - /** - * Utility for determining if `options` should be included in the updated properties - * @protected - */ - protected includeOptions(mode: UpdateMode, sharedOptions: AnyObject): boolean; - /** - * Utility for updating an element with new properties, using animations when appropriate. - * @protected - */ - - protected updateElement(element: TElement | TDatasetElement, index: number | undefined, properties: AnyObject, mode: UpdateMode): void; - /** - * Utility to animate the shared options, that are potentially affecting multiple elements. - * @protected - */ - - protected updateSharedOptions(sharedOptions: AnyObject, mode: UpdateMode, newOptions: AnyObject): void; - removeHoverStyle(element: TElement, datasetIndex: number, index: number): void; - setHoverStyle(element: TElement, datasetIndex: number, index: number): void; - - parse(start: number, count: number): void; - protected parsePrimitiveData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; - protected parseArrayData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; - protected parseObjectData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; - protected getParsed(index: number): TParsedData; - protected applyStack(scale: Scale, parsed: unknown[]): number; - protected updateRangeFromParsed( - range: { min: number; max: number }, - scale: Scale, - parsed: unknown[], - stack: boolean | string - ): void; - protected getMinMax(scale: Scale, canStack?: boolean): { min: number; max: number }; -} - -export interface DatasetControllerChartComponent extends ChartComponent { - defaults: { - datasetElementType?: string | null | false; - dataElementType?: string | null | false; - }; -} - -export interface Defaults extends CoreChartOptions, ElementChartOptions, PluginChartOptions { - - scale: ScaleOptionsByType; - scales: { - [key in ScaleType]: ScaleOptionsByType; - }; - - set(values: AnyObject): AnyObject; - set(scope: string, values: AnyObject): AnyObject; - get(scope: string): AnyObject; - - describe(scope: string, values: AnyObject): AnyObject; - override(scope: string, values: AnyObject): AnyObject; - - /** - * Routes the named defaults to fallback to another scope/name. - * This routing is useful when those target values, like defaults.color, are changed runtime. - * If the values would be copied, the runtime change would not take effect. By routing, the - * fallback is evaluated at each access, so its always up to date. - * - * Example: - * - * defaults.route('elements.arc', 'backgroundColor', '', 'color') - * - reads the backgroundColor from defaults.color when undefined locally - * - * @param scope Scope this route applies to. - * @param name Property name that should be routed to different namespace when not defined here. - * @param targetScope The namespace where those properties should be routed to. - * Empty string ('') is the root of defaults. - * @param targetName The target name in the target scope the property should be routed to. - */ - route(scope: string, name: string, targetScope: string, targetName: string): void; -} - -export type Overrides = { - [key in ChartType]: - CoreChartOptions & - ElementChartOptions & - PluginChartOptions & - DatasetChartOptions & - ScaleChartOptions & - ChartTypeRegistry[key]['chartOptions']; -} - -export const defaults: Defaults; -export interface InteractionOptions { - axis?: string; - intersect?: boolean; -} - -export interface InteractionItem { - element: Element; - datasetIndex: number; - index: number; -} - -export type InteractionModeFunction = ( - chart: Chart, - e: ChartEvent, - options: InteractionOptions, - useFinalPosition?: boolean -) => InteractionItem[]; - -export interface InteractionModeMap { - /** - * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item - */ - index: InteractionModeFunction; - - /** - * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect is false, we find the nearest item and return the items in that dataset - */ - dataset: InteractionModeFunction; - /** - * Point mode returns all elements that hit test based on the event position - * of the event - */ - point: InteractionModeFunction; - /** - * nearest mode returns the element closest to the point - */ - nearest: InteractionModeFunction; - /** - * x mode returns the elements that hit-test at the current x coordinate - */ - x: InteractionModeFunction; - /** - * y mode returns the elements that hit-test at the current y coordinate - */ - y: InteractionModeFunction; -} - -export type InteractionMode = keyof InteractionModeMap; - -export const Interaction: { - modes: InteractionModeMap; -}; - -export const layouts: { - /** - * Register a box to a chart. - * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title. - * @param {Chart} chart - the chart to use - * @param {LayoutItem} item - the item to add to be laid out - */ - addBox(chart: Chart, item: LayoutItem): void; - - /** - * Remove a layoutItem from a chart - * @param {Chart} chart - the chart to remove the box from - * @param {LayoutItem} layoutItem - the item to remove from the layout - */ - removeBox(chart: Chart, layoutItem: LayoutItem): void; - - /** - * Sets (or updates) options on the given `item`. - * @param {Chart} chart - the chart in which the item lives (or will be added to) - * @param {LayoutItem} item - the item to configure with the given options - * @param options - the new item options. - */ - configure( - chart: Chart, - item: LayoutItem, - options: { fullSize?: number; position?: LayoutPosition; weight?: number } - ): void; - - /** - * Fits boxes of the given chart into the given size by having each box measure itself - * then running a fitting algorithm - * @param {Chart} chart - the chart - * @param {number} width - the width to fit into - * @param {number} height - the height to fit into - */ - update(chart: Chart, width: number, height: number): void; -}; - -export interface Plugin extends ExtendedPlugin { - id: string; - - /** - * @desc Called when plugin is installed for this chart instance. This hook is also invoked for disabled plugins (options === false). - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @since 3.0.0 - */ - install?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called when a plugin is starting. This happens when chart is created or plugin is enabled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @since 3.0.0 - */ - start?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called when a plugin stopping. This happens when chart is destroyed or plugin is disabled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @since 3.0.0 - */ - stop?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before initializing `chart`. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - beforeInit?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called after `chart` has been initialized and before the first update. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterInit?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before updating `chart`. If any plugin returns `false`, the update - * is cancelled (and thus subsequent render(s)) until another `update` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {UpdateMode} args.mode - The update mode - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart update. - */ - beforeUpdate?(chart: Chart, args: { mode: UpdateMode, cancelable: true }, options: O): boolean | void; - /** - * @desc Called after `chart` has been updated and before rendering. Note that this - * hook will not be called if the chart update has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {UpdateMode} args.mode - The update mode - * @param {object} options - The plugin options. - */ - afterUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): void; - /** - * @desc Called during the update process, before any chart elements have been created. - * This can be used for data decimation by changing the data array inside a dataset. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - beforeElementsUpdate?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called during chart reset - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @since version 3.0.0 - */ - reset?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before updating the `chart` datasets. If any plugin returns `false`, - * the datasets update is cancelled until another `update` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {UpdateMode} args.mode - The update mode. - * @param {object} options - The plugin options. - * @returns {boolean} false to cancel the datasets update. - * @since version 2.1.5 - */ - beforeDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): boolean | void; - /** - * @desc Called after the `chart` datasets have been updated. Note that this hook - * will not be called if the datasets update has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {UpdateMode} args.mode - The update mode. - * @param {object} options - The plugin options. - * @since version 2.1.5 - */ - afterDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode, cancelable: true }, options: O): void; - /** - * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin - * returns `false`, the datasets update is cancelled until another `update` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {number} args.index - The dataset index. - * @param {object} args.meta - The dataset metadata. - * @param {UpdateMode} args.mode - The update mode. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart datasets drawing. - */ - beforeDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode, cancelable: true }, options: O): boolean | void; - /** - * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note - * that this hook will not be called if the datasets update has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {number} args.index - The dataset index. - * @param {object} args.meta - The dataset metadata. - * @param {UpdateMode} args.mode - The update mode. - * @param {object} options - The plugin options. - */ - afterDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode, cancelable: false }, options: O): void; - /** - * @desc Called before laying out `chart`. If any plugin returns `false`, - * the layout update is cancelled until another `update` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart layout. - */ - beforeLayout?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; - /** - * @desc Called before scale data limits are calculated. This hook is called separately for each scale in the chart. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Scale} args.scale - The scale. - * @param {object} options - The plugin options. - */ - beforeDataLimits?(chart: Chart, args: { scale: Scale }, options: O): void; - /** - * @desc Called after scale data limits are calculated. This hook is called separately for each scale in the chart. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Scale} args.scale - The scale. - * @param {object} options - The plugin options. - */ - afterDataLimits?(chart: Chart, args: { scale: Scale }, options: O): void; - /** - * @desc Called before scale builds its ticks. This hook is called separately for each scale in the chart. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Scale} args.scale - The scale. - * @param {object} options - The plugin options. - */ - beforeBuildTicks?(chart: Chart, args: { scale: Scale }, options: O): void; - /** - * @desc Called after scale has build its ticks. This hook is called separately for each scale in the chart. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Scale} args.scale - The scale. - * @param {object} options - The plugin options. - */ - afterBuildTicks?(chart: Chart, args: { scale: Scale }, options: O): void; - /** - * @desc Called after the `chart` has been laid out. Note that this hook will not - * be called if the layout update has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterLayout?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before rendering `chart`. If any plugin returns `false`, - * the rendering is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart rendering. - */ - beforeRender?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; - /** - * @desc Called after the `chart` has been fully rendered (and animation completed). Note - * that this hook will not be called if the rendering has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterRender?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before drawing `chart` at every animation frame. If any plugin returns `false`, - * the frame drawing is cancelled untilanother `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart drawing. - */ - beforeDraw?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; - /** - * @desc Called after the `chart` has been drawn. Note that this hook will not be called - * if the drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterDraw?(chart: Chart, args: EmptyObject, options: O): void; - /** - * @desc Called before drawing the `chart` datasets. If any plugin returns `false`, - * the datasets drawing is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart datasets drawing. - */ - beforeDatasetsDraw?(chart: Chart, args: { cancelable: true }, options: O): boolean | void; - /** - * @desc Called after the `chart` datasets have been drawn. Note that this hook - * will not be called if the datasets drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterDatasetsDraw?(chart: Chart, args: EmptyObject, options: O, cancelable: false): void; - /** - * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets - * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing - * is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {number} args.index - The dataset index. - * @param {object} args.meta - The dataset metadata. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart datasets drawing. - */ - beforeDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): boolean | void; - /** - * @desc Called after the `chart` datasets at the given `args.index` have been drawn - * (datasets are drawn in the reverse order). Note that this hook will not be called - * if the datasets drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {number} args.index - The dataset index. - * @param {object} args.meta - The dataset metadata. - * @param {object} options - The plugin options. - */ - afterDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): void; - /** - * @desc Called before processing the specified `event`. If any plugin returns `false`, - * the event will be discarded. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {ChartEvent} args.event - The event object. - * @param {boolean} args.replay - True if this event is replayed from `Chart.update` - * @param {boolean} args.inChartArea - The event position is inside chartArea - * @param {object} options - The plugin options. - */ - beforeEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean, cancelable: true, inChartArea: boolean }, options: O): boolean | void; - /** - * @desc Called after the `event` has been consumed. Note that this hook - * will not be called if the `event` has been previously discarded. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {ChartEvent} args.event - The event object. - * @param {boolean} args.replay - True if this event is replayed from `Chart.update` - * @param {boolean} args.inChartArea - The event position is inside chartArea - * @param {boolean} [args.changed] - Set to true if the plugin needs a render. Should only be changed to true, because this args object is passed through all plugins. - * @param {object} options - The plugin options. - */ - afterEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean, changed?: boolean, cancelable: false, inChartArea: boolean }, options: O): void; - /** - * @desc Called after the chart as been resized. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {number} args.size - The new canvas display size (eq. canvas.style width & height). - * @param {object} options - The plugin options. - */ - resize?(chart: Chart, args: { size: { width: number, height: number } }, options: O): void; - /** - * Called before the chart is being destroyed. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - beforeDestroy?(chart: Chart, args: EmptyObject, options: O): void; - /** - * Called after the chart has been destroyed. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @deprecated since version 3.7.0 in favour of afterDestroy - */ - destroy?(chart: Chart, args: EmptyObject, options: O): void; - /** - * Called after the chart has been destroyed. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - */ - afterDestroy?(chart: Chart, args: EmptyObject, options: O): void; - /** - * Called after chart is destroyed on all plugins that were installed for that chart. This hook is also invoked for disabled plugins (options === false). - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {object} options - The plugin options. - * @since 3.0.0 - */ - uninstall?(chart: Chart, args: EmptyObject, options: O): void; -} - -export declare type ChartComponentLike = ChartComponent | ChartComponent[] | { [key: string]: ChartComponent } | Plugin | Plugin[]; - -/** - * Please use the module's default export which provides a singleton instance - * Note: class is exported for typedoc - */ -export interface Registry { - readonly controllers: TypedRegistry; - readonly elements: TypedRegistry; - readonly plugins: TypedRegistry; - readonly scales: TypedRegistry; - - add(...args: ChartComponentLike[]): void; - remove(...args: ChartComponentLike[]): void; - - addControllers(...args: ChartComponentLike[]): void; - addElements(...args: ChartComponentLike[]): void; - addPlugins(...args: ChartComponentLike[]): void; - addScales(...args: ChartComponentLike[]): void; - - getController(id: string): DatasetController | undefined; - getElement(id: string): Element | undefined; - getPlugin(id: string): Plugin | undefined; - getScale(id: string): Scale | undefined; -} - -export const registry: Registry; - -export interface Tick { - value: number; - label?: string | string[]; - major?: boolean; -} - -export interface CoreScaleOptions { - /** - * Controls the axis global visibility (visible when true, hidden when false). When display: 'auto', the axis is visible only if at least one associated dataset is visible. - * @default true - */ - display: boolean | 'auto'; - /** - * Align pixel values to device pixels - */ - alignToPixels: boolean; - /** - * Reverse the scale. - * @default false - */ - reverse: boolean; - /** - * The weight used to sort the axis. Higher weights are further away from the chart area. - * @default true - */ - weight: number; - /** - * Callback called before the update process starts. - */ - beforeUpdate(axis: Scale): void; - /** - * Callback that runs before dimensions are set. - */ - beforeSetDimensions(axis: Scale): void; - /** - * Callback that runs after dimensions are set. - */ - afterSetDimensions(axis: Scale): void; - /** - * Callback that runs before data limits are determined. - */ - beforeDataLimits(axis: Scale): void; - /** - * Callback that runs after data limits are determined. - */ - afterDataLimits(axis: Scale): void; - /** - * Callback that runs before ticks are created. - */ - beforeBuildTicks(axis: Scale): void; - /** - * Callback that runs after ticks are created. Useful for filtering ticks. - */ - afterBuildTicks(axis: Scale): void; - /** - * Callback that runs before ticks are converted into strings. - */ - beforeTickToLabelConversion(axis: Scale): void; - /** - * Callback that runs after ticks are converted into strings. - */ - afterTickToLabelConversion(axis: Scale): void; - /** - * Callback that runs before tick rotation is determined. - */ - beforeCalculateLabelRotation(axis: Scale): void; - /** - * Callback that runs after tick rotation is determined. - */ - afterCalculateLabelRotation(axis: Scale): void; - /** - * Callback that runs before the scale fits to the canvas. - */ - beforeFit(axis: Scale): void; - /** - * Callback that runs after the scale fits to the canvas. - */ - afterFit(axis: Scale): void; - /** - * Callback that runs at the end of the update process. - */ - afterUpdate(axis: Scale): void; -} - -export interface Scale extends Element, LayoutItem { - readonly id: string; - readonly type: string; - readonly ctx: CanvasRenderingContext2D; - readonly chart: Chart; - - maxWidth: number; - maxHeight: number; - - paddingTop: number; - paddingBottom: number; - paddingLeft: number; - paddingRight: number; - - axis: string; - labelRotation: number; - min: number; - max: number; - ticks: Tick[]; - getMatchingVisibleMetas(type?: string): ChartMeta[]; - - drawTitle(chartArea: ChartArea): void; - drawLabels(chartArea: ChartArea): void; - drawGrid(chartArea: ChartArea): void; - - /** - * @param {number} pixel - * @return {number} - */ - getDecimalForPixel(pixel: number): number; - /** - * Utility for getting the pixel location of a percentage of scale - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param {number} decimal - * @return {number} - */ - getPixelForDecimal(decimal: number): number; - /** - * Returns the location of the tick at the given index - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param {number} index - * @return {number} - */ - getPixelForTick(index: number): number; - /** - * Used to get the label to display in the tooltip for the given value - * @param {*} value - * @return {string} - */ - getLabelForValue(value: number): string; - - /** - * Returns the grid line width at given value - */ - getLineWidthForValue(value: number): number; - - /** - * Returns the location of the given data point. Value can either be an index or a numerical value - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param {*} value - * @param {number} [index] - * @return {number} - */ - getPixelForValue(value: number, index?: number): number; - - /** - * Used to get the data value from a given pixel. This is the inverse of getPixelForValue - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param {number} pixel - * @return {*} - */ - getValueForPixel(pixel: number): number | undefined; - - getBaseValue(): number; - /** - * Returns the pixel for the minimum chart value - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @return {number} - */ - getBasePixel(): number; - - init(options: O): void; - parse(raw: unknown, index: number): unknown; - getUserBounds(): { min: number; max: number; minDefined: boolean; maxDefined: boolean }; - getMinMax(canStack: boolean): { min: number; max: number }; - getTicks(): Tick[]; - getLabels(): string[]; - beforeUpdate(): void; - configure(): void; - afterUpdate(): void; - beforeSetDimensions(): void; - setDimensions(): void; - afterSetDimensions(): void; - beforeDataLimits(): void; - determineDataLimits(): void; - afterDataLimits(): void; - beforeBuildTicks(): void; - buildTicks(): Tick[]; - afterBuildTicks(): void; - beforeTickToLabelConversion(): void; - generateTickLabels(ticks: Tick[]): void; - afterTickToLabelConversion(): void; - beforeCalculateLabelRotation(): void; - calculateLabelRotation(): void; - afterCalculateLabelRotation(): void; - beforeFit(): void; - fit(): void; - afterFit(): void; - - isFullSize(): boolean; -} -export declare class Scale { - constructor(cfg: {id: string, type: string, ctx: CanvasRenderingContext2D, chart: Chart}); -} - -export interface ScriptableScaleContext { - chart: Chart; - scale: Scale; - index: number; - tick: Tick; -} - -export interface ScriptableScalePointLabelContext { - chart: Chart; - scale: Scale; - index: number; - label: string; -} - - -export const Ticks: { - formatters: { - /** - * Formatter for value labels - * @param value the value to display - * @return {string|string[]} the label to display - */ - values(value: unknown): string | string[]; - /** - * Formatter for numeric ticks - * @param tickValue the value to be formatted - * @param index the position of the tickValue parameter in the ticks array - * @param ticks the list of ticks being converted - * @return string representation of the tickValue parameter - */ - numeric(tickValue: number, index: number, ticks: { value: number }[]): string; - /** - * Formatter for logarithmic ticks - * @param tickValue the value to be formatted - * @param index the position of the tickValue parameter in the ticks array - * @param ticks the list of ticks being converted - * @return string representation of the tickValue parameter - */ - logarithmic(tickValue: number, index: number, ticks: { value: number }[]): string; - }; -}; - -export interface TypedRegistry { - /** - * @param {ChartComponent} item - * @returns {string} The scope where items defaults were registered to. - */ - register(item: ChartComponent): string; - get(id: string): T | undefined; - unregister(item: ChartComponent): void; -} - -export interface ChartEvent { - type: - | 'contextmenu' - | 'mouseenter' - | 'mousedown' - | 'mousemove' - | 'mouseup' - | 'mouseout' - | 'click' - | 'dblclick' - | 'keydown' - | 'keypress' - | 'keyup' - | 'resize'; - native: Event | null; - x: number | null; - y: number | null; -} -export interface ChartComponent { - id: string; - defaults?: AnyObject; - defaultRoutes?: { [property: string]: string }; - - beforeRegister?(): void; - afterRegister?(): void; - beforeUnregister?(): void; - afterUnregister?(): void; -} - -export interface CoreInteractionOptions { - /** - * Sets which elements appear in the tooltip. See Interaction Modes for details. - * @default 'nearest' - */ - mode: InteractionMode; - /** - * if true, the hover mode only applies when the mouse position intersects an item on the chart. - * @default true - */ - intersect: boolean; - - /** - * Can be set to 'x', 'y', 'xy' or 'r' to define which directions are used in calculating distances. Defaults to 'x' for 'index' mode and 'xy' in dataset and 'nearest' modes. - */ - axis: 'x' | 'y' | 'xy' | 'r'; -} - -export interface CoreChartOptions extends ParsingOptions, AnimationOptions { - - datasets: { - [key in ChartType]: ChartTypeRegistry[key]['datasetOptions'] - } - - /** - * The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts. - * @default 'x' - */ - indexAxis: 'x' | 'y'; - - /** - * base color - * @see Defaults.color - */ - color: Scriptable>; - /** - * base background color - * @see Defaults.backgroundColor - */ - backgroundColor: Scriptable>; - /** - * base border color - * @see Defaults.borderColor - */ - borderColor: Scriptable>; - /** - * base font - * @see Defaults.font - */ - font: Partial; - /** - * Resizes the chart canvas when its container does (important note...). - * @default true - */ - responsive: boolean; - /** - * Maintain the original canvas aspect ratio (width / height) when resizing. - * @default true - */ - maintainAspectRatio: boolean; - /** - * Delay the resize update by give amount of milliseconds. This can ease the resize process by debouncing update of the elements. - * @default 0 - */ - resizeDelay: number; - - /** - * Canvas aspect ratio (i.e. width / height, a value of 1 representing a square canvas). Note that this option is ignored if the height is explicitly defined either as attribute or via the style. - * @default 2 - */ - aspectRatio: number; - - /** - * Locale used for number formatting (using `Intl.NumberFormat`). - * @default user's browser setting - */ - locale: string; - - /** - * Called when a resize occurs. Gets passed two arguments: the chart instance and the new size. - */ - onResize(chart: Chart, size: { width: number; height: number }): void; - - /** - * Override the window's default devicePixelRatio. - * @default window.devicePixelRatio - */ - devicePixelRatio: number; - - interaction: CoreInteractionOptions; - - hover: CoreInteractionOptions; - - /** - * The events option defines the browser events that the chart should listen to for tooltips and hovering. - * @default ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'] - */ - events: (keyof HTMLElementEventMap)[] - - /** - * Called when any of the events fire. Passed the event, an array of active elements (bars, points, etc), and the chart. - */ - onHover(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; - - /** - * Called if the event is of type 'mouseup' or 'click'. Passed the event, an array of active elements, and the chart. - */ - onClick(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; - - layout: Partial<{ - autoPadding: boolean; - padding: Scriptable, ScriptableContext>; - }>; -} - -export type EasingFunction = - | 'linear' - | 'easeInQuad' - | 'easeOutQuad' - | 'easeInOutQuad' - | 'easeInCubic' - | 'easeOutCubic' - | 'easeInOutCubic' - | 'easeInQuart' - | 'easeOutQuart' - | 'easeInOutQuart' - | 'easeInQuint' - | 'easeOutQuint' - | 'easeInOutQuint' - | 'easeInSine' - | 'easeOutSine' - | 'easeInOutSine' - | 'easeInExpo' - | 'easeOutExpo' - | 'easeInOutExpo' - | 'easeInCirc' - | 'easeOutCirc' - | 'easeInOutCirc' - | 'easeInElastic' - | 'easeOutElastic' - | 'easeInOutElastic' - | 'easeInBack' - | 'easeOutBack' - | 'easeInOutBack' - | 'easeInBounce' - | 'easeOutBounce' - | 'easeInOutBounce'; - -export type AnimationSpec = { - /** - * The number of milliseconds an animation takes. - * @default 1000 - */ - duration?: Scriptable>; - /** - * Easing function to use - * @default 'easeOutQuart' - */ - easing?: Scriptable>; - - /** - * Delay before starting the animations. - * @default 0 - */ - delay?: Scriptable>; - - /** - * If set to true, the animations loop endlessly. - * @default false - */ - loop?: Scriptable>; -} - -export type AnimationsSpec = { - [name: string]: false | AnimationSpec & { - properties: string[]; - - /** - * Type of property, determines the interpolator used. Possible values: 'number', 'color' and 'boolean'. Only really needed for 'color', because typeof does not get that right. - */ - type: 'color' | 'number' | 'boolean'; - - fn: (from: T, to: T, factor: number) => T; - - /** - * Start value for the animation. Current value is used when undefined - */ - from: Scriptable>; - /** - * - */ - to: Scriptable>; - } -} - -export type TransitionSpec = { - animation: AnimationSpec; - animations: AnimationsSpec; -} - -export type TransitionsSpec = { - [mode: string]: TransitionSpec -} - -export type AnimationOptions = { - animation: false | AnimationSpec & { - /** - * Callback called on each step of an animation. - */ - onProgress?: (this: Chart, event: AnimationEvent) => void; - /** - * Callback called when all animations are completed. - */ - onComplete?: (this: Chart, event: AnimationEvent) => void; - }; - animations: AnimationsSpec; - transitions: TransitionsSpec; -}; - -export interface FontSpec { - /** - * Default font family for all text, follows CSS font-family options. - * @default "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" - */ - family: string; - /** - * Default font size (in px) for text. Does not apply to radialLinear scale point labels. - * @default 12 - */ - size: number; - /** - * Default font style. Does not apply to tooltip title or footer. Does not apply to chart title. Follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit) - * @default 'normal' - */ - style: 'normal' | 'italic' | 'oblique' | 'initial' | 'inherit'; - /** - * Default font weight (boldness). (see MDN). - */ - weight: string | null; - /** - * Height of an individual line of text (see MDN). - * @default 1.2 - */ - lineHeight: number | string; -} - -export type TextAlign = 'left' | 'center' | 'right'; -export type Align = 'start' | 'center' | 'end'; - -export interface VisualElement { - draw(ctx: CanvasRenderingContext2D, area?: ChartArea): void; - inRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean; - inXRange(mouseX: number, useFinalPosition?: boolean): boolean; - inYRange(mouseY: number, useFinalPosition?: boolean): boolean; - getCenterPoint(useFinalPosition?: boolean): { x: number; y: number }; - getRange?(axis: 'x' | 'y'): number; -} - -export interface CommonElementOptions { - borderWidth: number; - borderColor: Color; - backgroundColor: Color; -} - -export interface CommonHoverOptions { - hoverBorderWidth: number; - hoverBorderColor: Color; - hoverBackgroundColor: Color; -} - -export interface Segment { - start: number; - end: number; - loop: boolean; -} - -export interface ArcProps { - x: number; - y: number; - startAngle: number; - endAngle: number; - innerRadius: number; - outerRadius: number; - circumference: number; -} - -export interface ArcBorderRadius { - outerStart: number; - outerEnd: number; - innerStart: number; - innerEnd: number; -} - -export interface ArcOptions extends CommonElementOptions { - /** - * Arc stroke alignment. - */ - borderAlign: 'center' | 'inner'; - - /** - * Line join style. See MDN. Default is 'round' when `borderAlign` is 'inner', else 'bevel'. - */ - borderJoinStyle: CanvasLineJoin; - - /** - * Sets the border radius for arcs - * @default 0 - */ - borderRadius: number | ArcBorderRadius; - - /** - * Arc offset (in pixels). - */ - offset: number; -} - -export interface ArcHoverOptions extends CommonHoverOptions { - hoverOffset: number; -} - -export interface ArcElement - extends Element, - VisualElement {} - -export const ArcElement: ChartComponent & { - prototype: ArcElement; - new (cfg: AnyObject): ArcElement; -}; - -export interface LineProps { - points: Point[] -} - -export interface LineOptions extends CommonElementOptions { - /** - * Line cap style. See MDN. - * @default 'butt' - */ - borderCapStyle: CanvasLineCap; - /** - * Line dash. See MDN. - * @default [] - */ - borderDash: number[]; - /** - * Line dash offset. See MDN. - * @default 0.0 - */ - borderDashOffset: number; - /** - * Line join style. See MDN. - * @default 'miter' - */ - borderJoinStyle: CanvasLineJoin; - /** - * true to keep BΓ©zier control inside the chart, false for no restriction. - * @default true - */ - capBezierPoints: boolean; - /** - * Interpolation mode to apply. - * @default 'default' - */ - cubicInterpolationMode: 'default' | 'monotone'; - /** - * BΓ©zier curve tension (0 for no BΓ©zier curves). - * @default 0 - */ - tension: number; - /** - * true to show the line as a stepped line (tension will be ignored). - * @default false - */ - stepped: 'before' | 'after' | 'middle' | boolean; - /** - * Both line and radar charts support a fill option on the dataset object which can be used to create area between two datasets or a dataset and a boundary, i.e. the scale origin, start or end - */ - fill: FillTarget | ComplexFillTarget; - /** - * If true, lines will be drawn between points with no or null data. If false, points with NaN data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used. - */ - spanGaps: boolean | number; - - segment: { - backgroundColor: Scriptable, - borderColor: Scriptable, - borderCapStyle: Scriptable; - borderDash: Scriptable; - borderDashOffset: Scriptable; - borderJoinStyle: Scriptable; - borderWidth: Scriptable; - }; -} - -export interface LineHoverOptions extends CommonHoverOptions { - hoverBorderCapStyle: CanvasLineCap; - hoverBorderDash: number[]; - hoverBorderDashOffset: number; - hoverBorderJoinStyle: CanvasLineJoin; -} - -export interface LineElement - extends Element, - VisualElement { - updateControlPoints(chartArea: ChartArea, indexAxis?: 'x' | 'y'): void; - points: Point[]; - readonly segments: Segment[]; - first(): Point | false; - last(): Point | false; - interpolate(point: Point, property: 'x' | 'y'): undefined | Point | Point[]; - pathSegment(ctx: CanvasRenderingContext2D, segment: Segment, params: AnyObject): undefined | boolean; - path(ctx: CanvasRenderingContext2D): boolean; -} - -export const LineElement: ChartComponent & { - prototype: LineElement; - new (cfg: AnyObject): LineElement; -}; - -export interface PointProps { - x: number; - y: number; -} - -export type PointStyle = - | 'circle' - | 'cross' - | 'crossRot' - | 'dash' - | 'line' - | 'rect' - | 'rectRounded' - | 'rectRot' - | 'star' - | 'triangle' - | HTMLImageElement - | HTMLCanvasElement; - -export interface PointOptions extends CommonElementOptions { - /** - * Point radius - * @default 3 - */ - radius: number; - /** - * Extra radius added to point radius for hit detection. - * @default 1 - */ - hitRadius: number; - /** - * Point style - * @default 'circle; - */ - pointStyle: PointStyle; - /** - * Point rotation (in degrees). - * @default 0 - */ - rotation: number; - /** - * Draw the active elements over the other elements of the dataset, - * @default true - */ - drawActiveElementsOnTop: boolean; -} - -export interface PointHoverOptions extends CommonHoverOptions { - /** - * Point radius when hovered. - * @default 4 - */ - hoverRadius: number; -} - -export interface PointPrefixedOptions { - /** - * The fill color for points. - */ - pointBackgroundColor: Color; - /** - * The border color for points. - */ - pointBorderColor: Color; - /** - * The width of the point border in pixels. - */ - pointBorderWidth: number; - /** - * The pixel size of the non-displayed point that reacts to mouse events. - */ - pointHitRadius: number; - /** - * The radius of the point shape. If set to 0, the point is not rendered. - */ - pointRadius: number; - /** - * The rotation of the point in degrees. - */ - pointRotation: number; - /** - * Style of the point. - */ - pointStyle: PointStyle; -} - -export interface PointPrefixedHoverOptions { - /** - * Point background color when hovered. - */ - pointHoverBackgroundColor: Color; - /** - * Point border color when hovered. - */ - pointHoverBorderColor: Color; - /** - * Border width of point when hovered. - */ - pointHoverBorderWidth: number; - /** - * The radius of the point when hovered. - */ - pointHoverRadius: number; -} - -export interface PointElement - extends Element, - VisualElement { - readonly skip: boolean; - readonly parsed: CartesianParsedData; -} - -export const PointElement: ChartComponent & { - prototype: PointElement; - new (cfg: AnyObject): PointElement; -}; - -export interface BarProps { - x: number; - y: number; - base: number; - horizontal: boolean; - width: number; - height: number; -} - -export interface BarOptions extends Omit { - /** - * The base value for the bar in data units along the value axis. - */ - base: number; - - /** - * Skipped (excluded) border: 'start', 'end', 'left', 'right', 'bottom', 'top' or false (none). - * @default 'start' - */ - borderSkipped: 'start' | 'end' | 'left' | 'right' | 'bottom' | 'top' | false; - - /** - * Border radius - * @default 0 - */ - borderRadius: number | BorderRadius; - - /** - * Amount to inflate the rectangle(s). This can be used to hide artifacts between bars. - * Unit is pixels. 'auto' translates to 0.33 pixels when barPercentage * categoryPercentage is 1, else 0. - * @default 'auto' - */ - inflateAmount: number | 'auto'; - - /** - * Width of the border, number for all sides, object to specify width for each side specifically - * @default 0 - */ - borderWidth: number | { top?: number, right?: number, bottom?: number, left?: number }; -} - -export interface BorderRadius { - topLeft: number; - topRight: number; - bottomLeft: number; - bottomRight: number; -} - -export interface BarHoverOptions extends CommonHoverOptions { - hoverBorderRadius: number | BorderRadius; -} - -export interface BarElement< - T extends BarProps = BarProps, - O extends BarOptions = BarOptions -> extends Element, VisualElement {} - -export const BarElement: ChartComponent & { - prototype: BarElement; - new (cfg: AnyObject): BarElement; -}; - -export interface ElementOptionsByType { - arc: ScriptableAndArrayOptions>; - bar: ScriptableAndArrayOptions>; - line: ScriptableAndArrayOptions>; - point: ScriptableAndArrayOptions>; -} - -export type ElementChartOptions = { - elements: ElementOptionsByType -}; - -export class BasePlatform { - /** - * Called at chart construction time, returns a context2d instance implementing - * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}. - * @param {HTMLCanvasElement} canvas - The canvas from which to acquire context (platform specific) - * @param options - The chart options - */ - acquireContext( - canvas: HTMLCanvasElement, - options?: CanvasRenderingContext2DSettings - ): CanvasRenderingContext2D | null; - /** - * Called at chart destruction time, releases any resources associated to the context - * previously returned by the acquireContext() method. - * @param {CanvasRenderingContext2D} context - The context2d instance - * @returns {boolean} true if the method succeeded, else false - */ - releaseContext(context: CanvasRenderingContext2D): boolean; - /** - * Registers the specified listener on the given chart. - * @param {Chart} chart - Chart from which to listen for event - * @param {string} type - The ({@link ChartEvent}) type to listen for - * @param listener - Receives a notification (an object that implements - * the {@link ChartEvent} interface) when an event of the specified type occurs. - */ - addEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void; - /** - * Removes the specified listener previously registered with addEventListener. - * @param {Chart} chart - Chart from which to remove the listener - * @param {string} type - The ({@link ChartEvent}) type to remove - * @param listener - The listener function to remove from the event target. - */ - removeEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void; - /** - * @returns {number} the current devicePixelRatio of the device this platform is connected to. - */ - getDevicePixelRatio(): number; - /** - * @param {HTMLCanvasElement} canvas - The canvas for which to calculate the maximum size - * @param {number} [width] - Parent element's content width - * @param {number} [height] - Parent element's content height - * @param {number} [aspectRatio] - The aspect ratio to maintain - * @returns { width: number, height: number } the maximum size available. - */ - getMaximumSize(canvas: HTMLCanvasElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number }; - /** - * @param {HTMLCanvasElement} canvas - * @returns {boolean} true if the canvas is attached to the platform, false if not. - */ - isAttached(canvas: HTMLCanvasElement): boolean; - /** - * Updates config with platform specific requirements - * @param {ChartConfiguration} config - */ - updateConfig(config: ChartConfiguration): void; -} - -export class BasicPlatform extends BasePlatform {} -export class DomPlatform extends BasePlatform {} - -export const Decimation: Plugin; - -export const enum DecimationAlgorithm { - lttb = 'lttb', - minmax = 'min-max', -} -interface BaseDecimationOptions { - enabled: boolean; - threshold?: number; -} - -interface LttbDecimationOptions extends BaseDecimationOptions { - algorithm: DecimationAlgorithm.lttb | 'lttb'; - samples?: number; -} - -interface MinMaxDecimationOptions extends BaseDecimationOptions { - algorithm: DecimationAlgorithm.minmax | 'min-max'; -} - -export type DecimationOptions = LttbDecimationOptions | MinMaxDecimationOptions; - -export const Filler: Plugin; -export interface FillerOptions { - drawTime: 'beforeDatasetDraw' | 'beforeDatasetsDraw'; - propagate: boolean; -} - -export type FillTarget = number | string | { value: number } | 'start' | 'end' | 'origin' | 'stack' | 'shape' | boolean; - -export interface ComplexFillTarget { - /** - * The accepted values are the same as the filling mode values, so you may use absolute and relative dataset indexes and/or boundaries. - */ - target: FillTarget; - /** - * If no color is set, the default color will be the background color of the chart. - */ - above: Color; - /** - * Same as the above. - */ - below: Color; -} - -export interface FillerControllerDatasetOptions { - /** - * Both line and radar charts support a fill option on the dataset object which can be used to create area between two datasets or a dataset and a boundary, i.e. the scale origin, start or end - */ - fill: FillTarget | ComplexFillTarget; -} - -export const Legend: Plugin; - -export interface LegendItem { - /** - * Label that will be displayed - */ - text: string; - - /** - * Border radius of the legend box - * @since 3.1.0 - */ - borderRadius?: number | BorderRadius; - - /** - * Index of the associated dataset - */ - datasetIndex: number; - - /** - * Fill style of the legend box - */ - fillStyle?: Color; - - /** - * Font color for the text - * Defaults to LegendOptions.labels.color - */ - fontColor?: Color; - - /** - * If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect - */ - hidden?: boolean; - - /** - * For box border. - * @see https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap - */ - lineCap?: CanvasLineCap; - - /** - * For box border. - * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash - */ - lineDash?: number[]; - - /** - * For box border. - * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset - */ - lineDashOffset?: number; - - /** - * For box border. - * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin - */ - lineJoin?: CanvasLineJoin; - - /** - * Width of box border - */ - lineWidth?: number; - - /** - * Stroke style of the legend box - */ - strokeStyle?: Color; - - /** - * Point style of the legend box (only used if usePointStyle is true) - */ - pointStyle?: PointStyle; - - /** - * Rotation of the point in degrees (only used if usePointStyle is true) - */ - rotation?: number; - - /** - * Text alignment - */ - textAlign?: TextAlign; -} - -export interface LegendElement extends Element>, LayoutItem { - chart: Chart; - ctx: CanvasRenderingContext2D; - legendItems?: LegendItem[]; - options: LegendOptions; -} - -export interface LegendOptions { - /** - * Is the legend shown? - * @default true - */ - display: boolean; - /** - * Position of the legend. - * @default 'top' - */ - position: LayoutPosition; - /** - * Alignment of the legend. - * @default 'center' - */ - align: Align; - /** - * Maximum height of the legend, in pixels - */ - maxHeight: number; - /** - * Maximum width of the legend, in pixels - */ - maxWidth: number; - /** - * Marks that this box should take the full width/height of the canvas (moving other boxes). This is unlikely to need to be changed in day-to-day use. - * @default true - */ - fullSize: boolean; - /** - * Legend will show datasets in reverse order. - * @default false - */ - reverse: boolean; - /** - * A callback that is called when a click event is registered on a label item. - */ - onClick(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; - /** - * A callback that is called when a 'mousemove' event is registered on top of a label item - */ - onHover(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; - /** - * A callback that is called when a 'mousemove' event is registered outside of a previously hovered label item. - */ - onLeave(this: LegendElement, e: ChartEvent, legendItem: LegendItem, legend: LegendElement): void; - - labels: { - /** - * Width of colored box. - * @default 40 - */ - boxWidth: number; - /** - * Height of the coloured box. - * @default fontSize - */ - boxHeight: number; - /** - * Padding between the color box and the text - * @default 1 - */ - boxPadding: number; - /** - * Color of label - * @see Defaults.color - */ - color: Color; - /** - * Font of label - * @see Defaults.font - */ - font: FontSpec; - /** - * Padding between rows of colored boxes. - * @default 10 - */ - padding: number; - /** - * Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See Legend Item for details. - */ - generateLabels(chart: Chart): LegendItem[]; - - /** - * Filters legend items out of the legend. Receives 2 parameters, a Legend Item and the chart data - */ - filter(item: LegendItem, data: ChartData): boolean; - - /** - * Sorts the legend items - */ - sort(a: LegendItem, b: LegendItem, data: ChartData): number; - - /** - * Override point style for the legend. Only applies if usePointStyle is true - */ - pointStyle: PointStyle; - - /** - * Text alignment - */ - textAlign?: TextAlign; - - /** - * Label style will match corresponding point style (size is based on the minimum value between boxWidth and font.size). - * @default false - */ - usePointStyle: boolean; - }; - /** - * true for rendering the legends from right to left. - */ - rtl: boolean; - /** - * This will force the text direction 'rtl' or 'ltr' on the canvas for rendering the legend, regardless of the css specified on the canvas - * @default canvas' default - */ - textDirection: string; - - title: { - /** - * Is the legend title displayed. - * @default false - */ - display: boolean; - /** - * Color of title - * @see Defaults.color - */ - color: Color; - /** - * see Fonts - */ - font: FontSpec; - position: 'center' | 'start' | 'end'; - padding?: number | ChartArea; - /** - * The string title. - */ - text: string; - }; -} - -export const SubTitle: Plugin; -export const Title: Plugin; - -export interface TitleOptions { - /** - * Alignment of the title. - * @default 'center' - */ - align: Align; - /** - * Is the title shown? - * @default false - */ - display: boolean; - /** - * Position of title - * @default 'top' - */ - position: 'top' | 'left' | 'bottom' | 'right'; - /** - * Color of text - * @see Defaults.color - */ - color: Color; - font: FontSpec; - - /** - * Marks that this box should take the full width/height of the canvas (moving other boxes). If set to `false`, places the box above/beside the - * chart area - * @default true - */ - fullSize: boolean; - /** - * Adds padding above and below the title text if a single number is specified. It is also possible to change top and bottom padding separately. - */ - padding: number | { top: number; bottom: number }; - /** - * Title text to display. If specified as an array, text is rendered on multiple lines. - */ - text: string | string[]; -} - -export type TooltipXAlignment = 'left' | 'center' | 'right'; -export type TooltipYAlignment = 'top' | 'center' | 'bottom'; -export interface TooltipLabelStyle { - borderColor: Color; - backgroundColor: Color; - - /** - * Width of border line - * @since 3.1.0 - */ - borderWidth?: number; - - /** - * Border dash - * @since 3.1.0 - */ - borderDash?: [number, number]; - - /** - * Border dash offset - * @since 3.1.0 - */ - borderDashOffset?: number; - - /** - * borderRadius - * @since 3.1.0 - */ - borderRadius?: number | BorderRadius; -} -export interface TooltipModel extends Element> { - readonly chart: Chart; - - // The items that we are rendering in the tooltip. See Tooltip Item Interface section - dataPoints: TooltipItem[]; - - // Positioning - xAlign: TooltipXAlignment; - yAlign: TooltipYAlignment; - - // X and Y properties are the top left of the tooltip - x: number; - y: number; - width: number; - height: number; - // Where the tooltip points to - caretX: number; - caretY: number; - - // Body - // The body lines that need to be rendered - // Each object contains 3 parameters - // before: string[] // lines of text before the line with the color square - // lines: string[]; // lines of text to render as the main item with color square - // after: string[]; // lines of text to render after the main lines - body: { before: string[]; lines: string[]; after: string[] }[]; - // lines of text that appear after the title but before the body - beforeBody: string[]; - // line of text that appear after the body and before the footer - afterBody: string[]; - - // Title - // lines of text that form the title - title: string[]; - - // Footer - // lines of text that form the footer - footer: string[]; - - // Styles to render for each item in body[]. This is the styling of the squares in the tooltip - labelColors: TooltipLabelStyle[]; - labelTextColors: Color[]; - labelPointStyles: { pointStyle: PointStyle; rotation: number }[]; - - // 0 opacity is a hidden tooltip - opacity: number; - - // tooltip options - options: TooltipOptions; - - getActiveElements(): ActiveElement[]; - setActiveElements(active: ActiveDataPoint[], eventPosition: Point): void; -} - -export interface TooltipPosition { - x: number; - y: number; - xAlign?: TooltipXAlignment; - yAlign?: TooltipYAlignment; -} - -export type TooltipPositionerFunction = ( - this: TooltipModel, - items: readonly ActiveElement[], - eventPosition: Point -) => TooltipPosition | false; - -export interface TooltipPositionerMap { - average: TooltipPositionerFunction; - nearest: TooltipPositionerFunction; -} - -export type TooltipPositioner = keyof TooltipPositionerMap; - -export interface Tooltip extends Plugin { - readonly positioners: TooltipPositionerMap; -} - -export const Tooltip: Tooltip; - -export interface TooltipCallbacks< - TType extends ChartType, - Model = TooltipModel, - Item = TooltipItem> { - - beforeTitle(this: Model, tooltipItems: Item[]): string | string[]; - title(this: Model, tooltipItems: Item[]): string | string[]; - afterTitle(this: Model, tooltipItems: Item[]): string | string[]; - - beforeBody(this: Model, tooltipItems: Item[]): string | string[]; - afterBody(this: Model, tooltipItems: Item[]): string | string[]; - - beforeLabel(this: Model, tooltipItem: Item): string | string[]; - label(this: Model, tooltipItem: Item): string | string[]; - afterLabel(this: Model, tooltipItem: Item): string | string[]; - - labelColor(this: Model, tooltipItem: Item): TooltipLabelStyle; - labelTextColor(this: Model, tooltipItem: Item): Color; - labelPointStyle(this: Model, tooltipItem: Item): { pointStyle: PointStyle; rotation: number }; - - beforeFooter(this: Model, tooltipItems: Item[]): string | string[]; - footer(this: Model, tooltipItems: Item[]): string | string[]; - afterFooter(this: Model, tooltipItems: Item[]): string | string[]; -} - -export interface ExtendedPlugin< - TType extends ChartType, - O = AnyObject, - Model = TooltipModel> { - /** - * @desc Called before drawing the `tooltip`. If any plugin returns `false`, - * the tooltip drawing is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Tooltip} args.tooltip - The tooltip. - * @param {object} options - The plugin options. - * @returns {boolean} `false` to cancel the chart tooltip drawing. - */ - beforeTooltipDraw?(chart: Chart, args: { tooltip: Model }, options: O): boolean | void; - /** - * @desc Called after drawing the `tooltip`. Note that this hook will not - * be called if the tooltip drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {object} args - The call arguments. - * @param {Tooltip} args.tooltip - The tooltip. - * @param {object} options - The plugin options. - */ - afterTooltipDraw?(chart: Chart, args: { tooltip: Model }, options: O): void; -} - -export interface ScriptableTooltipContext { - chart: UnionToIntersection>; - tooltip: UnionToIntersection>; - tooltipItems: TooltipItem[]; -} - -export interface TooltipOptions extends CoreInteractionOptions { - /** - * Are on-canvas tooltips enabled? - * @default true - */ - enabled: Scriptable>; - /** - * See external tooltip section. - */ - external(this: TooltipModel, args: { chart: Chart; tooltip: TooltipModel }): void; - /** - * The mode for positioning the tooltip - */ - position: Scriptable> - - /** - * Override the tooltip alignment calculations - */ - xAlign: Scriptable>; - yAlign: Scriptable>; - - /** - * Sort tooltip items. - */ - itemSort: (a: TooltipItem, b: TooltipItem, data: ChartData) => number; - - filter: (e: TooltipItem, index: number, array: TooltipItem[], data: ChartData) => boolean; - - /** - * Background color of the tooltip. - * @default 'rgba(0, 0, 0, 0.8)' - */ - backgroundColor: Scriptable>; - /** - * Padding between the color box and the text. - * @default 1 - */ - boxPadding: number; - /** - * Color of title - * @default '#fff' - */ - titleColor: Scriptable>; - /** - * See Fonts - * @default {weight: 'bold'} - */ - titleFont: Scriptable>; - /** - * Spacing to add to top and bottom of each title line. - * @default 2 - */ - titleSpacing: Scriptable>; - /** - * Margin to add on bottom of title section. - * @default 6 - */ - titleMarginBottom: Scriptable>; - /** - * Horizontal alignment of the title text lines. - * @default 'left' - */ - titleAlign: Scriptable>; - /** - * Spacing to add to top and bottom of each tooltip item. - * @default 2 - */ - bodySpacing: Scriptable>; - /** - * Color of body - * @default '#fff' - */ - bodyColor: Scriptable>; - /** - * See Fonts. - * @default {} - */ - bodyFont: Scriptable>; - /** - * Horizontal alignment of the body text lines. - * @default 'left' - */ - bodyAlign: Scriptable>; - /** - * Spacing to add to top and bottom of each footer line. - * @default 2 - */ - footerSpacing: Scriptable>; - /** - * Margin to add before drawing the footer. - * @default 6 - */ - footerMarginTop: Scriptable>; - /** - * Color of footer - * @default '#fff' - */ - footerColor: Scriptable>; - /** - * See Fonts - * @default {weight: 'bold'} - */ - footerFont: Scriptable>; - /** - * Horizontal alignment of the footer text lines. - * @default 'left' - */ - footerAlign: Scriptable>; - /** - * Padding to add to the tooltip - * @default 6 - */ - padding: Scriptable>; - /** - * Extra distance to move the end of the tooltip arrow away from the tooltip point. - * @default 2 - */ - caretPadding: Scriptable>; - /** - * Size, in px, of the tooltip arrow. - * @default 5 - */ - caretSize: Scriptable>; - /** - * Radius of tooltip corner curves. - * @default 6 - */ - cornerRadius: Scriptable>; - /** - * Color to draw behind the colored boxes when multiple items are in the tooltip. - * @default '#fff' - */ - multiKeyBackground: Scriptable>; - /** - * If true, color boxes are shown in the tooltip. - * @default true - */ - displayColors: Scriptable>; - /** - * Width of the color box if displayColors is true. - * @default bodyFont.size - */ - boxWidth: Scriptable>; - /** - * Height of the color box if displayColors is true. - * @default bodyFont.size - */ - boxHeight: Scriptable>; - /** - * Use the corresponding point style (from dataset options) instead of color boxes, ex: star, triangle etc. (size is based on the minimum value between boxWidth and boxHeight) - * @default false - */ - usePointStyle: Scriptable>; - /** - * Color of the border. - * @default 'rgba(0, 0, 0, 0)' - */ - borderColor: Scriptable>; - /** - * Size of the border. - * @default 0 - */ - borderWidth: Scriptable>; - /** - * true for rendering the legends from right to left. - */ - rtl: Scriptable>; - - /** - * This will force the text direction 'rtl' or 'ltr on the canvas for rendering the tooltips, regardless of the css specified on the canvas - * @default canvas's default - */ - textDirection: Scriptable>; - - animation: AnimationSpec; - animations: AnimationsSpec; - callbacks: TooltipCallbacks; -} - -export interface TooltipItem { - /** - * The chart the tooltip is being shown on - */ - chart: Chart; - - /** - * Label for the tooltip - */ - label: string; - - /** - * Parsed data values for the given `dataIndex` and `datasetIndex` - */ - parsed: UnionToIntersection>; - - /** - * Raw data values for the given `dataIndex` and `datasetIndex` - */ - raw: unknown; - - /** - * Formatted value for the tooltip - */ - formattedValue: string; - - /** - * The dataset the item comes from - */ - dataset: UnionToIntersection>; - - /** - * Index of the dataset the item comes from - */ - datasetIndex: number; - - /** - * Index of this data item in the dataset - */ - dataIndex: number; - - /** - * The chart element (point, arc, bar, etc.) for this tooltip item - */ - element: Element; -} - -export interface PluginOptionsByType { - decimation: DecimationOptions; - filler: FillerOptions; - legend: LegendOptions; - subtitle: TitleOptions; - title: TitleOptions; - tooltip: TooltipOptions; -} -export interface PluginChartOptions { - plugins: PluginOptionsByType; -} - -export interface GridLineOptions { - /** - * @default true - */ - display: boolean; - borderColor: Color; - borderWidth: number; - /** - * @default false - */ - circular: boolean; - /** - * @default 'rgba(0, 0, 0, 0.1)' - */ - color: ScriptableAndArray; - /** - * @default [] - */ - borderDash: number[]; - /** - * @default 0 - */ - borderDashOffset: Scriptable; - /** - * @default 1 - */ - lineWidth: ScriptableAndArray; - - /** - * @default true - */ - drawBorder: boolean; - /** - * @default true - */ - drawOnChartArea: boolean; - /** - * @default true - */ - drawTicks: boolean; - /** - * @default [] - */ - tickBorderDash: number[]; - /** - * @default 0 - */ - tickBorderDashOffset: Scriptable; - /** - * @default 'rgba(0, 0, 0, 0.1)' - */ - tickColor: ScriptableAndArray; - /** - * @default 10 - */ - tickLength: number; - /** - * @default 1 - */ - tickWidth: number; - /** - * @default false - */ - offset: boolean; - /** - * @default 0 - */ - z: number; -} - -export interface TickOptions { - /** - * Color of label backdrops. - * @default 'rgba(255, 255, 255, 0.75)' - */ - backdropColor: Scriptable; - /** - * Padding of tick backdrop. - * @default 2 - */ - backdropPadding: number | ChartArea; - - /** - * Returns the string representation of the tick value as it should be displayed on the chart. See callback. - */ - callback: (this: Scale, tickValue: number | string, index: number, ticks: Tick[]) => string | string[] | number | number[] | null | undefined; - /** - * If true, show tick labels. - * @default true - */ - display: boolean; - /** - * Color of tick - * @see Defaults.color - */ - color: ScriptableAndArray; - /** - * see Fonts - */ - font: Scriptable; - /** - * Sets the offset of the tick labels from the axis - */ - padding: number; - /** - * If true, draw a background behind the tick labels. - * @default false - */ - showLabelBackdrop: Scriptable; - /** - * The color of the stroke around the text. - * @default undefined - */ - textStrokeColor: Scriptable; - /** - * Stroke width around the text. - * @default 0 - */ - textStrokeWidth: Scriptable; - /** - * z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top. - * @default 0 - */ - z: number; - - major: { - /** - * If true, major ticks are generated. A major tick will affect autoskipping and major will be defined on ticks in the scriptable options context. - * @default false - */ - enabled: boolean; - }; -} - -export interface CartesianScaleOptions extends CoreScaleOptions { - /** - * Scale boundary strategy (bypassed by min/max time options) - * - `data`: make sure data are fully visible, ticks outside are removed - * - `ticks`: make sure ticks are fully visible, data outside are truncated - * @since 2.7.0 - * @default 'ticks' - */ - bounds: 'ticks' | 'data'; - - /** - * Position of the axis. - */ - position: 'left' | 'top' | 'right' | 'bottom' | 'center' | { [scale: string]: number }; - - /** - * Stack group. Axes at the same `position` with same `stack` are stacked. - */ - stack?: string; - - /** - * Weight of the scale in stack group. Used to determine the amount of allocated space for the scale within the group. - * @default 1 - */ - stackWeight?: number; - - /** - * Which type of axis this is. Possible values are: 'x', 'y'. If not set, this is inferred from the first character of the ID which should be 'x' or 'y'. - */ - axis: 'x' | 'y'; - - /** - * User defined minimum value for the scale, overrides minimum value from data. - */ - min: number; - - /** - * User defined maximum value for the scale, overrides maximum value from data. - */ - max: number; - - /** - * If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to true for a bar chart by default. - * @default false - */ - offset: boolean; - - grid: GridLineOptions; - - /** Options for the scale title. */ - title: { - /** If true, displays the axis title. */ - display: boolean; - /** Alignment of the axis title. */ - align: Align; - /** The text for the title, e.g. "# of People" or "Response Choices". */ - text: string | string[]; - /** Color of the axis label. */ - color: Color; - /** Information about the axis title font. */ - font: FontSpec; - /** Padding to apply around scale labels. */ - padding: number | { - /** Padding on the (relative) top side of this axis label. */ - top: number; - /** Padding on the (relative) bottom side of this axis label. */ - bottom: number; - /** This is a shorthand for defining top/bottom to the same values. */ - y: number; - }; - }; - - /** - * If true, data will be comprised between datasets of data - * @default false - */ - stacked?: boolean | 'single'; - - ticks: TickOptions & { - /** - * The number of ticks to examine when deciding how many labels will fit. Setting a smaller value will be faster, but may be less accurate when there is large variability in label length. - * @default ticks.length - */ - sampleSize: number; - /** - * The label alignment - * @default 'center' - */ - align: Align; - /** - * If true, automatically calculates how many labels can be shown and hides labels accordingly. Labels will be rotated up to maxRotation before skipping any. Turn autoSkip off to show all labels no matter what. - * @default true - */ - autoSkip: boolean; - /** - * Padding between the ticks on the horizontal axis when autoSkip is enabled. - * @default 0 - */ - autoSkipPadding: number; - - /** - * How is the label positioned perpendicular to the axis direction. - * This only applies when the rotation is 0 and the axis position is one of "top", "left", "right", or "bottom" - * @default 'near' - */ - crossAlign: 'near' | 'center' | 'far'; - - /** - * Should the defined `min` and `max` values be presented as ticks even if they are not "nice". - * @default: true - */ - includeBounds: boolean; - - /** - * Distance in pixels to offset the label from the centre point of the tick (in the x direction for the x axis, and the y direction for the y axis). Note: this can cause labels at the edges to be cropped by the edge of the canvas - * @default 0 - */ - labelOffset: number; - - /** - * Minimum rotation for tick labels. Note: Only applicable to horizontal scales. - * @default 0 - */ - minRotation: number; - /** - * Maximum rotation for tick labels when rotating to condense labels. Note: Rotation doesn't occur until necessary. Note: Only applicable to horizontal scales. - * @default 50 - */ - maxRotation: number; - /** - * Flips tick labels around axis, displaying the labels inside the chart instead of outside. Note: Only applicable to vertical scales. - * @default false - */ - mirror: boolean; - /** - * Padding between the tick label and the axis. When set on a vertical axis, this applies in the horizontal (X) direction. When set on a horizontal axis, this applies in the vertical (Y) direction. - * @default 0 - */ - padding: number; - /** - * Maximum number of ticks and gridlines to show. - * @default 11 - */ - maxTicksLimit: number; - }; -} - -export type CategoryScaleOptions = Omit & { - min: string | number; - max: string | number; - labels: string[] | string[][]; -}; - -export type CategoryScale = Scale -export const CategoryScale: ChartComponent & { - prototype: CategoryScale; - new (cfg: AnyObject): CategoryScale; -}; - -export type LinearScaleOptions = CartesianScaleOptions & { - - /** - * if true, scale will include 0 if it is not already included. - * @default true - */ - beginAtZero: boolean; - /** - * Adjustment used when calculating the maximum data value. - */ - suggestedMin?: number; - /** - * Adjustment used when calculating the minimum data value. - */ - suggestedMax?: number; - /** - * Percentage (string ending with %) or amount (number) for added room in the scale range above and below data. - */ - grace?: string | number; - - ticks: { - /** - * The Intl.NumberFormat options used by the default label formatter - */ - format: Intl.NumberFormatOptions; - - /** - * if defined and stepSize is not specified, the step size will be rounded to this many decimal places. - */ - precision: number; - - /** - * User defined fixed step size for the scale - */ - stepSize: number; - - /** - * User defined count of ticks - */ - count: number; - }; -}; - -export type LinearScale = Scale -export const LinearScale: ChartComponent & { - prototype: LinearScale; - new (cfg: AnyObject): LinearScale; -}; - -export type LogarithmicScaleOptions = CartesianScaleOptions & { - /** - * Adjustment used when calculating the maximum data value. - */ - suggestedMin?: number; - /** - * Adjustment used when calculating the minimum data value. - */ - suggestedMax?: number; - - ticks: { - /** - * The Intl.NumberFormat options used by the default label formatter - */ - format: Intl.NumberFormatOptions; - }; -}; - -export type LogarithmicScale = Scale -export const LogarithmicScale: ChartComponent & { - prototype: LogarithmicScale; - new (cfg: AnyObject): LogarithmicScale; -}; - -export type TimeScaleOptions = Omit & { - min: string | number; - max: string | number; - suggestedMin: string | number; - suggestedMax: string | number; - /** - * Scale boundary strategy (bypassed by min/max time options) - * - `data`: make sure data are fully visible, ticks outside are removed - * - `ticks`: make sure ticks are fully visible, data outside are truncated - * @since 2.7.0 - * @default 'data' - */ - bounds: 'ticks' | 'data'; - - /** - * options for creating a new adapter instance - */ - adapters: { - date: unknown; - }; - - time: { - /** - * Custom parser for dates. - */ - parser: string | ((v: unknown) => number); - /** - * If defined, dates will be rounded to the start of this unit. See Time Units below for the allowed units. - */ - round: false | TimeUnit; - /** - * If boolean and true and the unit is set to 'week', then the first day of the week will be Monday. Otherwise, it will be Sunday. - * If `number`, the index of the first day of the week (0 - Sunday, 6 - Saturday). - * @default false - */ - isoWeekday: boolean | number; - /** - * Sets how different time units are displayed. - */ - displayFormats: { - [key: string]: string; - }; - /** - * The format string to use for the tooltip. - */ - tooltipFormat: string; - /** - * If defined, will force the unit to be a certain type. See Time Units section below for details. - * @default false - */ - unit: false | TimeUnit; - - /** - * The number of units between grid lines. - * @default 1 - */ - stepSize: number; - /** - * The minimum display format to be used for a time unit. - * @default 'millisecond' - */ - minUnit: TimeUnit; - }; - - ticks: { - /** - * Ticks generation input values: - * - 'auto': generates "optimal" ticks based on scale size and time options. - * - 'data': generates ticks from data (including labels from data {t|x|y} objects). - * - 'labels': generates ticks from user given `data.labels` values ONLY. - * @see https://github.com/chartjs/Chart.js/pull/4507 - * @since 2.7.0 - * @default 'auto' - */ - source: 'labels' | 'auto' | 'data'; - }; -}; - -export interface TimeScale extends Scale { - getDataTimestamps(): number[]; - getLabelTimestamps(): string[]; - normalize(values: number[]): number[]; -} - -export const TimeScale: ChartComponent & { - prototype: TimeScale; - new (cfg: AnyObject): TimeScale; -}; - -export type TimeSeriesScale = TimeScale -export const TimeSeriesScale: ChartComponent & { - prototype: TimeSeriesScale; - new (cfg: AnyObject): TimeSeriesScale; -}; - -export type RadialLinearScaleOptions = CoreScaleOptions & { - animate: boolean; - - angleLines: { - /** - * if true, angle lines are shown. - * @default true - */ - display: boolean; - /** - * Color of angled lines. - * @default 'rgba(0, 0, 0, 0.1)' - */ - color: Scriptable; - /** - * Width of angled lines. - * @default 1 - */ - lineWidth: Scriptable; - /** - * Length and spacing of dashes on angled lines. See MDN. - * @default [] - */ - borderDash: Scriptable; - /** - * Offset for line dashes. See MDN. - * @default 0 - */ - borderDashOffset: Scriptable; - }; - - /** - * if true, scale will include 0 if it is not already included. - * @default false - */ - beginAtZero: boolean; - - grid: GridLineOptions; - - /** - * User defined minimum number for the scale, overrides minimum value from data. - */ - min: number; - /** - * User defined maximum number for the scale, overrides maximum value from data. - */ - max: number; - - pointLabels: { - /** - * Background color of the point label. - * @default undefined - */ - backdropColor: Scriptable; - /** - * Padding of label backdrop. - * @default 2 - */ - backdropPadding: Scriptable; - - /** - * if true, point labels are shown. - * @default true - */ - display: boolean; - /** - * Color of label - * @see Defaults.color - */ - color: Scriptable; - /** - */ - font: Scriptable; - - /** - * Callback function to transform data labels to point labels. The default implementation simply returns the current string. - */ - callback: (label: string, index: number) => string | string[] | number | number[]; - - /** - * if true, point labels are centered. - * @default false - */ - centerPointLabels: boolean; - }; - - /** - * Adjustment used when calculating the maximum data value. - */ - suggestedMax: number; - /** - * Adjustment used when calculating the minimum data value. - */ - suggestedMin: number; - - ticks: TickOptions & { - /** - * The Intl.NumberFormat options used by the default label formatter - */ - format: Intl.NumberFormatOptions; - - /** - * Maximum number of ticks and gridlines to show. - * @default 11 - */ - maxTicksLimit: number; - - /** - * if defined and stepSize is not specified, the step size will be rounded to this many decimal places. - */ - precision: number; - - /** - * User defined fixed step size for the scale. - */ - stepSize: number; - - /** - * User defined number of ticks - */ - count: number; - }; -}; - -export interface RadialLinearScale extends Scale { - setCenterPoint(leftMovement: number, rightMovement: number, topMovement: number, bottomMovement: number): void; - getIndexAngle(index: number): number; - getDistanceFromCenterForValue(value: number): number; - getValueForDistanceFromCenter(distance: number): number; - getPointPosition(index: number, distanceFromCenter: number): { x: number; y: number; angle: number }; - getPointPositionForValue(index: number, value: number): { x: number; y: number; angle: number }; - getPointLabelPosition(index: number): ChartArea; - getBasePosition(index: number): { x: number; y: number; angle: number }; -} -export const RadialLinearScale: ChartComponent & { - prototype: RadialLinearScale; - new (cfg: AnyObject): RadialLinearScale; -}; - -export interface CartesianScaleTypeRegistry { - linear: { - options: LinearScaleOptions; - }; - logarithmic: { - options: LogarithmicScaleOptions; - }; - category: { - options: CategoryScaleOptions; - }; - time: { - options: TimeScaleOptions; - }; - timeseries: { - options: TimeScaleOptions; - }; -} - -export interface RadialScaleTypeRegistry { - radialLinear: { - options: RadialLinearScaleOptions; - }; -} - -export interface ScaleTypeRegistry extends CartesianScaleTypeRegistry, RadialScaleTypeRegistry { -} - -export type ScaleType = keyof ScaleTypeRegistry; - -interface CartesianParsedData { - x: number; - y: number; - - // Only specified when stacked bars are enabled - _stacks?: { - // Key is the stack ID which is generally the axis ID - [key: string]: { - // Inner key is the datasetIndex - [key: number]: number; - } - } -} - -interface BarParsedData extends CartesianParsedData { - // Only specified if floating bars are show - _custom?: { - barStart: number; - barEnd: number; - start: number; - end: number; - min: number; - max: number; - } -} - -interface BubbleParsedData extends CartesianParsedData { - // The bubble radius value - _custom: number; -} - -interface RadialParsedData { - r: number; -} - -export interface ChartTypeRegistry { - bar: { - chartOptions: BarControllerChartOptions; - datasetOptions: BarControllerDatasetOptions; - defaultDataPoint: number; - metaExtensions: {}; - parsedDataType: BarParsedData, - scales: keyof CartesianScaleTypeRegistry; - }; - line: { - chartOptions: LineControllerChartOptions; - datasetOptions: LineControllerDatasetOptions & FillerControllerDatasetOptions; - defaultDataPoint: ScatterDataPoint | number | null; - metaExtensions: {}; - parsedDataType: CartesianParsedData; - scales: keyof CartesianScaleTypeRegistry; - }; - scatter: { - chartOptions: ScatterControllerChartOptions; - datasetOptions: ScatterControllerDatasetOptions; - defaultDataPoint: ScatterDataPoint | number | null; - metaExtensions: {}; - parsedDataType: CartesianParsedData; - scales: keyof CartesianScaleTypeRegistry; - }; - bubble: { - chartOptions: unknown; - datasetOptions: BubbleControllerDatasetOptions; - defaultDataPoint: BubbleDataPoint; - metaExtensions: {}; - parsedDataType: BubbleParsedData; - scales: keyof CartesianScaleTypeRegistry; - }; - pie: { - chartOptions: PieControllerChartOptions; - datasetOptions: PieControllerDatasetOptions; - defaultDataPoint: PieDataPoint; - metaExtensions: PieMetaExtensions; - parsedDataType: number; - scales: keyof CartesianScaleTypeRegistry; - }; - doughnut: { - chartOptions: DoughnutControllerChartOptions; - datasetOptions: DoughnutControllerDatasetOptions; - defaultDataPoint: DoughnutDataPoint; - metaExtensions: DoughnutMetaExtensions; - parsedDataType: number; - scales: keyof CartesianScaleTypeRegistry; - }; - polarArea: { - chartOptions: PolarAreaControllerChartOptions; - datasetOptions: PolarAreaControllerDatasetOptions; - defaultDataPoint: number; - metaExtensions: {}; - parsedDataType: RadialParsedData; - scales: keyof RadialScaleTypeRegistry; - }; - radar: { - chartOptions: RadarControllerChartOptions; - datasetOptions: RadarControllerDatasetOptions & FillerControllerDatasetOptions; - defaultDataPoint: number | null; - metaExtensions: {}; - parsedDataType: RadialParsedData; - scales: keyof RadialScaleTypeRegistry; - }; -} - -export type ChartType = keyof ChartTypeRegistry; - -export type ScaleOptionsByType = - { [key in ScaleType]: { type: key } & ScaleTypeRegistry[key]['options'] }[TScale] -; - -// Convenience alias for creating and manipulating scale options in user code -export type ScaleOptions = DeepPartial>; - -export type DatasetChartOptions = { - [key in TType]: { - datasets: ChartTypeRegistry[key]['datasetOptions']; - }; -}; - -export type ScaleChartOptions = { - scales: { - [key: string]: ScaleOptionsByType; - }; -}; - -export type ChartOptions = DeepPartial< -CoreChartOptions & -ElementChartOptions & -PluginChartOptions & -DatasetChartOptions & -ScaleChartOptions & -ChartTypeRegistry[TType]['chartOptions'] ->; - -export type DefaultDataPoint = DistributiveArray; - -export type ParsedDataType = ChartTypeRegistry[TType]['parsedDataType']; - -export interface ChartDatasetProperties { - type?: TType; - data: TData; -} - -export type ChartDataset< - TType extends ChartType = ChartType, - TData = DefaultDataPoint -> = DeepPartial< -{ [key in ChartType]: { type: key } & ChartTypeRegistry[key]['datasetOptions'] }[TType] -> & ChartDatasetProperties; - -/** - * TData represents the data point type. If unspecified, a default is provided - * based on the chart type. - * TLabel represents the label type - */ -export interface ChartData< - TType extends ChartType = ChartType, - TData = DefaultDataPoint, - TLabel = unknown -> { - labels?: TLabel[]; - datasets: ChartDataset[]; -} - -export interface ChartConfiguration< - TType extends ChartType = ChartType, - TData = DefaultDataPoint, - TLabel = unknown -> { - type: TType; - data: ChartData; - options?: ChartOptions; - plugins?: Plugin[]; -} diff --git a/node_modules/chart.js/types/layout.d.ts b/node_modules/chart.js/types/layout.d.ts deleted file mode 100644 index 4c770711..00000000 --- a/node_modules/chart.js/types/layout.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ChartArea } from './geometric'; - -export type LayoutPosition = 'left' | 'top' | 'right' | 'bottom' | 'center' | 'chartArea' | {[scaleId: string]: number}; - -export interface LayoutItem { - /** - * The position of the item in the chart layout. Possible values are - */ - position: LayoutPosition; - /** - * The weight used to sort the item. Higher weights are further away from the chart area - */ - weight: number; - /** - * if true, and the item is horizontal, then push vertical boxes down - */ - fullSize: boolean; - /** - * Width of item. Must be valid after update() - */ - width: number; - /** - * Height of item. Must be valid after update() - */ - height: number; - /** - * Left edge of the item. Set by layout system and cannot be used in update - */ - left: number; - /** - * Top edge of the item. Set by layout system and cannot be used in update - */ - top: number; - /** - * Right edge of the item. Set by layout system and cannot be used in update - */ - right: number; - /** - * Bottom edge of the item. Set by layout system and cannot be used in update - */ - bottom: number; - - /** - * Called before the layout process starts - */ - beforeLayout?(): void; - /** - * Draws the element - */ - draw(chartArea: ChartArea): void; - /** - * Returns an object with padding on the edges - */ - getPadding?(): ChartArea; - /** - * returns true if the layout item is horizontal (ie. top or bottom) - */ - isHorizontal(): boolean; - /** - * Takes two parameters: width and height. - * @param width - * @param height - */ - update(width: number, height: number, margins?: ChartArea): void; -} diff --git a/node_modules/chart.js/types/utils.d.ts b/node_modules/chart.js/types/utils.d.ts deleted file mode 100644 index 8313d9fa..00000000 --- a/node_modules/chart.js/types/utils.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ - -// DeepPartial implementation taken from the utility-types NPM package, which is -// Copyright (c) 2016 Piotr Witek (http://piotrwitek.github.io) -// and used under the terms of the MIT license -export type DeepPartial = T extends Function - ? T - : T extends Array - ? _DeepPartialArray - : T extends object - ? _DeepPartialObject - : T | undefined; - -type _DeepPartialArray = Array> -type _DeepPartialObject = { [P in keyof T]?: DeepPartial }; - -export type DistributiveArray = [T] extends [unknown] ? Array : never - -// https://stackoverflow.com/a/50375286 -export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 8627f416..00000000 --- a/package-lock.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "project-github-tracker", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "dependencies": { - "chart.js": "^3.7.1" - } - }, - "node_modules/chart.js": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", - "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" - } - }, - "dependencies": { - "chart.js": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", - "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 832728d9..00000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "chart.js": "^3.7.1" - } -} From 5f9c925105a7c16c563af79d65b0577124acd8bd Mon Sep 17 00:00:00 2001 From: idanaslund Date: Thu, 24 Feb 2022 20:15:29 +0100 Subject: [PATCH 08/28] added info about repos, started on commits --- code/index.html | 4 ++-- code/script.js | 57 ++++++++++++++++++++++++++++++++++++++----------- code/style.css | 2 +- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/code/index.html b/code/index.html index 1072ba73..e25b8972 100644 --- a/code/index.html +++ b/code/index.html @@ -12,8 +12,8 @@

GitHub Tracker

- +
+

Projects:

diff --git a/code/script.js b/code/script.js index 233e3f72..f511d228 100644 --- a/code/script.js +++ b/code/script.js @@ -21,12 +21,12 @@ const addingProfile = () => { console.log (profileInfo) profile.innerHTML += ` - ${profileInfo.login}` + ${profileInfo.login}` }) } addingProfile() -const findingAllRepos = () => { +const findingRepos = () => { fetch(API_URL, options) .then((res) => res.json()) @@ -39,20 +39,53 @@ fetch(API_URL, options) ) forkedRepos.forEach((repo) => { - projects.innerHTML += `

${repo.name}

`}) -}) + let updated = new Date(repo.updated_at) + projects.innerHTML += ` +
+

${repo.name}

+
+
    +
  • Most recent update: ${updated}
  • +
  • Default branch: ${repo.default_branch}
  • +
  • Link to repo
  • +
+
+
` + + fetch(`https://api.github.com/repos/idanaslund/${repo.name}/commits`, options) + .then((res) => res.json()) + .then((commits) => { + console.log(commits) - //How to get the reponame here? - //let API_URL_PR = `https://api.github.com/repos/Technigo/${reponame}/pulls` + // profile.innerHTML + ` + //

Number of commits: ${commits.length}

` + + }) +}) - // fetch(API_URL_PR) - // .then((res) => res.json()) - // .then((pulls) => { - // console.log(pulls) + + + + - } -findingAllRepos() + +}) + + + +//let API_URL_PR = `https://api.github.com/repos/Technigo/${repo.name}/pulls` +// const getPullRequests = (repos) => { + //repos.forEach(repo => { + //fetch(API_URL_PR) + //.then((res) => res.json()) + //.then((pulls) => { + //console.log(pulls) + //}) + //}) +// } +} +findingRepos() diff --git a/code/style.css b/code/style.css index e49d95e5..60af4e57 100644 --- a/code/style.css +++ b/code/style.css @@ -22,7 +22,7 @@ h1 { background: white; display: inline; padding: 2vh 5vw; - margin: 5vh 5vw; + margin: 5vh 5vw; box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); From 564eaf6fb814703cec37afe97e4e6a85c47ada6c Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 10:53:36 +0100 Subject: [PATCH 09/28] fetched PR --- code/script.js | 57 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/code/script.js b/code/script.js index f511d228..9f749ddc 100644 --- a/code/script.js +++ b/code/script.js @@ -39,6 +39,7 @@ fetch(API_URL, options) ) forkedRepos.forEach((repo) => { + console.log(forkedRepos) let updated = new Date(repo.updated_at) projects.innerHTML += `
@@ -52,40 +53,48 @@ fetch(API_URL, options)
` - fetch(`https://api.github.com/repos/idanaslund/${repo.name}/commits`, options) - .then((res) => res.json()) - .then((commits) => { - console.log(commits) + }) +}) + // findingCommits(forkedRepos) +} + findingRepos() - // profile.innerHTML + ` - //

Number of commits: ${commits.length}

` - - }) -}) - - - +const findingPulls = (repo) => { + fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`, options) + .then((res) => res.json()) + .then((data) => { + const commits = document.getElementById(`commit-${repo.name}`) + const pulls = data.fins((pull)=> pull.user.login === repo.owner.login) + fetchCommits(pulls.commits_url, repo.name) + console.log(pulls.commits_url) + }) -}) +} + //const findingCommits = (repo) => { + //console.log(repo) + //fetch(`https://api.github.com/repos/idanaslund/${repo.name}/commits`, options) + //.then((res) => res.json()) + //.then((commits) => { + // console.log(commits) + // profile.innerHTML + ` + //

Number of commits: ${commits.length}

` + + -//let API_URL_PR = `https://api.github.com/repos/Technigo/${repo.name}/pulls` -// const getPullRequests = (repos) => { - //repos.forEach(repo => { - //fetch(API_URL_PR) - //.then((res) => res.json()) - //.then((pulls) => { - //console.log(pulls) //}) - //}) -// } -} -findingRepos() + +//} +//findingCommits() + +//} + + From ab9ff699577bb0893ed57c6d8ea322d5a99d0449 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 12:18:04 +0100 Subject: [PATCH 10/28] testing fetches --- code/script.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/code/script.js b/code/script.js index 9f749ddc..d2a6c3d0 100644 --- a/code/script.js +++ b/code/script.js @@ -75,24 +75,19 @@ const findingPulls = (repo) => { } - //const findingCommits = (repo) => { - //console.log(repo) - //fetch(`https://api.github.com/repos/idanaslund/${repo.name}/commits`, options) - //.then((res) => res.json()) - //.then((commits) => { - // console.log(commits) - - // profile.innerHTML + ` - //

Number of commits: ${commits.length}

` - - - - //}) - -//} -//findingCommits() - -//} +findingPulls() + + const findingCommits = (myCommitsUrl, myRepoName) => { + fetch(myCommitsUrl, options) + .then((res) => res.json()) + .then((data) => { + console.log(data) + document.getElementById(`commit-${myRepoName}`).innerHTML += data.length + +}) +} +findingCommits() + From 657580413ce2ed81f626dd86914095b97ae48b9f Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 15:53:12 +0100 Subject: [PATCH 11/28] fetched pulls and commits --- code/script.js | 91 +++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/code/script.js b/code/script.js index d2a6c3d0..93e9aa57 100644 --- a/code/script.js +++ b/code/script.js @@ -26,57 +26,57 @@ const addingProfile = () => { } addingProfile() -const findingRepos = () => { - -fetch(API_URL, options) -.then((res) => res.json()) -.then((repos) => { - console.log(repos) - console.log(API_TOKEN) - - const forkedRepos = repos.filter( - repo => repo.fork && repo.name.startsWith('project-') - ) - - forkedRepos.forEach((repo) => { - console.log(forkedRepos) - let updated = new Date(repo.updated_at) - projects.innerHTML += ` -
-

${repo.name}

-
-
    -
  • Most recent update: ${updated}
  • -
  • Default branch: ${repo.default_branch}
  • -
  • Link to repo
  • -
-
-
` - - }) -}) - // findingCommits(forkedRepos) -} - findingRepos() +const addingRepos = () => {fetch(API_URL, options) + .then((res) => res.json()) + .then((repos) => { + console.log(repos) + console.log(API_TOKEN) + + const forkedRepos = repos.filter( + repo => repo.fork && repo.name.startsWith('project-') + ) + + forkedRepos.forEach((repo) => { + console.log(forkedRepos) + let updated = new Date(repo.updated_at) + projects.innerHTML += ` +
+

${repo.name}

+
+
    +
  • Most recent update: ${updated}
  • +
  • Default branch: ${repo.default_branch}
  • +
  • Link to repo
  • +
  • Number of commits:
  • +
+
+
` + + }) + findingPulls(forkedRepos) + }) + + } -const findingPulls = (repo) => { + +const findingPulls = (repos) => { + repos.forEach((repo) => { + console.log("repo", repo) + fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`, options) .then((res) => res.json()) .then((data) => { - const commits = document.getElementById(`commit-${repo.name}`) - - const pulls = data.fins((pull)=> pull.user.login === repo.owner.login) - - fetchCommits(pulls.commits_url, repo.name) - console.log(pulls.commits_url) + console.log(data, "data") + const pulls = data.find((pull)=> pull.user.login === repo.owner.login) + console.log("pulls", pulls) + findingCommits(pulls.commits_url, repo.name) + console.log(pulls.commits_url, "commits") + }) }) - } -findingPulls() - const findingCommits = (myCommitsUrl, myRepoName) => { fetch(myCommitsUrl, options) .then((res) => res.json()) @@ -84,12 +84,11 @@ findingPulls() console.log(data) document.getElementById(`commit-${myRepoName}`).innerHTML += data.length -}) -} -findingCommits() - + }) + } +addingRepos(); From 3fb11d9e2e5da07ecd13d8202af247f54c00621c Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 15:57:11 +0100 Subject: [PATCH 12/28] done with fetches --- code/script.js | 1 + 1 file changed, 1 insertion(+) diff --git a/code/script.js b/code/script.js index 93e9aa57..f36e42dd 100644 --- a/code/script.js +++ b/code/script.js @@ -14,6 +14,7 @@ const options = { } } +// Fetching profile info const addingProfile = () => { fetch(`https://api.github.com/users/${username}`, options) .then((res) => res.json()) From ec6927456716e826f0684a005ca5c1151ea20e58 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 16:41:10 +0100 Subject: [PATCH 13/28] created if-statement for pull requests --- code/script.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/code/script.js b/code/script.js index f36e42dd..52fd42ad 100644 --- a/code/script.js +++ b/code/script.js @@ -19,7 +19,6 @@ const addingProfile = () => { fetch(`https://api.github.com/users/${username}`, options) .then((res) => res.json()) .then((profileInfo) => { - console.log (profileInfo) profile.innerHTML += ` ${profileInfo.login}` @@ -27,19 +26,19 @@ const addingProfile = () => { } addingProfile() +// The first fetch of repos, calling the function below all other functions + const addingRepos = () => {fetch(API_URL, options) .then((res) => res.json()) .then((repos) => { - console.log(repos) - console.log(API_TOKEN) + // Filtering all repos I've forked and that starts with the word project. const forkedRepos = repos.filter( repo => repo.fork && repo.name.startsWith('project-') ) - + // For all filtered repos I put the following info on my page forkedRepos.forEach((repo) => { - console.log(forkedRepos) - let updated = new Date(repo.updated_at) + let updated = new Date(repo.updated_at) projects.innerHTML += `

${repo.name}

@@ -54,26 +53,27 @@ const addingRepos = () => {fetch(API_URL, options)
` }) - findingPulls(forkedRepos) + findingPulls(forkedRepos) // Bringing all filtered repos to the next function }) } - -const findingPulls = (repos) => { - repos.forEach((repo) => { - console.log("repo", repo) - +const findingPulls = (repos) => { + repos.forEach((repo) => { //For all filtered repos I fetch each pull request fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`, options) .then((res) => res.json()) .then((data) => { - console.log(data, "data") - const pulls = data.find((pull)=> pull.user.login === repo.owner.login) + const pulls = data.find((pull)=> pull.user.login === repo.owner.login) //Comparing all pull requests from Technigo to show only the ones with me as owner console.log("pulls", pulls) - findingCommits(pulls.commits_url, repo.name) + if (pulls !== undefined ) { // If pull requests exist = + findingCommits(pulls.commits_url, repo.name) //passing the commits of these pull requests to the next function console.log(pulls.commits_url, "commits") + } else { // If pull requests does not exist = display this + document.getElementById(`commit-${repo.name}`).innerHTML += ' Is either a group project or pull request does not exist' + } + }) }) } @@ -83,7 +83,7 @@ const findingPulls = (repos) => { .then((res) => res.json()) .then((data) => { console.log(data) - document.getElementById(`commit-${myRepoName}`).innerHTML += data.length + document.getElementById(`commit-${myRepoName}`).innerHTML += data.length //Getting the number of commits to be displayed on the page }) } From 3e4acda60ead74b7c01a79cd198829322e200760 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Fri, 25 Feb 2022 17:42:52 +0100 Subject: [PATCH 14/28] changed some styling --- code/index.html | 3 +-- code/script.js | 6 +++--- code/style.css | 55 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/code/index.html b/code/index.html index e25b8972..88c93217 100644 --- a/code/index.html +++ b/code/index.html @@ -10,10 +10,9 @@
+

GitHub Tracker

-
-

Projects:

diff --git a/code/script.js b/code/script.js index 52fd42ad..1f868e8e 100644 --- a/code/script.js +++ b/code/script.js @@ -21,7 +21,7 @@ const addingProfile = () => { .then((profileInfo) => { profile.innerHTML += ` - ${profileInfo.login}` + ${profileInfo.login}` }) } addingProfile() @@ -38,7 +38,7 @@ const addingRepos = () => {fetch(API_URL, options) ) // For all filtered repos I put the following info on my page forkedRepos.forEach((repo) => { - let updated = new Date(repo.updated_at) + let updated = new Date(repo.updated_at).toLocaleDateString() //Turning date and time into date projects.innerHTML += `

${repo.name}

@@ -53,7 +53,7 @@ const addingRepos = () => {fetch(API_URL, options)
` }) - findingPulls(forkedRepos) // Bringing all filtered repos to the next function + findingPulls(forkedRepos) // Bringing all filtered repos to the next function }) } diff --git a/code/style.css b/code/style.css index 60af4e57..b5907392 100644 --- a/code/style.css +++ b/code/style.css @@ -9,29 +9,34 @@ header { background: #006d77; margin: 0 0 5vh 0; display: flex; - justify-content: center; + flex-direction: column-reverse; + align-items: center; } h1 { display: inline; - margin-top: 0; + margin: 0; padding-top: 2vh; + } .profile { - background: white; - display: inline; - padding: 2vh 5vw; - margin: 5vh 5vw; - box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); - -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); - -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); - + display: inline; + margin: 2vh 5vw; } .profile img { border-radius: 50%; height: 20vh; + box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); + -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); +} + +.userlink { + font-size: 20px; + color: white; + text-decoration: none; } .projects { @@ -43,16 +48,36 @@ h1 { .repos { background: white; + width: 100vw; + max-width: 375px; margin: 1vh 1vw; padding: 1vh 1vw; - border: solid #006d77; - border-radius: 5%; box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); - } -/*@media (min-width: 668px) and (max-width: 1024px) +@media (min-width: 668px) and (max-width: 1024px) { + + header { + flex-direction: row; + } + + + .repos { + width: 20vw; + min-width: 210px;; + } +} + +@media (min-width: 1025px) { + + header { + flex-direction: row; + justify-content: center; + } -@media (min-width: 1025px) */ \ No newline at end of file + .repos { + width: 20vw; + } +} \ No newline at end of file From 81436f0f49d423bb335e306b1a386c40e8790282 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sat, 26 Feb 2022 12:47:15 +0100 Subject: [PATCH 15/28] done the chart of amount of repos --- code/chart.js | 44 +++++++++++++++++++++++++++++++------------- code/index.html | 3 ++- code/script.js | 6 +++--- code/style.css | 2 +- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/code/chart.js b/code/chart.js index 6d789db8..ef4dae51 100644 --- a/code/chart.js +++ b/code/chart.js @@ -1,35 +1,53 @@ //DOM-selector for the canvas πŸ‘‡ const ctx = document.getElementById('chart').getContext('2d') - //"Draw" the chart here πŸ‘‡ +const callingChart = (amountOfRepos) => { + + const labels = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', + 'Projects done', + 'Projects left to do' ]; const data = { labels: labels, datasets: [{ - label: 'My First dataset', - backgroundColor: 'rgb(255, 99, 132)', + label: 'Technigo Projects', + backgroundColor: ['rgb(82, 183, 136)', 'rgb(0, 108, 117)'], borderColor: 'rgb(255, 99, 132)', - data: [0, 10, 5, 2, 20, 30, 45], + data: [amountOfRepos, 19-amountOfRepos], }] }; const config = { - type: 'line', + type: 'bar', data: data, - options: {} + options: { + indexAxis: 'y', + scales: { + x: { + suggestedMin: 0, + suggestedMax: 19, + stacked: true, + grid: { + display: true, + }, + }, + y: { + stacked: true, + grid: { + display: true, + } + } + } + } }; const myChart = new Chart( document.getElementById('chart'), config - ); \ No newline at end of file + ); + +} \ No newline at end of file diff --git a/code/index.html b/code/index.html index 88c93217..6e2d88b7 100644 --- a/code/index.html +++ b/code/index.html @@ -10,7 +10,8 @@
-
+
+

GitHub Tracker

diff --git a/code/script.js b/code/script.js index 1f868e8e..bee722e8 100644 --- a/code/script.js +++ b/code/script.js @@ -31,11 +31,10 @@ addingProfile() const addingRepos = () => {fetch(API_URL, options) .then((res) => res.json()) .then((repos) => { - // Filtering all repos I've forked and that starts with the word project. const forkedRepos = repos.filter( repo => repo.fork && repo.name.startsWith('project-') - ) + ) // For all filtered repos I put the following info on my page forkedRepos.forEach((repo) => { let updated = new Date(repo.updated_at).toLocaleDateString() //Turning date and time into date @@ -53,7 +52,8 @@ const addingRepos = () => {fetch(API_URL, options) ` }) - findingPulls(forkedRepos) // Bringing all filtered repos to the next function + findingPulls(forkedRepos) + callingChart (forkedRepos.length) // Bringing all filtered repos to the next function }) } diff --git a/code/style.css b/code/style.css index b5907392..e8d2a54b 100644 --- a/code/style.css +++ b/code/style.css @@ -6,7 +6,7 @@ body { } header { - background: #006d77; + background: rgb(0, 108, 117); margin: 0 0 5vh 0; display: flex; flex-direction: column-reverse; From fa28a13d0bfd253bc97aea56dd8c2d3766ceaf1a Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sat, 26 Feb 2022 18:21:55 +0100 Subject: [PATCH 16/28] trying to sort repos with drop-down --- code/chart.js | 2 + code/images/GitHub-Mark/.DS_Store | Bin 0 -> 6148 bytes .../PNG/GitHub-Mark-120px-plus.png | Bin 0 -> 4268 bytes .../GitHub-Mark/PNG/GitHub-Mark-32px.png | Bin 0 -> 1714 bytes .../GitHub-Mark/PNG/GitHub-Mark-64px.png | Bin 0 -> 2625 bytes .../PNG/GitHub-Mark-Light-120px-plus.png | Bin 0 -> 4044 bytes .../PNG/GitHub-Mark-Light-32px.png | Bin 0 -> 1571 bytes .../PNG/GitHub-Mark-Light-64px.png | Bin 0 -> 2330 bytes code/images/GitHub-Mark/Vector/GitHub-Mark.ai | 1564 ++++ .../images/GitHub-Mark/Vector/GitHub-Mark.eps | 7696 +++++++++++++++++ code/index.html | 25 +- code/script.js | 44 +- code/style.css | 61 +- 13 files changed, 9370 insertions(+), 22 deletions(-) create mode 100644 code/images/GitHub-Mark/.DS_Store create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-120px-plus.png create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-32px.png create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-64px.png create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-Light-120px-plus.png create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-Light-32px.png create mode 100644 code/images/GitHub-Mark/PNG/GitHub-Mark-Light-64px.png create mode 100644 code/images/GitHub-Mark/Vector/GitHub-Mark.ai create mode 100644 code/images/GitHub-Mark/Vector/GitHub-Mark.eps diff --git a/code/chart.js b/code/chart.js index ef4dae51..68535fca 100644 --- a/code/chart.js +++ b/code/chart.js @@ -25,6 +25,8 @@ const labels = [ type: 'bar', data: data, options: { + responsive: true, + maintainAspectRatio: false, indexAxis: 'y', scales: { x: { diff --git a/code/images/GitHub-Mark/.DS_Store b/code/images/GitHub-Mark/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..81fe7de0fc9cddf7d09a9d7f4449af0527e883fc GIT binary patch literal 6148 zcmeHK%Sr=55Ue&q0=eYqael!+7(ygB5d_a-;w`Y?mri^f33h5mX8<~ literal 0 HcmV?d00001 diff --git a/code/images/GitHub-Mark/PNG/GitHub-Mark-120px-plus.png b/code/images/GitHub-Mark/PNG/GitHub-Mark-120px-plus.png new file mode 100644 index 0000000000000000000000000000000000000000..ea6ff545a246caa64074ba809bbc86fcb8589071 GIT binary patch literal 4268 zcmaJ_c|25m+@2YcEGe=tO+zT_42H4qTL_VT8D=nHX3PwRki9HfBH7BIQ7JCj_beeI z(PA%IQuZumf5*MI`@VnN`<~A^=eL~adA{p8f1EgTGXqv8J|+MFz-nZuYe^f)M;9Xl z?T$df2WbN@Nzaya1?NEuL=w;dEfmfT4L0&cdZI1SNK}yDE3_&AKqrE+vL)G?nkc*D ze5H{`7-_OEp2h|MR5i$Wq`Nno1a?DvVz6qEm4+4w7=u!S*eICFn&NfPUKqn*0{Tj@ znU#C6w>ts_(NG7gl9g!!zGxB>O!oD`5|znnkUw>mY4f9P83_1K2+3Ow@|RP#rsiNB z903hhkd~8jmxV&XaJV#7UI7k=N`hgsP?(G??SxA~<&_oS$}mOn-v@+djezn{w$#=C z+ZJu52Js@1@X9hWfq{Y2fpXF~f~O1=fj}H-z+h4|gcLCdOG1*RuteeC3c6^bI{||y zVQ^URks{I!=TB0D&^-Ms1Yi6=vRLBZX`&@ehK$6^K&54mLi!CfHU0mgzP|sUi6l$( z|N8r{!bGbeJX*#QO~m;V+-ZgL5I!=6SJok*kt7_!3WxLgokepm90^DC!r{R>SKwfA zQ=~fvd$e)kPllD+ zRvxaUgpifj{ms?Ix%>N~v83Nz6pahhl84G`Y3tCq(0}C~HG?mnW?2_azyzRC`UIRW z_|Kq~G5_t0?0@_67Z>#}zWf~rt)x_q6t=RejnvErW>9V+3xJmC z`WZuvjAn72w+0gZ!c zA#ROc&m%S~RCo}xuD5jUEbXg(tZCM@w!T|#S$ju3+PKnZvOq!Te!k1i>ZlAY2d$hq zcr3hl)6*dTc>dY=Qd5hg9F-3ZJx12?th3 zY?KG;EA_?MEA`bUgvx84mEd_1K6WD6Zh&~3v&UiJT=<@uGaZ9%(IN9U?-o?uhZNz# z0#o|=;zl}_TF1jsmf+jyEQ<#bNr0KCAUYnr%4g{D(N{m#MffRnz-^cE<1DqGVEx5r zS9<&IEpl`xM442IxYkCk*}6`7oUa@Kl_Om(Wi)GrS2ItP;Ou5QroVSmsVXN0)hk8e z;lQ7wszq5KKkzMEul9)W#^WhAdM9n0$1xd~J`)gN+?&lyrT2u#TL&e_WNZu=06!YS z_X6e%y?CXFn(qe)=6ByvLZ1sdi9L_*4O%9s*q`)g@<+ngXLPynb=p>5ndD-SPd(4C`aTbdZ?bxKHELC zZeth7;3PqZD?s#@He`g7m$B$qvPY*AnR5l@#vg7e+&xsaNZJ7s<$W$OK|T@wSM zh`E>hGt7-jtmLJrt}Ivhf&`2+J~l%A7}}Xca7jJxI^wvclcjQLM5Eta<3kf9Toscy z2I56cmFzMI1s+2ser!B|B({ns8CaFV`-AdpPxNlkWi`M4xfYlJ>bcQa_Db9t&LAY; zx^2E~@4$Karl&<}9jvxNSjTQMt#zzn;Qqi*Jw&F8Na(c1_Jsc6N8&(xJElah#X~^m zO$FtV=RBR5){5SC5(*jhk?uKK7`fi`Y}eJ#ci%vh-fi6~JE0;=vP_jpjlbT?{#e-Q zg~+X2Dcc7K^U`4_pWG;HNCdX~rJUssvKg;+f3y~ob_om7(fWQVrk~|8c+5Oyh)!0u zH&@f%C3-|i_!B$Ex|tDNvP7;t@z^Uj(%<;2W8RZEAuh0EPbru^)k9_D$^x*({E+n& z{y0*heI0x$J9Uj|T}LA6SZHS^U1@BX{##YX50iv${&P>g_W{k;`KLa}>>L)9+be$H za1Hq$db|JP;I|C#s!D6abpfQ!SMEJxNrX5Po=~2~$zN$@d{C4ae%`0;u5lJIc<5zV zW0x;w_KUnGPtktlP2P#J6QNQr*8K9PVlhCrtEJW_VcAdqvfOn2!G(Z&x2T5n3f@d6yv9qGdpFIWgxra94$P&Yhsnc!#t)-Gv2pxFx>U@5&M# z7#U*2+|*`pSdAT(GQiPE$Ex`}N+I!wwb~zatxGDuvCL1$dV-cI>A&21r3eoG;Lk8> zhmAcpb*$KgS=PzD#t!=+rn>kYXx#YR)Dn+tD7G%>f%NHRvzUhtr}1(z(HiB$A-%vD z`5X-Jp!>%UspC}u?_WmmD;h%*I*Zz09eZ~A{G;;OSqJ&?c>WA=&gyqG%p)(6V*26E z{`k1QNoE~O9dKi0)Wme|c} zpD9V60svR6jT^^lPq@XY4fnzWFP@(qA|#AoRZ#%ui7nS&g(Xw!JO=DIRz0X4b&exr zkY`td`J1Q{ea9M&%2%T#Ta;&a<1sj6L)n2PV_y7NO8EsgholQRo&m^2^@skl2bJt` zu{-&e43fXh6JRAQ*3k{gK53WkKIN2vD)Z{THopDGy|Ji5&I%H;Ecs!{lt{IB9_h<_F@CJB{)}FVpTFvK zXP(=eD=e5uI3>NH`X-wAtvibZtmZ?rL z7wsuLRIVuCeEjQ}R}+ZAfvu;^h{(w;f2~*YCtDTpuuti0eA}tHeTR8%o~dzA^q5{z zUQNy_)>BQCr4&n zY9ifZI%XxIcTU~-B#>+|02RG{!zI=^*x31j0>MV-*^bTh_(BK8Ju&5MRoaw8+1sG1 zL%CEWY*}Ha7nicSa&3PfVrP_f!DVI}!S&!{Ym;aR{feM{vMO6NOZr%GWB(&Z`wMOR z#)*@43&=FFCXmN^kEWAz)MHgZ6DzNPf8RC_rbOG((u3cI+!P)?mdoPYwy+W=xS^mz zfWC?vOdizPc*paTy;7&k%4PvouNbGIDHnoj<91_&*-aZqO)}LOa&*pZeF>N7l>Pz< zd;rv0z9>AUFFFYW!822_#dpkxb^lmTJyFw~@j`t0>4*7~9p0D`MHX1=O>e$JdK(YU zaj~=9#M%X_gvkYeC*Lkko|dT;vWBG#k0&O6W2g6_Mv4}FWx^J#7cBEjg3w2YH@g)Q zuPcXBzOk0d9;`^u*e`sV2s~bPHkR-tDYRo6Xua4hTUwLG+tvh)QIX*oR|Y1Ov28Zk zylyfJyrpjDH=Jjhz5$=Jg(|PB@fV!q?btPZ{rS$TKfdo!+1YTi23~<47U94_5&pH} znfUigS(B@ik&Xh(E?Ua@PItu=bDG)ZUT{R;eznP5G{Em}%@vdRrM`+tN6I(JQMxzt zzG?+!S4Ta~BX5?vtMn^pahCg%YIEzN%1z!wZj%6cu}N6lF1c=c&0t!fJ{z?E+8|pX ztL03D#Wef7T$WgBgBg5GX1JT$UHCk!=iSaW`dgj`dWdyaEzWVS!D%kH>i&#|Y?8|9 z-4$lE_MykI*a<$47lk7Bjbdv}w_`*zdXZuGN3Iu`_YOWZs2xJ(qa;J)R&SUlR@|sR zt8oL;Vk6BgD)ama+gNdT3rq5$E=wTS_vPNL5v7O8(WRT)ia$MvhreFxtoojl@A>L* z?V3N9{Or`QzB8zrK~Wzy9(B6iNvvA2IDC!4FDT_F{|-W_zsO%Zd!zcZU$$SrY)QbT z+}KQlk=a`^_W*hzPZ#yMhjHq8PQ9i6db5c4WxBN_N7p?>>OOl+NcT)WrFk4NdiE{l z;%pD)D#!i39~nk@^PUQri!2Iu0oQ(*7KqFFs)#t$B7j`oGM}O2VyLY`9N-5vh@n;< zRNIc6&UJhY@?%IVdD-=xjGWJqn^0=jZBU)tv{v1U7ED&2v5=oi(iJ2&r=CAe0V;*$ zW$8S9fv(wveNqLlBQuhxlIr{{L<<*+21HMjNzwF5+p`Q`+5~JF9k>|vUCpaTL{(Py zw>le+8;vV|Ci0p)i8;A|+2>n*&Llb{e1az3q!#5`h2t?5>RN5A0%e*-$ySQrj$M&HIK~a9W)6d?W8J*D|_Nsk$ zGP@D92-<(_m%Dt`w&=aK1L=et-x-8!#A~nMjd>p5y_E~xqvBa(g-xz$rbrZzJy}@V zMDqqtV5Q@0Jnd^ZegdA!J_j+KUwf*Q89r!GpX^tCjM-_vCiKDr%LHG*Tq?b|4*FY1 zr|I5VzQbkN?NfI!QSV9w{6i7N+PZuZNn#B7s)KDhPO1TQJe zZL1UgBIOOdRP;I*>7?O<3ezgLDn5OQ67L#>r1#{bKe8hz0Pg XLyRvu{aX3a{{tgEGu={c*U0|?Dtn-9 literal 0 HcmV?d00001 diff --git a/code/images/GitHub-Mark/PNG/GitHub-Mark-32px.png b/code/images/GitHub-Mark/PNG/GitHub-Mark-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..8b25551a97921681334176ee143b41510a117d86 GIT binary patch literal 1714 zcmaJ?X;2eq7*4oFu!ne{XxAht2qc?8LXr|_LPCfTpaBK7K$c{I0Ld=NLIOeuC;@2) zZ$K%a)k+m-s0>xHmKxL%0V&0TRzzznhgyqrIC$F)0{WwLXLrBvd*^wc_uSc%h%m9E z{W5z3f#4_!7RvAyFh6!S_*<8qJ%KOIm?#E|L=rJQq=gB5C6WLG5;c?r%V0>EmEH#X z5eSwPRa6WXBMs#$5H%GtW2go-in9p>zW@UYDNNWc^XOXZQ? z1QjEV00I#$3^1wQUJ8&-2UsjB-G|9y(LDhMNN3PM{APL4eYi{(m*ERcUnJa{R+-3^ z34^A6;U^v`8N*O6ji%S@sd{fJqD`XFIUJ5zgTe5^5nj414F(y!G&=H(f)Lgzv?>%+ zAsWD}2qhpH7>|TU`X&W6IxDNuO_vET7|j5oG&&VDr!)hUO8+0KR?nh!m<)a!?|%yG zqOwq!CWCcIhE{<$E|F|@g>nP6FoYr6C<8>D?ID9%&5J(4oSbR1I^byW*g@__U z4QsF&uJSEcFeleM3~ChjEQGbHOjsGDMbyAl(p=Ttv9RaVo8~I#js@@Y9C^_2U})yn zzSHU%6FxuY?d;&65MyR({^lU*3$z$ZllDb(o&<7d;A_`h2U+3~BJ2Hv`{W}KEU801#cv_B|9Cm!ynR{S`AMsSn z;7E=B;mb!wx$L;S>yGXG^6=&WlQn9$s?&L%Y1D8TI^MlKB1DqsEng$>f4=xYWBoPI z_S1p!sJ#d2?YI4kPA{k}Eby?F=f-J9zIc`YDl^pzjVm~9ebE?Hn?t0Nx+la|D0MB; z9)2xv1G>a1|A9kQ>~DV<=X3-4yC&n!m8-3K#P z{X@0zRuQsy$+N ziSCoLJU{Z$nQy4A4Y5UJ07$5FA~qL2%Q+cLaqDU?Lz3?=BC5;Nk6BbTmmceEaM>-Z zi>O&-dSE=%ex;vcvCOk{*JQ5^_4M z4lW7%l9IqY(z7pV(?I@@8=KPFO82)O{VDI18-*d-k$YmI^XiuPs_LuFw<^ZcD}yP5 c*NrbeloN*74g`U%%F6r~k%+>C^#XapzmV0H-2eap literal 0 HcmV?d00001 diff --git a/code/images/GitHub-Mark/PNG/GitHub-Mark-64px.png b/code/images/GitHub-Mark/PNG/GitHub-Mark-64px.png new file mode 100644 index 0000000000000000000000000000000000000000..182a1a3f734fc1b7d712c68b04c29bad9460d6cd GIT binary patch literal 2625 zcmaJ@dpuNWA3rl=+=}acf|9E@P=bZCA&+qg7et*|Lo`cMQ4SL!u zv;hFnqx;f=RIA70r>U;`S924)Rm*a*H%lB0$B2{JLJ07ThNB>m&SUR{f*^KuO5#1p z6#!6H+z^(S#qg(aU>=seh`~yD0u>toT-_xCHYXkugHg~ylAk{k$56lW5JxEB2QU{v0O z(J_=Dn$JgHsuL9xD;5hVI9zgaGB()}3k!GR2xKyOQG-ZyP$3*dDSRx+6H zxzS&ah4w`*P8AGpv9Q5%s{48!i53cI)dGsN^YTkva!Csa-!~y{IALumC5XsY* z;oO9fP-D5HNp6GjVXS9_c1V2u^I_zB1-k6a`@n;|eN2-wq}`FLV<<0w=RlfKU9(3Z z?Vv$*-_m{)R9A=k2=5$JrJ5 zd(x-6(zYwCSQA3wWMBj;Lem(jL~x}3pjUMga+Tt=q9Zf4cjQq+R^GwOxB}onmdyq9 zYa}1po)-)mjV-^ZRfS$nm0JP%%2J6zkxp^p8J$PEwHnnPw39eZX}|bwVDI+Gee`@Y zbah4{SeoLiGPW@75vPCvM=#55zb)v1eNE+tfD*T%9$`a#UqDqP6flo7k-aV>IQ3KL z?3H`(H3`?q)i9}4YoPsfZeLPwKtG(KQ-oT2jcN(B%hrz*1V7UCp6GY!F4e!okh(0O znQ=jWE*4#p8`djsr?kI5jXKJRYt>(U){i0emy7~ePChu6oUwefQNQixI-(=d{P1%3 zhx=v2`Ry0lVKW&Jksh#X2ZBp#{a!;N+otQU!S}lvS5Tvvl5Ubd2b5Jj5-;BoY_WOF z_XCPI9rvwO_zYof?DOK%D7k0_M-eMq1#4^uYW@wUg*5e?z1mhW|GkISQ*)gK!lPx| zhZQN7o3b?xTTW$o)&y=wPN6(!-WiNpD#qR}nK9og7lxJS9YRlhEp9)yU^-uiJhow- z`8UtZ449xibZb6f>W1(}6}*;8Q}D4jvc47_zV#=gHPpIg&^BV=sY7Dmal^rQ{Rb1n zUwQSwn=K>Hdns)-UfJcmNaEkVZt&=3p#x^9uRr~)MJC(+R7*|u#l#|6Oe!OSxM_Eu zmB;$9eNW8?oI@Ao1juH&%}d;U z?#98zrD2Iola(vNeqXDEj5{li7yeqImbZr^`ax#dw1QXei_~7G_g(WFx2Du3&m=l? z7h;1<#irByqG9b@3u(qlI+?8(e{@D`x>QxAscV^@j}^G0H9KoHh*`OVvLl5^wL?J< z7)$I5W&Q|c2#?m>)|0U<*(h6S(odPBl0+QpHsP-r8hDCI;Xy;ZB-GTjC{Lh z)^{?@)XZUvU2)|rYeZga0RK+{;)>14TJ^#VgLD29(mB!`H~7S*Fw{zJ%hPczWn=cg z8jH%4)vX%o*KhVWOn7IlqI@$mJZW&H8;wZubZI_Uwrk`&rADaRwb@W?@%Lq;XVYdZ zzbfh08?cyaez+qbJi_UZNiw(*%k&9+amj>L{ED$OWuQs3t3SxwFrj;;X7JtUOggr3 z9_gyPyNb>f4!Q6KY~O5*EcJ8lx!Eo+mu1XJ+Yaf*g#ElRyLa`VS#Nr;#Tl#HQCW>m z{&_c0soAKyl5Hh_n6KLo+?X66U)GDrzLZ!MuKsS1=~Z-jmeYyn9r@L5{%zdITF>DU zc(z0NN5gMd71f1LPTcD_?PI}M(r1raF|bl_rTXz3>u}j*j^Bmd){0~OhHAcdT%96T zl^I$j>vYCuJ?O7Db;K6G{^kavEh#naE`IOB!FIb6?Rl2b>{14>p?RueVYk~ro9y;T zIrcx#*ZIGkiL#&hR%UZ~U8&hb7!h+vGUz&Kgw@+NpF@^rzAM$3da`Mn#XcKJdEb+n z%Ja~1JE|B-plr+1ckkS)J%8tndxzxYNf*b|;HiBz2ekdat!a4bi8!V6uKj*dC6Dra z#ewE=I4u9YXWc$ zFQ)EwjtXc}@pjCV#OF{`{F&M=E0)#J@Tkkfv83XA7q4{3`Po^?`^#!I#t(`mS z?yFbdpa!*s0@tn$0{aDCQgU)Bq;savHLt4{2qzE7+ W4I>>0bz>}E>ge79vaGRl~FEHV3FIF9Vfr0h$`Nq8%zL{iAU z#5hVRL@G>)Ls=v09p|m{{{A@E`&`%ae82a7eLna7xtD*QbH|f zc{v_4BT~tRgdL0_n@r=g1q3Xt*)#$%6kve@fS?eHC3vy11q=!yS%N){9ifgi3=kZ0 zB$@%ZMmxC?qeF=(64=@bWWhG$2OtA10*FlxqcF|bmf*kQn(^;DZU`9k7lajR3I2~L zFUR8`43zO{XGJ+s56bc1_!Xa?D0Uu$&jH0jzYy%2Y<7Wgc zz$7w4Xsi$_1+){95I_xQS%UdW|5E~)=IHo$U<&g`qxda@un9B>%n%A8lXvR+3(aJ? z0RNTok7%Y_6b*p508DB)gUFvppvF%!zjyyT(GHNW#tcg(hLZsb%N}b9=6eiDAtW;_ z)&^z+MI%g+7#s|SL!i;da2yVSFot7cHW(x1Pp&mv_#18&|;&a6L-1gm36j4%xkt~@|aub48UIJ z$zhq@B7I*@K=JsszBQ|u#fgozh3$<;UrW}%K3KOv47M8PGaoHmt(#jfMh*TN&0?`K zaIH*Nnf((zUiD`J>uX-|Jvf&~@?201A-;Py(xizM0Ra%x1Qld{N{* z;L_VqaCaRIZyty_w^4SdaP+hY@}fFdmut^mu5C&u?4oYNd9u80uF1{Tt|=mSmRnVL zmAHA{fSb(S;QD#^QyVf+oG4T+T-}mjzAVKpg_YhH3@V*>1YYZ9S7-`l*M2QqJt-O0hICdOjT6Jmm^OAW)J9SfEpQ35%9yW<_^$%0UD}6$*XHEs5@&0!5WZQRd0BMQ1O^6a}xk-$MhuEM3<(S~K0oKEDlVyOServwIXUu+-_H3Wpowmr_xrReUt=aPWcm^)}_>9sT`pv}A(3VbdIy7J(!}o@UgBT z2l(wFsMA~1>G_0xg<1foUY$JTDt}VBr)R>N6d3be2i541tFFAu!3e)rSKZl(>uZlH zFa4D(S-dB4F3PjoM6u{Q2VB5z&0domdfcvzlrH%!!LYEuimCop1}NwDMg(<;a9cKY z>bwKVI*Ox$ccRh_?wrKM3c-$Ti%3{L9CsyA2yk5kKuuDY8b%wBp>#8=*ov?7Ood-N0~ zDAu~)M&)u&&vd$~(xJ-p?{)z6{>DAz%S+TaZjMaW-3fT+iihW6z+m7%vauQmXtn=!h+dC_Gw(c8g z_;6rqUp({E*uFC(y{d&Lx)rzpmpJ46%rv9IDLc&n(WJ~7e14VWhO%cHezCU9gZE1{ zJOvhs(1wK;ypl8t%PVULi8bK8dvwSL`0bmG=c_iMDHAo>1v?v$<*;A5*}8+qVYp*@ ze}K0g?m`P~hMqLMj#5d#)=tuR-b(zvsL@U7 zh4kwU&aUyQz9%UMyRZ_GikkzroQdlzA_seV%XhEOzpXzuebfqdxI>z2lF{Dic>*{^O;}%mk6~@5$}WdW&(-m9)pbkKk_$ z3az`+BVT`Obr)0J-(TL??IY{?lA?2$uCDFyP|<#+Yus*)@N@v{Xa;?$qzB31;WO zx&b3151u%^el}?Dy6X8%$bdB%I$vL~JEqq3O4F6I;cvIVFHXPb=`Lb|wk&JDLZc(ZU6VHXw7wOo22x-k*8)F=r? z#@_d^LRf?2tz~N(XlARcU&p(OP1(+Q*0K98T+H-7g#^*Re4b9qtfr?Ujy&0bi3J+HR+a876j%v8>FZqq9cA~{aE-5bp;y_qUAm&EEB zX}I>w`!ow-*_D5N(l9#>4DEkW6snmtN)q?Akj}bcu!8!0l&BMR5j5*sMqNM`zC46< z|9v)bbi`*%es(e+=2C=Gx3u%xod_HOXh9<_ zv8-{Mx3&SD^gIi@uo~U-;vL7RNpJ2Q%#thlLQ+cOAWLnX;xNJaDY(oQ@$7TDcQw6y zMcd!uhjBwZGQslzkN_91QAf@xFCE;Mos@G-rGgwh#XMn&eXjK3jds@_n=h60c}8x} z_w@+j!H>oRZk#%xq3%ywjwo`LgA@@KD<2#UT=u$k<-^^_8h7i|Q@^zQ@*cn3XR3s_ zAo#C%$+fE9(ayuPUC0BphK+t7r(II~Uaou-Sqd!c@dmwnBxk45?d{KzRZKL<`Fv)V ZsK8ky_?39l4gAjkwLQ)WTW#Z?@NW_mBhUZ< literal 0 HcmV?d00001 diff --git a/code/images/GitHub-Mark/PNG/GitHub-Mark-Light-32px.png b/code/images/GitHub-Mark/PNG/GitHub-Mark-Light-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..628da97c70890c73e59204f5b140c4e67671e92d GIT binary patch literal 1571 zcmaJ>c~BE~6izDPQq)#Nu*KOf(n^(VHY9;fiINM65``pc+9*v(mL$bwfCjbc%v9V{8r9iX|O%>Nr%pLD2qT{mty}c=LVleeamv znz3SOSm@kP8jThvOOq(56Yzh*fz(booe!uZij=BJC6+_lbvQ~B8nA2>kXdv_RDtRY z`5QXWWEySCe6vbTs^#f?J!WC*{1~RgVx!nJTJjQyO{dRANgx|FnymtGbD9%JmCh9^y)##j7{Dcqfn*1ta$rG89pJF6w-S7Z037$rr|y0;1Onp_ zGFJdT6Q!1C0AdVB0WOmpuV=AgAQ550Tn+-mivTtYPJmz*#75#_n9oV%!#rSOfmAfy zki%C~=fTp1{O#BLpJ|0jj#m6#|LRWit-vq3PE1z9ZqyvET4sX$-Icqy7t z<=aq5ff86AuBZBu6EjJsYWM0uejufWFTwPA7Su}0Bm$7KFb!q{Um_8~A{LUG#1l(l zSehUda@kU8LIRg9fkk2tZ;~ss5~R+mM<==F7hLHpxqLB>>PQS%Vc7b~?q!%T5+h8Q z4G=4Nzyi5WZ?^gkasJ{?Xhm`JC#WG6$1K2jb@=9&D3EgD#3UhGh#*21rJjulVXjCF zvp76q62jt0zzMG5C7DlfMgPl%C^3+~wf|}Lq=}jz|MmIcQjh1Ok6NjD$Em^Iv26D> z8tt_TnM9~^Tt8mflRGPOrrX|HtT3gG4LEuuk{g2Rn}QgJIa?gZo))!!=o_l9bvD%A zZ`aHajl8#~u?!4f7F#*b*->A=R2L)6!>saz?h>#wTXT-I(XmQ zx{84skS>k=i~i`(6k4C7;Zpfx%dCPVjPayMf8pugtGM=~s=Id1l#8MZJ1-73wV#Q3 zR3>v3%}jbQs1f_Z0xo;%=LILlA+nTpKI4ha%xWW}uqHrNao~&T4AY6m`P$_n-6h*g zhoX+e4n%~gl_lhe#s+AMb7d{5WzvYTa%6Q~si@@4{;s(0zU|H&P3fE+t{7X`S#Cj@ zC#vd}^4pcBD*77Ny5=j$h8EL2_t$O38$SQiJ6fPjJMimypr~MB2(&P0aI|h}$64<0 z>_~duqNjaT=DM^6+N{&B_lED;F2wrl?!4Lk*2((x!fmrcsw+=cI^qttuZ9C}-m~5E z-ryYVpL%^xR#&(0YI5hz<(}F7-p)?FPcyJO-zVO>%9ZDXJH8pnY;GJYFDQ>vd#j_* zRrd}L(r=!g+1#nQwsO?kpS`Qq8`NxE+Zy{gf7*_7J*U2V_|NpLo{iasj7VCg_V9&| ShohtYzipXxh2)4xTkbNS=9n;FC~MOYyq z5Qu5ON?Ne?^wWKYaP5AUm;6k7ER@nCq#?pMX&OrmLdYE9CJ-6GXT^iTAd9m(`4;E} zfy}Yzg+@pt0@sk(LOz-_L`>RbTB#+~b3MT|& z14UGj%UhW)21C+=LfPqwY$6Bc>x1-?k+cr@pp=D_@sk7+lFS?R)h|hV*O@UW6`Ai_H`049j)JozV)4d8r`BUo7M!zgCCD`;G!S0dV&q zp8LL%~Ba#6Eg$iKtZe$N47EeRXa5>+}e1_})f4LZ~7>us9|I_MOlXiY|*KdQX zeS8~zP@tW6v39VXfr*USwp~rS`=B$j`)nk?@}kq(ClF4d>YOz8hkr;=W~kkm zCW7a<(pcz5X#A0R<9Z{E*BfJ?`u2(tHC?l!+(h-PRUM^q=-1CbjbNI^81U7VyU;3( zT2f^?#ma%q8;EN&iz|Pk@=)pdaMq3d25mbDNrIP#bi|hqP`3*fT}kuvR+%ng#;F!o z!3#SBB2F;iNzfJ(L`*fNFT`NdGQiAH|Ej|Hc2f5bF>p2ufwkUZTFe}(dJ$`MX;C(0 z-V{r-E2m(c5BI}drL(~k6SEswne#fEUdvi&3FiZh%N)80&$C_2kh}Zs$!WSMT5)2L z->t!4_PuW(@0iMUf!tM3EXsxR=8aqQJS!tI77vxXD$Q$NZ1vCFp)TCJPPKgJ6$dq6 z6AvwIT>T_kTfhs9Ro&hblgcP`#)4Y!f6RfcKKz5}fFeLswhx__Ru z`f>qsFw=AMC$D2)!n`KC&FVyxLH=oq<|UuIL`hLk2jvOa!Qq_R3CqNXSp|NlZhBlh z@V0BxvHNAmtK__)^rv^SNw9j3M7}#zg*ToWtbKT~2{x#g2)k9TC|R>Dzhq!T-pA~R z>ZL3u2sdInHHePlU?n!;#-16SNWGJd=j+gQ4vI}N_YbJpa3kc$Q-$nCw8DusXXMl4 z*nJS|qzj=rNJpZI; z$vRbg>YS|lmxjj--{P0zyGBQ?yoS4%MX$EkOMqE$O+Pm%_1o-3WM-q=b4f2dQfTt> zOFR@zTq!4JBAQzKEZEFs#YOE+WUR@=e`!;~PCh-+ddeAuP%>I*Cd8Cb%!1YNZFKDIJTra-- zG#+}%TS;ZSZaqDK8^0CL=AU{B|LU>Hu0mU~}a9D5U= zlszxG=SokFC;8liaQHBlh z2BUO}iYG`REj!%$Xj-syeaVfwq3hF5*L>e!Jm^2?Jo?@}>G*`TrXZHmap&CnfJ4u^ zk68!bvsByruv+!zzl{#!R8}8y9^Ra-sENMbl68A9w_o}?z5eO*E&If08t#Rq+K#s{ zb}mq^_${jVjmeHhTXNWUoFMIe)lJ26`vXz zWvk~HR@whs?OF8cKV8YyEs1et|A`i*;GS`_+RH=ns17TKJg|lJv;Y(H<+2}hIXsat z5ANw;3-!HT?J@e?t>VkCV$sSaXTfoVh-!;h=kN@TPi^X~Dlo@yIP4fl2 z#pt2|1Jj>Ov$71^ei~h1H$uM|R6wY=ZG3Q99U>X|mV`BoS9`4vYw~J@(FazM_8hI9o-&aIo@yE| z6xi92RAt7!kM;6HVQV)mjXu!6Snn}L!YlYRm7CF)XL~-WsBd9Uk6GUDFm8S4@oR}s z!f_@&&0G2FHTy?nQd8F&@&}*SrC)xRgU!h6eepUXk}}=;?q@wX1aZ#AJc}avS@*XR MKo6o-Qerdz3wwRZj{pDw literal 0 HcmV?d00001 diff --git a/code/images/GitHub-Mark/Vector/GitHub-Mark.ai b/code/images/GitHub-Mark/Vector/GitHub-Mark.ai new file mode 100644 index 00000000..ab7c01cc --- /dev/null +++ b/code/images/GitHub-Mark/Vector/GitHub-Mark.ai @@ -0,0 +1,1564 @@ +%PDF-1.5 %βγΟΣ +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + GitHub-Mark + + + 2014-02-05T13:24:21-08:00 + 2014-02-05T13:24:21-08:00 + 2014-02-05T13:24:21-08:00 + Adobe Illustrator CC (Macintosh) + + + + 256 + 244 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA9AEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYqhpKfpKAbV9Gam+/wBuLoPDJD6T+O9ieaJyLJ2KuxV2KuxV5l+YX/OQv5feTJpb GS4fVdYiJV9PsaOY2HaWUkRp7ipYeGKvGtW/5zJ82STMdI0CwtYf2Fu3muW+kxtbD8MUoW1/5zG/ MBZAbvR9JlirusSXMTU/1mmlH4Yq9M8k/wDOWPkbWpY7TX7eXy/dPsJpG9e0r7yqFda/5SUHjitP bLa5t7q3jubaVJ7eZQ8M0bB0dGFQystQQR0IxQqYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYqh3J/SMA7ejL22+1H3yQ+k/jvY9URkWTsVdirsVfMf/ORX/OQF3Fd3XkvylcNB 6BMOs6rEaOXGzW0LD7PHo7jevwilDVS+bJrDUI7aO8mtpUtriphuHRgklCQeLkUbcdsVQ+KuxVXs 7G9vpxb2VvLdTtuIoUaRyP8AVUE4q9N/Jb879Y/L7VFsb8y3nled6XdgTV4GJ3mtw32WH7SdG+dC FX23p+oWWo2Fvf2My3FndxrNbzoaq8bjkrD5g4oRGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxVDSD/clAdv7mbvv9qLtkh9J/HexPNE5Fk7FXYqwL88PPUvkv8utR1S1fhqVxxst Nan2Z5wRzHvGis49xir4GZmdizEszGrMdySe5xS+/fyt07RdT/J/yzZT2Mc+nzaXbLcWlzGHR3CD 1SyPyBDScmGKEFaf848fk5bTSSr5cikeRy9JZbiRVqa8VRpCoH0Yratf/kD+T98hWXy1bR1FOVu0 sBHuPSdPHFbZJ5S8k+VvKOmrp/l/TorGAAeo6CsshH7UsrVdzv8AtH5Yq+A/zANsfPnmQ2qGO1Oq Xpt4ypXjGbhyg4npRe2KX0b/AM4hefJ73S9R8mXjl300fXdNJNaW8jhZo9zsEkZWH+ucVfReKHYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXkn5q/nLreia5/hHyPpH6d81rbm7u4yrOkEXHkAIkKvL IVPLiDsKda0Clguj/nt+dfl521Dz95Vl/wAOJIi3d19VezliEr8V9IuQklD+zSv+UOuKvo7T7+z1 GwttQspRNZ3kST20y1o8Uqh0YVod1IOKFfFXYqhpK/pGDrT0Zu232ou+SH0n8d7HqiciydirsVfN H/OZ+pkQeVtLVzR3u7qaPelUESRt4ftvil8//l9oMGv+edB0W5qba/voIbkA0JiaQepQ+PCuKv0V hhihiSGFFjhjUJHGgCqqqKBVA2AAxQuxV2KuxV8bf85a+XbHTPzGt9QtEEbaxZJPdKNgZ43aIvQD 9pFWvvU4pY//AM42am1h+cehDf07v6xbShe4kt3K9abc1UnFX3Tih2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV80HU/wDAf/OTOvapr1hc3tpq1tzsbq3iM8scc/pBZEjUc3VDG0LcRUfrUsl/5yi/ MHy9Y+T7jydPby3Os61DDPZr6ZEcaLcA+oXNPjHpEBRv47Yq9D/KLRtR0b8s/Lmm6ipjvYLJDNE1 eSF6yCNq9CgbiR7YoZfirsVQ0n/HSg/4wzd/8qLtkh9J/HexPNE5Fk7FXYq+Zf8AnM/Tjx8q6kqm gN5bSt2qfSeMfg+KXz15P1waD5s0bW2Xmmm3tvdOg6ssMquy/SBir9GbO8tb2zgvLSRZrW5jSa3m TdXjkUMjD2INcUK2KuxV2Kvir/nKjzTa63+Z72do4eHRLZLGRlNQZ+TSy/SpkCH3XFKVf8436c99 +ceg0rwtjcXMjDsI7eTj97lRir7qxQ7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqkXmvyN5V82Q QQ69YJd/VX9S1mq0c0Td+EsZR1DftAGh74q1q/kTylrHmCx8wappsd5qumoY7KaYsyxgtyr6RPpl g24YrUYqn2KuxV2KoeSn6Rg8fRm7f5UXfJD6T+O9j1RGRZOxV2KvPPz68jS+cfy3v7G0jMmpWRW/ 09AKlpYAeSD3eNnUe5GKvizyf5b03zBey6VPqJ0/VpgF0mOSLlBPPX+4kk5AxM/SM8SC2xp1xSz7 8vfz387/AJZSSeXL6CPVtItJWX6jLJRojX4vq9wvMBGO9CrL3FKnFX1J+VX5lxfmFoEuswaVcaZb xzGBTO0brI6qC/plTyIWtCSo9u9FDJPMGqvpGh32qJaS3xsoXnNpBxEsgjHIhOZVa0Hj8t8VfK/n r/nLjzJq1lLYeWNOXQ0mUpJfySevcgHb91RUSM07/EfChxS8Cd3kdndi7uSzMxqSTuSScVfUP/OH /kSaC21PzpeRFBdL9Q0ssKco1YNcSCo6F1VAR/K2KvpTFDsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVQ0n/HSg/wCMM3f/ACou2SH0n8d7E80TkWTsVdirsVfKn/ORH5DX2n6hcedf KVuz2ErG41Wxg+3by15NPEq7+merAfZO/wBn7Klj0X5o/lN5rt4bn8w9EvB5hiVFudR00Qul0VMQ MjiRkeNjHDx4qSnxOwAYiir6Y/Jy48r3P5c6TP5Xhng0N/rH1VLtIY5/guZEcyLB+7qXU0I7Urvi hmmKvzOvEVLudFFFWRgo8AGOKXoH5O/k1rn5haurcXtPLts4/SGpldjShMMNdmkIP+x6nsCq+5dH 0jTdG0u10rTIFtrCyjWG2gToqKKD5nxJ3J3xQjMVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdiqGk/46UH/ABhm7f5UXfJD6T+O9ieaJyLJ2KuxV2KuxV5F+YX/ADjN5B81zSX1iG8v 6rIavPZopgc9y9seK190K+9cVtnH5b+S08k+StN8sJdm+GniWt2Y/SLmaZ5ieHJ+NDJT7RxVkuKv BvLn/OIvk+z1WS+17U7jWojKZIrJYxaRUJrxlKvI7/7FlxTb3HT9OsNNsobHT7eO0srdeEFvCoSN F8FVaAYoRGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KrDEDMk1TVFZAvYh ipqff4cN7Uil+BLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVaV0Y sFYEqaMAa0NK0P340qU+arG9v9EntLGX0rp2hYESGFiqyqzLzAanNVK0p8XTatRfp5iMwTy3+5o1 EDKFR57da6/j38mLxaJ+aUFiqQ6siyRwpHFAfSljUiIqTzlheZiGow5OanrtmWcunJ3j9/6DX2OI MOoEdpb15EcvMX57lNvJuneZLO4vZtfuknnukt0UJJyHrRiRpaJRVXkGBooynUzxyAEBQF/ob9ND JGzM2SB897ZQrKyhlIZTuCNwcw3LbxV2KuxV2KuxV2KuxV2KtBlJIBBK7MB2774qwjWLf8xUiNvo 89vbcLi6lNxLKjmSO4uS8I4yRvw4I3H50HTpsMZwc5AnYfYN+rgZY56qBA3P2nbp3IJIfzYnvLuG 11ALb2s4jWe4W1BlVZZTyXhBsDD6fIdeXQruMsvTAAkbkdL8vPvtqEdSSQJbA+W+5/o91X59zPrC K5hsoIrqdrm4RAJp3CAs9NzSNUXr4KM1syCTQoOygCAATZV8iydirsVdirsVdirsVdirsVdirsVd irsVdirsVYVceQNSfVJbiDWZrazubr6zc20LzxsytKzSxh45UA9SN1BbjUcFptmfHWR4aMbIFdP1 fi3Alo5GViRAJvr5316/oV/NPkIa3dTXEVyls0zWzvyjLgvbx3MXNgHStFuVIB2qlCCDkdPq/DFE Xz+3h/V9qdRo/ENg1y+wSH6fsQ2j+TPNcMlncXnmGcNEKzwRvNICzxKjGs0kiMysC4qnGv7IyeTV YzYEB9n6B+3zRi0uQUTM/b3eZ/RXk1rn5cNqMsoiuYo4bi5kuZ3aOs3OSG3j5I6leLepbeoeNK7D 7NQXFreEcuQry5n9dIy6HiJ32Jvz5R/Vf7LsOn5e+ZF9SKDWhpsLHkq2IniRC8ryOsUImEaD4x2J LKK/DVckdZj6x4vfX31+PtY/kp8hLh91jqTyuv289tmd2sckdrDHKwaREVXYFiCwABILlm/4Ik5r pGy7GIoKuBLsVdirsVdirsVdirDL7yJqkuqXl5Z6xLaR3sryypG9wjAtGY6KUlRd6rWqmnFeNMz4 auIiAY3Xu/V+LcGekkZEiVX7+6uh/FbKnmfyEurPI1s8MQnihgnE6GUskXMfaJ+0UfiG6jqPioRH Bq+Dne1stRpBkvzoFLF/LrzBBeyGx1ZLS3kDFmhE8RZw6MryLFKgeR1VkeQ70b4aHLvzsCN42fh+ rl3Bp/JTB9MqHlflz359CflTI7Py9rEFtpEUmtXDtp0zvduKH62hEgUS+qJWr8a1o3H+UD4eOLLN EmR4R6uXly5fj9LkxwSAiOI+k7+fPn+PdW1H+YzkuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvmL/AKHG 1L/qV4f+ktv+qWKad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0 lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFa d/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1 K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW 3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3 /Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Ur w/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf 9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9 Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD /wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFafOeKXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F VQQsYHmqOKMqEd6uGI/4hjSqeKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KoqOv6MuOtPXh7bfYl74eiOqFwJdirsVdiqaeW/LOueZdYg0jRLR 7y/nPwRp0Cjq7sfhVV7sdsVfUHkD/nFXyvpcUd35tlOs6hSrWcbNHZofDbjJJTxJA/ycUW9i0nyt 5a0eJItK0q0sY0+yLeCOPfxqoG/vihFXumabfIUvbSG6QihWaNZBTwowOKvNvOX/ADjj+WvmKJ3t LIaFfkH07nTwEjB7crf+6I/1Qp98Vt8t/mT+VPmnyDqCw6rGJrCckWepwgmGWm/Hf7D06qfoqN8W VsMxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVFRgfo2c9/Wh7/AORL2w9E dULgS7FXYqq2trcXd1Da20ZluLh1ihiXdmdyFVR7knFX3N+Tv5Wad5B8tRwcFl1y8VZNWvKAkyUr 6SN/vuPoPE798WLH7/8A5yY8k6X5z1Dy3qtvc28VhcNatqcYWaLnGeL80X94oVqr8IbpitMzu/zY /LO0himn8z6cEmUPGFuI3Yq3QlELMPpGKqVn+cH5X3kwhg8z6f6jGiiSZYgSewMnEYqxTzv/AM5L /l/5buGsrFpNevUNJBZFfQQjsZ2+En/UDYrTPLzTvL/nrybFFqFuLnSNatYrhUanJVmQSRujfsuv IFWHfFXw7+ZHkW/8kebbzQbsmRI6S2dzSgmt3r6clPoKt/lA4sgxfFXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FWwCTQbk9BiqpPa3VuQLiF4S26iRStflUDFVLFXYq7FUVH/xzJ/+M0Pb/Il74eiO qFwJdirsVex/84t+VYtY/MY6lcIHt9Dt2ulB6eu59OL7qsw9xigvsOeeGCGSeZxHDEpeWRjRVVRV mJ8AMUPz38+6tpusedtd1bTA4sNQvri5g9TZiJZC/IjtyJrTtiySHFXYq7FX3x+UGvaRrX5b6DPp TN9WtbOGxaN/tpJaxrCyN/wNa9xvixeb/wDOW3lWO88p6d5kiQfWdLuBbzuOpt7nbc/5MqrT/WOK Q+T8UuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvoLyOmj/AJW/lRpv5izadBqfmHWrxY7eO5JV o7asnwwNRuDMkRcvTuBihPfLn55aR+anmCy8leYfLVrBpupidHllmadw6xM8XpH04vTeq/ar8qYr T5787eW28tebdW0EyesunXMkMcvd4waoxp3KEV98UpJirsVRUf8AxzZ/+M0Pf/Il7YeiOqFwJdir sVfTX/OHFvCLTzTcdZmksoz02VVmIp33LfhigvYvzca5X8sPNJtjST9GXNTv9j0z6nT/ACK4ofAe LJ2KuxV2Kvq7/nEBrn/ButqxP1YaiDGO3MwJz/ALigs5/wCcgYY5vyf8xrIKhYoXH+slzEyn7xih 8MYsnYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXu3kPzl5N80/lhF5C82eilxo8jz2L3FyLL1I6 OyNDclXjWWMyMnB1oynap2xQUN+QV9+V3l3T9R86eZp/T1rSp2j0y3aUO7JLF8Po24AZpK8l5n4R X9mlcVLyjzZ5huPMfmbU9duEEcuo3ElwYhuEDtVUB78VoMUpTirsVRUf/HMn/wCM0Pb/ACJe+Hoj qhcCXYq7FXvv/OIWuxWvmrWtFkYK2pWkc8Vf2ntHI4j34zsfoxQX1LqFjbahYXNhdLztruJ4J08Y 5FKMPpBxQ+CPzH/LvXfI3mKfS9RiY2pZm0++ofTnhr8LK3TlT7S9jiyYpirsVRel6VqWrahBp2mW 0l5fXLBILeFSzsT4Afjir7p/J7yE3kjyJZaNOVbUHLXWosu6/WJaclB7hFVUr3pXFixb/nKTXotO /K6bT+dJ9YuYLdEHUrE4uHPy/dAH54pD40xS7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FUVH/xzJ/+M0Pf/Il7YeiOqFwJdirsVTryb5ovvKvmjTvMFj8U9hMJPTJoHQ/DJGfZ0JXF X2zqHp+ePKth5l8p6pPb3yRNcaVJFM6RM7LRre6hB9NtxxbkCUO491il3lj8wfJPnTy39U8xi2N3 CDFqun6jHGFWaP1OXJGMiI59B24cuQAr0oSq+YPz0XyZB56m0/ynp0VjYWUSJM8XqgTTOPUZuMho qqGCjio8d9sUhhehXenWes2VzqVot/p8UyNd2bl1EkQPxrVGRgadN+vtil9/+WvJ3lHy9BTy/pVr YJKorLBGod16jlJ9tvpOLFOyQBU9MVfFX/OQ35kxecvOX1fTpvV0PRg1vZupqkspP76ZfEMVCqe4 UHvikPK8UuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVFR0/Rs/j60Pb/Il74ei OqFwJdirsVdir0j8n/zo1j8vr9oJFa+8vXLA3en8qFG6GWAnYPTqOjd+xCgh9FweT/yM/NWvmG0t 4bq9kFbt7aWS1uQWFCLmKNkPL/KZd/EjFD5j/Ony1o3ln8y9Y0TRYDbabaC2EEJd5CPUtIpHPKQs xq7k9cWQYRir9Fv0rpmlaBDfaldRWVnDBGZbid1jRRwHVmIGLF80/nb/AM5GjW7a48t+TneLTJKx 3+qkFHnTvHCDRkjP7TGhbpQDqpAfP+KXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FUVH/wAc2fr/AH0Pfb7EvbD0R1QuBLsVdirsVdiqJ0/UtR066S70+6ms7qP+7uLeRopF+ToQ wxVq+v77ULuW9v7mW7vJzymuZ3aWV2pSrO5LE/PFUPiqYap5h1/VkiTVNTu79IAFgW6nkmCKBQBB IzcRTwxVL8VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqvZ2k13cx20IBkkNFqaDYVJJPtko QMjQYTmIizyVX0jU0cqbWU0NKqjMD8iBQ5M4J9xYDU4/5wv5Hv5c1l1p17aJE9zEY1mBMdSKmlK1 Fajr3yM8co8xTOGWMuRtDZBm7FXYq7FXYq7FXYq7FXYq7FUQmn3zsVjt5JGCo5Eal6CReS1416jJ jFI7ANZyxAskD9i79FapUD6nPU9P3b/0yRwZB/CfkxGoxnlKPzChJFLE5jlRo3HVGBBFd+hysxIN Hm2xkCLG4WYEuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kpo3l3UfRhljCSLND6/wBtE4jqftlT sCKn3zIGlmRYrlfMOMdXAEg3zrkVXRLC+9e3urSaBXcScRIWoOBVSrUHU+oKYcGGR3jXX9A/TsjU Z4R9Mr6fpP8AvTaZG884oDMYUZYyQQvpt+1SlFap3FNssl4wPEf0NcDhIER+nu+77EPc2msay0Kz SwKyIHRQHFPVJUqaK1Cpioa98TjyZasjv/Hy+5Rkx4roHbb5C+/z+woBvLeq1T0kSZJFDxyI6gMp puA5Vu47ZUNLM8t/x8/2tp1cB9Vx+H6RY8+fLcpa6lHZDQlSQaEMNvAioP0ZjlyQtxV2KuxV2Kux V2KuxVNB5d1J4YJIVWX109QKGUEDbsSK/aFadMvGmkQCK38w451UASDe3ke6/wAd/RNtLl1o2yvb NaLSkDNRmdjFRFDGMNWg79Kb9MvwTybcJA6fL4fjm0aiGOjxCRrfn3npuN/111REz+YbWK3jtooK 8eEr81PORFHxH1PTPIKnv+GW8ebhHDXn8vPuAaODDxEzB3O1++9qurMutHpTGrjT9Taa6kkhZniJ e5ZaMoJox3Wo/arQZgnDOzt9PPydgM8Kjv8AVy80FlTc7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYqjBq2pCAwC4b0SvAp248eNPlTJjLICrNNZxQJuhanb395bACCZo6cqcf8ALADffxGMcko8jSZY 4y5i1e51zVbn1BLcMUkqGjFAtD2pkpZpyuzzYxwQjVAbKdvqmoW6FIJ2jUrw+GleNWagPUbuTkRk kBQLI4ok2Rv+P1Kz+YdZZOP1phuSWWgJr7jJePPvLHwIdwQMkjyyPJIeTuSzse5JqTlRLaAsxV2K uxV2KuxV2KuxVGxazqkUaxR3LrGoAVQdgF6UyYySAoFgccSbIW2mqahZqVtp2jUkkqKUqaV6/IYI zlHkUygJcwrr5h1hYRELlqClG25UXtXwyYzzAqy1nT4yboIOS7uZHkeSRneVQkjNuWVaUqf9gMgZ E9WwQA6KORZOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kvs3/rF/8A79r/AKd8WLv+sX/+/a/6d8Vd/wBY v/8Aftf9O+Ku/wCsX/8Av2v+nfFXf9Yv/wDftf8ATvirv+sX/wDv2v8Ap3xV3/WL/wD37X/Tvirv +sX/APv2v+nfFXf9Yv8A/ftf9O+Ku/6xf/79r/p3xV3/AFi//wB+1/074q7/AKxf/wC/a/6d8Vd/ 1i//AN+1/wBO+Ku/6xf/AO/a/wCnfFXf9Yv/APftf9O+Ku/6xf8A+/a/6d8Vd/1i/wD9+1/074q7 /rF//v2v+nfFXf8AWL//AH7X/Tvirv8ArF//AL9r/p3xV3/WL/8A37X/AE74q7/rF/8A79r/AKd8 Vd/1i/8A9+1/074q7/rF/wD79r/p3xV3/WL/AP37X/Tvirv+sX/+/a/6d8Vd/wBYv/8Aftf9O+Ku /wCsX/8Av2v+nfFXf9Yv/wDftf8ATvirv+sX/wDv2v8Ap3xV3/WL/wD37X/Tvirv+sX/APv2v+nf FX//2Q== + + + + uuid:8314b6c2-1523-0c47-8642-89a7e30d89cd + xmp.did:162c07b5-eacb-47c0-8418-83fd74d7f25d + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:19a4da30-e681-4471-bf3e-45206515d623 + xmp.did:19a4da30-e681-4471-bf3e-45206515d623 + uuid:5D20892493BFDB11914A8590D31508C8 + default + + + + + saved + xmp.iid:0280117407206811822ADB221B803221 + 2013-04-15T13:46:51-07:00 + Adobe Illustrator CS6 (Macintosh) + / + + + saved + xmp.iid:162c07b5-eacb-47c0-8418-83fd74d7f25d + 2014-02-05T13:24:09-08:00 + Adobe Illustrator CC (Macintosh) + / + + + + Document + Print + False + False + 1 + + 530.973085 + 551.985800 + Points + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + CMYK Red + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + CMYK Yellow + CMYK + PROCESS + 0.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Green + CMYK + PROCESS + 100.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Cyan + CMYK + PROCESS + 100.000000 + 0.000000 + 0.000000 + 0.000000 + + + CMYK Blue + CMYK + PROCESS + 100.000000 + 100.000000 + 0.000000 + 0.000000 + + + CMYK Magenta + CMYK + PROCESS + 0.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=15 M=100 Y=90 K=10 + CMYK + PROCESS + 15.000000 + 100.000000 + 90.000000 + 10.000000 + + + C=0 M=90 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 90.000000 + 85.000000 + 0.000000 + + + C=0 M=80 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 80.000000 + 95.000000 + 0.000000 + + + C=0 M=50 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 50.000000 + 100.000000 + 0.000000 + + + C=0 M=35 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 35.000000 + 85.000000 + 0.000000 + + + C=5 M=0 Y=90 K=0 + CMYK + PROCESS + 5.000000 + 0.000000 + 90.000000 + 0.000000 + + + C=20 M=0 Y=100 K=0 + CMYK + PROCESS + 20.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=50 M=0 Y=100 K=0 + CMYK + PROCESS + 50.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=75 M=0 Y=100 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=85 M=10 Y=100 K=10 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 10.000000 + + + C=90 M=30 Y=95 K=30 + CMYK + PROCESS + 90.000000 + 30.000000 + 95.000000 + 30.000000 + + + C=75 M=0 Y=75 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 75.000000 + 0.000000 + + + C=80 M=10 Y=45 K=0 + CMYK + PROCESS + 80.000000 + 10.000000 + 45.000000 + 0.000000 + + + C=70 M=15 Y=0 K=0 + CMYK + PROCESS + 70.000000 + 15.000000 + 0.000000 + 0.000000 + + + C=85 M=50 Y=0 K=0 + CMYK + PROCESS + 85.000000 + 50.000000 + 0.000000 + 0.000000 + + + C=100 M=95 Y=5 K=0 + CMYK + PROCESS + 100.000000 + 95.000000 + 5.000000 + 0.000000 + + + C=100 M=100 Y=25 K=25 + CMYK + PROCESS + 100.000000 + 100.000000 + 25.000000 + 25.000000 + + + C=75 M=100 Y=0 K=0 + CMYK + PROCESS + 75.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=50 M=100 Y=0 K=0 + CMYK + PROCESS + 50.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=35 M=100 Y=35 K=10 + CMYK + PROCESS + 35.000000 + 100.000000 + 35.000000 + 10.000000 + + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000000 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 95.000000 + 20.000000 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 40.000000 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 40.000000 + 45.000000 + 50.000000 + 5.000000 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000000 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000000 + 60.000000 + 65.000000 + 40.000000 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 40.000000 + 65.000000 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000000 + 50.000000 + 75.000000 + 10.000000 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000000 + 60.000000 + 80.000000 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 40.000000 + 65.000000 + 90.000000 + 35.000000 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 40.000000 + 70.000000 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 70.000000 + 80.000000 + 70.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999400 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998800 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999700 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999100 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999400 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998800 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999700 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999100 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998800 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000000 + 95.000000 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000000 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000000 + 90.000000 + 0.003100 + 0.003100 + + + + + + + Adobe PDF library 11.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 530.973 551.986]/Type/Page>> endobj 8 0 obj <>stream +H‰tWK‹€ΉΌΧ―ψΞ†HΚΤλκY0Ψcφΰƒρ©νυΑ³ kΓΒό{GDJUέ=Σ4t}©g>"C™ŸώςωϊτηΟωϊύŸ―[ΎψWά>ύαΗ|ύϋi–ΣvΥњύϊοΏn?έ~ΕTkEgΑύ `Εί_n9œϊ¨όίψ¬γΕ%qUi5υ<νrχΤΌωυς³nύωvŸi-μΏξ₯§:ηu©.{Šό]ΧΛν1P-ω˜(©Χy₯Ά*τJΕ1m% άΰΙΜ40WΏ fληVυΛΟ@Mσ-ί―ž©,-ž©Ν₯ιΒΕ‹VAμ)ηq}…²Κβ΄κ©Τ.e fSω^›VΤ4©^…kŠkEυ²9W,ψlh€WL™Ε­§ι'ם3WͺΈ,D:šgήίRος†₯)<ƒ-œ)ηTΔΆnίΚΫ}h)F!Γk\§ΏKΣ1/·η μtΘhŒQM•jL„6ζΠf¦I- #9m'ZΓ¦Ž3:TψΛ§,:αΨίnP}ŒA9w^‘Œœο@b¦k *ΙΉvζΈmm8sž#_nΈoλ¨K;Ί|½QQ?Šˆφ0‚6ŽW6ΒΦqΑ[|γΏΧώE<θ}ΫήGN¦΅±γƒϊYj±Y0ΊИ[θɁρ—Ϋ'²“S.x{}%ψ·ΘΤΰάΙ›…Q€UίYΥ¨(³nFbΰΚΞ²ΣβIΪ#GNΣkγ +ώyΉύτ»Ϋ__q„΅LŽ˜4‡Ο™ΒŽ0Kζάyοπ“H` [ΫSήΏξ™XA¨:|QB@heY)KΗ2€εC-τ3†&’ψ†7…&Μaςπ4€nz Q»¦`fRΙd‡ΜΩ’a‘‹7HF1DΡη-Ώ²B„έ $ΓπN`Ν°Τ+τ2 ŒŽerטωΜI—ΌςΘz¦# Ε¬*ζχ•q²ΈƒξƒBχ΅’uϊd&“}5; Έ…ΨƒΟΓV+\’jΒ΄ΘhНΧ5\>”ή@£C³!”Ψ›šd‡€UΑϞ‰βφ6 +&Εk›α0έ”υΪ"²8u³Tε*Υφ7mΰ"©ΏzxuAaΌΚE§•_³©XXψφfέQ¬Ν H|ΧnίΧ―v™Μλ…”„ήκaΆ¨NTcξPΐ‘*—«IύΚ"$of€λ¨˜g>>A*(XΆϋQŠΤΔ*ŽΑ,ψΞα ^…YΚ2yCθ"rΛχ hL4€ηΘόmΈΞφ‘D˜U˜ο3τ§z˜›= (KΠ"šξ¬c—"NβΓR†΄mͺ5ϊΊV…ͺΩΈ\+a9"XΖβIΉBUh…Ο¬@9Σ+^b[$–rnjμ]3 +c˜gL‰x’cT·Θ=NV`o?(’qͺVζΚπMΥΗP›nŸs'2‹iˆκt¨…`½ZΔa4_o,˜=|­x %§²3z ‘ˆ2«ΒSC1„YjQ`{Π=Lˆ–-«y€‡•N&j`© —φ6 Ε-XA½·ƒΰ œS™§^Ί•λΧ+ Aπ«V”>Iξ εζλΛνGœυw,ύGΎώωΑήN”Όέ ’Fyig‡›‘μ8ΛSwιm‹Γλ―  …;Χ;v9„“g Jf›[n]σ9Ηn/‰ΌMv@eZέž«EΒPSƒz2ξΑ„,w0,€ͺ\Η©cΎ’ω³κcΝ’ΟΡρH{eˆ]’€ΠTΜΌŸDa¦lμτ¨›Μ’AΜd–­bU0,+VtI5ΫΥ…‚φΣH²dΉϊ ϊ*”‘rv> 8Φθ[{3ΑWΗ Ÿ’9ΝP/ς`GYΑ.4…D©Rίδh6‡-Kt9`a9jpέTɊ­τeδ9ΊΠΚG€°ΏrΠN=«‘u[l™s™­Gω*©™e„tνR―‹ς°ˆ{ρ=3…Μ ‚ΙσiΖPΡE¦οβ1ΙϊφΆσΤ›δζϋ°‚κφkyDFgΔ.; γ‘Ρ³ΐ»5z8ω‡n68ˆSΠ8Ψ}d“5l?Ψ3h²Ζ’$;c!Λ8zΗ57Νtα³%WΉ©ϋυЇόε•ΌL +uΣήM_5ΌΎχςεƒ<ΊΦ–[Χ@—Ό]Z tlm‹ΰμ.Cάkπ’ζZέ…Ζ4Ε°ηa΄«Ψ¨ω!EΉΡ“YΙC)Šο΅Ύb)«§} ΓZC±‹T«ρ²’Dκ…Šf7+’Œτvcρ"Ϋ;§”vl6ύ)dΧ[tq;ί¬ˆ–SPxΘ Υw’Ύ*θΊΖ³·α°Κ6š##ο₯œΉγΆ΅dάv1™΅΄EΩζΑP>£Š!ε± ŒHKSο•ψ !=Έq1Εkε*eν<–ψv/f›ηϊCόBqcF)aΡΗΰΤο•OΕΐ_μ Μϋ»:pQ]Ρ#νh=­u.•Gw5xΤHΡΤ:'|¦7^ DLπ©λ=Ιθ'F +dρE:ί½u­4Εͺ¬§ΰΆΧŠ]GBiMρuΘ\@”1Σδޞv3ŠΐΐΊyŠχ¬ΟθM-σ8"Ο«3o΄[•2‘gα7™>PΝ6₯(ίRτ"C†€(£š’θzΫXΛ£ "bχ7¬AΨ#ΒΑ+>Α)z5Κ|/Ÿ„T€6Ύ»ξaϋ!ͺ}29Vd6›Β •j“πUΩΥ©„.©μέ"*χΤ(ι£\βυα†Ι¬_ώπΙι–δJnΆΟ)|O‰"υ;O*UYL6Ή"@υ{cO6v󡀦ψβD7(V$M―ΐ`q†qΤ¨‚α9zi,6vΦ 0±ƒ.¦9ΕΣ τp-$ΌΌoΓΊ<‘<\ΥKͺ«&"ٟGFXΖ *όψfΆ|ϊϋ+x Pη‘-hκiΏPό.nέ’šCΌ‹ΏΝκWΜΟΦMMV©Bq².mš§i«ΰ :ΞMζιΎNaΊ*2ΔΦ\¨8ΤEQ³¦[©R₯wO‘qυF[o†χy,ν85GΆHΉ(ΠΉ5Η₯ΡΉ΄N%U…›$0ΝǝΣ*e₯T’ΐtψ.Fu( + &₯Yή«24š;'C•Π}«±Θƒ\ [_΄’j¦ΦŽΰYΎ―bΉχj$ΤπΓπͺffL£8γΒ~TŸ1kΒ;GjœL¨Œ]υ7$ΩςΛ/. ζρbldΝ/AΘJvμ? βšΥGNμFρ>§ιSQ\c‘-({μΎ2l©_ŠΒΰ ψΩφYRτžΙžŸχƒ΅Η5Δ§_ƒ©8Ο«~nGU#’ΥΌ(›ΨΦY|ΉΧΦ?*ΟVLΜgρ›!_Οι«β¦5LΙ^Z:E·Žͺ)±rκ½,?E›Κn‘΅VΈuΉΠ:’ η“j0›”O3fΟͺ6‘ΗδΨ8xΧ‡Ψ#Ή³»Φ5NπhD΄νx…ϊbϋγ’uΦ­9„ΣX7ΫΊ„9 ωΨj¬Ο)N‰Ϊh~!θΒ3Π)HΣP έΕμYβUg—”zkι0‘ΘσδhoςPΏ5‹©YΕY&“r3tύi’0Ξ¦τ°ƒ{ΥN \`¨©φxζqφ‡σ>U9N~ΠrΨ €σΡVM€ύ=3u1ΡκQΜqΌs oUρz‡νNxΞ`;Ξ;ώ$H=Φ(œr]gb‰Θ3Π§#ɐΠI‡ΒW+Ά +rƒ˜ΐ·3¨χerΈhJG`ξ>ζʺÌWχ=„M ΝγΊ)ΰcpμΧ41z†’Κη*€£ώ]λdAΐ‹³U,βυ`ν/8,Ya#Q΄Rq§ήΚ%6V^{ύ‚7nΡ@σ,GγzΎt‰˜$|kT~οϊΜ+#NWyI0£τz#-g*β€ gg(XGZEˆΖσyq¦ž±΄•6*ΊuΗίXZύ@κVφ)ΛξτΤ ?‘zXΡ s€5`˜¨/Ώ-ŒSκΣόΆήЏQΟδ©ΥΝ‡ς²BϋδmIeγ1pΠΘ“ρ,ι€U°nDεω‹<»ύςτ9²°Ητ/ζo™cK9…2ΜτdΠ”Oz˜(]'ο;jjτ6ŠB"μ'€‹v΄…’oW`t¦ΈΟ=£θμŽ₯tvb^³!kΘαΫ‰],J_C›ΔυΓˆ1ΘC'c,ο3ω3„£qΝd„υλ2Ξ¬>λΠ’“dΨjζφ=§€X_΄ΐ½τν΁@―:%œ‡Ώω7μCq[έΡ9…° +ΧΟCš(.(ϊQ!Σ3Ηφσ¦σ,μPξYJŽΧHW…U:―[­0 ώ’t‹φά “Ί.ύIq£`άg…I–Θ UEŒ4₯-»%OΎ2%&ο!}“7΄š½`’žζΞζ”ˆ Y«ο6JΝHψDςšΑ‰‘`ι™!Νr‘Υynp‰x|#“ΎκΛAjsΚ3˜„†#‚ΩΔ5"—vέkς°³zσρΐ™ϋyΦΧd5¬nkλuΎΈ(Tΰ“wμ…ڏWE&X€Ίƒχu³YWΔθRi1‰ G""·ΠBՏ2ΨΈW搈Νg—’dZκS•―ς’’ωxX‰.χUu±ͺŽ{iτϊœμχ +“žŸ‚++€°E1/Ά?ΏBŸe~AΠέΉx½O6ΐO2Rh ¦αΝ.’½YˆCe”UꍼJQ›ΤKΈ!Ί}H=XΒ‘bτŠ€/βτ>σš ŒΔ9dt §΅ΑPΙ‚nψ†˜ο+ Œ*„΄iKΆ1Ό¨ +?/ΏΥ6Tσ”Ότšζzސhƒ53«^™|3;^:RFΗϋHB”ήΎΕx&MlοΤ–ίΜ“^€^λe#ž]7ž\ΆvΑJnOZΣYL™ό•Ρ"ηN²²zK$ζ­δπ™Ϋ•š—qnΣ‚v%Hΰ’\rSR‚‘‚&5Ρ8q&ί‡`'q¨θ Šˆ‚H8FTDc[ Š₯2tt­->}(š-=κυ}k,€Ρή­EΞumΠ†ιLAΐVE_‘xμΦΪ%ρ3 '8gG°Tμb5Τ+¨N’•Ι°ͺͺFE˜B]KeΉd°γ!Λ`¨ύ1Mΰ§]Ωτ'^'ζεͺlMΐwPC^6Ν_\σΉ ρ^5V ƒ‚?’ΈΠF’κΒ΅M ebc—ΨŽ¨ίYυ<“»ΘM?¨ΖZ₯]rT—]iΉσΠόE0ί ζt±w9B>"1χύ]¨a5%N’Κ:rv'θ"yΨBύ¨gžε―7˜)˜,tŽηΜͺΩΰ`¨EΑ€ϊψ>Ίψ.Ί«‚Y‚Ζ +.ύ˜ΐŽ3RX§πΓWb₯?ŠEΤ$0ar›³ Ι±―(ΰ$JΞF?t΄Q5<ρΜΞΉΖ/P—C—πŒXω˜e!%X{Ά7Λ0¨/œ‹Λ“F‘ϋ:g~sl +~»U­Λρ2m‰†šL .$•±€Ohu‚_R”NΊκΫΉ‹ +[§™X2ΫΓYυΥlͺβ4φ’ Απ ’)JtΓθΫAρf"‚Ζˆδjϋ +οΌζ§*Ϋ”R0Νr|ϊ MˆξV¦ ƒ·1DaBά~άkƒ ˆaμIΨοάΓ)9Εe€ϊΛ½βJf}†]Θ$Ιi―¦Π1ΐ,T+“@†!ξ18γm|ŽBτE.—”—)cΑ¨J—cWςΆΥί:Yε;ΐΡ₯`zTSFρΆ³‘§D=+ξ{ΝΨEύ•(Ρh6ΒζίH“oθΨ”?ύδ-}ώ2͐c0€qyPΦΎΖ±Υ‘4 r £ZXlsS)¨ΫDիύ<΅°€}!uΈι) ₯wάWY―ΑMλ)|TfΧ:€\4Š ^Ν…Ύͺhs³ζ|I&eΔy‘ ‘Δ;‹v Ω§Ž/kŸ‘΅΄r¬F œ;ΗaΉ―UkGZΤά4N35±-FζΏΧZ€ξS +.αsΈ¨ρΗΕθΆξο™lvO―9­ˆ.-νQΝεgΌ½ε—m‰€ΜΠ‘UΓ³σΈΣŠ ΝEX“;γM~–άhDΝ‚-€!§δςŒΝ!€ž΄`xμyΦΞR’FƒόUΰ,Ή©@ƒSvι₯žύISΕrM ΐC"ΊζΟ “ΜΜΗ@ΟτYa$kPœ bd¨€χ5Qι3.RˆΫuΞΖ£ίΒΖΎΔI›%ψ!¦‹».²šΖΰ}3H32‹Pl€¬τ#Όeλ”qLτΥTs>eζ*κUI4ΥTˆŠBΜΌf²α›j׎‰Μ‰²…xi –ΜRz\8Ύοuj8٘μ‹ψ/Z]CΈΐž·gΚ²%zxΜ.p_:Vw}€iJ(©Η΅t³ ϋPΚS«΄ ¦OW‹jtΒqgΠώ#ΏJ’#Ιqΰ½^‘¨$.οik³9d_懁»ƒ‘*©~0—ͺ€‚ΙAΐ—κΞ…Ώ{­βΧΟΌΏ@μ‰F?cυζœƒCͺA„ύ0¨²£ Ύ4ύXψϊεt6xι΅ΔΔΆθΰΙα5oIΙ0Έ7¬ύtzΪτψ§ΧΏΖhω€'$iι{ΒX$IO\άΙ5_Ny9+%Μ±=Œόiπ’‘α̞d“ƒwlžΊύR₯π )ϋ€ΜΑΑ%ŠΈαΩΙ«AMΪiΤ|ή}ρ½ž‘Ξu&~—d_(I-•D ·%2'ΆW>ƒ-x0§a=ωζhWΦ8( aq€A2lœζœ‚gγL c`xGfΐ%Α— ΡωΥ³H"ςiΧdμ ¦fΐ[pσΥ4žAΣ‰σ†ρ€πƒ„”~jcL~žΟΨƒ₯“]V` +Eφ€EμΊνΌΆν φŸNmΤ… NΘΒuωd8Ο‘γ―φ&ˆ#]›ΨŒ…Y’³Κ¦e>₯ͺŽœgUmZαλ†3?šk―±@ΨNʏ9dB©–9 μΜΘO™ΛΜu ’dώΒ©ΣƒVΑ_ωb&)Š•Oo₯ϊι²> +ƒ“-{ρr”Οϊ–ύ”OŸ)8ΗΓ$ )Β§DΏ}M"»΅‡τΌΝRε謁ήQySow—’Ccaπι%ήΟsΤ2…¦wN΄ΑΥc;Μqk«ŠCpЁμ"½(’•ΕΨ́΄Mjšζ‚Z © ¦½`=—@—3ξυLΰ«’lΑƒ7[v––t±9ήt> @ξΞ<‹†τ‰τα―ροMς½3}φ$n•|`87Z’ͺεΖη-A|JΪΈ±Έ&J6ρ7@CT3Ε‚΄έ7$ΩŸ 60Ο:ώ’J‰CΡΊύξ*—‚Ovu¨ρ–'’ƒ„ϊ \-ιΟsκDΓh ©•€’–°Η]λR2Φoςvμ½Pχ~)οΣύζ₯%»Όφ§0(~cι¬Ί›Jπ°žWΔΗΥ΅:εFƒHζ„όθV—‰Ξ;ε*dΉΎ Αk₯\ƒnŽAέh²»Ύ©γίΓEθκoŸW<°‘Iσš•szŽΟ6¦Ϊ—LrΓγρͺΌž ώΌι§Φ罝g£,Μ©/`ͺΌΎ¬y»)‘Ϋ*Χ†ΦΧΤ5χps cK%¨ΐΕωΤ©]»ΐ^TUωμOΑξΊ VwtŸu{Št―ΪMχ]~§S η’8eˆ~³EΚΜrΚ§†TYsΟΣΘω&ƒΧ‰’GœCz…ΝZ,Ϊ‘ƒ™¨μ"C€Θ‘g5 Ό˜ΓάΖe7φbδΐ'WEe+β/Σ1±Ν¬›Τ3Ghή8¦υ’²w#£φΥ'¬n^§Ίίœˆ¬ΚΦι—t ωŠ{@gwιθNΧ¦’Έ¨CΕrŽκ˜„έ½κλ°*<…C%Υ’ΐ5ۊηB3ϊ‘@-ν”E<Κ)d‘†λ²»Λ”Υ§œΰίΏό:ΠΡ)j‚8}~<ήihu|°ή.Β‘qς7†kjQKP*;ždΛ¦ήS:)4ΈAχ„!‡ά"Eϋ½Κ +0•Έε +ΛTκGjŒg?υL}‹½TIT›=VVϊκΞ:—χ9³zΊκQέ^₯ϊ|ψJuԘT‰5?Uόš­{1f1τXBiέ€οίΘκMΥΏMκ2[i­ΓFl`ϋβŒhEΘΒ+T‘AKΐV€–„2¨‘ŽFβ•~QŠN4‰R<ƒ2žUqJ2W7ν6+ψή«Η}•ΈLS`‹72)i‘Ήξ „½©1gπŽ„Ε’E‚7€•q]Γ0Ν¦ύ2š„SC-ρωΤφm"ƍ»ZΏδ9\r3dΦͺ΅ΠΫh™4§Ÿb6tSgDφ€ΧZ8Ht’†ŸΓA;8Κ΄ωΦωMοά―)ͺθ‘’vbΫϋ-Ώ ΛςYrήn@Sάτ( ι 5θ‘βm΅Ά3»‘š.¬Ξy’κZζεd9Ξ‘μ9ύyΞ$\tYaΔωP~ͺ‹wTθόb&πο σpYΨC5Λ ₯@V+= 9Α$©ί{οͺ£ŸKœƒ–g\”›sT ή7€B’X‰-–‚žh»κβZ/ 5’˜’}ϊΨΉ% ϊδSN²-ϋΐ k$ω+ΜΑ˜wŠw|LnFΑ!]TΨK!vS,2:;©Οωπ!ζ΅ζ]—"ASu2λ`Ρ\(ΧΚy–”υΌ‡]!χ)θIαόωpΑ΄}#0Ώ<‡Œ:s(Σ +΄RoΫΤJ”‘ΞR7*$Ő0Ÿ '΄2yΊs‘Α΄©ξ±šΟŒ¦OΏ#+‰€žF«ψυΔ‰—“Φ„3VcΎ~ύηΠξ˜*K¬C’Πζeλ΄όQK£‘ρ"Σ:_Δ_1΅Δδu₯LπN$“Νω‹€\Ώaν§ΣΏ~©Σž·ή―1„­ΰΘί,r—μΘDώΝωƒ·λωψ\ ‘Kίǝ} 7³q|ό{Ψώτ1Ο£S)Έϊo¬4ΪQCjΔ338Ε@~˜"U[³ΠΕΒ¦OΑDΒν¦rq#i~HΘ/!' ₯””›ίlΊ’v”:ΥD›οc5Β3² ΐ1]„€ˆ7Ιϊdή,ό”"£‚kΏƒ]œ#]‚}_πXλ ς ωε•ό’€’ΰLvB(“lΔΧb6}£΄μ + }L]ΏQH–ΗΫvί±}νώ ­$₯¬=QΟ½ξI:Oj¨Οθ7βMœηέΈY—‚pœ„Δƒζ{‰ΦΡ!Μ”ζΈ09 +t…ήͺ·§°Sw]rev6ηήΞΕ”aeί|£Φ*n’&³sŽVπx€Ÿ¬š7QyqL©K„κ’…^λ5›β—Œ:θ’2ˆz]"%±γ2]²mSτϋd;bxƊRqHΠ΅uSέ»h/§Ύ?<§H±Q˜·‚ +δ˜₯}π³έ˜™!‰€€+£ΟV'‘Χ{­ *ƒaΟ#,[šΡ”‡£ΈΩLΠπΫ3εx­Qπμή³φb₯Ζ[†X«.SXb‰θ!οWί;'t8υ=zΔ•Ž +ͺrλΎΛ$ƒΫλʏS+΅£«H.D†‚ΫH~Ι’i;₯„»Y…s:Ύl!BξΌEΣgPŒ•†¦  Υf"k°αgGŠϋ*€Ί]4λΧ‚’«ίβΩΌ©IB¨@5k² +ͺ%όύ?7βs{pΓ‚0ܐ¦ RWΎ—ΰ²°ͺΡvf/4ν *Ίή_d‡#qtV[,Τωυ'«GάΧ„Π4ΌSΔe9.4’ι‘l α ΄ΛΕ Šήάjο‹ψ Žύ¦ƒό±h +!¨‡…AŸo |Ζbg U%ΡΈύ ŠΏVΘ›9ΥΩ΅‰¨«¦C ₯±Ύ‰!o8ΦΈwΥ.Σ£³š2—»ΕAΖ™δΤb…`ε°Όδ78Ηt}Φ QcŠ…C§;$<š.ύ,&5:­©Δϊξ„L&ηΥiSλBΠ)²yΆ5ε„αyθ΅δ+ΙgΙt}•!D^Hτω=ό£ ΟΞΚ-Μσ Πw‘σžQ₯nt ‚AΥb;χ27Q …§«±EδΓ°Ϋ¨’ηΉσ*aDΡƒšK—Tΰ“ηe`’a˜Πχη<³&FΤo| :!!oŒκH―²δΘnv_ΐ)‘’Ά;Mξ ^·=3IMεΗ[zZΈ€ΐjrl°pά:?RMPdfTƒQ‘’ΝΛΖEΕ˜ ψΧXJ°yΝ ŠϊD”ΝΈ—ΰ Ε +š₯Š +@±|\±γh­ŒptbΕOlΈtk—&.‚Y'}˜Ύ‰σ2l²ΑΜγ—X#Pυ<\(R ™μM’ι*hUΞ7ž€^‘\¨ηvfκΜΔm(Υδ;]½…€>“UXio³^•φp2Rk¨cΪνN\π#G.άrοΗRpΦ3iκρπ-‹l‰"Ε}UΣlίΕ₯₯‹« ‡ϊΉφhΥXC0άΰΉEL%jBχ n4ιC²'φρλάŠΞεό 8؞Γ&ΐΘξΏΝ‚iρΒ:`5ςΖÖ́哇‚Ηδ?bdP3-="_hψDψ|2,܏ŽŠHήσΜ'o›«n²Prόk6ͺ’ΟΛGϊΰ΅ΐdΉW&W#+cλb²­ΙρdžŒ + + ²+TuΜ₯#i–ΰ\b3ŸΔΟ”[`¬2˜[ΝβΞIΟ ύΏκqέƒΘΙsAς½ΨΒΖ8Π_]ΰ4βM#§lψΜκΩGΊ€ˆ(K/ͺq89‡"Ύ«3Ιd—ˆTd»X–}Ρ«ιŽ‹Ί—g1Κf\»Υn‘˜>ߘΩ:’ E²Δθcλ(δoZ;δΝέ8 /‘B]CΎνΝΰΆCV4nΣ½Τ§u»Κ©$ΙZ.QΛ47ɜΚK˜j‹όͺν[νθ#DΫWύ sxώX‰Ωo•ΨψͺΔΖo”X|QbρU‰=Β Jl^‰ω›‰½R¬•bϋ₯Ψ»ϋ*ΔΎ ―οΊΜ~­Δlgz'#κ=νΌί›£σEωΙκ΅ς’|cΟG„3Λ6ZώY’IΠ6Θvˆƒί©2¦Fπτγώ|&P,‹Ή&Ώ7h*€$¨ϊ‚Γ>ƒkΘ4:{q§κqfq''γζΟαό’e'tˆQ­™tψFΤχg>3Ρ8cXλYb`Θz…vvΗͺ6ƒ„hΦXΪ«`Ι›Ίχ—qŽjΕ3ϊLΔλξoζ/ƒκpόλ+Ώήƒϊ—δΠavvΐΑfEΊ‹όˆ:Θ;V·ΨΧ»Δ“Σθ$;‰K‘Χή”KM¦Sΰ8“ΆLgύΥWιάχ]E§!…ϊ½GF.ΞλŠxβΈΧοaz/ΨΔΡ—ΰ`ΟβQ7m„:m«d!oτ…1΅΅ΤΊΊΞ΅ΊV^;”*Έqώ ϋΠSΕQ―~/ͺ]S…”Έ^NΣΞ…?οŒs/|‘ά½Β°ιpτ^K±Φ…‘Ί@{hδΞh aωγŽε)YνΆ |"ηŠ3}ŠζζΙ™Ι™Žšβeˆ‘θ(\ Slt½³bS,Ϋ$‡P€QgC²YZ†DC˜“œŒ(—iLΗζ₯e ‹ψA›M&žxαgdμοΡ9ΝΤΠ­‚’χMJĘβ©šΧ ±huR˜N9‚1šπλ8YνŠΎΡ­vϊTΣΒͺPͺΟ‰]ΕΣΪ¨{‘Zoޘ„~’ήE ™υHP©­:³Άr τ…―[™2Τ ϋ5εδϊJώΏ*2uVΕ¬Q}XΑϋ+ κe•"Ο³Qχ€˜&αΧS?‰WΌ[ŸΘν_Rξ'ΡA2’‰υŽΥΙA‹p²ˆyiη;‹Ψ/1ίHΔψJ"f‘ˆyΝߐˆώ/$βCΜ?ηϋΌqˆxγρ…CΔ7Α!ϊPΜ>μ#Ο€ͺxΉy&0‘#Α2c~2Y"’ΜΛ‚Έ Œ»Ζδ²uΕ@Ύ{eΔX:™ž‹΄ Ω•-beœ%Π­$Ɯ+5έf–Ι}ωΫ*ΝkΉΫ&‹AΦδ Μ™2~Θψ₯%c–€#37yoΉ ’;SθJ’ gR …h δ‘»S˜ΰ/’ΞJͺHoeŒQHe‘@σ6‚l‹« yYΐ3±\΄ψ}βΘ™ΚAΒ'“Έo \°—Ϋ.πrdό’ψτΞΘ+nJΑ\4²"`X6‡‘I¨ϊΞ ŒΩΧΡ„$pΜ‰w;„.Šγ”‘\“πdΌΑ„€›ΒLκŸΩ’Ξ™ Lgρ»ΥΈqaΘ-v–`νXά†ΰ’RU`Υ΅²IJΓΕσ p‚Κ;"ύ"ŸΞ37g†+X‘N“ /ΚΗP±ξͺG³Φ±,ύq˜opvz4uδ>€h™?9SLhΗ³ίνN’ Ί¦«wwXrdΦAb n4ΨΡMΧf ΖhNβSOwR©}\OšςJ&:ΗŒV,ϊS›ρw ±q°€P8 ΰΪR₯s·Έ?°q`]νΚ*‘yu[9΅;ΪαL"CƎ`d;ΊpQNπƒ]Tχ5Ώα2™lΓ‚@ލc;”qk³*‰ιOξΙΚξ$ `ρW‘Ž1‚Τ |ƒHΎ¨eXR»EΥ-S`"ˆή5&Η‰UV¦ΉΕlλΞκœβŽ[cdΙP΅βց―ρw$7Ÿ‡yf€Ύ`‚ΔRƒnυ,ήh«ϋ\nΨΥ³”}6Dϋ&ΧαJ<Šdρ~Žά Ή–Z2σ;W½α§x’AŽΣΚ9hΔc9cL2—E{½όΐΛ!¨Œq=ΥΚ}`nΚ{Μu9Ν]Ρ€Ρ+Jw¬ψΙRdk»ΚξGE[6ΓΏiΒY½Z'{Σ‘2;sΥ΅ΉιixxοΌ€z?α… 8μZFβΖU€€»X-솀Ψψπ(V9­Ω©š. wχϋΜ>ΑԘU4―•L@α™-c<;e†-―3zE_―Αξ₯ˆ­Όm†Ϊ’^‘ΐLwΔœε’ΟzΜrH¨uΘUΑϊ‘³W[”wΡ·Oω«F€Υ*JΝΎϊ3nSόH°Ύp3|J4k«τ’T"Ξ`–·iŒΊ‚uΤopa’ώθr9–#θοWΠΐEUeίρLAΦΚ Κ}^qdχΜμrAƒ›ΣΥ]yFFŒΤ°$ϊueŒ\lΕZ‘αsνi·vcΔ8χζpZ™JξΤΙDΤ%γhφ€σ‘iΒHι9'ӎVτBDR<»^¦«Ÿ/Ή1ξο₯†ς]κ₯t"Ϋμφ0[0έwsf\nΫ;ζlιLHv{ζ*GαN€Η$sμωΙμηleaRnΉdjW^%Ύ¬0κWMς4θ?υΛB›\»ΒvΠΏƒΧB“Ρ^™‘–b€ ‘Qƒœι!zŒKΏzQ1v6‰]”†Œ­€τōήπ.3Κ:G€fɁXΫκPs,FΟ5šΥ +± +zšΥ6.©#ͺΗ¦nuik ³ϊόIΨαžZ^λΣ7€΅—]έ-|S‘tΞqT£΅¦Ο―ν³ΕΒ׍κU?Zž€ψd+zJΨ-Œ΄*³λύ·ΎΊnuo9ηκ|^ν³ Š˜3žžΦ’ΛλRΈΫΜ8³ΐ]%OΉ)=jVͺΗ΄·\ŒJJ;0Σ\·i¦ΔΌVDκXΝFΧ`VσͺVͺƞέMΰΣûη{χ8ΥΈόο2ί©»δmšˆ¬’¬ž|tΘΙ=Έ#kΝfκGλσ8“\ͺΡ5@sΆ4άΕ;g$J<Θ-˜ ―(;SΖ₯½8ؚH/u>Y¦(Bγ%±’Ϋψα“ςΘ$ΨΘΓagΏΙθk?ŒS-jͺ5ͺ©b 7‚y™Ϊ©Ξ™[ΡMgξιjoi»~άRp|ΈcwΈΌŸ7/€ϊΌβ]lδKΕΤiύι0c_–rΘ»)9Ž/μ:YvBAΔςGέtMJ―8˜¬ι‰κ³[νΏG’Ό}υiΝ39d‘S +f&Dόσ‹ZOήDw³₯ύλΆ'κ'ΛΕΏΎΨnΞ_oω‚Έpε€ŽEτ6rt#.Šΐ/x©Q\(‹ίΰΚνz0 ˜Άώ +k^3>Ψ4'nνzcοn3ΏΗθΜ*z?ε?Ϋμ―Εσ§Φakl­ŒΚiyh S:eHeκωj“γgεgϋ>?qŸνς8ϊτg“^½/ωd–;ˆςΓώϋN8UΈTζ5β’Ί7ΰ•Ηθ’C‘2‡…ΕΓδήΠωC o˜Š~oδƒ-€¨†›:ΙΒT4B?lχ~α !:& Cυρλ‡A,τ„ργiπκ-΅πA―‡Τ"ͺΓΓ‡QΑDΑ0~ΓYŒτf1qΔσJ°θr~’/y]EχΨu’iΑY ]i\RΈk+.~10NxΎrGLμuΝλ ›Μ΄Ζ— M’FL#‹χu«κlnΑY-“«tό#ΝS‹‡Ή!λOfϊΜΗΫγŽ.3²Hΰ*GtΚωκ4‚•ΐM/ρΦJ ˆšA‘Ž‘ι_C/lΝNTΓΦ'ΙΥώf΅h ‹Θ|‚]΄EF…a0–;ȐύŒ―λ5Bαυɏ7άwλθΛΈ|ωύv4Kι(ƒwŒq=ΕxŒŠ™‚Χό|Ιίs~Qf?2ϋάƒ'›§/˟ΝYGjWu=$2&Œ₯‹Μύ>%•Ίϊ»·'Γݟ&gƒΟΑ±ͺ«3NJŒZc·=θpgΝΖ·yMνe{¨™΅•ψ–όWΜd€¨s«‹Rκ ΄Fˆ %&ς$XΧρ°σ6nώ²—Έ#‡mώYˆ}Δ=s_ΨRΔιλΖ²Ώ‘Ν©†E°M?τχ΅½_οŸθέP1 ©ΒΓς"7λ’‘Zf1\ψƒ’UvΨΟΚ°Ό½¦΅άLV:ώΠ„RηLvΩˍŸΐΤsœXIΡ¦šαψ–vΏΗ·}ψγνΣΝtMDΜύ~ϋδϋ§ΠΎΔΞδδζŽ‘fξnσJξυΓζμcΐΊ ‹ο*Ueuυ<΄Ty. μΥΕĐdψ21*"υ.η°ƒ:‰8Cμ΄ΣΓΎFηρΛTσsόΤ…?μΣz­Ι εβZ–‡xbΊ_†όΗψ„Μκ¨ίO₯D1+ΰje<†,άv–aN.%Β‘Δi 걐¨βωMβu¬%yωβλϊζaΔΞ8ΈGπΰ©5ōΔΒ’H© AŽdŸ’`5™n²^τ„ˆώ›Ίc‘ΐΪε'[„ΒΟ@άЍŠ P5oΥNI7.eΜƒΉ”1Ν\’’dΣ‰a]ΣθωΦ7ε9.ϊΖύυ~H+ J―Eωϊοψ’’e‹Ββ£ RοΊ[T-f<$οΟtRΟ”t¨ϊZΠχ³‡Έc!ΧcQ΄Βzψο6γΟΎ7ΚUj^όΡ¨w_|w•C«Β3+|Βq—²*’‰Vh­Ρ±^Έ{Œ)R˜ +s[ς6Όθρ*<ν žP6€."΄ό9€Α9Γ˘Όˆώ:]ίξKs°›Z^j WΡ=<»d$εμO7…AܚRΥ_πl0Χ­)ΌΉ«Ϋς WΩ•ΛΕ +r' +]a}Ζ䛝O’Ιέ‚wΟvΗ*Ž'`{Σ΅Rό9…ίν&XΗ½—ϋD6Ύ*]Λ·Eα6ΣΎwΞ1Ή4L)zΡΏ‰xΞn`Φθη%‚=k W;Ή5œˆϊ―.7Θn*O³cέs$Q»?0»C˜j"ν€ kœBΘ@¦‹”ΞζqbΩ ¨ογΐΤ#V4A-$‚ΏΘΧ΅ψήψ'Žώ«όψχ?Ώ«^x}h ΧϋίΎŒΥvΞσ ΎάKίΗW•Šocϋμ‹H~>!ΐ‰άSE―ΖΕ±Σ0|žύxFAΖe‘Μκ₯Έ'tΞ[…ηZ•±€[jΙn<³νΘhπ³ΊQŒ/ȝθΗϊ.Zw«κ)1‹U[υΆˆyΤfX ͺΪC„ Χη5 GvΤXvNq)"Ž+©iφQS―ΥγSVs{N)MΜ|?"")ιζM­D\ Yc…{Y›ΞκQ}fυ-,ΣϊE°›Ξ$³ea(DCΡωP¦)G‘ΩId΅ΚΤβΉ-ZŠW™L3”f[„ΧJ…΅„]ž)ΟΤΑ4Gα³B}1Π‚ά=R¬¬‘ξ=΄ kU‹Ώ7· +Ϋ)Jُ8–˜ρ|πΚ(ϊ»œΖ>džk@ΖρΤ·4r'^&Λ³όV\mΗOZ˜ ½ΝBM bž–ϋ β#xlΜ€XІƒΒ@£(c䝀νƒδjΜNΧ³…ifκΨ?iuqJέ―]mϋΧ“}BΝΠ»YΞ~š³žοrΏΑ^SgλΤ­g«C²]‡Ϋt₯·Uύά»ι½ύτl\4m‡j8Kˆƒξ’­ά–IΕΈM-SŒξμy|”)―aY›=HrDߚ8›”-$Z0νi!>“°Νpoδ( +~ς‘’²?Œ" +f„s5Ή\†κ‹JN”ΊμπS΄mκ ·[φΓ©5ε!K塨lfαK.)cΡΡavΦ R}›+/[e%π`†Φ;χ&ΈΧ SͺΌζΝΫu™A κ&ΡBOσ:ο +­‘–βLρΦζ5nN 2Tχ]ύΫͺ‘“0\βμΥn­Ψ1Ήσ«E$2ŠέΪ­β!‘4pΝτ΄±$gΉyͺ6s¨1Ešq©;ͺQŸ\œ˜λAΦΓtρtWI’$9»Ο+β&ŠΤφž±1λCυ₯h <£²j.™bH… `«;ƒΉ¬›„ χ³]|‘2$Δ§™Ρ α2ˆbmγ CG’:†E0€ίjXAΖκ·_ζ8ΘQά θζcώ„Y9Σ‰{R+ΉλŸΨ…ytjίΨv©λά±©^3J58ΓΖ$―KΫ0œ_₯œOašι΅ΊhΠ<s‡ΙΜ9Β(|Ά^…”­ +Δίκj¨§PΟΗŒ‘δ0§ΊΝŽAε˜—7ο…EΥ½ά`_“5©£Πα€#$pdSU‡ΧcΡ9χ„ri¨…­Φ[Κ50η*[u‰ ³{½'ϋ j½•XθHw<ΗδͺB)°²ωΆ}Z™¨ωΥ΅’δMsάΈΙJχ&PjfΠ½σ]Š3“―Ϋ—’O‘>’·Ή,΄EsμΧ·ŸGMρa$žΛo|ϊJΞ:Xe0ςςγ-Ε±ψΔIρ)˜ΑήΖ~rL‚Ζ[ V> λ3Β‚Š£aBJ(π_^H’²Ώ[Χ'²ŒΧΞρδ9IiˆΣ°˜λ¨°±nu92VΎ²b#@Έ€ƒΆ„«:Ύι"ξβK8^nΨ(ϊOŠ]§X±4MΓbc§Qγζ¨η₯ΆΨXYƒςΓϊGΈ¨ζQƒžΓ³|ςς½ λrS*]jτ%5T“μϐ–qŠ{όfΆύυ;ΘσΘΪHΚ΅¦ύΒρ»Θu‹ͺ Ρ.ώ6«\Ε7Π=»*K5Y%ύDΙΊΈΆ©›¦­|/δ8G4™»ϋ:…θJΘYsaβPEušn%=έ=EΖUm}ήηU©΄γTΩ"εb@η¦—FηΪ•LΧtΕ@:ΧΗνΚdET’ΐ΄ω.Bu* +m "₯Nή+1Ԙ;ϋBeНUSδF.Œ­­δj©΅#tΦݏWάw5ςiάΓ0U3¦Qqa?JϘΥߝN)NTΖτly2Ί‹ §Ή½ψπXέKHͺ’ϋχPFqΝ*#'τ’ψžΣtΖ”ΧXδ +Š‹― [*—"0˜c?Ÿύ(-zχdΙΟ{ 1νΉόΣ―ΑPœgͺίK·£¬Εj^„M\λ,Nξ΅υoqMρ0βΨΝΠ]Οε«δ¦5LΑ^Z:EΆŽ6ͺ&±Μ>,?EšΚn‘΅V°u΅Πˆ9R κζͺ/›„O3FΟͺ6Ηt±q0Χ‡Έ#™³»Φ56πh΄ν˜B~±ό±©:σŒΦ‚i¬›m]Ίœ†ξΨͺ«Ο)F‰άh~!θ’3Π)H έΕλ™βUg—xkι0QΘσŒQρLhZ3^±ΐ,w,tˆizγ±δ!ω7λ΄«=fΉ./B‘¦; ‘…ŽŽ@«ƒψ!‰ΖΒE―Q~›wNΜδέD'‚Χ¨LμŽQ}ˆΡήd‘~sM³’ ͺL&ΥfθωΣ$<`œMαa;φʝxΐPQνρ΄γ¬φζ}*sœτ e―AJηΠVu€ύ‚š™z˜Xε(Ϊ8ζ\ΝΤ[F%D|Ναs'<§³ϋ€k” N΅‰ͺΗeb‰ΖΣΡ§#ΘPI‡²O+rrƒ”ΐΩιΤ;Dš.‚h»Ή2οΠβU½[‘@Σ†ϊqέˆπΡ8φW7/*Aε8› +ΰθ u2!p‹³ULβυ`ν/8,Qa#θΡ™€nszνΌμzύσΏ\a#iB†ζΝ‹―άπv~i±H\¬Qτ}Z(2¬t7οΙ‚ε•7br¦ά ŒpVoϊΩp€S4„+φ˜ΟΔ™ci;/ε5Ψ)JIΗߘW=՞ƒμA~ŠΒ²4=υΒO(ζF4hœN²H;σ[ΏψRJEšgk†χΨ5&G­R>ܐ3Ί +έ“Ϊ(‚Κͺ£+±ΌCcΙ¬‚u=ͺ›³Θ±Ϋ/£#³zk XΡN²@jυzφέ§|˜^΄ΐ»tvg3ΰ­:Υ.ϋζί°—βl΄z£³ažŸ›4Ι/‚IΉμ"¨Όyg:χΒŠΐέKΑρjη*’° +η½V+<Β}‘zE{ή†.]ώA]#gά±ά$Kδ•Eτ4U-»%MN™‹ο6ˆΙZυέNτŸ€¦†ž³Ω!bCΡκάF• pC>3Ψ-δ,ιLYαNO ƒXƒ32θ«Nš{©άƒAhΨ"M<#riΧϋ°f!;³7‡—‰±Ÿ±N“Ζ°^όŒ­ΧFxϊβ’P‚OΎ±f?·*"Α$eΓlΖxh›Νz"Ϊ–R‹AL4Ι±…ͺz”ΑΒ½‡$l>_ΙϋwC†₯ŽͺxΥ-*˜Ο +Πu}₯@=¬²γ>΅>gωί{ΉIγ'αΚ +)4|"Ÿ&ΫΏ#Ÿe|AΞΗΐΪυΩΧ€>IF!šϊώ5»ψυfemPQ±Ÿ7R*9mR*ί†˜φ!λ`‡rΡΛω-PzŸyM0:β’9zΣJ=)‚n8CάΛχΥNFBΖ΄₯X%X,…Η‹ζoU ΐ<₯,½zΉΖ:ΦΜ (e^ΰ7σΝ₯C₯wβ$ΚΛ~Έx&αΡH¬τνoζΙμόI₯ΦΛ;Œ]ž\Fš„8ηηΙh:S)CΏθ,€•ηΈχ‰x+Ω»Z@†v₯Ϊ₯›[Ίte^^ρ‘Xd#‹ά“ΰ¦ HMN|‰yAγΟΨIƒ’€$y2tωΗT…Έ/€CΨJI,=dπžΫψomιγEέΈς¨2Tσ­1ϊ£}Z«ΚŠ&ˆΙ™ͺώ-BpΧ­΅Kšg + N°ΕŽ`šΨ…iˆVOνDύ)’>UFr1ΰ„r–‚rΙ`±C–A?ϋcšpO_e½ŸψΪ1ίV)k*ΞAu²7ά²©υB7ΰ lΝ]`·¨|π©Aœς‘Ύ…Ύj€¨‘ +\Ϋ΄P&ϊ0ΎΡι[B!«zghy’©ΪEX«  =Ž’² >: #kj½pζΜς-Φ-[/\Θ!<sίί…V½Xš$I¬£gy‘G°y.ς†-ΐs/šA;ASαεΈΟ¬Œ φhY$ Xο£‡ο"ΊΚט₯c¬ ] ΛŸ”@tΠ ?œ!Uη‘/’š€ ΫœKŽοŠύM"δlΌ‚Ž"ͺj'(žΩΩxςd^ cψΚΗ, !ΑZ=&θ₯Βσ…mρv(Τ^gΛΜ#Η–’ΰΡΝ¨e]—ακ,Σ–Θ‘y|LDȐ•±$Lhu_‘N’*ΫΉ‹+§™ψ1«Γ™τΤ¬©b4φ’’AΫ FΊaτνtq Θu3Ac 8r΅} yw^σ‡Ÿ)($ $`κβ8ϊσ5ˆβV ‰7 ΡD^AΌ~άgƒšˆ[μIΘοό† rŠΕH%τ/Ċ+T”ΎB$IK{Υ„Zˆd£";±ŽΑφ.oγ8Φ .†ΐ„Π’‚β‚5œ€t±8Υ!#m[ε œ“Υ™έωΨΉ΄K―„jŠ(f;λyJˆΓ±b½ηZ‹]€οP‚ŒfΒƒίθ’oΨσ™)Ϋη/ !7—eκ«{PzΓ ϋ9J…Ε"7e‚jM½ͺάΘP + Θ’…»Ν2έq§2]ƒ­'ο‘˜]λqS@œ)"©ΘQ9›λœ)ΰ΄˜$λγ kЎώ%ΏJ’δΘqΰ]―¨”Œ$.οik³9d_懁»ƒ‘Ω’~0U@Αd€ ΰ Δ{v Χ§¨’}Bkwϊ°"2φ7ΗΕΛ΅6RΙ’εf'—i†­3"^δυZ‹›ϋ–uΛ?ψΪωŸΣKΛmίς9@ά½XZ]Z:ΌfΛN|Όε—ϋ’ψ˜M«…ηΰv§•>bETS:ρa ΏΛg4‚f‘°Ή¬πbs΄02π,Ož΅³μ†dQPΉ +ϊΡ‚ε3UhΘɁ&½Β²°/†j– 1:@ώ“άΰ―ή»κθ™1—ΚHΝ :ΑΎ(Pο’Σ§_ €ΦΔίYΒΖ±ΔN›-ψ%‘‹³.jšΖΠ| $†Μ&"wsΡ;ύn9:œ.εΪΥs;ψ•š`‰q~S%>β•˜χš—άΤ»ύtI9 6—&mΞ–YΊŒο{ά…v"6x}ώ₯θΑΠ±„ Zΰy{¦’Ύδ?·ΩfKΫ*ᑏ4‘„.υ˜–nΒŽ@›μuΙΟ!@˜6Υ@V#*ζDβ&…¨ξα\ψ»Χ*~=ρΜϋ Ğhτ{¬ήόƒip΅”Ώ9SωΠF_~¬{ύpzΌˆ4ZbβZ4π䋍πΊΆ$d8ΫΦ~:< ,Α‡ΕλŸ1:D&ΰIΏG#EFVwa%;qmύ;—|œ/ΝPώΪΒȟn8[b%“Ό+ Ξ±yJε6φ +•’3€ιgwdŸχB7<;95(G;m€•ςΟ»’½Χ3€ΑY£"£ΔΔοΞΧEHΚ¨œ’gΈ₯‘-±½ςL ΄Γp9­JcυhΤȞ v„Ή^‰°q’ƒ. E·xΣ‚λ”ή‘pGAΰ%`t~υ,ȁrΪΓ5;ƒ©π\η|5gΠh@]γό€‚a<)œ ΐ UŸšSŸη36?€ dζδ>W2ÐRLT™4‡·±»€UΒ΅}ώΫ©‹ΊPΑ WΈ.Ÿ η9τ`όΥήp€«s—±0KrV΄ Βΐ₯Τ‘Γ¬ +’K+|έpζBCMΟρ !€λtŸόθšCφ“‘j™£°ΞŒό”­Μ\—‘Jα/-œ:=(ά%‰Οž‘˜XUτoι}Ϊ«―‚ί$Κ^”ε°„<‡U?ε@Ρg +ϋdρ0iBΚο)Ήίo[S{ΘhνA €•Gc ΄Ά8Κ›Z»»Dϊ +cOρ~ž£–)4½s<ά<ΆΓ·Άjž8 Έ‘n,;ΏΚάjζ@Ϊ&!M[AΠTΞ^0KˆΛχz¦ϊχUQvΰΑ›-K3ΊXŠœnzžm·Ÿ”#CΚDʁΨ†ΆMŽΆe–\%΍†¨bΉρyK +ŸR…6n,š‰Lό °ΕL™ Uχ ŒΞμN°Z€Ύό_0* c4 “U%Χ»ΪΣxΗΉABv«–„η9u ‹a΄‚I4‚œu­CH­XΏΙόμ½ χ~)oΣύ扑]^ϊS 8“GPΑP: ‚ή¦Τ.<―δˆ+hʍaΜ‰χΡ­π-)wκTθq}a‚­$k¨)yž…Ÿ³ν&2ΗΏ‡‹:‘Υή4>―h<\PC4“ž5 ηœς¬ŸmLυ.#7ͺζŽΗγUx= =όyΣO­Οk;ΟFY—S_ΐHy}YΓvSB―U ―#¨iξα§@Η–@P5€‰σ–©UνΎΩ‰ͺ)Ÿύ)7Γ]7ΐκ†ξ³ξN‘nU»U[Λζtjΰό@rζ? ΡmΆΘ–ωΓA:ωΦ„*iξyιήδλ:q‘Ÿž›Cf…»Z¬Ω‘q™(μ"9€Γ%cΙΈ—Γάd sΟ_η΄'MAε&β§ι˜X£©‹Τ3hή¦υ’°w#£ζΥ'¬.^§²ίœˆͺΚΦi“t Ω‰{@gsιθN³¦’ΈhCΕrκ˜\έ½κλp*<…C Υ’ΐ5ۊη¦Œ«Bϊ₯@-ν”E<Κ)δœ†λrΉΛ”Υ· ΰ_?όΟΡ©g‚(}~=–ieu|0ή.²‘_ς7†khQKΠ);VD˞ήS)4·AΣ„‡"=ϋ½Κ +0”Έε +ΛKκGjŒg?υL}‹½TIT›=VVϊκΞ:—χ9³zΊκQέ^₯ϊ~ΘJuԘT‰5?Uόš­{1€e±σXΒhέ€οίΘκMΥšΤߘl₯°„¦ΘKy˜Œ„ ΌB4μ¨Hˆ‚šιhδόΫQγw‘τ‘άD(Γ3(ΰY_P˜fΪmVπLWϋ*Q™vΐ/dRΜB!rέ{S_ΟΰhŠEoOHγΊύ0β…1`šMϋe4‰8¦~Z"σΩζG΄ 7ξκό’ηp ͐QX«ΦBi£c”~‹ΦΠL©π]kaшš|•ρΞTšoίτρΞύš‚‘Š.-*i'΄½ίςΛ0+ί%δν$ΕνJKΉQM@«‘?Δn«΅Ω mΤtap½ †4ΜΛΒr.œ3Ω%rϊσœIΈ½Βˆσ₯όV ν¨ΠωΕLΰŸζα²°/†j–J~¬VRr‚IRΊχήUG?δMυ!ͺNsŽ +Τΐϋ†”GT*±ERΤ »κβš.Μ4’˜"}:ΨΉ% ϊδόRI’-ϋΈ S$ι+ΘΑ”wκv|Œ£SΑ![T˜›ΣΙtSHŒ±“ϊœβ +Ya^kήuι4A'³Νr­<η#a:οaWΘw +yPΕ‡ +¦ν±€™ψϋεΑ8dΤ™CΩΥΆ Μ¦vUΊ˜ Œt–ΊQ)†„ω„ΐ½όξ\h0mͺ{¬ζ³λΡοιw$%ρΟΣhΏž8αr΄ŠοΥ˜―ω gwNκχˆ,4ϋΕΩΌ°μœ–Ώ—`kBfΌΘ³Ξρ3¦–˜Lt ^ΐ„d£9κ7¬ύtψΧ5Ϊσ³ϋ£?Ψ ώ‡τΝ"wΙ†\ΜΉώmxΎΎWδηqcΏ„›ΙΏ8<ώkΨώτ-Ο“ƒgηΒόχQhGέ¨1Ι4ΰύtϊ\Šm BσΘYr'§Iׁ­ gΪ[/ΟVŠΦΊΜDpI»Ξ[ρΞLV‘SX^Ή4δΪg ‡π޽Π5ΆfGό'}΅«Κ…ΪΥ>&)›o€­ζ’wbwΧdΪ|‹^:ν>¦OΑDΒ…λ¦rq#ι~HΔΓ%b§Ci"’ρcσ›MWԎR§”hσ}¬FlF7¦‹p"Α&)Ÿ΄›…ŸAδp΄"pνw°‹p$J°ο φj]Α΅C4Ώ€’_JτœΘ.AYc’Œψΰ:‚Λ¦o”Ž]˜©Λγ7*ΓςxΫξ;Ά―ݟ‘•€’΅'κΉΧύ ηI υύFΌ‰σΌ7λ’.„“θƒrΠt/‘ί:ϊL Ž‹‘£Wθα­z{ +8uΧ₯Ufgsν\L.φΩY΅Vq“.™s΄„½δž¬š7!yqL©Kκ’U^λ5›Κ—†:θ22Xz]%«γ2]šmSπϋd;bxƊςpHΝ΅uSέ»h-§Ύ?<§±Q”·‚ ͺγ(‹Jγ±33$‘πu5τΩκ$τz―΅AY0μy„zeK3šςodφΝ Ώ=SnΧΕώΑξ=k/JjΌe(΅κ2…₯dPα!…ˆQς~Ε½ΓmB„Sάc‘G\έ¨ *·ξ»L2Έ½ό8…R;ΊŠ$Bd(ˆ±δ— šΆSMJ΅ηε)”˜Σρe ‘rη-Ž>ƒJ¬4Υ\h¬ώGz•$Ιγ°―τμ)jϋ“ ²ͺΪφL8ζ-–”ZΈ€ΐζE–3α§αŠϋ€zΏhfW{’œ―7ζ Ί΄‹Ο‚₯€2k2*%β5‡Ο;ρ9νά° R•ηJσ\V5JΞΜ…§§š’β]Eέψ86£·Υ…Œ§;T¬†ˆΧ ‘ι# ·Λqa'šžt)ιύ'¨IΒ8on΅χE|΄Žύjω±ΪL΄:Ϊ †Ν>όbρg UΕΟΈύ€βοb5+&ΩVVυ .ϋ`!ΰQ‡PίΤ ―ιΛo¨ΪmτH¬¦‹KΩβ~&Ϋ\±†PεΠ»lΡω +Xh9]οΨg].&W8TΉ.ήΡσ³x)7ΚRυmDΦΛ J6–Κ(Q+HIΌΎUδDαy¨³€)Ω΁:•&ήγ;σ»ωG6"+·˜#γ`ο~Ξ(ΓIΦ)>ͺΕdΆ5£9ύNAΣq₯ή½<2XΝΖHΐˆ‘.+)#&g,PΗΠJΘϊsι’NΜoœF3a;ή(ΤΥδΧ`Ωyu~₯ ΎΜ ƒ"1›—‹‰10&θ―±D`σšAυ‰›q;/­I +Ϊ0δJ•`bωΈ:ΗΏΠXΰθDŠ%–ΨpιΦ.I\„²Nς0}ηeΨ(\ƒ™Η/qF ͺyΈ0€2Χ›6DΛUΠͺ˜oΈ8ι4‰Ο!"ЎΐώeΡ]>ζliI‹9?Ω±nω±b¦jnMΏΈsSM‚U€ά•ϊdμhΚt›_ΟM“Vwφeζ$ΰΞ’γϋ|=πšΡX=Π1ΪοΤ~ύu0R6CΥγhϋ–­λ;§’ŒL.₯^`n•δL03α’₯Ε+"ϋV]žE‚ΙP~υΧTΓ2g«Τ†žœxd·z o$κ›²~•5˜ι€"g³d{™FΎΣΩ€Ν7„ϊ¨Μ|3κξ„  ϊΣ@ρ5!{ˆw©o‚q‰7I2.‚ΚXB”DU,™psU󀎸₯3ʐߟ)§˜ͺUΟv(Ϊη$gMαp.Ϋ›}uxΡl6υ~sΖώ fρCΜ/m%(A‚ωΨ#ΌU ‘q#zΜ-V`*˜(QΘc­<χCΕ©6!’›@EΡΉΰ?BXΞη°† φ€5²o³@bZό‡¨XΎͺZŒŸš 'ΙDΚ,‘fZzDΑΠcρ‰PϊdXΈ9‘Όη¦Oή:$:Wέd3 $ϊΧl”&?.-Aρ`ΧIβΪ‡V&e#9cc²­ΙρdžŒ + +ΐ²+„uΜ₯#i–F‰ρoζ“hšr ΌUs«Yά9‰4!!ΨA9Ξb}P:y.XCΎ[XΓώ«œF„£¬i€– ŸY=ϋHόe‰F΅'υρPΔw΅d&™μR’κ’„±.²eF_τκ½γβξ₯[Œ²Χn5έ£ ‚ΆŽXCq-‘ϊΨΕ +@>Κ―Mk‡ΌΉgα%2©kΘ·ύ±YάvȊΖmΊ—΅nW>5b$ΙΛεk™ζ&±Sy S‘_΅}«„`ϋ*°ίQ.Ρydb£³ΏΚ±ρ)ΗΖ_δX|Θ±ψ”c:ƒΫ—cώ&ΗDe―λŸzl³{—cŸjμ›ϊϊ.ΞμΟrΜvfw"QΚ²³σzo~Ξ―?δkld¬ΧΚ{ξ=ρΝΫhωg‰&Aΰ Χ‘"Z|§Τ˜ΑΡ{Œϋσ™ό}@Ά4.ζšόή l(gΰλ z ?ψ !ΣθlĝǙÝ"€„΄›?‡σ‹–Pδ€8Z3ι)π¨1ξ7Ξ|f’qΖ°Φ³ΐΐ’υ +νμŽUm Ρ¬±VΑ’7uοqŽjΕ3ϊ1˜‡ΧέίΜ?ΖΤα’το€οΧ{LŠMV_gϋμ΄QL »ˆθ§ƒψ°]εi‹M½K€15@ͺ“΄wν(ΉΤa:EŽ3eΛtV_}•Ύ}ίΡΥNt2¨ί{dΰ⼈Ž{ύ.-¦‡φ‚M ώυ,΅FœΣΨΨ£±JF_³Xϋx1K‘«λlΠP«kε΅C™‚ηί°/=IυJ€χβͺΪ₯1SȈϋˆršΖp.όygœ{α Εΰξ₯πθ†M‡+ χZŠ΅.ŒΠΪσ8#w&: Λw,OΙj·Wΰ9W„ι‡Έonž|™„ιΰ¨)^†Š‹Β• 1%υΐΦΑqˆ|¬ωMf u6›₯eH4„9™Ιγ2ιΨΌ΄,A?Θc³ΓΔο ΪΰŒŒύ=:§™ΊUPBςΎΙ‡SΌ#ωσz!­Nώ©F0FΎc'«]Ν‚!8”vΒγ…2}NθͺΦF] ΕΒpσΒ$pΥ.ϊΗ¬7‚Fm•‘X΅Εψ’W -|έΒ”‘NΨ―)ΧWrέP©³*duŠηsŊuέ_YP/« Ή―FΥ“]šδ…_?iό€]Yπm}"§$άo’ƒ_$εΪbύ?ΒI ζ%œοbΏΔ|γγ“?Μβσšαρ_ψΓ;}˜Nφy£ρFβƒ>Δ7ϊƒ>τ‰˜I{ςΘ‰——g‚:1²+Σε7σ"ΓΌ,¨ΚΐΈ«YL.[•+-Ÿ½2`,›ΜΝEΒ…ΤΚφ°2ƒ ΚδV2bNαΗ•βŒΎn 3Λδ½όm•Ψ΅άm“ΐ grˆεΜ?ΏdόΡn’!313χxοΆ ή;)E(s)5 5EξNA‚ΏH9+‰"a”/F•:€Κۈ―-j¬ώγeΚDoΡ9fΰχ9ˆ!g*‰œLαΎnΑ6n»pΛ‘s‡ˆzŒδ=3ςŠ›0¬–}ad +ͺΆ3ΏcφΕu4!s’Αέa ‚‡ž%1άNh²ό)αΒμk +/©{fB:g6ΰœ₯ΨVΟΖ…!³ΨTBB΅oΐ<2BgˆuHMTΓΚώ@bΓƒ° z(οˆμ‹|θΞܜ`Ez8M6+Ό(C₯jΈ«ΝJΗ²τΗ9_²»AΈΩιΡ4Φ‘ϋ‘eώΊζLM0UžΟ~·;m¨$x蚢έaΙ‘Y‰,ΈΡ`37]›έ{ 1‰fL=έΙ’φq 7…3χOZHΙ’©ρ›d €ͺ:ΧuHΤ~ƒϊ6+P¨χ+ϋoξη ¬s-QΣΞI?’z΄]…y•J‰ϋ…jυΠ b–O‹e(pF‘Ϊ€λψ« +Υ~Άω%*cρ lC ꋉΓη“œ£} yšGgε›NR<ύtg^Ϛύ½A jX;)ΓΥrωΫj·λTaε.Ή‘’Pεάψ@<›#;¨NcάL§ό‘Ɲd…sSNsϋ6`4ί}ΦύΙΝϊ8WχΣO%±π7M$«9 M‡šμΜe·yθ)Ό5:)θηtDίb6-£4©ΑU˜ώ˜ν’΄ΔΧm<ΐέΞ/αaJ92­ T%<έ톙ο2υΜ.šΧΚTζ<ᆬ–1ήIYa NόFσν+pβh₯·yΥΡEΞe*Έ#βPΩ.ΪΦϊtBΊC©κμe1‘:Ί³ Ψ>Ξ;VzδU™m΅χ\¦θ‘¦ϊ‚gΨF4}TfQϊί +Ϋ4Ζκr —u7p˜ŒX½‚εΗrŒΐ΅"UŠπzμΕMhlνΨJ+R HHD,ΠU/32Ε‘ Υη Z„hFΟ‰(ƒrgΗ5uϋή€ΒxηY@ι[¬%;α2{ΊνΎŠΣq©l_Μ.i'ΔΥξ\Ή^"Υ&Ξ±ϊΗΩwoωb¨΅š―ŒƒZ7©Η{ΕΧjšϊΑNžϊϊ Ο&P77ŽΌ” !xρŒ +„Όœj)<θ‡Δΐ-=(@Ε"ΓΑτ!_GΘCκΗΆ™“Ύ€η]ρξ2mό ΝγΎΚΙL1ΠΦ–2d“Ογζ*̐: NΖ“%Ληh\”FPŽ•ά,‘ΦΪhΜ’Ι§#Σ–h*©%TŸϊ‚­Ν™qνP±`'Cι’›γπŠΦšZ;„Ϊ²E’Wu*€Υ+‘T±»ιz%=-„φΌρ.ςΥ01₯> ³νk1‡¨ΊχςPΗ‘}α`ηΚ²= +Z[:TEW©σŠ‚ρžZ»Yώ{xΘΛWAH­κΡζ&kξ$fœΪHt½b³ύλΩ3οϊΈΏΎΩ*Ξ_όσmΰ¦+'ΩΨ™·LΡΈyg9ξKξ‘΄`*ŽΰvΎ©–6Ÿš―ψ ^l˜3?ΪΉcδΈ{¦ΟCπ+Ν }oΡΐŸm”ˆ@ρόŸλ 26#Π+H|Ž9Θ9%ήω_ί9€ϋ_ν·~rΐ}΅ΛΗO•Zυ}δ‹Y^ ώυσGώϋW€N. 4 endstream endobj 11 0 obj <>stream +8;Z\6;6n+O&9J$MEe9X]\UjY8_0$fN))2tE]rG/AP[\4KFLNT:mT]ZXZ,[G5)(SP+ +[s\[6EN5KFeEn'M[Y4_o/>C3&Jc\[n-.Ief)$?Ob$KcBcpm6S`YSS]RQnfMK!(1;o +_>m,uNjg]5F9kQGK-@LL4>DbEKjokZ[f,-i&%;F5PRsh0@L++Yqg1%_I6YZHCF?I& ++9&QZUG)=lT@ZOF_.^_VnFL6ab@erirMViHkKiN9Tel^#+"[Du_-*gG-9Drki37V0 +_k@EVN$)Rh<+6PI=22W/ZPWlT/WL)8O^Xn(>k*Hkj4_H[IOH&%K-9i>9mt0c&t5dA +OJsigAWBW^@K.U3A".ee^/^oDi"-'EJT4,rhBD4O#O6rm'.jDfRpp>b*<^g>7`bP2 ++0],G6_V>f$k\6,!t9eOrF!b"09'9u\K?.*Y endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 14.0 %%AI8_CreatorVersion: 17.1.0 %%For: (Cameron McEfee) () %%Title: (GitHub-Mark.ai) %%CreationDate: 2/5/14 1:24 PM %%Canvassize: 16383 %%BoundingBox: 81 -832 613 -331 %%HiResBoundingBox: 81.1021 -831.082 612.0752 -331.0938 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 10.0 %AI12_BuildNumber: 273 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: 81.1021 -831.082 612.0752 -279.0962 %AI3_TemplateBox: 306.5 -396.5 306.5 -396.5 %AI3_TileBox: 40.5886 -951.0891 652.5886 -159.0891 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 2 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -195 -184 1 1270 730 18 1 0 78 132 0 0 0 1 1 0 1 1 0 %AI5_OpenViewLayers: 7 %%PageOrigin:0 -792 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 81 -832 613 -331 %%HiResBoundingBox: 81.1021 -831.082 612.0752 -331.0938 %AI7_Thumbnail: 128 124 8 %%BeginData: 21268 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDB6FFA9FD19FFA8A8FD05527DA8FD75FFA85227F827F8F8F827F8 %274BA8FD5BFFA8FD15FFA827FD05F827F8F8F827F8F8F84B7DFD6EFF7D27 %F827F827F827F827F827F827F827F82752FD58FFA8FD13FF52F8F827F827 %F821F827F821F827F821F827F8F852FD6AFF52F8F827F827F827F827F827 %F827F827F827F827F8F852FD56FFA8FD11FF7DFD04F84BF8F8F827FD09F8 %27F827F8F87DFD67FF27F827F852FFFF5227F82727522727F82752FFFF52 %F827F827FD55FFA9FD10FF52F827F8F852FFFFFFA8A8A8FFFFFFA8A8A8FF %FFFF52F8F821F852FD53FFAFFD11FF2727F827F852FD0FFF52F827F82720 %FD54FFA8FD0FFF52FD05F827FD0FFF27F8F827F8F852FD63FF52F827F827 %F8A8FD0FFFA8F827F827F852FD40FF7D52527DFD0FFFA8FD0FFF27F8F821 %F852FD11FF52F827F8F827FD3FFF4BF8F8F82052FD1EFF27F827F8F852FD %11FF7DF8F827F827A8FD3DFF52F852275227F87DFD0DFFA8FD0EFFA8F8F8 %F827F87DFD11FFA1F8F8F821F8A8FD3DFFF852FD04FFF852FD1CFFA827F8 %27F8277DFD11FF7D27F827F827A8FD3CFF7DF852FD04FF2727FD0DFFA8FD %0EFFA8F8F8F827F852FD11FF7DF820F827F8A8FD3CFFA8F852FFFFFFA8F8 %52FD1DFF27F827F82127FD11FF2721F827F827FD3EFF27F852FF7DF8F87D %FD0DFFA8FD0FFF27FD04F827A8FFA8FD0BFFA8FFA827F827F8F827FD3EFF %A85227FF7D2052FD1EFF76F827F827F852FD0FFF52F827F827F852FD3FFF %A87DFFA87DFD0FFFA8FD0FFF7D20F827F8F8F827A8FD0BFFA852F820F827 %F8F87DFD64FF2721F87D2727F827277D7DFD05FF7D7D4B27F827F827F827 %27FD54FFA8FD10FF7DF8F827A827FD04F852FD05FF52F8F8F820F827F8F8 %F87DFD66FF52F8F827FF2727F827A8FD05FFA827F827F827F827F852FD55 %FFA8FD11FFA827F8F87DFF525252FD07FF2720F821F827F827A8FD68FF7D %27F8277DFD0AFF27F827F827F8277DFD56FFA8FD13FF7D27F8F8F827F8FD %07FF27F8F827F8207DFD6CFFA84BF827F827A8FD06FF27F827F827A8FD58 %FFA8FD16FF7D20F8F8FD07FFF8F8F87DFD73FF767DFD07FF7D7DFD5CFFA8 %FDFCFFFFFFFFA8FDFCFFFD6CFFAFFD05FFAFFD78FFA85A7E857EA97E5AA8 %FD29FF84FF84A984A9848584FD46FF5A5A5A84305A5AFD2AFFA9845A3085 %363630A9FD46FFA9A8FFA9A9A8FD2BFFA8A9A8AF847EA8A9FD41FFA9FFFF %FFA9AFA8FD05FFA9A984A9FD24FFA9FFFFFFA9AF84A9A9FD42FF7E5A5A5A %FF855A365A845AA97E847E5A5A7E5A5AA8FD1FFF845A5A5AA8857EFD065A %FF5AA9FD3CFFAF7E8584FFA8A95A5A7E85A9FF848584855A855AAFFD20FF %7E8584FFA9857EA95A855A85FF85A9FD44FFA8FD05FFA8FD2FFFA8FDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFD3DFFFD80A8F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F8FD04272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F82727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F82727F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %2727202727F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F8FD0427F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD0427 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %2027272720F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F82727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F82727F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F8272127F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F82727 %202727272027272720272727202727272027272720272727202727272027 %27272027272720272727202727272027272720FD04275227272027272720 %272727202727272027272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %272727202727F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %2727F827F827F827F827F827F827F827F827F827F827F827F827527D7EFF %A8A87E7E5227F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F8FD0427F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F827272EF8272727F8272727F8272727F8272727F8272727F827 %277EA8FD0AFFA8FD0427F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F8272727F827F827F827F827F827F827F827F827F827F82752 %FD0FFF5327F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F8FD042720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %2727522027272720272727202727272027272720272727A8FD11FFA82720 %272727202727272027272720272727202727272027272720272727202727 %2720F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F8272727F827 %F827F827F827F827F827F827F827F827A8FD13FFA827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F82727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8FD0427522727F8272727F8272727F827 %2727F8272727A8FD15FFA827F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F82727F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F8272727F827F827F827F827F827F827F827F8277DFFFFFFA8 %527DFD0BFF7D59A8FFFFFF7D27F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F8272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720FD0427522727202727272027272720272727202752FD04FFA82027 %27A8A8A87D7D7DA8A8A82727277EFD04FF52272727202727272027272720 %272727202727272027272720272727202727F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F8272727F827F827F827F827F827F827F827F8A8 %FD04FF7D27F827F827F827F827F827F827F8277DFD04FFA8F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F8FD0427F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272752F8272727F8272727F8272727 %F8272752FD05FFA82727F8272727F8272727F8272727F8A8FD05FF52F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F8272727F827F827F827F8 %27F827F827F82752FD05FF7D27F827F827F827F827F827F827F8277DFD05 %FF5327F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %FD0427202727272027272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727522027272720 %27272720272727202727A8FD04FFA8272727202727272027272720272727 %2027A8FD04FFA82027272720272727202727272027272720272727202727 %272027272720F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F82727A8A8A87D27F827F827F827F827F827F827F827 %2727F827F827F827F827F827F827F827A8FD04FF7DF827F827F827F827F8 %27F827F827F827F87DFD04FFA827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F82727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F827272752FD05FFA827F8272727F8272727F8 %FD0427522727F8272727F8272727F8FD0427FD05FF5227F8272727F82727 %27F8272727F827272752FD05FF2727F8272727F8272727F8272727F82727 %27F8272727F8272727F82727F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F8FFA8FD0452FF5227F827F827F827F8 %27F827F8272727F827F827F827F827F827F827F852A8FD04FF52F827F827 %F827F827F827F827F827F827F852FD04FFA852F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F82727202727272027272720272727 %2027272720272727202727272027272720272752FFA827272027FFA82027 %27272027272720FD0427522727202727272027272720FD0427FD05FF5327 %2027272720272727202727272027272752FD05FF52272027272720272727 %20272727202727272027272720272727202727F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F82752FF5227F827F8FFA8 %27F827F827F827F827F827F8272727F827F827F827F827F827F827F827A8 %FD04FF7DF827F827F827F827F827F827F827F827F87DFD05FF52F827F827 %F827F827F827F827F827F827F827F827F827F827F827F8FD0427F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F827FFFF5227 %277DFFA82727F8272727F8272727F8272752F8272727F8272727F8272727 %F82727FD05FFA8272727F8272727F8272727F8272727F827A8FD05FFFD04 %27F8272727F8272727F8272727F8272727F8272727F8272727F8F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F87D %A8A8F87DFFFF2727F827F827F827F827F827F8272727F827F827F827F827 %F827F827F8277DFD05FF5227F827F827F827F827F827F827F82752FD05FF %7E27F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD %042720272727202727272027272720272727202727272027272720272727 %2027277D7D2752FF52272727202727272027272720272752202727272027 %2727202727272027277DFD06FF5227202727272027272720FD0427FD06FF %7D2027272720272727202727272027272720272727202727272027272720 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F8272027F827F827F827F827F827F827F8272727F827F827 %F827F827F827F827F82727FFFFFFA8FFFFFF7D27F827F827F827F827F827 %53FD07FF2727F827F827F827F827F827F827F827F827F827F827F827F827 %F827F82727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8FD0427522727 %F8272727F8272727F8272727F8277DFFFF7D52FD04FFA859272727F8277D %A8FD08FF7D272727F8272727F8272727F8272727F8272727F8272727F827 %2727F82727F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F82727 %27F827F827F827F827F827F827F827F852FFFFFF5352FD04FF7DF827F827 %F87DFD09FF52F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827272027272720272727202727272027272720272727202727 %2720272727202727272027272720272727202727272027272720FD042752 %27272027272720272727202727272027277DFFFFA8527DFFFFA8FD042720 %2727FD08FF7D202727272027272720272727202727272027272720272727 %20272727202727F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %272727F827F827F827F827F827F827F827F827F8A8FFFF7D2727522727F8 %27F827F827A8FD06FFA8F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F8FD0427F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F827272EF8272727F8272727F8272727F8272727F82727A8FFFFA87D %527D2727F827272720FD06FFA820272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F8272727F827F827F827F827F827F827F827F827F827 %F8A8FD05FF27F827F827F827A8FD04FFA8F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F8FD042720272727202727 %272027272720272727202727272027272720272727202727272027272720 %272727202727272027272720272752202727272027272720272727202727 %2720272727207DFD04FF272720FD0427FD04FF7D27272027272720272727 %20272727202727272027272720272727202727272027272720F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F8272727F827F827F827F827F8 %27F827F827F827F827F827F8287DFFA827F827F827F827A8FF7D27F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F82727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8FD0427522727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F8FD07 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F82727F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %2727F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F82727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %27272720FD04275227272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F8272727F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD04 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F8FD04272027272720272727202727272027 %27272027272720272727202727272E522727202728272027272720272727 %202727272027272720272727202727272027272720272727202727272027 %272720522727202727272027272720272727202727272027272720272727 %202727272027272720272727202727272027272720F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827272F2E532E2F2E2F27 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F82728282E2F2E532F2F2827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F82727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2E532E522F532E272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F82727522E532F532F532F27F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F82727F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27272EF827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827272027272720272727202727272027 %272720272727202727522E5228272E532E52275227522E532E5328522727 %202727272027272720272727202727272027272720272727202727272027 %27522E5227272E522E532E52275220282727202727272027272720272727 %2027272720272727202727272027272720272727202727F827F827F827F8 %27F827F827F827F827F827F827F827F827282F0D53F8522EFD042F522752 %2E2F2E2F2E2F2727F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827272F2E53272E2E532EFD042F272F52F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD04 %27F8272727F8272727F8272727F8272727F8272727F82728522727272E2E %5328522727275227522E5228282727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F82728522727275228522E532852272EFD %0427F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F8FD0427202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %272727202727272027272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %2727272027272720272727202727272027272720F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F82727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F82727F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F82727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %272727202727272027272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %27272720272727202727272027272720272727202727F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD %0427F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F8FD042720272727202727272027272720 %272727202727272027272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %272727202727272027272720272727202727272027272720272727202727 %27202727272027272720272727202727272027272720F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %7D527D597D527D597D527D597D527D597D527D597D527D597D527D597D52 %7D597D527D597D527D597D527D597D527D597D527D597D527D597D527D59 %7D527D597D527D597D527D597D527D597D527D597D527D597D527D597D52 %7D597D527D597D527D597D527D597D527D597D527D597D527D597D527D59 %7D527D597D527D59FD7FFFFF %%EndData endstream endobj 19 0 obj <>stream +%AI12_CompressedDataxœμ½λŽΉ•&ϊρy~4`ZιΈ0n>rη₯ΗsΪέ†Λ}1ƒ‚¬’Λ«€‚JεŸ§?λϋΧGr̒μ±OK—%nΙ Χύς7Χ/ΎxvυΥΫίΌ|6]φέίόΝυ»—ΟίΏ}χΣ Ά^όμυλοΏ{M?ϊε/†tΩ[§«Ÿm_ζŽϊςέw―ήΎωιΕ°^όρoθϊω7/ί½}sρσ·Ώ}ωςΗ?ϊ±ύτ«Wο_Ώ΄αΥϋώύožύόω»ί_>υγ˜ΦΖΉyώή:Œ?™2€‹α§cΊψΕΟρσσ7xώέw―ώ_ϋqX¦m²ΆΓΫοί|υκΝΧ‡·ϋ§Ϋpρl›Ζ‹e˜.žMΣ`ΏχWΏ|ωέQ§Λ‘ΩΣ–Ί‘χxΩ―σΘW.ϋ}Ϊμ½›·/Ύζε›χΏxχφΕΛοΎ»~ϋϊν»ο~zqύΗηφ5ΟΏΆ_ž_όϊελΧoσβπϊω‹ίwΆσ—w―^Ώ΄/ζωϋ‹‘Η>\ύlΏ<|κυWτύ7Ώyi{2š§/9δΏ|gcΩ°ψ;šΧ/φ΅|ρςύ{[―Mˆ½Όώω―ŸzφυωωΡόςεΧ―x4ΆmσΗyδwoΏύΖvυ»?v\wϋΨeτw~υς›o_ΫΆs‹¦~Ήœm;vό_ύάΧΎ’ύR9oΫrρlŸ1ϊ>\,σ˜›†yg“ΏRΆσε^½όϟ^όΣΫ7/}Ο޽4₯Ύχϊ/ΏόώυΛwςζΥ{ϋ.sχMϋωΫ―^ΎΞM|ξυsξŸ‘όΧ;όκω»―_Ύ70xϋϊϋχ„-f°CωΗη|‰“|‚ώφε›_½ύWρΩ°Ϋ‡[Β^k±N6πΖ±Wϋ?ƒ΄˜rˆϊΈcΔ૝β/μ\ωέ«―_½ωiρlέG?οxχκ«rάλx±ωψ—[υΏ=ώη+΅~ώε›Όr³λŸW`Σ_ώό ›τφΝWΧoΏΑΞ‡ΛbΐςΖ ιυΫ―ύ7ύΏΨλίλΐi‡τ‹w―ή`ΜξŸψΛφε/^o?ύΓ»·ίϋ³7Ώ}ΫύΘQΔΏΎ|axΐΞρ«‹ώΝ²Ψe'(_όκέσ6€ύ[}μΊϋㇳ{χςΒ΄7ωΟψΏ}σς·v Λλήzϋζ/_ΏύΆV-Οί|uρoΟί}ϋα‘ρϊω›ηο.Ψ‘ρΥμ—ηΆSeμφˆA HΎ΅Να+μr4ΑͺŸ1ΡσχΏ3|υςΝWίilg»poϋπx_Ό Ύ»8Όϋώ»ί]όκνΫΧΆύI£ηfΆ’_ΖΏΰ oώωoΠιLΉΓρL†{ώβf±ήχΟ`?ώ%~ύόυλW_Ώ{ώνο^½87Α™ί5“φΐϊγ7ΏyϋϊΥwίxͺZ~ρόέϋW/^Ώόβί½ωΝ£χβφ«W†δξΉΖφωβ?ŸΏρ»|υ›wΟί½zωΰνΓόφΥ›― φΏψώΥϋ—eƒή~σ-˜‹/~χόΫ—όŒχΏ»cΟ/4ΰό₯‘ώΉ?{φΦϋ‹Γ›κχxχό«WFPŒƒ»{κβ‹ίρΗ]ύ#]γΕα«ξ?:£\φΏΤυέίuFtΎ.ώζΛΓ;ΕhY"•λνΟδDtΉ˜’`݌€}ω‘n‡οκ‘HƒωΫΉκ_ν½Γ6#Ύιόgώσ»ηoΎ~ω·™ί³O=j°αf\ϋΘω>Λω§«ώϊχ6ώαpΈ>άnwΧύυp=^OΧιzΎ^ΧλνzΏΎΊΎΎΎΉΎ½Ύ»ιo†›ρfΊI7σΝr³ήl7ϋΝΥΝαζϊζζζφζξΆΏnΗΫ©»M·σνr»ήnίz?ώI~Ίκ―o`Οί6jzΰIOΊ“¦fωq[ΪζmΩΦmΫφνj;lΧΫΝv»ένύ>μγžφy_φuίφ}ΏΪϋυ~³ίξwWύΥp5^MWιjΎZΦ«νjΏΊΊ:\]wW7W·Ww‡ώ0ΖΓtH‡ω°ΦΓvΨW‡ƒoθϊ€gωΠӝi¬Ξδh“ΗOϋψΠ>ψpkL‚Ϋ§«ι0]O7Σνtg‡6€1M)₯9-iM[ΪΣU:€kƒžΫtgΗ8Μγœζy^ζuήζ}Ύšσ΅}φν|·τέ2,γ2-i™—eY—mΩ—«ε°\Ϋέ.wkΏ«‰_kZηuYΧu[χυj=¬ΧΆρ·λέΦoΓ6nΣ–ΈΊ»»»[{nμΉΆη`Ο•=»=›=«=ΛέlO²g²g΄g°§Ώλρβ-ώάάΪeΌ΅λz{Υέ^έ8έΐΩm[νΞ-vσf»ιv²«8Ϊ…μZφ˜Ρθν ώΨmΆK{°«kΐh—x»YŽψ±†Η=έc;~ŠŸ~ww<~ΜH4ΌΉφ[ΏχW½]ΓώΊΏ±Ό³±‡a΄g0Γ:lƒέςαj8 †8‡μφp‡q;λ‰?“=i4 ŒF•Ρΐa4Δ0Ϊυ톏†oGΓͺ# ηΑyΰΓ&ϋΣα?SΚϜŸ₯zΦ£g»οɟœχ αΘ»'΄·'‡Ο„(@ΦF8»βΠβEό!LίυAιΐ‡_Α'ρ™ω,|Φόl|φό\ι9θΉξxIπά4ΟνΩηj§ΠΣ Αw€$<Υ„ΌαξFN‘‡4ί_SςNΛ\wΫΆΛuIΥ€ιΗΡeΆ= Υ=—εr›§½ψ1έ}δ~AΧq”ށ}Ζ Ϊ•zΘ‡ϋa,Χ(,ϊyά*6ιμOα’Ύψώ[°£oϋή5bϊκλ7/α5†ιώίl)XΕQβτΟ6²οEόO αrΩ―γ~1―—F@¦²3ξʍ>κvΉΜΓhη²\LƒνK?]¬ϋεΊχ|gΗίη3 όP§§ΖΏΌyσό›—_]|›.;…3Ά)XWc!ρ,|ζό$>’ΏkbOc>ωδϋO4s ‘2φԟxΥƒρAxv>[~V> Ÿ™OΚΟΔ‡ΈΦx*<½?@7ύΗΡΪ Ÿλόψώgη³εgε³π™ω$>“?έ1»±wxz<δvβНTΧA<ω#|†έl|Φό,ρΛξΜ¦M€‘{ŽuΓχ―ψƊ.ΖlNFYC¬·FΥ―m[l¨Ν˜ΣŘΤd¨4v€7τ{kμΙυzθμSvγYVγ]fγa&#PΓΪžΎ5ώζΪφςΚ&ߌοYŒIFeF£{½aσ[cm—―ŒaڌqZŒJσΤ₯ζސώ­ρWΧΆύWΖomΖw-ΖΩ½0^lH½‘†[γΟν`Œ_یZ-FΝ’QΈΡˆžQe#…7‡Ξφr7ŠΉυœ’NFS‡±7*skδφΪNσΚπf€x1’œŒdŽF¦{πKFΆ―qΚFΘ훍¨ΫΊŒK4βζ»ψK~Ο>7gŸΫsOΧƒ7½kωG»ͺWέ«Γμΰ’»TL–μIέoΕ—mxΣVή­δΰήΎDmggιςϋlΐΫP§}»4m)ψοQ½‰NΧΝdbέiϋ΅•ο—ρrkTύ¨ή>έΝyaΟ~]Ζ£žƒύΎΥΈιν:Ša_z¨"–%ΩΊ_[ρpΏ#ύY*Π7d€\rϋl'ΟzζYΞ<†`:ό§z™g:yΖ3OώΣ εΟ,ΰ@~τœή†κΆtϊλιυ:œyNoμΡ½ξψηΠΐzςœΓ,'θ<²:‡ΧNρίΩ=:ε=Ά3ΖzAŠ@Œ@Žœ ]‘Ύ(,9aJ”KFΒAŸ Τ-•Χ€λ†:**'V WN°F‚JOρβ–„ΛIׁ4δ ΜIˆ˜“±±#4υ”Mn3=»&ηšͺζt ”΄ΝžΡΙ HœΉkςWQ:Π:§v wNρ@σHυHχœςݐϋ9cΨ3\)ΕΝ”οπgμΆ=Ι‘Δ²Kr{¦‹+%KΠΖDaq$`χ™F‚J:4JΩebΉε»WgUθ3ιΌΝ  Ή ’TΖ.Γ‚9υ5₯8P=±Q11g•Δ@eΔ-Υ‚Ψ¨’‚ζo²/tͺ@štd#9“g―Ψ“;Wx Έ‘ρ›ΙκΕλΙΣݐ‹»ͺιΙ#ω§ Άΰ :Βζ'δ :Ω'δ :BΛ'δ :"qPΑ ŸH±σ_`ΐOςηρκ»§Xl-Χ5d΄žΫκΉΡs­η ‡bη7μn’xςέ~ψjwq·C {'½Qh•BΧtZ6T³‘žέ€ΌZς㊭ΉΛz.WAίGp3Ϊ|2ΝΥ%«·ŸZΘDM€?KΦHΤJϊ³gνδ5”ώ\gMεMΦVRc9άuΆ΄'Ÿ©7jSΖτtcΖ±-£k‡k?Ž’,ϊΑΠΦZΒ{τ„ΗJΒξX+θΗrzχ#Ψέ+ΟuΗΒ\c‰¬‡ΞJ%χύξϊΉ}O3ψυyΩ†‰ώ9sZ‡φJ'κqRVŽ—°;TZ»ς6ηξ‡ŽξrΆέ’.ϋΡVz@\yΚKώuλlδ +λ3rκεΎ χcJΓYζIo}œD“ΞJ4 zEI4ύ}φ‚ϋ¬n+pKί½;^ΆΡ -+ma€Mΰ.ΫF*]εΏΘflθ’©+»:Ω»άβ6/Z½²έ –/Œ™Θβ.Ωζ6°+²ΒΧ4‚=Ύλ`#–i›ΘJΓ*Ά½ήhΫΙth!»ΞΆD0εw΄•υYΫ:u4S$šΞfšΟšΠVšΡ6švšΣhRσ'keέΌΥsΧ sΛH'²fQԘ ½ρ΅ž¦UΓ΄ŠiRΊJy"!EEaœψH6$Σt™/δΰν§V?Εμ»ΧώΦ‰r—ν3γΥTΌώ35OjžΉ<]6lΥΟzςlgŸύάΣι―WzNUxε<ο{>dœφ!x¬A#f‡tƒέ‘ηΌξ°zΊwyPαxςtνΨοηΟπSρ«υη―VˆψsX³₯ανπ OΜΙξ>N’Œ€ΨΘ½—΅Rχ¦βΏD›7¬έ7„T’ζB˜ Y’όDΟ“Žψ^η“§ϋžtηO>|~sg‹,>ˆYž†ΖξΕ}BžχIΒ;ςηD\υ€[Ζ‡ž'όιΞΆήγ„ρ˜§ƒ³ΘÏkgb‰…˜b%ΆΨˆ1vb+bޱΗ51Θ ±Θm–;²ω (hέXλ†Ϋ…Hf₯ΔΊQjέ³ΙΧΝΏΧΔ;7Δ=xzb!{:š”έΌœˆ’f’₯…2.€ά-k#!΄2Β”YΏcαφXF!ΠΠΣΡ=¨¨Λ^p ’ΪIͺ{NŸζ³Ž?κΊ|Ίϊ«ΞΰΦ'cΧξΔ±οδ“ΞK鐧ιjχ#•3?SŠ΅ρ!Z67DP[%%Q“·‹ŸΜ~iΫ0W–ΘΗΏΓ9ΰ? +‰wKμHW€θ:Ψ―“ύ-]z«Δρ'Όγs€Ξ!λ8ΐδ8­πGΊœζe?z©q)yΚK'‹/geρΦΕ©’ΕGΘΕ@ρΚΐπv€+T2ΠΫ μ’χlΙΰ Pv0»#tΑ +¨:’ žM3 ©γέ0(²σ~=~@—*ƒ&;EvzΤ8ό@EˆOΩ’§1EΗlΡΪIΕ&ΦHΜQ°G³°ΠNlv Ν ½jξ2³4ΠϋΖ¦Ž<ΣL7πMqκΉ§­σ7δ‘n©hλι >ΠμΤ”έ±g²Ux֎άΥFkwκ<τ>uΏΓΡ#wλλεƒθ~ˆώLώttI ·ΔpM\δ θNŠεΩυ\UΟ‘<]φb,Ο‡ˆδy·ΓB΄Ž¨Ψπΰ3~ψι*Gʏ{\=BOύɞΟ=r&v„΄m<ΨmΉJZ2RŒΒΝZΊ%Ω›ˆ˜V’;;#uΡ:P:§sNΈΔ ςVD‡cΑ‘Ίϊ¬Ÿ +Et(h+Wκ2ξZ3ƒv•ٲ̐‰3Vs_…οͺxξ„έ +^+ »U|Vφ£s¦ψΞ»άyαί+Ξ›9d+Σ$–;Bς7qΦ‡Τn3Ο<ς$.xΙ2[ζ·aωw•τ6F~ί{˜½‹qE+’\ζœ‚Μ ©δΉŽ;"”V¨KGBέ.‘ξ:„ΊJ¦›Ί3"ݞINˆs·™πΈ 7γ^†›!βb΅Μq§ ΎΟΐχaΊΫPήξžάS³CO ½έ=ω;ξΙΰρκϋtοθ?£9rš/χωiΦΘόΚc‘Ϋ|i‡8>Ιοδ9hP\aIμ/SZ^ΉιAcδ^ϊ8~V£΄C£4†Fi;4Ου#ž΅•ξƒswίsγםΖbζηΌ(Ψ>χ€xΊςWJηžε쳞yμvu"³Ϋ‚{JzληΠ>ηΣSοα(€@wάŸΈ^φώLDΆGeŸ½ΎmυOͺh‘†Zω㚨QG(€(r^'΅Ÿθ€ŒŽžͺ₯Ž”RgυQ§š(O„t”‘MΰΙ˜υ€AyΊ3ri=;"J9@oοP:+No¬‚I#”τJαz°!{%ha{γφκΘ½:v―Žήk3 €£>…πuŠα;Εwo_ ‘ δλŽ"ω~P6…ς΅ρυiG΄_.Ψτ₯Dͺ¬—Ά¦Tf<¦3‘ϋ‚Τ½4Ψ‡³,λkΓ#ϊ~*Οζ.‡Ζ―δLJ­ϋ“jΥi΅Jb­M ΨhsσάΔ@Χ1ί£^inφz“mˆFΏ^1vΟ€β(—Jw"•{“¨ξΙ B†Ύ{d•‘$PαSgPir¨tU•γD*‘Je•p37 Uͺ€*E@κŠΒΌ +•Ώ;J±R°K`˜λ£„+Β8]“{₯ΞΐOKŸZ +vLηNΘα)έ‡‡žc.κΡOvΐ80ώ!₯A―ΞŒŸ†Œ·AγuΨx8^BΗ#xΌ„Gy„οUε0(䨣…―Ν_°fͺT² Κ^p[Q§οZ€.ΘDͺ£»θ”)U½ Ξ_ Ά*ƒΑBαXY Hnj’uΚcpΫδ284ω Ά*§ΑBα<)³ΑDFBǝλ γ:Έ8GWωFΪΌ"GιCΊ“L!G)AΞ€ώ(ΜΪ™όέ½ =R‘>·£»7Šψ>3ΧΓv²'ώtΊΟγ<Œ΅IΎ6ʟΣB=Δ‰£q'λ|ΙΓͺžb /jžβvœŽ4η&η |\’(G›ΓΓΧΜm2y7§:±Β½]<_ιe:Κf:]ΑίλξιρQΫw6©@jT‡ύγœΡΞ»’‰κξ «ωΑΆξGΔ =ΝΦݝσ=ώ°SΧ©KΧڨڎΊ°]₯P«i΅­vβΊ?­J֐u•‚μ4§J­«5a­'Φ,λO«ψXΙuκιΞQΊEεDι?ΐ%κAο§ξΤRZτ‘^Mέ9?₯Ώ'£π&ψTξ χ›špϊΛcE-|\Γg5rΦϊ‰0δΩXΚξ1ψρΨ::ε ±TΙ~d¦.FκRŠœΒUuya'‰γ3²(ͺς# ;΅Qœ^Ργ›Χ˜"Ί#KΔq*XO_ωˆ»φƒ!ωA™τγ ۘ5„"ŸhԊ€ŠΒjgϋqέ?Η³p=VωQ‘»½ŸηέΆΌ‰Θ‰θA&λ―β:cw.‡η £biYηςξi±”9Ρ>ρyς€žθνiϊΈζnμŸΌΡs7Άu9<œ'~σ„ožζ bϋ΅8r%Ž›œγς "kΞt9w2 9αεjo”φr“i ύeΠΆΆ–’%Ψα}5όΕΠc·“-?ε₯\ε ^˜·aYYaϋΆxΑqκε§Ό”+¬+s5γ9{ΛdΈsi^8Ξlφ”—’BbΒ΅u4tΌx*4Q8›Ρμ1½? +χœ•ΨζΟ0Ÿ`>ΐ|€ωσ9ζO!›ώ΅ψ9ζsΜΑ,Ÿ`>βϊσ9ζsΜη˜Ο0Ÿ`>}ΜΌ\iXžd׈w>‡ΐΈς謕f*'€Ώλ†›{žΫG='©ΊF?•χΟ…Τ~‘σ³hίΙσ­¨~ϊ»Ξ©—TšWˆp£±aW!ΔEΕw Rt΄θ»FŒ5jlœΗΊΚ{μϊƒϊ5_όΈϊωςλϊ)„ΈI»U£Β@§YΑΞ"‚ξ‡ž-Ψφψη€\w’7: V9Φ#Ua+§Ϊ€ξ‘+ΗujŸυΠΦ΅ϋŠxΦΠΣŽŠ:W΅œ8έΘΉ9 9nf9†ΫαA€sΫUDuΌrΘΉ­Ι©hiP«ξvόθ?ξΟIiΎξH·8h[]cίt&Β©{„ΦρζΤ‹γ~?Žξ裠•‡#nκΆα¨†ΊNα 䬑 8tΔ3<€:jΜΡ‘Ž»?±βλ‡K΅΄Mώ0ι½ΪΠΗωΏœΡHλ,ξ©ίzΆlλΩ2­έqδ`;ΨίsχΞ_³ΉΤά¬ξWk-4hΪw°8i²υ'ώeJ«m›—ι>ί’§½ηuŠl!4άχ€uό2Ϋ&ΖjŒ™ƒeU₯θΡ―|tΦΝΟZ䏞ĝ2Bέƒ|Π1Τ7Ξ2@έ ϋ ΣΘƒgpWχρT¬Ε`έΫΞP±»‡©X–oά¨Χ‰ͺE‘#οΔ³ΒΠ=βPwN9όtι\Qά#v¨;β†ΞsBYՎ «ϋ ΄Q»0@]Eςξγ€ξ…s ΣpΞ-ρ»u>O |ΊF­p#αΉ&‚-ό„-j¨ΛFΰ-~ COη“NΈ’S†¨{7t +9χEz€tηω ϋΈ  +0 +Xl•2ιͺ;Ρ(=ΐ}€’ Υ=€DŽγoξE!5t +9S˝@V&qόσ=Ηƒ’G*ο°?’½91τ>ΜΜάoV­x—ξΦεη9θξcQ*˜?οχ0ύέ#ΉώG£Βξœ2‘ε—[τNη’mOiσΏlέϊχωβ>ρ½ΗρKπ„LOγ—τΚGρKgsτnΰ–ζΚCι“ώωp:Oj>ϋ<ΰη?ψ§°˜o1Μ6ΕdslΉ'fͺΨiΊ#χˆcCM1Υάϋ,Ή,fϋVw’Γ=Èy->ϊΫ)φ7 ]Ε{±ψ/{0ΦαΏ΅cγΙΎŒαΝώŒαΡΈΙ"|uδΧX<ΑρœqoΌ]λΟω7{ΪΩΖw +%ŠΫgΎχYNŸϊΗϊθη?έC?ύ9“ηκτιΧνρΟέΫβ,W‹šνF”²,#/eΑ…ΗuOn•Ε‡€Y’^Τ•κE ’\υPd†Ϊτšu έ‰Ή₯X]οwB«5 2½Ίρ΅ΛŽQv₯.Ί€nͺz+Η΅VŽλ¬\uΉΜΚQ‰•μΞPͺ«”Κ*uU•Ί’J¦U•TΪ*απr\5ε\‘”ͺ0JwZ ε€ψΙ‡*—œ­²quφ9<π\ŸΊ“¦όΣUυ΄>ΙΣ}b¬Ώžλ@)UL9ύ ƒdμΚ'έηiλ}Ώ­&;M•RyΒ;mE•yΈμν’Ÿ)«Ώ¨ΆΚ2ΫΛp ±ωbJ&6Ξ©-³rΆGϋώj£Wt1φ—ΣΈ―gή?ξρgͺν²MgεΖ© =NβT…•˜1?yhι~X½ZΐŸγ<«|ͺιrέ‡*Δθ‘NξΦ’;ܟπΰ.OΩγϋέ«χ/φβπϊω‹ίΫζ6¬ •»Ιar{‘›ΧηΠΈλ·εΈ”£αϊ wQpƒΰf¦ΕCJΌž©πn˜οЉοΞεςΊΉ?›Wχαt^žΖvζ ^³2IφΚέε™»J +ɜ£;Ɋ±>-/†F怑έqΦΘϋrF₯ŒΌ7adχ˜Œ‘­ΧΦp^_uξ7ΟΓρ€Θή{ΑΨΎό§·o~ρξΥ›χ―ή|ύμYέυέ?}‹_&εΟίΏωύέΫΧ―žύ >ώv1€ΕξΤjxuΨ 3―σ>]ϋ:]LλviΜάΜe^ρΏώŸφίσ―C^ωΏ‘όφΧeiί|ρσ‹ψŸύΕWώΚ/c’σβk=™ιβλΦXΠ?ΦœmlήcϋΙΥ»χ7―^ΌυφΝσwΌψ)1ςOoίΎΎψΡΥΟς~|yϋΥ«χoί}y°Ko{φε―^½~ωε/_Ύxγ‹Ώ΅ώoϋŸΎφŸ=ηLΰ―ρβχXιW6CjΓΆ^PϊGMύεnDΝΈYClσ~aR΄QΝZΦdΏŒ[Lͺή.Τ¦§‹kΎ·ϊ{Φk³«q1'8ι­ƒ„P»26Roοm\μς{Ϋ劬=Γ6_¦m›8ΌροΆ¬u·ΏτλΕΏ²ίt‰›eύlRρ‹“εΪΊύ]‡Αmμ3σΓ†Ts΄Φρr4ndx½\ϋɈи^Ϊ­±–1eμ'kI—6~^β8\.°vΫm½΄— ΠGŒ΅Žœ:fkY|y&g ^vΞoΞ—vΐθgG)Θ¦Ϊ 3p¬‘Η>a96˜ΝΉ\ŽkΜ‰cθmo«~F½‡_eƒ&μ|*νΖ„ ψ~Ι/ŽρρΆκ₯·₯MϋεŒ0y|ζδG³!S8>άϊμΫxρo{α4$γ3vێΕV4ΆΨ~6β·Ψœ‹ν(ΆlΨ“}―­šs¬x±·ŸŒ±™gΫ–ήNzμWί:@ƒaζήFZ7ƒŠΉ•F`₯δπ7ΨͺlW[rƒCψΎ˜~²5ΜO»!Fa.nϋ΄α*6Η΄Y‹‚ΑŒ΅ΨΦμy1s?Ϊ₯κφqΓ‚~vFˆš–έ>c[­e·γœ/„ΆsΑ›i @Œ%–ΩΦf‡oδr™ϊcY[…ύe2y“-ΌZώ¦ύ<ΫΡΩθv6‹Fy.Gd>ΒX₯XEο„άΎs†ΙdΧτ‘­il»g£Uk<ΙBΒͺ1·q™φΏαF1/7‡cgΆ/φ;Zΐ’Η ΌΑΜ¨Ε§ΔΆΨYΈd‹ήy›œλˆ±_λ„εi­ eΩ:GYΐWΨ(­ώ—(ΐ‹‡ίežΟ€υΜS²CFYΔ<΅1 ΰοΧdΨ9†gΖeογ~ s)·ϋm$ί~>|mc?';ΫͺgφΑΔr»‚u}6©ŒφΓdΫc`d|χ²΄ ( ϊlZ XΰΊl½γ!nφχ“!¬Υξϊ2 τ@£@ε`΅χ.Α\<³Bςˆ³ €―ςf°dΏ·-‡'-ΐ†Ψν―vΔΖ­—ΫήΟ>oIV‡σΔκ'υΏ/~ςOoί]zϋξ+;‰Ώ•(tοδ—/ŸΏώωσχο^ύoλ|ρ£λ«Ÿρ«ίΎ}χ”©œΔ―ήώζε—W?ΫΏ΄…|ρώFΛτ -ρϋχ―<Əψ/a!οΓrρ£_όϋΏΩίώΫχόΘώ†Λhe2Œ:XϋΡωΫkΓ‘]Γ’³IƘ 0Fΐ.ξfB¦5l8ήωbΝ€ΐ½‰BνΒO °²½6)],vmηΝξ―ρ"Λ6:eP/ΛeΩw{m@J» rεf΄œΣ“ Β}Λ”―MΚΛtُάh€α­‚ ο€Q»₯F܌¬€ξy‘ΦέȐ–1Xυ>č|-«Α@Ϋf·~‰8Ψkk4l9£\½‰ŸΫ~ `½Hƒm•탑)ΎmhcΪ6'?Λ69m1aό΅u2ΊξΒ°†έ[:0?hμl…‘UŸ+άϋ„½έΩΙΨ» Ψ4“$lΕvωΈ?F/anπΩμƒο3—jC8y΅UF³CLΙYΫ§Ν)Ώe˜lκy²λ‚G`Sγ ίOΙξο2B™`؝ϊπ5»’3ΠΛΎΖk†ΚΣΌb―{ΰΝ¨a[L?ν™ XŒx&2ΰO,άθϊ₯Ν ‚/5(δƒΡυ/σ%PΕu0R>˜Ε‰·mη:£a™Τΐm΄kλέΥkσOœLЏDΓΪ;‘χΧ’Ρ™7;γΑμuύΫζšπ]ϋεΊn“ΆΏfώe10°Σ7 c–Ζ©4, Ά›v5Ϊ鏛o,ΉO ©ΑΉ1˜|2i°Ψ"Κ›8ωΞΞΖμν€Ψ l+Ωρ2αr&}£f‹ύ{NC>θι7ˆ3Š„Nήΰf°Zψ°iφ³1πCEqνFšvP^ΓχΨ2»ΘΘbo_ΘΫ‹€β§ή9sΞτn΄v˜BΑLˆd΄Ρ0υδCΫΉΠh§»σ"Γd$Χ."n‹νψˆλk<ͺIž‹p +ƒηOBn–§±L¦ΞoΩU²eΊV°`CŽΩαmͺZ#l2Ϋρ±TaŒ0ƒmxšΡ§χ½3Xί ,α»Ld6*Έ9βΧΧpdoΛ΅]ρKnœΓŒTšŽΗΈ1άβΙ g1;KC4ω|CD’­cζΰφ:·Υφl%~3,`£p—bˍ·HP`ΘεΒώτ˜ “O³²ŒΫ=ƒx(ϋ Η›Σε₯ο½Γ>•­Ÿw°o@”=*2ΰςZίΐ™§‡Ι9u[ΕΌΗ~`GmΩ½οαΐ̚#°»sNΠΎ#_%Íΐސ/°σΎΰ [Βnb­ύ Τ‘γ:ΛΆFNψ•;f±a)³¦A0ΤΑςW>ϋloςyIbξσ$ƒΣύnD·;Ώ¬ηPc¬dg½ΟK!$·ί“‘―607Δ0–]π:Rœˆ3.ƒgήάά2ςήcϊxψVo@‡ˆΟ!ψΖ1jρ7ΐ`Λ€»dŒ Ιί•ajΆ#Y0Yxs"»7<)ˆξ†G€!yρNΤ`‘“ψ=Β DMq\£ Υτ{s₯Έlm\<ϊ3py\M ܝΤx6ς™*nΉ±7.;d40Cv„S‘ŠΩΦY(π xW™ΐ8uη₯ΑK³ϋ:₯$μe@o”\ψ r§αΩ΅A‚θ5m L9ƒCTŠο"R#ά`°Zžƒ±Δ y9~vχ]\¨e0_±―ΰ…2ψΗNv@5ΑIo3ΐ*ΣŸ}]’„sά ϊ‚rΝφγBα:“6€pΏ΅8/ΩmyA&g01ΐ_AHΥP“[5Q†aq ² Bv¬¦νXΒ|žμΗrζŸmΑh:ν~ŒbEπ&9 Γ‚‰ΦmzΩο‘μ Ζg·ΫπGFō/\ +… O(Έ¬§‚m­y1,Ь{plΨŽΝ–)žŽj☚υΓΪgΘ³Α Bƒ― 7ΎŠΟ4t‰$zβFΡ«l―3» +°"νh˜Ϊ9³ΑϊBg‚ΔΌρ<–νβΦ τ<φ>t°ΩΠ πSƒ‡’Zς†]OφέύυAζ鑎!v ˜`^ ]Τ’δ|jœ²ό€;M]BŽγΦ΅C γΫ υHX2κΜg€A–}JΠE w)D#Ό6μvBx‚:ŽμG-b©Wbΐ †^v‰jψ4 ³ZžΓ—)…ΠG!φSrαLŽ}£δGŸΝ6r‚|b³lPΎr~P‹ .“ΫωυX‘ΕΤϋN&Pz¨c KΩΠΤΪ¬ ’ΪΩnΣ^ΡΖ풁€‰½‘ΗΩ ύβz;ΗΩφ&`y'‚μ'nHl4ΊA‚ΔuΪ7`„žαΟ›!0κ8Όέγ-%NJς•ΘšBP~[’€‘λtEϊ’5SΡmDΦ?£i ~ eS ψ’YΩ4Έ"°|Ιso/όšd'&ΤU»Ιe+π&–-ÜvZyΛbk'¨€F(σξ Θ—»‘ - ΰEΐFUfΪΤytn&Upa«…IHpαπzΞ―ΟٞΖ$0 Ι¬@qNΦa&ېαΪΆd΄«€=Ty=ΤQ άCΕΪΔύ€@&\ςΈfΠ₯’mŠe\°•ΞΊ°P½L}ZΛ½ŒφI—˜1~r5 Ρ΄ŸkΏ$2€σ2™•ΌΧ †ΕyΠBG—VXk@ξΛeΞ»Θ ­4όΒΠ&0H`IθdG)Ή—β‹ &d ₯ζ†y +N6.ΖfΟζXΉC-KAO4`0"@γŒ]*Ρ}Ϋ§ ΡκQ +U4’g豃2Μωb/μύ²‘Ζf‡5P(»ΞΆ’Bθ†w|¨ε} Π³ˆ*E₯=/5h/`ެ¦ΘσRΏC”*–™’Ψ—~™€Ξ}B2ΡƒU?4Lτπ€w1₯%ψ€=ο}μΩ9₯Aq:8ΌXUΛυΖ”ZŽpA kEγΨ +Ξ,80€+%δ`|·7ΰj ¨`εΠβΖ–ΰψpΧ(Θ_g€Œ!¬hKΌ#lΔϋb1a3Ά|Υ‘MvZ +»Š)χ”ά&χ†Vπ½ƒαF‚³Ψc΄ΐ3.#έΜE;4­β²­ΝNf«˜q”z™α‚g7xwKpυh LΜ?Zϊ5ψؐL²•BΏ)1:,76Ζ±§uνZhɐœΐHf±nKώD—lΠwΞH KΜ",iC%Ia©K’T\c1rlΘd4ρ°ΥIt£UnΪ‚ƒΛϊ =njΎ_ΰBVδXsΨύB’„Moš@ΥCθl‘dΎC4%Φ² A,Μh4iIΘ₯ –$ΙΒΐ‘†±ΰY„Ξ”»Υ τηΜ’7Œ”T*9žτΡXΠ …'IXΧjgCpu)Lz„ΧwK-Ι>Zc!PŒΆιΤI…1NFοη`>CΣ‘~E?c•–zΞͺ΅…κ₯¬?44GίI5Nl†Τ<Ϊ―P5Ϋκ’Ψό¬LρHγΤ£SεΈCw%Šλt²&, Lͺ2‘4j °Jρ& –nN€ŸxΝυ–OΧHŠ@]5ι ›+)΅’nΡ<ζΫ]τ“5(jΜ@EΡψDκΠν₯i`'ιU…Α€~m0΄΄Βˆ‘Η œ)eoƒZ₯ +–Φ8#i©–T. ΄P~訃(H‘-Ϊq]«»ƒΔH).JτŸuη’X‘]Q“Ύ!~Τ‹HJ™/B*Cpea–υ@Δ»΄ΤDΎ΄3Φ +ρ ²i4|…,β?d9ΧR±2UkζxdŒS$›MΓ<Ι΄Sϊ…υGŒX±Υ ›[’‚©“‘I|ŸμQ (³•ψHYΆΔkΚVq€²’‰q•!MΜ­μm ,³œxeξΔO_ΝwΛ(ώ\–ΒΰΰeOl}™CaR"C˜/ΙBFNI a•"ci#ΜΘ€2Œ‹d›­„'p%bΙΖ+1L¦ΰF\“ΕXbŒΚ!ωΙτάˆ₯[’2bKΨ”­»Je—μZΜζ!ήσz-/ -Ψc‰Λ\©NˆΤ@΅Ύ΅θ½€₯X筈θF1.νΆνEŒ_!^Rl¬Ε}λ|‰η’ Ξwa<«ΰHΑ‹!ƒ§a6]¨"–-Σ/©,ˆχΥIŒT+Ήep~Yϋ±ΪLδAjIιͺ”2R¨[ʌ‘–yΡ¬,Τ7ε BΝCσd|©λ‚ΚV„²¨lY­T*[Κ'mθ§tJ΅K‡Ίrή‘;u»ΐ„ξΊR9g,π˜ƒ\‘·‹Ύφ‰Nο ;/ΐΩ ΌηΉzΓ€iέōχ=ZΈ.»τΆΟCΥNQΐ}6Ελ:ΓqjΞ§t2ϊΊΓ‚­qΰl~ΏΜ-~<±.υΣځQαΘwς‰eΎξ²l£€΄ϋό¦mM.x.Ϊ΄½όL{_>ι΅Έ½G-yΎΑΉ²rFm€,šm%=NΛΨφiΛϊC“‰RSιk/cγ‹v~±H©ΣΏͺΨD“m ΎΐΗFCN©‘©ή€”θj…a‚>\‡ ΏΏuΫ©Ίe@)C,•)k˜+KS?-?ΰ·ώΐγ㏍ߜώ¦nœ ίήͺßΗcj€M=šΓ/½ςΎ—qβ ςl/XΠΓ7·iv:¬—?…΅£HτŠOΡ8Gί§q€bΆΎυγ–yΒάHŽ VΔŒΌ&!>MδlNbήή& Αϋ9 «λ€η,x ½{ΎΆΓήΜ*άp%ΐ5AΣ–Q@3d(η?Œbp}ΧYFτ•ΐεΜZ6ς`l 9W7;ΑƒΡΘ_²Β V\_bL°°ΓΩ›V‘=ΤL°„‘­3uΥ ψp`VœΐL!4-‚ε °ζϋ+JHιgΤ^Ce―πvΖmɍVžμ²V’―ͺϊJ΄ΞT]ΖfΜ†Q{Nχ CΡHΦμ+^€υNϋ?oαΚge¦{ιΦg9ƒƒͺ3Ÿ!§γΈΠ"jπ‘Β‘^1fπ vu`†Δ™ΦδΎuWΥχ@,ysυΡ@σžUiZΠ#M—Z:ŒρϊĚZ—­"JΩzκΫΧνO±­ΠΙΓXλoζ…‘ϊ͏Ν¨‡H+rŸ] αοεσ† H+ apμ6ƒ€»Kό,Οαk‡W4Q†@hχ›@D,¬I…“”NβΛ0q1šΙtbMΊd±μΈŠυ·• .ulSΉόυn$»^IœLA8 Ώ%Δ']W@CYE 5pβΛc¬ +(₯·mD +~םχΜF<` &zŒ6xρ41(―ΏΠ?žΩφΓFEŸeHKH₯L·ηΚgωΏύKχΧλΈάlε9/ζΣ­|Ψ_yf Β^"’„<§CL™θ=²€†Cσ 4΅©0QrιΧDυb!=+$ΦJ; +c)ƒY¬Ε=@Bi;š¬2μB.` „ŸrΜΥΤoΰ ¦μ[DΉ‘α2P›d±‚νΑ2¬Ϋ“πΩQ#Œ4 Ϊΰ”&Τ KM˜ˆ` ?&Ό kμq6YpΟΖOΟ°»"r¨Xί—”ί„}q; ƒ‘2–»Jώ0¨Fυ’ Έ2κ ±’mr+%h>sΪθ‘I»Λh|šF±έwlΡg-Z@NŽςΊ{D8ΔHqΏΨ+Ό3Ιη3Aϋ ΕΉa-μλΙ-΄0{BŽ}6Ο£ξy GVYqόΫjΜ£X7‘!Φ,ςjG~Ο«†‹ hNu€ΥΐˆeιήΉ€ΉLκ8΄uηNό1Έ’*ΩώϋΞ]\ΙΦΥ\tΏϊƒΈC§P·έ%Τ~%WΎz„«~φ‰jχέy£½‡ipϞ]ΰ‹Œœ%rͺtΘ‹…1ύΕΥϋ“Λ‚Ψ~gqΗ>§T›b s +ONτr Q\°>τ½»‰,;' vvς₯ΰfιlYuλγ5Τΰ<ΰΡ”}ζ^σΒ οv)?–nxjήΈΤκ ‘X2ι§3šΙ΅YvΝίΎzSαyDε’6α^4›ϊρ£zΔ\%V6W³”Œ' ©΄L8d M q_y„jρ` PŸ‘|£ρ i ηNνψ ΊΌi·¬iQΩΥ!k΅«ά}˜Zvͺβ„z¨&¦J~‹Φos1Ρω—~e¬žvΞ±²ΆΓ²ώ€Φζ;ΥΪAΎφL7€ήΫr“β ͺ»–ΟιψF†¬Ηs&ψgί}ωΛ—ίΎ|ώώεW@8 ‚Ω…γ4ŽPϊRΩ[…`‚L’ *u4}‰ψUgTλθK΄Ί0’/AΑψ³’/νΩΔRG_‚ώΊZ,’/ƒko%ϊ’c%ͺΌ«θΛ1­uPτε˜fw”ŠΰΛ‘¬`yλΨK¬c¦².b/Ηyv»T„^ŽP·sgκΨΛ¦:ΕDμ%ΨΘ΄Ρ·=Η^Ι»^‡^KU΅z‰χLŠJ ε8‡nΎ½Δϊ{ZQ#τof£G½α +Ι΅Φ±—γœΑZ±— ΐ₯±—§η(nγώθΊGς Ύάrμ₯νΥ3\œsδβΈΫO0 χGΡ—Θζb«ή °žΩωΑ@θ3Ÿ a"\ΒhΩωβwη {iΐδ±—θΜόp·YŒΧΰΛ,…<~ώ•¦g¨9φ2ύΧ`M>.ψς$ΝŒνŽoͺ4°Τ»ηgδ9αα +Ɯη€Ζvb‡’ζfsΟ}y`Y'ΦQžΈ0ΠΊTη9 ½Ξ›‘η’Uoς@y=#ΟΑΙϊ#Οnhς@."γ―<#(?-Κs=9S,4yF:₯Ήδ9©lώŒ<Π§syMžf €@’<t]€Aω ΰ,‘fͺ<<lcΥos―Θs€‘l$Œ–Ώ=§9€΅D"²ΐsa£pTg9Κφν‰,μ[γTe9LtΝTε6O"ΪΘršΰŒ‘,€…<έd9ΐό°Ξ*Ι€:ρ΅$98=Κ Ϋ˜Νͺ–Νa?^χ©ˆζ° χpo’hŽΘξ'E4Ι₯CdsΨ…·Ϋ²9Mτžξ’’Ν‡Ž\€¦ΝIJ2$›ƒϊ%8Τ²9o‹ϊY6Η‹T*I6‡ ˜œd#›A©$›»Γ`#dσ +Ο1-­lN36ί Ωœ‡½₯dsΌι‚Z6w_ͺΌΘζ`GθΓ²9hφΫTΙζΈΥεξΝaΜ§Χ€dσΣ£όΑ²ωγd•hξ"ο@‘wVΧΨIζEXž Α/ aη^΄νB6άζcΉόΎ‰j±όρ}J‘ό/Cyχ§ΙOς 0W„Ϋ «|ΔΙΣ\Ε•Œ΄^ΐ†žCOˆωΑΗΥρ)ΈΝ Γ:1/γ¬(ΰ?:Φ±0κ3 :ξ“–cjpzτ¨#oπZŽ“v{°'TDπqC"ͺγ|€A$"_F:•£…H^ά宅‘Βΰx„KΟθΏM§Ÿ Ή¬˜ˆT F˜ΣhΌ₯‹„ΒNs>4αR χ}w©2iΝ}%#θ +Ntά &4‹¨>Ήσ|‚0Μ9<"Ό`|wo£bθF“,Ό†·#˜Μ‰ήœΪ˜3αΔMφ#+Αk’Ζ&Δ ƒSδ@8ΰibψ•#1o"κ Ρ—+ο ―ν :=4#Σω²ΰΓ’ό,£μFΓΝ³` u΄`it6 +ot%ŽΓeΤ«ŽJδŽX#vΎ]¨nŒΧΡa’dπؐ)1υγTn‰oεΦFP&œ#w ¦΅Iχ°i›šΠN:ZΊϊ'ά S€Θ!’82žNp€²2όΒr΄)θ#υ uΒμ7#p•+HΜσγ‘­p¦πόU,|3Hθ#L$ANΛq΄#΄fΈΑu°-± bˆ"$WšŠψΪkCνGΪ $2v"δ–»ˆcΰnπ%Œ ΘόC12Λ‹F,2Ύ‹YΙκ€eμμP% K+Loχ ΐ’¬ƒ£qˆŒΊˆj MΪAΦc€«C±Ι-“Άι· §¨ι&ΗυTψMύ+G‡ƒk£m„S«@³hd Š>ΐΠƒJ¬·SrjuH;‘˜ χΈwΎEή)Ζγ~ηΰžž' +­YΨ‹ΫŒόaŽτ U ώ@MΝ—’bγθ.β ­ƒ§A_π ΰW˜%'Hf44t5E|Ai@ΕDΗΩ―††Γ―dΐN+ό»f’Q,΄όΣT1p„_ P³&γδ*υ‚²{στLΞβdοφ–“Kύβ—ΰΠ‡ΣGΥΟΎ­ ί…» TάφBͺψ7˜xˆE6o˜}‚Ώ‚ n¬&Τ 5Ki;:¦’εjΟα™+Λκ’|Ν».¬ώ=m­δ€·FUsΙΖ—r\εXό•R ω½¨ςΉw_G%Xέΰ¦,bΖGMcΛϋ/ɝ#Ωβ*’Pm*C_ό°CΦD;‹’%Ζͺ…™uυM ‰‘vͺB$2>₯ˆ.%•JFα‹ί°₯6!œ­εΓCгΰρIΞŠpeν Ν·Β_s§©$@ZΘ~=Κΰ#*uμ$sρݞ²£Ν€0ΪΨ²'8QοœΕα-B5k3`YΒX) ­ƒ‡k“1`χ©μΑNΖH'œάϋΖ¦Ÿ#O@Ό―41K%@k Ο|­ΈΞΏ©dˆŽHmM“ ο_ɐOLΙς!4 +ω Ζ “ŒH‡rΰuD„ΰBpJlE†6#ƒ "5FΜ‘αΈ ωP§w‘„Žδ ΣD˜δK₯8”Έt +UΙ³ gρ«[b^ςΥVTLΎώm"€Œ#bH€€Ș¦ΝΡ‘"z_EΜOΰ΄&2(π^Δ^T„QAŸu$RΰX,e¬¦ΐΣMδS sH έ+ˆͺ…*ΦJΔCY’/ŠΪj’»D­&‚b"{u,™ˆ£bΞD?—&2ΫΔ―‰Wύ2ΑV,\ΥRΕΜU­9Ά.Ψƒͺ!3M˜žx …σ‰QΔ_i©#KkDϋ£ C1IM0’x)-ŠΫR`cfɚπΗ`Ϋ%|β(Εύ5‘β#,Sœdω/†3‚<3Cͺ ΠΜ³6‘’ΑΧ*žΤΉήpšYγ6.5σΟ%z5;uDxkζΑΫ XgΣK°°ρŠ¦Ν¬~s›…ζ†°±»’(κ_‰9Xr‰b…%Ύ41Ε’r{rΒ“CXj’˜³@₯HηΈ -±¬ š–π¦ΰκο"όZ2`₯’’‚Ή%K*ΰ["g.ΑTδEvs ΈM Ίδ`Ε«KTސv ΤMά»ΔnΕΗq=bθKKk_Zc!RTV²¬)hβϋ₯P(ύ€†ΠXjiζT«Φ޲ώP„}gΈ +Εv„F₯μX¨]ڝ•vF'ϊ›rJ‘ζiO3΄AεΤCaT #τJ-…ϊIpϊ©‰‘Ζj!6΄]‚l)Δό›5WDκ5έ$iΰtΩBOΧήΙΠζ•»ϊΎ|»‹R°ΖEw¨’h›HY£)*/I•)Τ%gƒΰ€”ξ4₯4¬ :•VXWͺڌ–₯Οmp·ΤΎΒπ  ώΈ‰σ—–Y%tΡMœΏTΦ…>…V[$LΚο†IE.z(-z‘™‘loikθδ ΞZϋB₯£‘!ζΡ(š‚Β„!‘εΒάPψŒ0Hœk©Y–¬MX@ +ϋ†’–M +{Jι&—ΒrΙ4Σ°faΑ6žΒγ…)¨εΓbTxΖ0*ΎRΖ§šύΜ*1©²aF6[ΊvWφ0qΕ²˜‰o.–΅š½–NlΈLtΑ¨ΛΧ°σ²χΣ/‹ ΔιAφE 2AJ‘₯²WdΟ ‘& ž’zd­D#ΩN%>ΙΌ* KVΨF“±VβšμΉ!ΠΙκۈ}₯[‡a>–ψ(#s#eΚ-a΄Ψ«C^-vνZ¬e]α"ρ—‹ έ ™Θ–;QΛΡ#c籈Ϋ#Υ7@3!‘Pήx p%·ΓΏs]§*±ΎKΧYδκ₯mκ@•‘M Μ^e&JΔ:Ό&G¨&FrΘ%Ηα͜-•‚CBQΖ ‰¦«cό΅¨P·”΅Χ!ώϊFΧά”MΕNΩ¬ZS65ΤDΪψΠ#ι|je“Ž14Rε€Ceuκι€ CόΝMFw”λΓ‘=‡HΓ+Mη0j|πΘ›^‡[ƒ œ˜[MύΣEθφH€us]uˁΰe¨/SΦAεeiκ§εG€ϊΙW–­ SHΝΣω—Ζ›_8]ήΧΏ›Σ^9_5ŽZͺxϋqω@Ή³ˆέ/cΧ1ώ Cλ–Ώ2χΛK/C}ΰ‹ζϋ‘ξ'E«`ΩΙ<82%l9œ’)Œ¬χx⏍^«D π½ή± +π_ƒ*ά^m9&Ώ:J'γΖͺΨώ +0’W|‡Ζ9ϊ°8op…K•\α›ΜŠ:˜Fυ­C‰ΉK·¨c³Αœ d"„Δ4«‘s˜7x¨a<Κ™'λ`ΓdrΕ†Ι³μ[^‘κxΣσηD0»3rΰάλ wŒ·Τ‘ύ ΊŒRό< \…TΗΩ£Υυ3ŽO2§γΙ%tLud?Z=;gι7d‘’Œ5xΥ³vN})ΗhmΘΙFYλ‡ŠΠΧUζρڍσbΛΰ½Κ\„ΝΦβ…Ή:Q#sͺCA#ΑŽΣΞrζ6‘³Τ‚ ­‘Φ€Ϋj8c χ\ΤA$ͺ’¦O{i Ώ.ΦaΪeaΞ]!ίε#k:]6#BΘc»"ΘΌljŒ^ΦAλε€"°]YΗΏλΌ#HΎ€DΔΡΠ©γνb–/(Œΐ}kέ/V§€z £ΛΡΜ¦K€Uε{¦uΗmlΎN—V› ‹­h6TˆB/d’£ œΣœ P“NZθKΠ E4P#t(θ:Α˜GhPϊηŽν_ 1Hrυ9Ά‡ΔλjΦuZڈοε­σˆPΘ”ž·7bF=’h²Š-"Ζ΄%9u 3”0UzφS‘WE³2֍ήτJeA Χ…~1γ©*v²œ—(π9;LŽΓ-4ͺ +ΧΓΑ@ͺΫ_¨‘’{M9e‚ rVe­SYΦ>Ÿ©–΅tωOs΅U !‘Ϋv΄₯Π/Ω·Λ·j=ςα T„‘K·WuΚa e -Φ!₯eazZα©ελ0Φ²ξZvkPμ`μj:[v?BlΛ En9Θ:\·xι@QΖ +ΰiηΜ¦₯ ΅|Αjσ™Ϊ A½vL·£ΩYέ"@ΉgqJΗΧ1Xχ?E΄nΙ 1/.‰΄i><πt―|0$κ)Ν\L"BTy>VΫ‘ Ωβ•ηκFζ½VžHE³Gžž”c•ζc™ru$₯ωXφzΖΘσ#Ÿ'bŠ<ΘZΞ„cΚσ1§ͺΊŒς|Μz3ς|€2€^y>'–HŠy>@I•η1+Μ€<ˆΟ-eq#ΟŒ#ΜΚ¦D ηžφ=2}ΐΆ9Ζj•ιύζm«2}ΠΌ‰S:9Νλξγ2}0$tμ=$Τ>?…ήY$ν}»φι†=ƒs„q‚Ζόδ {ϋΝΧ?:^Όψώ›_Ύ}άΩ@ξ­)>OU2Α\T|"…ƒiŸΖΘύEΕ'pƒΚ`{UqvΫͺ’β‰Uΐ£¨Έαh―ͺβΨj¦¦ͺβ“αhλΏ΅UΕ'XgyΡN>ബψΌΉΏ^[Vœv–V‹²β@],Σ’²βΘ^?D Ω/αζ0 ξΚŠc†#*+wΪ1κ»DUq؍6θRUρeφŒB**€ΎΔŒ**na`Ί8―±J)*ŽD +‹΄GQρDSUSφ9`z*ΚTSU§Y₯I5ΕQ=eTS|κAvηMh—˜*{d6RMq€K‘ΘD5Εα9§TMq€ͺC ξRSš3:=Κ »χ—ξVXuMόnJχNpτeaΦΘS<&£zJωŒ§)yv :šDήγ ΜsνGndΌ‰‘"ƒςdgΊB|O½¦Ν ’’1O¬ε<”œΝϊaκš‘Ϋwή/‘ύ™΅₯§a+9’'ΤΩ#Ϋ[δ’ž1ۏ{©ΰ;…+£RO0ΜCSΓwκQύ)»#ΏυΤg`Œ4ΨγžkτpΒΘ–ΦΈ‘O{aιρΙ‘w{‚ >Fœ0s㋆[˜SxOά·©dϊž` I±§‘|‚“ƒ#kψ„ΜˆΙWvρ Ή.€©ό͜…œ§Ν:‘©SΞΜٝσ™OΨpΒψb€=Ÿζ%^Μ©Ρ±ϋ# S)Τ±ˆy,α‘j}‚§ >ΑS±OσΛDΎφ μ‹Ž1ςΊήz‘”ϋ}³©^9βΥΒm\ςUΏœo~‚I~²₯&:XύM΅‚‰ΟΙφiΛ­Zr.ό ˆc‰ͺΡ9e>€ά€Ž₯δڟhoU 5v‘Π^­ΓζHD™όI*P7ώOttάsΘF˜θ†Α:²ΉxΐD“V£ΘnΪ2刊¨E‚21ou”+˜†>"FrY§Ω8ΧΆΨο„24,σUπζΎΟCSοwάs­1•[˜ύ€ωώ£,ZΈ=œ Š7L=ςΝ¬s©ω;ΑσŒe T*«a„XΝΞEώb(1δ‡ΌήQy-[δΕ(*’—₯`UΕŽ +€G±‹Υ.6¬$ώfΕΨ`LA„… +glπε@ΐRxs.Ωο}Τα`"*ΰΥκ@š¨U΅sM~ΡŸ©Ϊ ΈH₯0φšΤ+Šˆ€JT©τΪ ¨ ‡glL”-αHk,5Κ›€ΖΡL© +(†›σύJ)ΐϋ:UT™ΰ{ΗzQueB΅#VtŽκ,@”k™ΣkΈΐg‡ΫškΌ¬™ͺ σ©EΤ‹Ω{/ΫευdFΊJ₯ΉT™az*su xrx₯‚Νn|έ°Υ²₯ͺl†Zc₯jŽδJeύFΡ€-όͺ +O‘?£RΖRK=gi΅©:Φ―*BGί ©ύPA’Ψ0Υ-ͺχ΅Τ7Šν/5β€T+©9FΥTq«ξ’@Bυ™ZΠ‰2N1•z*`%‘pUι(΅ΚK τKͺϊЍ\•.R)i•οš*_5W²TȊ«[ŠhΕυΚWh@5Ή[”²]QJu―σ”*`‘J₯°ΐbͺ(Φ`;UVTq2aΞRΔ¬F°*v&D¬rhBΦ*›Φ u•WςW6Ujρ­ΝέDoTψMt©).,ϊ₯"r’q*6אB₯ΙTα:‘UΈkΘ― +α•V­<ςRόŒκσ‰yPΏ†ΗP½?ρ"QπLCΕΥ¨1˜U ƒ€J… #₯І₯_T=S¦κˆ σ¦"ŠbςThQ\  +26ά’ +7Š«”ŽJœ§j@6ͺjEŠ‘r’βuUu²α‰URΌ³*XŠΏV₯Λ†‚˜Α­«b¦zUΦlΰ”€ "!C¨–g#j¨ζ§$Υ•Τ’ϊ‘΅l£*£T‰Tb’κ•6β”κšJμRνΣ,˜©Bj#Ύ©’jHyͺ΅*AP5Y±τs±RΥ]%xFΨF>R±cUMV’ͺΞJ$φωruΪiD£QΑvš‘€:8*έ …ό’«Κ£qLΓXκO„ ₯βΊUF­σ£οΔόC*υˆ δδ’ /›¦(Τ…'&lμ«ΑόL`™¦$1ζe šj O€Λ¨Ž’Δӊlόƒ_£jδ{ΠXΘLΟ$šsΫU’YΪήgNAŸ€ϊ<ϋ˜ΪšΔ½ΐ‘AAΫ-=[Ω6L9fΝ²½ΰ«€ήt ινˆωγ€}Φ‘­Iœΐ«†ζΙOέ,/ -θ KvhΡEPπγ3 %dx¦Ω!ƒc‚χΔιkjτl9‘ ΧxqY*πO=ž³›eι6x17nRVλ—`¦šΗ’—γ½Lpͺ’Δiμ3ΏW ΡiΪέ#a;Ν£'ΑVByZ–Ό―!Έ'ό…9BΐOHΦb § !@#νΕτbΆd©°o©‹”?rΞ·7”i<^’΄¬ƒΫ{%†–!…HB²‰Jt!ž +ι3|Ξ¬`Q?)a4Vi©η,­Z[(~ΚϊCAΤ|%•HΪ i™b³BΥliVXiγ³BKG#΅Ws„R•£šΐAͺΆ#°Ι*9—ΤvA©χP•P -U‘ΐ>+›Λ!΅£.‘4“qΟ€ΐ¬.£ΤœΊ²R…κZKeΪ\©V…&€~&‘šΆΑ8Rη +3Iε+μ%Υpƒε€B6 -³¦”ΡZ•ΚZΘWjm!h©ΏD.5Ή~hE€pνΈσ’1Rΰ‹5u‰E³ΒTMƒ†ψΙ² ")냩¬ Α•1C„YοRωΜ@ΨXΔ/ΘΣπ2وYηLKΝΚT­™γ‘)IL‘LN σ$ΣTιζ+1bΕΜU3ln W'c™8?ΥQΖ7q’Ε@ά¦μx5S*sŸ˜W™ΕΰΚtΨπΑ21Š_–R’Ί(ZέΡ!*’Ε3 F₯Ry£ΐq,†]2 Qυt‚ + -j£‚ϊνQIT'‘)Ξζ*«Ÿ ₯+(“PΆJΆ‚5#ƒ¨ͺ©·…±0£ξ)K—°}D‰Ψ/‘-Cε’.νŒQ‘6Φ%kΛΚ£²mσ…ͺ€«ˆ"ΉΪ+ΥmφT5w΅χͺΛ«σQύήζUη7Ž[₯€ZC 8*,,Sνa‘J«Εw'ύ4ΈΒm¨>{}pŸ2VF S§₯ͺΎ±¦Ωe/˜ΈeN₯Fρ±wί–j_™)*—Ζ:–œ@Ήœότι|' ΊN΅„Ώ'Nΐ:•*ΕΣ»! Ύ·CU׏.’σδV_ΰ1ή ͺ¨>!abXά€«~μ«±βz4Sκε…•{kλΨ|bΉ΅±εfΗv PοjΑ±ϋ›Δ ¬Σp_BNωΐ ώ +˜(‹¨a§ΰΓ±38σ·\Ο+†€Nέη€Ζ‹ΓΕ„Πšε²ύβ5,§”+Β€Ζ¬0“3A Zά³ά]Xpfy^ΐΞCχρLcxa‡Ÿ‡l|λΓ±³Ψ₯ϊΡσvMˆ3Cžα΄Οώ\DhΨMP†kΓ΅„ς¬³QπΤ€xΟδ1#Ψ­”ِ]t  ` @KΏ5xŽΈAΈebKžZœC!QlΪϋ컝W~ήχD>Π‰"E2ψS慁‰‘Jθ)ΓΒyc‹π θ©δΔΆ2Œουϋθn»tΊƒ5™¦΅ψŒ¨ΕH£>τ#°¦ΉΨΣΔΰf¨VΡϊΠ"αυ>Ήχ 35ΝύΰJcϊ1 λΕ \wUs0ΐ­Ί&†¨ ΅1|ΑπKΪΖ±δ σ½"φCh#&»Ιΰ WνΈΙ0 Œ +|7&‰B=½#mΟΡhDήQ½žΕΩQΧkσ0₯g,8} +ΤΜQ{29τ ›mΧJUΟž0Ή ΐŒ{’ϋŽ”₯‡OVrιΎ­ύ ¨Έτ‘₯ΟΧBnyυ(ЊVWvGW0XTn¨Ψ+@ˆιοƒP»Ÿώ6xπSԍ’f‘κΛ‚›γ½φsZςjt‹Z΅h‘“-ΜapZ,ΒN“SYΎ‹ςΈ+…U"5Xέmξκ!—n}|c ”λφΝ—SΌ•uE ΰ²φ¨ά~cΤ.{u‡΅]QžΈέΥ(c\v?Jλ„TΉ‘H«~k–XH2₯I5g6…|ΰKc:8WhωΘΝ`&}¦±:KΊ(Ϋ>†ΞxΪ²utskΩZ˜UΆu-[ΛX²H_iYZ… 8Aϊ’†uЏ\έ(ΚH<νŒdeeˆeυ°ΝW +°΅‚}νXΉ#ΥΞ–»'Pέ·|J'Χ2Τ Šλiπδ2cŸπœ₯wΒεY‰«žάŽx( μŞ—‘O˜»xΚ:Eq"žαoqfqλ+’Θn:1_+.Οx’q6²ΪM“Ϝ‚Ό―¦d a&€ρ '7ηXC¦`Ρ‚3b œ3sAτ³oš˜(Αo,fLα3f“δ—η&Hξ}δŸ9δ7§>‡Οπσr–?g™H(Χ‹§]oΒWbςΗ09—E3™g ?­Ή84μ!S8ψυzSτ[<˜aߐΎ==¨«ƒ|‡ρρ‘Υ[΅ —ŽΑ(ϋ ―ˆ‡>‰¬†‹ϋ0,ϋ=o>3+ΡΡan#«ΣύS!άaN§‘Υ˜j…yeNϋZύ)B«a;σ΄v5:ΎΚ³> +μΉJA'¨Z»,Ϋ:\ΰΉ¬¬Sδ? |©ΪσπΧψ„f™5UψήYKψdΛ‰O[|B2Η’OΆ\ρΆΰΤSρ9k|‚~ύ°Tψδ‹n…O nωm―ρɞ•DŸμΉΈnΑ'Τ·.[‹O¨›σ•d|C!στ:‘ٍμNR―τ²ŽN xΩΩ@'§§ωƒqJaͺ‘E6˜κ{QJ{Y“ ²GE·άŽ1q›ΟΏφl›zΕξ‘“ϋ¦©±Ιc§ω”¨δαέϊ―IŒͺ3ΩΨHuιξ*ΨĘvqςtw€) Ζ8Ήƒ‹›1ͺi‰@πLŒ"Ϋ=I’Κ +χ!tf…Fj’{OD¨O(M%–χ@|ΖJk:ΖZ±ΡΣ#Αpš°ηYKΞ•ΜJŸ„--cΚ‡΄Δ‹ƒ'θέϋ +ιb<άΝξ#τX¨o’€5ΤΉ +ƒΚθj…^lΪ{₯η΄G¨$°ασΐ „Σ€‘Η›ΘG€Π†Ζ„Yl`KΚ ‘0a"X$έΩι()ψlΩ +}© ž‰₯Ή`<³υ$ΊζyϊT}θαx|ώ©1y&Υβ ίE§Ο§*OͺL¬7U&#^£Φa6j€wYρΞnhβb…#°‘ŠΝ1<βΈL`™Αښΐ¦Zΰœ7Žφτ‚ΐ&Fβ—šΐΒ‘Ÿ™h,n$φτƒΔJ…’ΟobΤq3ΐ>b4!Γ`$…-¬bσB!†sGΠ†τaTz#D@ϊ0ϊ©δ΄υR‡Ρf£‘kͺβΥΙ’†:Μ‘,XP‡!ϋΑ6CQ‡a‚yYSQ‡ΑB²ΞΩωFκ0¬hΓ J†έΨΖκ0ŒΞ؊Fœ κ0:ι υ―Τa˜Ό_ϊΠjeuζτ`ЬσL}₯›@Νϋ1τhYΖ~<ΤΠ‡ai<ΊΣΓόH}Ψ‡h₯υxX#FέΔΔV#φlΪvT·™ιςvζE»_LζΊ‡Fμ™«Δ¦ϋ怃Υ:l‰f`$ŽeΥf3όσQδŽ/$€Ίa‘2ˆkΈ†©Τ_̌ΒΠUXK‡άο9.—[Ή ^ΊΔߝΏΔ bΊ[abΩ#λˆyμό/PŒ.ώ^fFτP:8†*— μΕW²)εrψ΄Ψ^” E*A•Bά³ݚzb―w†Ϊ‚[,šΰGΊδ‚§ ›X‘G?;eΰήvf/┨9ƒK†b’σΘο)g«³c[Š,σ¨ʜΧ™Ÿqυ7E-Δ_Ž«χ¨ό"ΘmΒ‹HΗ‰œl·…•Α@ΰAΑ„9=59<Φ[Ϋ\­ΰ`υšKEvΊΒ«΅ΙΘdΎΘ7'·fΙ3Ί‚’΄τΉz#βSΦaΠξŽς²―d α©λι(‘ΐa―°ˆN©Vpƒ6θ£|(3‡νͺYΙδϋbΌΈΧ τ AΤ$]•Y +ΤƒGUζvtPvθsωη-§Ϋ‡6z-—Ρ“θxω8c›v†5™Ppύςτ+'΄U YΏfΏΕCKQLΤ%EΖ“Ξ­^BK΅Š¨y‚Ε­α’ƒ*”@;,•ΈffL=€_§pUΗύf²§1\λ ;˜žz`hΖ‚/ž²„-αΔΜ³Ψ%dͺΧJg'`gΚE}Ί™Ψ[ŸΛŽ₯9 ΟsδΦIαdcC$ |άe―»Ή2ΟOΏ.^λΨ1CŸΖP/‹b Χ‹Aw7εlŒ‰e Ž%rRLQ-υŒΧOQ"wΙυ&CΨdΐ)ŽdT>8Œq†sξΉ<Ζ‚}”ΡΌ5—<…§XP―λI‡^Τ”eŽοq*‡ΉΔ+iΒ—‹ώΤ,瀂ΘΟ1μcκtAόQΓ.CŸ“ΣαMΆ ΰ~¦―cŸΛwEP΄D΅Ρ_τΈh9* <¬ŒΌβ@ΓrCžh7s‚Ώψ”0Ρo¬£Κ,$j@°Dvߞܨ Ρ¨ΗΎ₯Ϊkgυf6ίcΛΡmή=俌€–fB΅j]ΠΘ¦­Z9 £#ά’š/” ˜v"Α•›ΐ»5οΉΪT³©Θηp›Ÿ²ΰQˆΉγϊγƒœΗ¨βHŸKj;P ;R:†‰^€8cPH€ ᡁ‚W ΄[”PMΣQH†|Χ\Οc{C˜Tψ(.4^?=.” “i.%ΧΑݎΛΛ4},₯ƒ―‹ΌWˆq„^‰>πς‹R-œ‚t΄ΤŠ4Έgd΄ΡΊ5nYΓ,<†Μ€‰…‡j|U>Γ™…ΑT'FΈ«0ω6΅8ύvx 32’lx kζ!…B©ΖκH‹HTΘ +Gl33KˆψΦ¦Μ›‹ΰ ₯ζΜrίN—ώΐ μΚΑ… ―‰™2Τώ} λΤAœ°WΣ b‰¨/•Q¬‘YΡ](―ΌΪΊΘ3€81(xi¨ ½Zƒ€FmaIΦ`˜\bΛZ€(·+ΔφΖ- gZ*vF­b{ΰϋ8²ϊk°Fτάϊ½ε ΚΕfι‡Έ/ΒLπbp₯₯aٚΛNˆ΅³ xl…ύƒWvΊaqΓ(7)N1œ”Γθ£Π0¦Σξ‘…ΕL܍`r˜`ͺa†!ΞS*¦™ŽΈ΄bc ¨#•jπ)Ψ1κΣYšOΜ<$\κpkžχ†H4€5Ξυ!>ŒHΖΙΉ3`WBΒ3I#΄€AW'‰——ΚέF²Αεel @΄ιΑ=KB’cJ΅0l‰²YβbγΠ~x Δ‘S+Ί1i1ιzˆxL‹ p–a?y ιJ\,ύB¬ΔΪ7Z(CτR€%³Qi(…2@’,νΜEβ.C# O!ϋj'Οo7π”Σ5;ύz ž"š²:Z˜.ϋΚ’υ»ΓΚW'X©C‘jˆšΈΪ€XNγΆBΔ4aΌ)'¬pδ7λ”˜χΩυν#²6M{ =ηΛGIx(›a^d” ΏZrV‡9`I^Θ›ΙΛG2Ο ΤͺΊξΙ…2τΛ†ΣθGUDΏεcΝ9²ΜiDŽφιΝΪP'†Φυ t#Ϋ])UΎUaθ„€ύ€u‚υ΄o˜sΜq_e—œ­―œΒ…Y.Xg§>Ε΅‹3]sςrξsςͺr>`)–§¨ΰ*~½`Ν(“gρLξ°uζπ»Œ†N{ua§κ¬Θm–η,ύΆœΧOw +ΩΉσW +Γ)κsκ†bΥ΄Ύθ +3‘ xMέτ•k3›W0"Θ© Φ°Cœΐ|»` Κd6­P―%η­}CˆΠ +b,:ηΏ9˜QΡK$SΫΔΛμA.‰Ήe˜Ž@š|U €D±\(»7j(#€Ϊn]*J bDδgύ°Pn$ςΚB‚θe:ϋ4Š’/*e¬PΊ”9C9σ’Y[(qτ ‘λ‘)U_:‘²‘7¦Υκ₯²·‘†*ϋͺͺrN΅J«œg¨ΎΚ™‡zμΤ»sη#E^υΪqνΩ7ωR“μ(85ς¦¬ΤŒΆ‹'9‡_*K΄8υξ!YϊΑ{ŸΔΐFΘY‡mz™ζ˜JΏέ2–έΙΪ’2g΄ψfδ₯©[Yύξz­Σ―,{ρu—νnΛΰΌΜŠμ"ί΄­“gεΛ˚tΞ ΰΓΠγEfΊΫ^Τ~₯Ή¨΄δ _dnΦ[Q ž1Mςκ4άΕ Έΐ N1Ψόœ§Aέbνκδ_΄{€to€p5$€μ2αŸφr€y²dμ7?«σ4Η22ϋ(bBΤ‘’`ΎtΔΐ ¬<Πͺ6KΏ 2e¬«2g ~emκW֟!ωτ;`!v@²Θί4­H+λΕ‡³Νy<ΎY δ§d<%•―ε4Qg“**Š,V€aozX‡Κγ(RmΜ‘π™£₯/N10ΰ1ΰ"°‹ΆΊ ψ5”.I3eά%­L·M«Χ­lΎR·W»‘&DΠ쫆φ_HEg$δӜ₯”Ξ\xLp‘E4π#ΌpvŠ;Oq,`φϝ«tfρΖα1†Pσ9Wι‹Αk’ƒ§hΕΰ)‘ΔΰΥΡŠΑS4‚bπ Ό&A1xŠFP ^ ΌˆF8ύ‚“Ό&AxŠFPž’Χ„$(O! §ˆ…ΰ5 ‚§p…ΰ)Π@!xM<‚Bπͺ~‘r(‚Χ$(O +ΑS@‚Bπš€Εΰ•€„ˆΑ+ „Χ$D žƒ§€Εΰ5 ŠΑS@BΔΰE<ΒιA^WGμ™DFΘμ:βΘ$3δΪ%“ ”^Δ)g’ƒ c—s&™AΰΉ3Ι,½†Ld’BοvέU™d˜X 42ΙΐˆŸ‘D2,¬½„Ϊ!g’ιGg•IfΨ²7š2Ι`l^*Ρ3ΙΐŒηRrΙ`¨e«RΙτΟ»2!RΙ0’Zj₯’AΨ + ”J‰FtΉ•JfΘ0K*™!κΤ)—L΄ψ›‘LχF‘’L©‰™gGΩdP’J«U6ζ}―σΙΐsgœΗ‹S(Έξ>E>™&ΧΙi +ޜNζ$›Μωd2Hε™Ž“Ιΐ‘κ4—ΛΉT2Ο†ΚάΑGM6™“d2'ΉdjΟ€μΆU‡§L_g’‰ΪjŸ6—ή™Νύ ˆυϋΈ8χ’{‘ΖI%σFΰ€’y#p’2o48I™7„“"σ†PRΞΌΡ $eήBRζ@H%ρF”y#’2o!)σFƒ”yC©δήΘ©€ή¨1RI½©€ήŒTRoΤ©€ήŒTRoώ)Ή7jŒT’oF*Ι7#•μ5F*Ω7#•ό‘Naΰ#1Ι ~”T»JΎ±#€:χ…R_€“ͺΤΟζ ή‘ΣLJπ£ΔŽŽ†ΣΔLή€έptτiσρύ2%8Ζ6ω ”·δ'ˆόΏ%?AδmσDώίβ=‘]Τ”ž@.uz‚Θώ[Dφί’ž ²Άι "ϋoIOΩKz‚ΘώΫ¦'ˆμΏ%=AR†¨HOΩΫτ‘ύ·€'ˆμΏ•";ϋΫ5ι ”ύWι ”ύWω ”ύ·ΙO μΏΚO τΏΚOМ㣐Ιι?”(―ΚMpOnέ69AΙΚkέας@ZήΕӎ„Ω'ι ξ›ͺΙOπ”©>e†‚Ώ‚όw?8EA[5==R5κs(h.„αΓΘ@z§SσΰEv™vJ6t±χŠΞΜ½₯Α₯3?m#T¦N9ϋ&τjπ‚΅Wυ,'Ϊ8©ŸεCO)jΫζTEΑυ»ΫטβΓ_ 'θ9_puyŸ€γ+f0ψƒ«20ΡΦJ%»Ί-ω#c$Δ31Ό«™‘VƐΤ@ηΕΓV2οΫΡ7‚9IYμ{φ‚^Ϊ/Τ€ζ6ϋjδ€ΎeVαHRŽ?‘ι¬νDU?x—Ož©ΗΗβ§λc™ΣΈ“ϋ .d<-?ε +σε3™PwŠΟŒέ€J‘q3Ϊ±wΞ\hΙw6%―  eL:μmΉ¦Ÿt-σR¬X#΅[OœΈΊ *4” §™QP¦• ΅zlσ•l톀_;V.I΅±q•΄ύεΆΕάΚЁ@ΑΩζόGπKΠηCε„ Ÿ>+½ wF»ΡΗ—iδπˆχqž™*ΰœ^ {<π 0Ξm0soAξ2t)ΧG !%bAΊ•1‚Ηq–¨ŠρcονVοY’3½+θ{Ψ'†±AγͺΜ¬/Ÿ6ΒΘhπ0ΨΰΑ˜FlΙƒ<ξn!k4Μέ{=oDdF¬Ϊ-©εu"D‹ύ‹ΥZ΅ͺ²2#γγ}ΤϋΗbXνzϊΚa>Η HΔ™χα_πœέ"TΆ?ΑΉΌMrφ˜ςBω™·= ξΖ)ϒʐ¦ς¨± Έt”Ϊ™'•œ„rΔzπ.Ϋς’Ν6J*ΨΈ€=ͺέ4 Νj<4)Σ¨«@·ΞlB‘ͺ4yΊu.ή!‰ŒΓEΎ„—Ϊ•’³ͺΎΟΕ ―'š*7Uώ»6θšΚ΄Υ!]έφ¨έgξ}’έ©Yκέΐ†γΞ΄ΪŠζΘς…dUe¬>«ξJ΄Ιm˜(KΖΥ€£­{†ΧΚρoc'κϋi\q¬»ΗX―A"7pΣoή£B—hφ°,\Ϋfλ:ƒamΐ^χήΥJ›¨+’5£²+Δpnt€cΣ­¬OG–PϊΕΌ0rcΧ₯nΑβaKεΊT,Ζκ/₯UΒ‹„·?‹­Οœ>ŸJP'~fNuu­R±Ί­π‰kP3ζ\λX  ˆ_ΐ<―BEς T΅ŠHuXΝκώ$w­P›mγΆν4! ++‡o|Φ°r«’‹Bχ8Ž££ϋφΦέs?[²€^ 6υ'kάzzG=8p‘+¦εΌl%TΣٟu‡(κ·ΏξΧ¬&"©¦$ςiάqŽ[ι1λVe|ŸVγcuαTfSΘχΥξφξ•΄Φ*Υ‹EΉΜ†ͺ†R‘k¨Λb5ΈN&[HΊ(θί7ƒΓσ,½Ο8θg€Ψέ‘BνT›±˜O;!ŸΓϊ–Έ‹Φέυ<Φ¬¬+›IuυΆ[‚ΗXt0q{τJπε)ΙΛΪ.+bQ»γ%GqsgωΑ?φŽxΝO*B ΩΞ^λDΧpη˜'ΝΗyΌόΦfΣαεΌμιρ€vaϋπτηώΚΗQM9Ÿ%Πψ}¦»½}~δΖώ0£π(€Kυώ#΄ΉΫz"ϋπήuZ#„°άaR³ΪiF$!νHλνόNA`Υω؍ՙγfβΒ[<¨uF€›.°2d`–―μο + 6μς‡τΐT˜wv\&SΒdΏλ+ς©*£VΉ», ‰οθb§5.„ne0ΛχŠ<άGΝτφ#Όσ8޲uSΗgMKωΞiΧΖμͺ–Ήyύc³(ξΧοŒ:ο%ρͺ Ž[F4ŒLj½³ΘΥθΔω> ³φxJντΥͺκΗVF5β1²™knΠd‰{AI™SO/ψžSο-^1;£_;ξ:‡?ήI3ύNΝZ φΛEncΥΠ}€§EΦΉΊΠ)!ŒA¬B”ηγeέ’ΩτΕJ=._ώTtΧΧͺG ’/suό Η­?{ZA[„ΛJ»»xm¬Η8Qυ%{ZΚΚ>­Σΰc΅~Nšz9†Ε—h.ΰ9]ŽΟšφΟX²ϋ2­ΣΝANE’€Σ’IL eΕejέ›υζqΙ'nλtΏθ±ρΚΡε₯}ΆqΖ†˜ήέ,zjΣγ£,MwΊx†ΌM™dσЇεez&eΤβξdDΞΎΌVœ(ύξπk?ΓΨu“ϋ{{ƒjψΘ¨›š±»ΡϋζBΕέo&œς‡;ޏ墓 V›vφξ!RκΓcpœ«Œm±,+rO› ΅Τ–{ŽΟ2g)›Ψ–¨tΆΥΝΛ V“οŠ-βηD΄ xխ吷Ή£’–’:`ΫqQ#P|ή–]ή°›·+Tpc{wςlΚ&pd;E&₯—b+I‘ˆzΨσ†]*VζΎ1'=ΨΊ2±–%ΆΈzZΫBmΧe—8,™ΥX@™A•γ9P›u‘GΟγc³ +ΟonVγͺΟΈ±…2―v‡Ν §ιƒΥ ξ›$Ξ«ΩΈβUΗ¬v<υ°ϋ*υψ3b؟ΩΓΪ2]Qh«ΙγψI*βƒςΐ&~»lΗό΄I¨Σ›ίsϋ§|1ŸA­U}^ςν58τρ»v£”φΔœ€=oΰ${ΘΪ=„Λ 7YβίLάρ$TΜΖ#ώΙ MΖτTΟ9Ÿη=¬ίb=vΠΥœ£6Ώ6Ζύ²”Η(£ΪfΖυc,©ψqΩ9 9 Ε)Οτ|jŽΚγ™>εv~nuΌͺlιέQ«tΤλϊλEγσyhρϊΡp«kπwtPJԎ9Xτ"«™šξξxΥ)ΓΌσ4πέϊ671f *Ϊ~}n΅Ο+4Ds‘>χ θe1Aa|¨=πŒΔžFTΜsjyήΙ³‘:Η)χι’[&οšU?#af©cςεα_Ό<>;΄­x1…¦πΗ;°c’ΧSeͺk]ΕS\kν’‘΅Φ±ιλ7ό>Ο΄Nq Ί±Ϊh=rd΄NωšGιδqhχ₯ρΩWν\Aυ“vΧΏΦ*;Δ…„½«ρ΄όδK£Vνtœ―μά Υ—' ϋάqVΐϊΖoχϊΫepŸcˆx^lψ& jσΒr” ¬L Žψ~?ΥΟQ…/=α1Qˆ«ζδιX1HUΛ`7Φ0ή’φ™˜N–q:wεθ‘ +ώžͺ?nv8„¨jςž~#νzη.Nψ—T«}ϊ‘κΦ₯τJΡ‹πW)OΥVΚ=ΪA)5Bξυ ΌuWΊ +Χ£ήήpžΥqΛΚ.ΆRςΣΑΆ^Μ#οξ¨[μΗQrožΏgφΣ=ώ‘žρλϊ!ΆšͺΪ+6A₯θ‰πέύ’r€bϋ1€sϋU&x‹6Σ3l$ΖV†"YΝs·C•¬e†bW€_ρLoΫzzΉΨ—›+ξι}“σχ-s7χ~|ŸΖAνώό€ΨΘι“Y»η~OŸΜۜWίͺi³m“Υ*BψYώrμ05‘GoSlDUΑŽ:Δά«Εωymχ΅§U·6#?Ή‡½/]΄ΊsL!μfξ£)ͺLάΉέdnQΔ‹9?ιΠ-Ž;UκqCc?T“³ ΞV=!ΛB! kg‰Μ˘qj{;cΖ'±Αξ™λΗXΗE¬c}Φ΄”οœΦym_YΧq˜ς+=Z³ξEtζ트O½«Zw?bHλ E¬©>ɈI­'q«5*"ΎUOΔΑΦ ‹XΩ‡S«γ5bos\Οψάϊ3ŽW^ο›οΡ Ζ›Γό6Ftq½³€œ―υŒS–·Ζ3η$1cžs™±Ρ2ΫDuΞI3Κ:§­-“ΫŒΪΞ)pFvη,9#ΐi*qβ9ίΞXςœ’gΜΉΜά36=ηχΏž+ΐŒsΟ•βΗ_+JΔΝηΚσwξU|}­Pƒ5l†κΛJ7Cϊs=œa΅fFz ­‘EXk°'Φ*†²˜‡qω‘ΧX~Aδ?ͺy’εgD.εg,ΕeYΦpm"³άŸΘσT7)ςAλΈΘ-—kζ–Šk9¨εΑEžjyy‘Οͺή`δ½–Χ8scΣ³œ9΄βzͺm:ͺ3·œYOΪ—wζφ¦g<σΣw^yΒμbΟtβtΕgΚqzλ35Yœϊ™ΒœΎΜrΖξ`&CΛb&M}£1Σͺs'2³―eΓ2³΄s_‰άΉσ™ωή²Ašyṍš™γΨhΝsٍΝ<τά΄Ν\υάΧ͜vΩώ­γ|ΉρΉ‰œ)τ²Χœ©φΉ%]ιψΨ΅΄}ήά"ŠlŠI± Φ5hρ‰}²f\݈Ό›n*=ΪΪtS†fE½±/§Ϋ΄pςξ]" B³Ε&_sΏφΨ`Š5±ˆΔ @Δθw•n²€FΛx°*Oy<+€AHΫm9Ξ1‹8Θϊ€•Μο‹€ΚOωͺ"μ².>’3R’?2‚8λFD˜gέ° Z76‚FσζΟ°|H9ψ4Ÿε Q­ηA¬w9_ω­°Β˜–xάΌc*ϊ@ρZ©ΦΟ-»w% ‡‡―Aw’mSEt]ΤκXϋ±E…΅rά¬B’89­­¬>‘uMι$'ζ'Ρ3Ϊ₯r_{Fq]σΈuνέκχo\wB…/άτa χΟν³Ί—eμβ.‡χx"i7-§Ρσ3‡=¦πΎ>iόϋ~rGΦ¬)jΩιYΣ]_ώωiS,G +5$?Ξ―}}ΤΧ/ό©άϊΣU^‘Ηΐη\Σ>ΫxΊ/5ο4₯ϋŠWηB“ŽΤ-ΓH₯Ώ€’γΡRΩm*ιi¬£lœΜρ4Ώ+ΆyAn[Wμƒφυ»ΎŸ»ίrςi8ΒΏ)Ζ‡―L7]©ΜaΙςθςΰΣavΣΧωίώm?₯QFΩη…=˜ScJλΟ&©·»TΖιΈωkζg}ύΎxκ8‰*ŸΚΟΧԊFŠΫfΝλ–Ο>Um€~6Χ €0ӐŸ|³!Š-΄’˜xΚ“œΣS<π9ƒΝ11―‘Œ9#Ξ1φž5Ώ'W†λίς)Ww₯‹mΉβs"ŸςΙ§°w4θ 4fs9Ζlαi„Vi‡ +ψΆΎͺŽU7@G΄Ά tΎξQ ΝfΚt€›βσ4‚ΫPε“nΥί―έPτχ~ NάTnjgrNά zεΨξ[κ)4z[Ρ2νΊΔΖήΏ`Β\›c™i•>q~γρ0mo­­Zψšζς³tpˆΕXΆ»§bŸ±½U’ŠfA`ϊΞ.$ ί@TEΝέΦ½ρΩςΖΎow&5CI±`νoΙσQ·γ»\ϋΥλ~ŒηπΩ(₯Γ’₯Ξη0)):εή +>Ν~9;³KTšΝTΤ%wΫEiΊ‰ΫΡB―’.-7τλήά·.'οHχ‰Š°[uΠ»-lΝͺ|,†ƒΐ’•žZ9Qt¨υκMΝάOθ +ϋΌψ“‡)΄ιΤζvX<Τ‰!~‹‘ωύLOX™¦qmΕυ„?#ΨΨ¬ͺoλ.ςHS‘0H^ρέΆ§£ƒuu?½f•lƒΠΎŸ‡uθίοV §#©rW«ύόΣη΄’^ρυψ,νκX%ο …)φ―wh·VŸ¦(ͺJTι₯.JΆ>†-Θ.Δα΅‘P}Kνο0i}>ηάLΏΣnL—„ΌοΓ]$A²ΰ΄I3MO|Ξ*έσ>c‡qΈξήy6+ΞR}fS£³”.οΥ=%•ΫζΩ“€ν豨 λ£²+•NM\ιgn‘«r81ŠΘ…ΔšT*#–Τχ£ρWά’)$ASˆξ~Ό°=SΖ£8©FΓBύuώΉ‘ΨτœŸ‡ϊGϋFZ’“ ψG¦θΛI`‘₯»ΖΌΫz)¨/ΏNDή―Ο vIλ3$E.εν>Ζ»«m;q"δΡ^wΠ«‡*ά^ο‚|”ι  R~o«Ρz;ΨRά&)ͺ’¬Ο­žOυ^B {―c/§>Vm:TeIOΝ£¨Ηή%ˆEΎ&ϊς9Μcͺ€`~ž›ΥGέW + ±e»mhŒ 5λρ γƒHχτϋϋϋΊ»λΊvS`^—Žθ—ϊVΛO$žFt`݊±y΅fά,”˜uχΚ=ν—w0Ν{ΟΘ§ΐ`=Vω@9¬’Ž»l^Ÿu +,NίιΉΝΨηΪ₯©)“ςŸyωi‰œ?tδ8ΦΟ΄ΫqΉ&ΫΊe(βpάΊ΅Χ°=lάZ{§G₯ΦC:ΟπλDΨβ+γ‘ΟΓbP¬OŠΑSΏΡΗΨΌ°9 ηΕΟαZ~dŒκy/渟χk½ωΎΞχhήυΕ3z½“αAόžέΑώΓΗΏϋέύ™nώτίύωίών_ώΝoύ§Ο―ύ_ώυ_ώωίώε_0υ”©fu/―Ώϊ“_ύ7ζOϋ―δ·αgΪίό—ρ―~λ–α‡υο~χ›ΏώσΏψέώ›φWιΏ•½ΨY=v" +Ϊ|β,=*ιέdьσoτ·ς+λ—Ž)κcϊ―ϊσϊόηυ1ώ—φν‡ϋΓώl?ό…ςοΓ‘ΝŸι _ίτßeλΌ’?˟πσΦς ΏύGίβ?ω‹ΏϊΫίύΝ―ψΟϊOυΫψλε―>“ϋg)©χšίϋίُώŸ΅£ωψvŸqρωίm±T!)‡α½†ΘI@υ7nΤ@ γΣύΩόΣ²Œ6•ΣΣ-{‡ ΰcώε<ia?-γՍ»%˜Ωš*¬Ι+kKδAŒ,$±θ°cJ"Έληνβ3`²<"Z‰7e±΄ξηe!g(K”ͺ“SϋΈ”»&3 ΠBΓx‰rοΖΣ[ΎS£Ώ¬€’j½­|πνΌi0m©φω‚Έωύϋi"g‘χ^­+Χ«Ωe>Ÿ‘yΨ|άAA›ΈX©έXΈ„€fa)2?ξΣΓ‡r<„VNο΅“•V¬‹ΰL!,ͺz·™₯Ϋgy6iΔ* ΛμϊόαmςƒυI΅ν})[λ,θŒˆ8Fͺιjνڜ΄»,Γ’Ϋ:oY/χžρI–+zc8ϋη2Ψ>&40:=ΜΚu›Β³ΪϋˆΊούΒͺΔ>Ί»~£}v%ΰv³HzLFlœiEΔΐ€R$•ƒΝb`7L,‡MžΈ΅3‘G †βˆι 3[’-š"Μr[ήΞ «4%»q½­ι’]Έ$ŒA)@»³¨Ί΅#Ηϋ΅νβJ?μΪ§‘<‘0’ˆί%žδο"₯…ŒpyΊΤ§=ΈΩΨ‡νω»R{”PΨF_he―“s€•ΏzŸί₯7ˆDΛ–6Ÿ7V…Ψ؍žϊ"…§[„<' ²©šφ±π¦”ξ½2½Ω6PΦrƒ˜‡ΤρŠž•mXt¦ AŒΌ°’Ζ·4;Α/aΩζLθ΅2ͺ«δτŠM +]ΈfΤσ1C™wg.FΙX©mZ¦ξΆYσ2.=ŠΓ₯#΅Σ*θ ³ΊC}U*ίρΦl@°YΚ‹2‹/(π’Ό5XT.Ψ™§ίsŒ]•ˆ”Ξz“±ΒXIΥ™δΫt&¬`Sΰ8 }0ΘZ¨άˆ(Κθ©"^₯Χσκω2)k =B‡Άd-Y‰4ρ@5±5σζθ+°―d˜©WrX–]w§u1τ<47³αŽUF‚ψhy£on±ύDoXmIA λ&Β©bΗ«Ωχύ(Γ₯’N/2ι˜ ΏqγΨΆέ^³ΓQ<+€aͺ‹ΉΊεoŽύδg™.ανΥ}z‘jξφ²'"ΩϊSάHD놔̙ޛζ° ΎK2³*₯ίΙ : –³ΨέqΤE»K|ž— +ufu―’”Q²]:Κf_M»X”Qη‹ͺ°u9έNqv;HλθΗπ\žΈ3Ω4*^χψ²ΓF½\jΖ ΅R«Ηž»κž4|\-8]§Ες–«*ΝΣB±› Δ'ƒ +ΎCΤι΄CυЦ‹§)N<’(•@f—L³{e[3ΒΉͺ7ŸnyΈΧ\Σ%2‘wνς;Λ@²q>37žΝb‡|ψ Κλ$˜¨:έ"γa0_ξ3Β}žG΅ΛκΒIꈊ†Γ›Oμ47~ξγ&PŽί.Υ«aΫΠ^\’‰ΡΤ&MΠολŒQόάΠ•χΨOΣiκcΪTϋ0Ή]ͺ?Σ&ΒQΙr=ϊΰϋt9EŒr³θ_c~ bD ±γ01BŠoΥΧ«¦πφ¦Ί’?Uύ’[>/K’aΠEDv³ξ)Κ—β,q₯ω(«Œ₯ͺͺιc„r’%R~θξοΜιΔEdχΗΚΩUΤΨoΫΏfΉXι‚£j1s*a’g·ΗΘ{qoώω8Ίjp?7Ν—kfGRfηΐΛyΓ’o€vN εσ8:“Ή/T]Γw†k³\EάMs²0T ‚κd3Κ.πΚ’=œtΪg=1ε8Šr]rNJgέΙ€ΖΨήβ΄0°¬Wλ`ΛKόŸz†Cέ΄ŸI( q3₯xΆŽ:ϊ™š©;£υ ˆ­Iˆ8V<Bυθρ3ε*ΥεŸ4)μ’ω< ·8χcϋiΥ§Δ"L¦,ςΦ0–ί5ΞτζU>oΧaZΥΝΊ[—ͺξ1†›½…χΗCιΔnCΙv +26xβΝ,κDΣ™ΓSš2v;ΜK4φǐИι£&‹kW0οφΫ8œͺm­ρ— ζXbΨ*Δϊ£Išžϊα€w’9»»Σ.bΉa€ϋQ Τηbθ3κΘΫ΅‹Ώm·³)= ±3@,Tc~ζU›œν³ν[΄3oΈ’PE$)φSP&¦Ε1₯γΌ«…ZW  M ³+1ο€Y£1‹βE–,Β_Ϊ£mΆ[βŽθ˜?Nuβ8έΦΙιεΗ²H€x7wI–ˆ¨Σ§?}ήιί 4 +λœΒ‚3,-‡θ}§δΙ]©Μ]4nΛΙ!ŒΞe>Ο£”IώL?ξpΓ¦ΑnMDB§•5™―{YmΫ\υ$NΛOz΅>Ξy—¬4-!αˆύiGGκ}8e€!1ΘΗψaŠ,^§Ιͺž&ΕG#$iV¨_|&K±M†IίΦ¬RX,m{τΝ4€eݚw^qœ!₯wΊ“ΜγLŸ)ΘΥI0―ϋΆ.tεKt¦&,3x<qR‘±6΄΄[JΜ9 ΛB7χyΖΫΦk—L»jστΑOΏ0 Σς“O₯*QXΗ©NJΧ—£η–e‹Υ²ΓδΥΘMΙΑθ—W +‡e8e ηqlΩ”έΈΌ›h©7‚ΊTΊΙJy˜UΥύ²(}E=gjFΌ|ˆ3퍹ܳΖrΚΝzλ°οT1£Ž!φ3€ŸιββτRZ†‹ͺ„ν,οj΅3ΓJCέφTPhyc»qή†°SάfZμήαžΗν·)E‘H²ζΖa?’"ΨßΩ]Σ›D‘\8–cQΕ8α1ΌOό9•Œqb·ΝΩfΈΐΚwiMà ۘ…ͺ ‹‡Ψ°ͺ?qS+Ζ°H–Η2-vfX#ϊΟP1ΈmZη;Υ;)XρŒΪ‚ύhMV&bΫόvQϊ'±%,{7}‚Ή―”UχŒ_DΊ^»5΄œ8ήL½^–p8·λθb―ΈŠΓ²PΙ‚ROŸ1w7n‚ώue[€‰ρ˜’Qηj±k6w§γNO—$RΔrsŒW₯;‘GI/ΜζΪ ²ώ™žeί"†!Η’ιΝν>“ε΄(βt@eE’DK3₯ΛzňNλ•P+οΦ–%–kKuΟγξ¨<ΰ?Ԉ<-1Ψ +ΦΓqΎLΪCs4y+-Ἇv‡š² ΆBτhζ8,JΰθγΩšh•π"v!M99!pF Μ¦rzΙϊqζ#7·Š@ώπŠ• +±±&RyhχvΫ"§Δζ‘’‰υ·ν#Gψdq;$ΣΉ»­‡rZX ³θΔ02+~$εΗZBα—‰Β„“ρ`•3°j°žί»νβ^γ%«wΑk]HŸZΩ~*τΡ†Πδb Ϊ‘O(‘ͺmN'εΞ3"Ψ-Κ’oiπ\ήΗ€dΝa\un³ žΐΫe-;{Df±ŽfχΤ#EΝ2r-τ;)`Υ”(gcΖκšχΫ`=›C7ηπΟbϋI€Μ2η—eTνD8jUΰ©9θ ­_ !-ψTΉh΅J& /8$^§ΎvMI”ΛΔΌ%?A­3‚β0›λ€—Λ…ξz/όΡ(ΞΘίhΕρ:7Cޛηp±*—&`,) +UQ(S}kk}¨όΤ=R?[ 8¬›%ˆ"'·ΠΓ,vΦΝkv₯ό…² šušS2€ΐ”μˆΧΈ0υmΛ9ρ$m ›κύ oŽΎ i£χΈΤΣ’Lt|0΅δFΌ[y(+‰εa;Ρ³±\GΣ»ΗO’—‘ UτqŸΝ+aΣڏYέ6=`½Θήζa M IT)J˜3Ο·ΊMYv—2νmOd=>K3aQήύcQβ/ΞΤ}Ÿ‚&BΑJπτοTTGRκ‡₯ϊ#ze₯*a=ˆE¦Š ΡRP§kΣξΦΆˆ‚ϋ– ¦VŽέΞΤ¦³DD3ξνiŠϊ§E΄"€ ESd[qNX₯EοV–kγaJhεGO)±t6H$…υΈρ’­X§n>άv…"ν½Ο|Šρ,ΖΤ‘=V©Ά)Θ9©(ΥFMΘ‘‘Ζϋ²Σ„Π ‰°“=ήLmL=ΉşwμO{h4ιYLΕηf9–a΅τ±1ΚΕ)²Mƒ[Αξ–f˜fCɘ ―ΑοGTF6ΟΪpY&5lώ&‘ΥΫ@ +― ς—\”%ϋ ό΄oν4ϋ2DΩχ¨/z³.­‘ύ6F!G ―Ώ›‘JG“„΄‰% ­ό€»`pŒ5}vIδt3Ζ‡eΎ›@)†¨φSe«N#‰τ˜φΗ~„χ{ \€$vγmΠvΦiΜ8εΔOU“ο«7ъι”Ο\Σ£Μ£… Z{άVΈ…AŒX χVγuofTΗs[εΦΕ' ͺlζ‘Ϊ$½[νjΏlω—¦ίΖX”„,I\dΣ\00&=ε^)°1ΉI¨ΉQυX)ΫιβτQ`{z 9ώΎ)‘>S2Θ$Ά΅];€)4f‡ βi…ε¦—Ό=­€’ΊΪσYi'9ZΜ@)5Δ +ia.'bbΒ~"ύF+άf}yϊ¦Λρηα™βl_Šόρ―Μ©R-ά†υ\«ΆšΡ·w+/Ή»$νUά­τή !lͺ +Etw‹Q=λIξ7ͺμΧΥqΈϊ3σ ^΅„Β>[e£sΊšΙOZ•PΉ€‡Αͺ*‘Σ΅†yΖΘFΉαξRˆTζβtJAvχΙYšHtνŠvv—TΞK­ς£:λ΄KτO»WTςs΅’α,)t΄»¬5e;μdIϊφ'~™g¦€Ο‘»ο•DμXLšϊ΄ό.Ր{ +PςΩ„‘hl’σΌUάdYΐΟ5ͺ&νk«Οz ǁŒˆ2ΓέΛηΩ©JZ–¦λΟ€‘3ŠTπT 7΅νιQ€pΉ@0«;A6ΘಡaΕΡR7ZML̏ομ˜K΅iΖ_y’O!*c+Υ„KρTΙ‘άv…”₯FNK6φCŠq£s»ό‘ Ι―ΤSΆγ±²8m#˜GŠΐZH/ :N­ω¦Ή —nΨ­6lξ°$€šͺ/k*RLΠΥdt’Τ%]f%‚€«&–ύmδ₯‘ žΞ_vzxƒφ)ΒPκ1€^oΑ9Ιβ© ’€Ι­VΝvD x¬9³)vΫƒό] c;ηi +Γ`4΅Αfq>gsœ±Νμ·©Σ­ΣπΘAQ'}^ΑHwβ!ΩCK“…3tΪ1sŠ­ͺ­Ž€4ύSͺ‘:Δ\ˆn)Ηœτζω—]›͊¬‚αJφq‡ζ­?Μp Χ΅›Φ‘Vri'vkΐmά$‘v§ΘπY&ΪLΆ{3―·9‰Œ1Q†―Ÿ„ϋ•7«τIΗlpΑ"%^/Ζ2K4Β`ΥΎΊ\ΝΓ#b­XԎƒEyI,³L}°ΈI•Ϋ΅Θ_ZԎ¨χg\Ύƒ^,φ£/Ÿj“ToœζΡ3ςY +Ύ«gౚ\ιΟ’,E\6Ϋςœ‡—!a‘sͺ0Βm‡ά^N‡Ρu‰7 Λ*‘¬€ΡεΒ€C‘ν΄ΆT€Bgœ61”G©m‡|Œ)Fy gΔΐLэ§_ɜa-•»0d}l,Ύ,Σͺ=†I ΠΒjAh'‡Χ =§ε ξ +½μ±†π5Ÿ%jNsd%J¦rτ•θ&³Lσc†ΫJι-vxοΩΤ]“ΓTψ*$Ε™Š<ψ΄e'SΔ¨8 !β°θOΥRιΟ(¦ŠWpbΔΓiΫR4GΩκ=r„· Ϋ ‡0βϋh±BΑέK€)ƒ9½^E1,ΦλŽεπn\¬*p‘•t―n’ |–…¦φΨ―μ’y±·`g4ΆΙ€Iθœξ\ωέCΪ‡Γψ’W*Q?/υ#”ΖT?Ž Žς@"hμ’7d»`cυπ’ ‰u;ΣbΪκ„QΕύn²~’γ…γf&;ΟηŠΕΓ#$ϊ jάϋLŠΙΘ wΙΑjχ:ϊ+ξθΞέ# „δ% ΐρΨάΩ7žQ,Δ"q΅΅Yh‹P6©ω‡™ω>^‡m0Ϊ½e˜ΕρωDU"Ε™φ–ͺδFj‡λ΅aaΞΕbI,w8=‘όΟR`mL§»&άi›]Ρc28Λ½D‘TΒ©ω›θΨξW«rdaiΒa²όΪ0U]{™{δ6wE2Tvo%KO”ζœ¦§πHςmΞš-ε}©lXXNe&Γπšπ‘pᴘWΥ xέzΡηΒ`Τ‚…ŒAΖ,eΖ‘ ένMγύΌ™gΨ–ZͺΨοΓF²ˆmUγ=ΑFε).RƒD€^ΠS5Φiyά8Νς‰XY«”an›[”jΐβ­™Μ&›ύ3·|^)Ά΅V{™ψzΝJĐ8δήξ7¬(ωgHΒ+ΔqT³έmΤν*Γ‰·¨,!΅l‡Χρ¬Šφρ½+““£Fζ­€ΤεSϋ½3ͺτΩ« ΒVD Ήk―³ GΖTΣ―5aΊΚž%P…?aΉ”α™ID_ΩTσ•⡨ μπW_EεΖ‚μΆΓQ›Φ­Ν$u±ŠqaΑρžΉ7•G!ήOΛξm’ Ž˜;g*`*Yφ+’‡E“ˆ xVΡ>ƒτ‰ε‡*nή‰η²ΥΑ>‘ Ϋ’³`‘2Ά—δΌΘ‘XUI%Μ3Ύ"–ƒΓ}(J§ +Uν0ά±xξΦυ£ίΦ-H…λ8δ¦έόVΡ½rΙΛέL3;ςnͺƒ•™šΖ [κΗaUgt<œVœs¬Φ3Υͺ«|Iͺ€}zpŸδ?(μrdtΚΟπ+m@VJ’…π.7Z%o|C³v" ωγΖ$e-[Νd€P€Εό#FέθρIϋ*=FHχͺΥΊ“,ΚΉ›h²,·}‘Αζ¦ΈIŸuxbλΆΪΕ‘Υ΅‘%OoN ςKijlκαγ]p‰O‹ξ’•WAd8Κρ ΈφP+|JΉ$šs–%³ ί΄9ςΑ¬›§βŠ?ϋ•₯Φ› ξάΟmƒάφŎSwW3•΅ͺι:ΞΛ=#Ι‡“ΐΊ.›¬Δ iuYpŠuΈ{Ώ$9b„ αSΣ?ψƒ’ΆŽiηΫύ§_½$†TξQq±ίΈΥ^™°*ω―WΆηΛRσ6Ÿ©{;–hυ-ο,£ Χ‡>w™.[MΌ[lτScgχΓPGE<΅šιˆKGΜ0Š>‹=’š|U^vXtυτ|)₯σ0<ΎO’ύLnώyiVZT• +7ΛΤGoΡΡ „Ω =]ΎW^% ΡkLι—j阨O:"‘“‹ήοC5—,νφœ¬„Rε/Ό?)φx‘ˆw›7\JΗXŒ@“Ž³¬svͺR·δv6Cyωί:‰4η±M€@œ΄θ,—ΛΠ<ΕhΨ.υ^ωnοrοpEU Zπhˆͺ©ΛE\€δAjIψΑ*‘d…A²L±ΓkήTT«uσπrŠΛ½w–dόΏωχ–Š—ΒˆGG;Χ’f¨ οv9’εšΠk²›cνP$Ε‘Ÿ†|λ§‘¬„Ί ‘œ`ϊ<›ΪRΈυšα…}p^ζ}Y•LΓόρFΰΣ‰!ͺzΌR@ͺ»a` lΑ;υ8αT¬?ͺΨX/'ψΪKfPίβcGσwwγEn–R•KQΥ‡ΗΑt†Œ+ω}a0‡άκŠζAxj«vΌ•Ϊoym)TΙjή}sž+ME‘˜ ψΎηΟΏwA€ŽIΘτͺRΤ‹A¨ΊωfJD%?Δ«ΐ§j:‘t―m…΄Pj»”—S2YR,+%ƒ2ΐO$Ώvο‘q5ž8ΝΒ‰άeE4/k*΅œ Ϊ1Σ΄ύΙ}¦k;,ΒBν‚djθͺ•φΓpπήπJR‹†ˆ©ΤΛϊΞΤψ(]«fˆ―›T3JΫ}h—y84 όΨ}ζuFRΟΰR`Ύy¦ŒδˆKΘΉ3Wο˜$κEΌ=FΟnD°ΧfΫΪ!Υ Biԏ+’Σ†—&²sfZ”ΩŠYkY=M―.~ΕHyŠμ3ζλ–Ÿ|χyΩnf7ƒϊ‡MχέαR’}šepΣJϋ1kύ("ξš—{τ§=Ο•ΓλΛ9»Uμ[\K²ΊˆρR•~EΠƒ=%²ͺ©‘ψ‡ZQOΣ}#Ntτˆ2+Ή‘ ½Έ§νφΜK”ο#‘ΏΫΪW’%UM,+ivUχ‘V‘¨έCΊcν4ЉmcΦ΅]ΦQΌDaKΞ²: „QΖ ‡U;l]©/ΌL=Ψγίές―QΌ]Ώ•­ˆ‹ς"έbgŸσvESŒmx=&ΡΗΜJ²¨ƒG€o띲Ζ=j£%ϋvΕμKhV•O*—34Bxx8±Z+»Χ$Ρ²Šq74­ +]0X‹:Ё³F|Z³ψ›Π gίήε/Ή<“3ΆbIΠ€ΔΆ­pθ6„σ€ΡΡξΠacΊTZψqY(,ςf•—€r^ƒXϋnςF²ΡDλΝ`ΆœξΐιŒsΆλ²΄4šUY#―§FJE9"*P©?5*Ρ½ηD–qf¨Rξ w+TCm %οGǍ΄μ‡HκΊ>L7@ΩΓ0θΛBƒ ŒtΊδfŽžYΞ1ξv+Γ(‰5r…€(΅¦-ΆJ‘Z­¦M·U)Φb³©Λœ°œΊύ—ΌZ–αPκπΟάΊyCz P!œ₯Vp†–€[β–ͺ„lG­ΌPc‘WΙ‘ΝwΝ\Šπ61G%θχΛ‘IγΘ_.I9’$v5 ±cYλξΩ[‚Κ玞D‚ξΎ$S<ΦΆH±οή‰­!Bœ?,φ+‡΅’Λ*NV;=ΝKΰζo·–)±3§υqR<ρmtέ}&Dοeœ}Yμb‡$Σq›K0°™=Ξ‘,ͺ!œυTae€kϋ½»>υ¦ζDR1²κ°Δ8Pό:m0₯υ‰ͺνNΦνΩ§:"‚‚Œ•ιžQδ|XχΦΰJa±«έCc4Ž‹6›YCΰQn‡|ί'I<ʝ5ω :†Nh“’: ©JUŸ°ηY=Ÿ¦ϊ’Ί·Cž΄άκ[―†΅…Ϋ;νΊΡμmMŠ18ŸF€zš?6YΌwOŒUε)Γͺκ,Mο”ΏPo›,ή kgN+Ν/ͺ0tϊΛ’4κ“°’zυœΛN³— £nΡ«εV9T²ΘΏ\>&N΄p’pγ²γ΄,~Δ3n~QX"jUΏx1y λΑz«Žβπ‰SuΛm±ςŸ|]6«ΪD/ѐΰέ΄ηZϊ{>¦½ξc$Υ•ΜΡνΞζ$9Υδχ€θΒmR”KEΊ· $Ξ€!ΓκΰŸ½­έ†φށ˜ΗΊ°b’ξ;ηi)3Α΄JuGΒ͘ $fX=±{΅ΚΎw΄ ±Vޚ¨™K&9]ϊ܈“œN|2έ"X2κL OΛίΉCj4 7RΊ!P}$Ό*4=ηn"Ν +N™|ω„Ϊ½κΕ,.­wΛ,WXξ¨kqε-«Ω,―,…ˆaΊ1ϊۊ-\”7Ξ³†D,cΈ |‡°+ΫΏcΎιξι£‡@'ξ#D oc$±‰³5’Ν}‘h‚=σ–Ν’›ν2 5•‰ΫqΟ#‹Aφ{g―Ms όbι¦eΦC +η²b Ϋ^>-ΡT"§¦λK}Έ4R,"][Χ6)τlμ‘ν§©Πb±ύ ΪΈοlΩV›'5 +>±Ϊ\€afbο#ΤQQΝ»TΞΓ’ƒo’„ήa+εqϊ!ξε-Fύ Q""BΥ±‚J3ώΠ› ¦{U4lKvˆOn6•O<^§ψ~7ƒξtΤ£άWς0ŸQ6•$˜aθɝθϊΫΧ‘˜£όΎ¬–OΖΔ]ΎY~>˜Ο‰zNY˜ Δ¨XƒΣΨ…(€>ΨU"—ϋΕ2E¨ΰ +©ΌmxkΌwΉΛΐϊρ€κβy”*8TΛ¬uΜ%‚\sΫvφ·mΝ./Βσc‰˜xΟ‘)·ΠͺΎΟ-€οΗUlfΡρ]’h·°QϊϋŒ*€n·mΔΊ5Ÿ6Wϊί!„4οβ₯T« +u‰[]ϊ1$DΫ·τ£Tn£Φ₯qyτc*lœΥT©Ά΄(W²I“%\Ηύρ˜Ώ -ιT{¦\φe―&]/rξΝ +κflΆ™Χž9 φˆc❇ρ(UFωΌϊ°θfL‰q7’8  °>ώ -¦–?:—™ω;’iT)φFΕ[Yb”E}Tk;BJUžX/XkΈlžBUΔU5csσ–ΠU@­„~ jΜc{Ά#v"€²Y7ΟΎŠ0šΈCwΉ7¨―»₯Ρ2,¦v)J?l" oIά”ΏY,•Sιήπεna˜xp +šltίτͺ–¦ZΐŽ“άFŽωQΪγλμ3\σ2§cuMΩς)ΆƒUyš<₯jζߏMf‰’1ZˆIŸŽΈη9LJώTGΚ³rUY””Μ£>/½JRYEš¦ΌέΘ†όˆ#ͺΡ¨6½dΣήβρ.c"›Duσ›°θχ5ΟS½'$ϊρox{˜Ίύ‡>xmοΣO;ώ΅χu“ο#‡Σ[ϊϋJ»Η`U…¦„Jn›₯[Sg²l%‹ +φ8 +αXοh'¨@‡Ν»—–ηΤB¦ΐ¦l°₯ϋ¨χΓν‘hθnα]yfxH·# 9JSβ0•9Ε%Ρg θ˜T©*’θ5‘αZρj-Ασ¨αυ›Κ…ά}†—hΨiaμΦέ’ +κp†«‹θΫ@1ρ9ll-^Q[K\U*΅(.ƒ:5φ”θΖxκ£Tcͺ‘HΡξΡΥ(Ά"_ŽOa_©NοΛS­©eEN. hfD§ό4ή~9$tόX׈2ƒΦlζ]GmV @nKzͺP}Τ¨ΧμΗλ©aτ–6iνύ™Φ£WΘ2±Έ|§šl#Ή τX…tHw‡Qτ&Ÿ`Š 2=(q²ΝET)όMΎΎ‡­,Α Οzύm»αFD_ΥYGZφNaw » ζ6G…Žα…«Ηπ(-eΝκώož¦γύ€jLέcύ˜‘.M·„IΡQ+)Ž5Y ΅ΓjΡΨ«azχ2_B£¬%π<„<ΓaIσάHCˆtI ‹bs»ϊβn‘FΧ&‰)TwZU9}”‚ ΌΦ½πIMCΝΕΑ4‰^ψR·•ψk½xLjΙ΄*†~oΥΠψa@,²ΝΠ‹g£ύ­ύόqφΟκ·Ώώρwύ_ύ»Sτ°ρo~χŸϊχ Ω^ΕMΏφUμ½υEΓXhb +M¬I>·Δ^L‘‰5e‘M .ρ›&…΅Δd)41;¦Δτi™&†‘Δ°Όib ξG‘‰513MLTΦM¬±₯όcΔ>/u₯‰5ε§ΎibmjζM¬Ρ^hbhΰΌibX+M ΛَEΓ ŒA‘‰ΙZhb²#ΡΔτQ£šX›eAƒΉ,܌“ΒΘΣΔφϋ*41Βf•&–,‰]•¬NCZθg’‰SzΡΔφ§UšWUibŸM© +LLΖ½'˜˜,&†ε ΓZabX*L ‹DΆ LΜRξ&†pT…‰%K‚‰-kΐΔψέ&F0ν 3ΕΙ ΫխȐšΨ²”G2­Ζ#‚Wyb<μ7O iŠΒ“Ε½•'&kζ‰ΙPxbбn­βΔdΌ·„ΓRqbVyπCm₯βΔφ§}αĈdΎqbm՘°‚Δ.81¦ΒNLƌΓ š­ΐ‰½&ήX­ΐ©GΜ±ΰΔ:]ε'Φ[―8±. ϊλQω7φgpbb—œXWsXΖ‰υήή81 NL–ŒΓπΖ‰a­81,'†εƒ‚^qb]’?'φ~”?ϊ£ξ”–γΔ0œ˜ŽΚ81 ί81l'†‘ΰΔ>φ7N¬ ‘–pbM† Φ$Όχ…ˆ^pb,Š'Φ@t1ρfœFΙMNL†Œkh}αΔ°i/81 '&Γ7NLu>#pb|`Ζ‰5*oΎpb !Aλ’·@n“μmΒ‰MCΖ‰-£'»Zp¦—ύ'ΖLRpb­ϋξ>pbΛ°pbΣζ81ύŽ„kT'}γΔZ?*NL†~.œ˜NϋΖ‰5΅΅'œXξ#αΔ0Όpb­·ŠkͺΏL8±eH8±i œ^pbxi/œXC,(γΔqθŒ›†Œ›Ζΐ‰5Ι£%œX;N¬)θpbZαŒkμiΎqbMαϋ„ϋ “ŠkΟxγΔ0œXc±Θ8±ΎmoœΖ‚ΓPpb]ZΖ'†­ΰΔdΘ81ΎqbM9ƒ„cR)8±Χ,+…)/œιΖ‚£ό¦ΰΔΠσyαΔ0œ˜d€2NLbAί81NL'eœ˜>φ'ΖΖ·ΰΔΨbœYΤoœΏ£ΰΔ8«ΰΔ΄/ώΖ‰υ©«ζ81Ϋ`'œ˜ ί81NLgœ˜Ύμ 'Ζ―-81ΉΰΔ¦!αΔ¦-pbμψ+N¬£ςΒ‰u­'Φι4,8±ή―7NŒΓ +NL\Ω‚€ψ…3ΆΰΔΈ '6 '6“JΖ‰υgΝ8±ήŸŠλd‰3Nl2Nl'ΦΩ‹.œ|ίN¬«+αΔϊ±Wœ˜TFΎqb2fœ˜ '֏φΖ‰a,81 'ΦU~φ…㚠+NLβŒ³1ρ…λγ(81'œΨ2$θΠ2z(»«e1αΔψφNŒ‘SpbBgœΨ4dœΨ4N¬«Γ"αΔDwώΖ‰ρ¬ N ‡~αΔζ_'6γC +N Dχ 'ΦΩτgœoCΑ‰™ΎMΕ‰I'γΔ0œXΏΪ'¦paΖ‰a(81;’βĈ:œXWgΒ‰‘SσΒ‰!¦TpbΜΠ'Ά 'ΆŒŽλ·+\Ζ2y]oš˜ ΣΔ0dš˜€tΎhbfK41”ibϊΨošλH‘‰±:šΨ2$šΨ4M¬kœib’ς{ΡΔt MLκM™&†zΣ‹&&Ω£Lγν/4±Ntμ›&¦Q¦‰±G)4±i(/vƒ&Φ)NΙ4±ΎošXίJλ[―4±pάLΓηΚ4±¦ C₯‰}v…&φρ +M 7ρ›&&[¦‰™!ΡΔΜπEΓXhb2dš˜ ί4±Ος]ib2MŒΏΏibΙ;ΣΔ +G™&Φϊω¦‰5n +šš˜Ά>ί41Œ…&f†DΣiQ2M¬‘˜ibM_‰&FΈχEcΫPhbM¬œD›†L›ΖIγΎUšX»φŸ‘‰5©ΪfšX£ΎΠΔ>τ341¬•&†₯Ě +ΏibX M C‘‰ιˆM¬I|-ΣĚΔφ3M¬Ρω’‰a-41 •&φρ―†&&k‘‰ιΜLΣgΏhbό‚Bk ΰL›†L cΠĚ֧DkχxΡΔΪΣ MŒ #ΡΔόΟB [ΠĚθη™&Φ(xΡΔΥ…&fχ-ΣΔ–%ΣΔ’Υib-jW&¦Ÿρ’‰ΙZhbX*M Λ›&†΅Δd)41Y^41¬…&Ζ₯šX»Η›&6ηΰyσQ¦‰MC‘‰-kΠΔμγ3MŒ]ξ›&Fδ΅Δ[,41B/šΒDS`1ΣΔ¦‘ΠΔ–Υhb4n¦‰@xΣΔ°Vš–JkSŽ*ΣΔ°Vš˜,…&¦3_4±φ΄/šw°Δ–%ΣΔ–5hbΌ +…&ΦλghbZ^ MŒΈL₯‰%Λ€‰-[`€š*Ρ3MŒ©οMΣ€+41ή²JkrαΏibX+ML–BΣ™/š˜¬…&Φ€IžibXή41­Δ΄BK–D[Φ ‰}FαMŒΧ›&֎λ‹&FœΈΠΔ»τM¬I{1ΣΔp2*MŒΐί‹&Ζa™&Φ6)am*–gšXkQ‹;£ΉΠΔ’%ΡΔ–5hbm&ž‚&ΖwΎhbJšQ$&ML–MLΦBΣgš˜~ζ‹&Fx½Δˆ”Λ‰ž4±dY4±d4šXS²%³Γ:Ώibς‘Bkύω’‰΅~ M λ›&ΦBDuΔδXšX²$šΨ²M¬1-41¦–7MŒεΊΔΨKTšΨ²dšΨ²MŒI»Δ…ΎhbdΑ*MŒΈQ₯‰ΊxΣĈƒUšgΎibΔO*M IΪJC]φ›&¦ώΕB3‰ L›–L›F§‰©«'ΡΔ$7όMSηb¦‰ΡXXhb―€qD’AšXNΑBλϋρEΣq…&ΦUKϊMλ4™šάJγΏib²²ζL C…‰ayΓΔτ L K‰)Nφ‚‰1v*L¬“½(01Β¬/˜ΡΊ +λgϋ‚‰u`Ή/˜ΰ #@SabD6ή01¬&¦Γ2L Γ&&k†‰)pR`bXή01ε +LΜκάL¬σ//˜˜Θ&F4©ΒΔΤ8ό “R=ΙΫ`‰Ρ„\Xb]IΨo–mΙ•%¦_TXbάζ7K ke‰a©,1Ι‘ΏXbŠ«–˜,…%&Λ‹%†΅²ΔΤ]Xbܞ7KŒΨUe‰ ‘PXbΰ3ί,1Ϊ+KLœ…ΒγήΎYbΓ*K μΒcz|³ΔΊϊΏ3KŒxΩ›%†΅²Δx“*K¬KΈπ›%†΅²Δd),1Y³d”˜2%ΖE”η½Qbύ8ΏPb]EΙ%Ζ€ψF‰ΩT™QbšN Jμ=ΗώΛ‘Δ,]π…c2Λ(±„‹@‰υk|£Δ0”†‚“α%&cF‰ΙQbΎQbΜ€%ΦLL(±.iΖ/”syA‰i!Κ(1ζφJL~F‰u•υ&”˜ ί(1Œ%¦Ώ3JLg}£ΔπS +J¬^Qb―Gφγ/8*π_ί(1¬ηu$”˜όά1J ‹X%&«ό@‰ΙΒ9Qbϊ¬σ%&Έ Δ¨)(1’—o”ξkE‰±Ϋ)(1J^τ$ J λ~l %¦˜‚Σ1Ό%&kA‰ιΆhf―CήΌm_,1Κ6*KΜΆolP‚%FτυΕ££²Δˆd–X“Φς7KŒπ{e‰΅Θ‰O–ξώ›%ΖώΉ²Δθ,,1ΕL_,1β•%Φ&ˆ8XbM$“/–˜‚…%†₯²Δdωf‰a¬,1YKΜ>θ›%Ζu–·«°Δix±ΔχT–˜βˆ™%ΦDFωb‰q^e‰ρ4*KŒθλ›%Fd‘²Δ4$2KŒŒΔ›%ΦHm–‘žΚγΓί,1FXe‰ρY•%ΦHΏXb\Ie‰)ΌTXb|η›%&kf‰ΙPXbMS|a‰΅³W–˜έ­ΜΓςf‰q‘•%Φ€qφΙ{ϐΏδͺŒ―υb‰51”Ηb‰α½–GΌXb2f–ε8ƒ%†AΙΪΜΓxom±ΔdΘ,1 ڊfU¬&ˆwb‰΅έΛ€%Φp„”πL,1 g–Ε‡ϋq–‘™K ca‰5‰ψ&–˜ κ†L,1Œ&CC‡>«C\*KsΚ 9ΔΔ#‚γu@Άj°4–™o–“^a‰Q0ZXb”¬}±ΔΘx–γΒkΪ­U–sMf‰΅g/,1ΝEί,1’&…%¦„Zb‰‘ +όf‰)ψ”Xb žΧvKŒ‡χb‰)ξ—YbMΕ°‰%FtςΕSγIb‰4-,1ΦωKŒ³ +KŒ ©°ΔYύf‰a,,1.©°Δdψf‰΅P” –˜ΆXb|ξ‹%ΦF,±¦ςb‰5υ½|±Δ4³f–Xχ:±Δšΐ8_,1ζ―ΞΫ,1ΥΧή}±ΔΝςuKLαΙΜkb \‹%Ζ5ΎXb¬…%FΪΆ°ΔΘχ~³ΔTXbœTXbx@/–—]XbMΜΥ>QbL₯ί(16·%¦ω6£ΔZΫ_(1Ω2JLi'8J¬©œϋ¨(1Œ%Ζ”†ΫZ΄WMQ%ΆKβ`Ÿ(1u}£ΔδUf”ΨςΧ±Pb_^(1νΠ3JŒpA‰±[ί¬z‘Δd” Ί3y0θJ ƒ5v'”X“βvB‰a8Œšν5γ2|‘Δt΄@‰5q°ϊB‰©+IΘ„#’QbxpR ”±”JŒ LA‰5Υ&”˜Bί(1kK(1ξlA‰5ε…ΏPbŠhΒ9J¬M‘Ρ@‰α“ΌQbJε'”X#Š”QbMjΩ_(1VŠS†­ ΔΜώB‰΅ ΣM”τ%ΖΙ%ΖΫ]Qbνz~%V­z‘―Ωάβ2*-*± +JLΦ‚kΧσ…“ε…ΓZQbMθ™ŒΓςF‰±zV”˜ύ%ΖΪύF‰ΙZPbX +J Γ %†±’Δ”M.(1,o”NEE‰a©(1|‘7J¬ ±’Pb€| +JŒB±JLV%FŽΎ’Δ:u“ΔψΚ7ILυδ…$¦›BΣΕΎHb–gΛ$1Y +ILgΎHbH:’˜κυ3I¬L%“ΔϊΡΏHbj()$1R(o’˜Ξ,$±]"‰Α~“ΔΊ +˜3I¬ΛKΛ$1%’ΏIb]˜§L£g£’Δhvx“ΔT§^Hb\D%‰Ρrπ&‰uAN2IŒIbκ°z‘Δ¬[+“Δ°T’–7I k&‰©©Δdω&‰)]Ib–ΧΚ$15l|“ΔψΩ…$Ζ»PHb€@_$±I@ž$1>¨’ΔΈ‚7IΜ¬ί$1ςκ™$Ζ ―$15Ϋ½Hb€„εHLbΌ$&ΪϋHŒq‰ι™f#χγ=( ±Q—@bLΥ/˜ͺzHŒΚΠc1Δ("* ±Ωψ $†“Q@bδY3HŒ^ 1έkΚΉ'υ‘ί ±vμ$Fτ₯€ΔΤό #YT@bŠ/dΨ+NόK‘@bͺxΔT P@bΚόg˜ /XWΗς‰1 HŒ6ΑH c‰ΙAbvΔHLŸ•Ab +H Γ $ΦΗ3AbύΈ+HŒΉφcΞ/ 1ήψ£κλcΡ/ 1κF +HŒwϋ°φνςΎgŽ˜ +D2G Γ‹#&cζˆΙ9bϊœ/Žzς…#F9[ሠZHΎ9bυ’‚c₯mΐ΅8bː`VΛΈG\ι²ζyg„I+_*‡‹#Ζ™9b\PαˆIω‹#&[ζˆΙ9b^1Œ…#6ΠIΚ±!ίϋ‹#†tαˆ!ʟ9bλοΔ›Ζΰˆ!v^8b(³+~9bg¦ %u£#6 εΞ‡10b&=ί&FŒ;―η„“>^D`ΔP§—W1b2Rd1πΐ#ΖίZRFL6ͺ€#&lϋΰΐˆaΐoΘ1†‹"8γyŒ˜Έ +ί1γŒ“;1bκ|aΔd-1,#φž=ήεΰŸ„SΔλ#Φ”O1λ6I1-“ί1%±2FL†ŒΣiί1Œ#¦hfƈ©ι#¦Π_ƈQΆP0bΤ;Ό0bθPŒ˜Ι2FL_ί13FL†ŒS5Δ7FŒΌHƈ©/.cΔZ\2FŒbŒγξŒΨλ‘ύψ Ž %+_1z@+FLΗŒ–7FLΦ‚Sδ2cĚΌbΔ’%L,k`Δψʊγ^cΔ€Q0bŠveŒΨ2dŒΨ²FL΅…#ΦGˆ±gŒ'VŒ˜g#Φ†ψƈ¬1β²#FφS\Ά`Δ΄+1%#Ύ1b2fŒ†ŠΓςƈ)pš1b2dŒ˜ρ#^\0bΔZ+Fμ=Qώ’Λ3ωβ7FŒbμŠkϋυ…£GλΓZ1bMSƈ΅Φ#&kƈιΔ‚Σ‡cΔ,ηž0bMνα#ΦDlϊƈ± 12κ#Φ&υ0cΔT©R0b²Œ˜U³|cΔd-1Y +FLίω£V¦`Δx #Ά,#f֌kr»'FŒΒΨ/Œ˜ŠwFL[#FQα #&έƒ‚S=\ƈQtςˆMρyT»Ύ0bfωˆ-c`ΔT‹R0bTωΌ1bV ˜1bxU#Ά,#–¬Žkgˆ¬iΦύƈqK+FŒθNň©Ϊθ…“΅`ΔdΙ1 oŒXSΨ3cĚš#†εSΰ)cΔ$ύV0b6DΎ1bMΚΣ#Ζέ¨±dIπ duŒ˜ +P FŒBΉ7FLm­#&Uΐ‚[–Œ[Φΐˆρ #Ζ¨~cΔ#Ζ>‘bΔ–%cΔ̚1b=TŒXS«Ϋ7FŒΪξŠkΡ01bv|aΔ$ν˜0br,1u’Ύ0bX+F Kňι˜F¬υQ1bͺΫ/±Οvεg0bLs#¦Β¬‚K–„KVι@πI#Ζ7Ύ1bΊŽŒΓP1b²Ό0bfΝ1Y +FΜ~δ7F¬I6cΔXo+F,YFlY#ΦNΘ±&αϋΪl«ηQ0b&¦›1bTν½0bΌ"#&M‚cuxcΔ΄w,1ΚA*FlYΚL0­kΟQ1bΦ<3ύ ŒC!±bΔHyΏ1b&X”1b3'\0b8€#Φ₯ؐ1b4½1bfΝ1³dŒ˜YΎ1bψΚ#&KˆιοFL©ηŒΓP1b8ζoŒ%+#֏¨χis_tώ F kňa©1mλΎ0b +,±bQα¨Ξ{aΔίŒέΦ#F˜ό#Ζ¨bΔ°TŒΨ²dŒ˜YFŒ›Z0b’ωƈ©–'cΔz#†ξς #†±`ĀΜ1b4GΏ0b3FŒΏ FL|cΔ$²’1b$Ν +FŒ*™F cΑˆa(1 /Œ˜Œ#¦Σ2FLόλΪ³&ŒΝu#&Γ7Fl51b]λΨˆIYϋ #Φ‰Ά'ŒSGňMKƈMc`ΔΨβŒ˜Τ +Ύ0b”ΟŒ˜ξPˆΕί#6mŽ#n•0b=ς #&Ϋˆυ}+16Ξί1l#¦Ώ3FL†oŒŸ\0b\\ňυύ~cΔΦΔ;C‘`Δ¦%cΔ¦10bφρ#ΦUίρ…£Œ¨`ΔoM1BΤoŒ1ΰŠSΔ΅`Δ¦%cΔ̘0bͺήΜ±Ύ_oŒΖ‚Ð1bϊϋ#†1cΔτwƈι¬oŒ.cΔϊΦ+FlFlΪ#¦4yƈuœ―oŒ˜-Ÿ #¦ΚΘ„['ŒΨ4FΧO—ζZˆ1™½0bY#ΖK_0bDyΏ1bΨ2FLgŒ˜Nϊƈɘ1b +F Γ #Ζ-Œ˜:ΈFlύ0bfL1•gfŒ˜bkί1 +) +FL‚±#ΦΥX1bRlΝ1\ƒ‚#δψˆυγ*1Ε%ΑY9LΥHί1ΒΥ…"†v@‘ˆMC¦ˆ-£SΔTύ’)bϊΆoŠ˜’γ™"†‘PΔdψ¦ˆΙ˜(bϊ˜L›…V™"FΤ·PΔT'”)bː(bΛθ±)€ΰƒd~QΔTx•)bά E¬«°ΰ‹"&γ7EŒΟJ1y|™"Ά ‰"6AλκΟΘ1f‡DSaͺQΔpυ EΜ _±i Š˜€ώ2EŒΝΑ‹"Φ³RΔ¨Β)1υ}SĈ Š˜šHΏ)b΄3ŠΡ―B£zηE#*Y(bτ‚dŠXό](bΣ1ιdŠ”oŠ˜ϊ…2Eμ³Χό’ˆ½CΔΏdϊ_(bEμB%Τh7"v)ΎΎlΛ=Ζ»QώK’Ή[Ο1ό—gί@μV‰Ήb€ΡξΚc¬nζΐ‡‰kότEΣcdx˜Θφڈ:)a¨_H3- aӐTΣ8aΒΖbQJΨ€3—aΈ+’_˜G1υgΒh8―£Β0ξν^|01HΎπ`πF[ί+Œͺ―κ5Υυ£ωHs=ΪηYΙ`MςHηƒumAlώ `a $XΒ‚ί?I_Rρz* ‘ΕUΒΈ-ΨVoψ6Ρ_[ΌIΡ!§j‡ϋ όuΐ=ψ Νί/κ)Μq&κW‹' _ΤE:lAΏhUv1KΗω;Ξ„όR+ήώEόΒί㍠+ΰ—Β©¬2Αρκ4Sμ•φ₯0{KFTG%©ŒυuIΉΈΤΆΟ–e’Ύ€`s· ϊϊžc•² +$ήξGΓ$sΎτ0tίƒσ₯,υ³?“σ₯Qδπ4w«KήζΛ†Zο σecΈ=σΕPίξν\˜/{#ŽΎ0_Jn½UΜ—šνΆηY˜/ͺNΪΰ +σ%Ω(+TO˜/₯7ωΚ |i8½-Κ‰°£΅ω’ιyBΎdΡ{”/,Ÿ»vVΚΦΟ9ε Kγ\”/Ϋ U}$ΚIοΟ΅ί‹ς΅Kη\―χsό1ž3niWωΧ‚|aΫφLΘ—Ž.Ο!_Lω’άχsέ“ςe"AΧ>)_jQ=ž£pΎv±ΛζkWΰX/œ6½Œ™σEΜG ·‘€>Ψs:εK ¬ ς…θΨƒ ”3Ύ$BfH/mnQx¨+Jˆ/ž7QK'|)OΫ_rοXΘ9€²ό Œγ½HӝΗ5ι^§Ϊm― χBΧogBuΆ—DtΆswβοLφš6O?Ι1GΛ‰]W·… c½x?χλš6iŸη„zΝΏΣ+LŽτββyςτ’Pˆ΄U&zκtθΕίݎQ³ηp₯ηuͺΩσ™¨*Α6ΞΙς’ί(£ΌτΚ r’zLϋ>&Θkώ8^a Œ»ΏA Χω\—DŠZxΡvŒ{Ϊ Ηa „Wό ^a €½Δϋh“ί…fΒP]ρβw©”ΰ‹γ»φΆnΙC˜αiήE`uίcωž[m•tΤΌKŠœLΧή₯$Α&Δ»½χZθ64ήΕ2ӟΎxΖ‘‘+X`ψxiΟ„wν’vΌWΠ»0ή,ƒAο’α0(ΊΊe@π-Ι_ξŠΤ}Β»˜)nxΐ»^³W,_”ƒœLEήE’oyΈ4(•.5}ο(ίΥΟvxΖΟtOx—twxΆο’:Ο­Ϋο’Ρη:kΒη΄fΣ£ςτΑ£οίŎσγ€<ίΕήφήΤ?jψ.²—§By‰ίΥΤ]xΙο’„δsάιΏK;Ωλ3„ƒίe[ΫIοŸψ™ή%#ΦΐwΙΐ–!π]ϊΝ_οβΧjψ..ωγ΅‰οš†„οšΆΐw±ΥΎευ–‹d©m*2Ύ‹€π!/sGzi‹ήEνΣηBφBοβ¨q>-θ]ΒΈj*—€Ώ—Ϊ$½k·nΛ{YΉ ΪI½k2½kƒή%υšέ‚Λ΅› κ^θ]ˆœ}V­gEjτc»¦!Σ»–Ρι]*ƒPί—“ΉHeά›^ψ]\ΒΉ=‹ς΅‹!w“ί%iΝC‰ί%£–$ηwΙ°εKyœ]2nν*ό.ŒΪΏ CcΛω]4Mg~—4Y›!+ΕοςχξΧDsΩ 8žΒο’μψ3'λ(…―1^ː8?ΛθAdy±†¬³Ι m%κ3Ώ‹±sςzΟ£žf{¬ΰwMCζwMcπ»Δΐ‰ 2—<άvΒοβiγ!ΜƒxγΊ ί5Κψi |Ÿ‘»`.Պ` }mΔ %£k? ᝇŠΌΰr! £ΠJ‚wI›w£1stΨ xΧ2$xΧ2:Ό«)ΝΘ‚ιλ$_v΅½z—@!I§wa8=2z—ΤkpQ3ΎΛŒΤ9ΎKg!Uψ.ϋe,* ίΕ:"%π]¬ςQί΅ ί5οjΪΞ~ξϊŒLK= +ž‚ο8?L«“.IΈ7‘bΙΎ|—€†n&FΗwρςoΟgQ +0 }rΖwiΟσΉΨu}Ν5Œ΄ Cy­Γψ.Uε©³ΡEQwΑωϊ„οR 3Gΰ»viњȼπ]»ΑhGΑw)N€χμh.ΙwlύΜψ.ιπ–Δ1)j«hΠ’ψ(4έ2½ οlΐ»τ7sΊΏ1ϊ{τ‚ξ"}ΌΛ wρ7Ώ;ΐ]ό½Sn‘Έ]>οœΨ.τυδ=΅ mVξA‚viφΙμ’Ζ‹3ΩuϊN5»”‹ΨEΒhοc»ΨΤ0j2―λtΗ&p]ϊ{»'­λ”$p+°.­Η1&«‹EοlηDuIGκ³δfRΊW›œ.Ah>7"0]ρw¦t…mBΊ€O«°¬3ΊD*ΪΊθβΉk‹;]xΗ#XŽ#ΊΠ€Π»X]X›‹Ρ% +cΡ΅«¨ή+k§N7ΦγΈφ‰θ’ΘWζ„. U¬LθRΒΠ+ζ„.I[$,B—*DŽ6*‘kWƒ)±@ta±˜P Ί(AR « ΊdUΰ1]:σbŠuD—>\ΎcFtρl&vDΧC@'#]Ӑ]a DΧEθΎ&~KΊ]lρ2£KΪ/Δ‚ηQ]…&Η,R™†κZΦ@uν"‹ο‹ΐΕε?Εb·…yLκfS̈Ϋwο‹Τ΅,™Τ•¬NκΪ­χ²ΒpibS9©k&¨kš°CΟδΰκΏΕ£ΌΊr9 Σ₯Ρ¦τά<Ž +Ά{_”.½’Η³WJΦΟ―Ϊ₯K–ΓΉ]ΣΥ™š3₯Λ^ρσY”.,§Ό© tIͺθ ’WPΊΈ4?Σ)]Τ‹Z¦)(]Ι’(]Λ”.t«l ϊΦγα™ιbΏνι(κ§orDŠ„ΈDε3‘‹\e"ΠuEZ$ψ\ˆΆœΚ7,<—δ +kxŸλΊΜeΨ-Σ•Ξ%‘Αγ^F鞠MleHhi 2Ω…αIΞn²³γ9-‘]δe5Ή•‹rήm»~˜Pσ4?¨0Ή0κ&’KH 5:‘K%ΗΉΚ±ρηΌϊ“ΗEΩάξM‚J-Γ’q-›ΑΈ”Y„-Ί+ӟς±6›—§QΐζΔΰΊv+Α…ΰRδ™ΐ₯ςΩέ^;Ε N%ƒΞΕίZ†„ίšΖ oQΜ―7'ͺ%i7ž«φ0‘νΈƒλΈ™ϋ€o-K†o-kΐ·.C³nΐ·Q~c|KΉa…ΆΎEΨ§ο}±·$ŒVΩ[š>47{‹ωw™½Eμ£7/7ΉΊ›Κ›+±ΆΔ"Yθ[Ν6›ω8ικμϋ’oMK¦oM£Σ·Τ Γςΰτ-)τrI™Ύ₯†Ώ½€¨%Q‹³τ­WΔ7BΑ }k·»Qι[ϋˆ _Π·t\W§œΣ·€Xͺ’ώLίθ»Τqετ-¦ΠS^yΠ·ΈοV’ι[²*Wψ-΅Δ“z˜ψ-,Mσ]Ζoι9jͺ ό–ρ83M’±Ά6*~‹αc N§oA·Pi·΄8ΙύΝψ-‚mŸAcӊj₯hœoΓ) ΒoΑšϊΌ,WΕoΑνz ΏEˆEAΒ‰ί"2‘OΑoaUΎ+π[:μvτ…4/©ΝU=γ·dέcρ·ωΈύ“‚Β’¨oαo)  6ψ[V!vν“ΏΥΨΧ°Σ.ό-ΡXΧΏEc’·ΈπGqΣ@o™hΕή+zK2JΆzK ž9zK–ΣγkO/)s‘·Έ«6 φ'ZέDfoΡ^ψhL{KεZƒ½₯YC Ϋ„ή²yr,ς–¦R›*œΌυž„cώώεΘ[θίΞBήb0]Цyk<[δ­ΆyΊ-‘·š)О½…αΩ 0 &Ί'Lfno–o’·μ s‚·ψ[Lή$Κ ςΟD΅€Aή²‚šϋ,δ-ζqΕs‚Ό₯EˆΨz·v).™Tίρ¦@Q“·vuΪZαΉ€ eψΌ…Ό₯ͺ­«½%Γcί&τ–N#‘Ρ[Έ)·@oqΥrΞ τzf?ώ‚Γ‚(%‰ŒBήBτ’±KΙ©€G‚ΏΞέ"Ψy_wΕn‡;£AέΒ ΊΚ€n©4θz*s οW±ΐ@n±lG΄‹·„GΫFn)‰΄΅ΕΫBNInœγΆN©SJΫ’6θσ,Ψ–ήQd©|ΝήΟJΪ:w_η΄u +Χp,ΠΦ‰¨εsWΞ-—O%φΓΨ…‰Φθ”-]κ~TΚ:μςώ²…>Ά3ΞΨ"*Ά)'‘[’¦ΦUckΜυdlαΥγV%Ζ–d»΅bcK‘JmΖ‚±₯ §*¬2cK¨Σ‹ΠΔΨΪ…ηmηbl`*,̐-…ž§/Θ‹™dKfΚ–ΪΉ&KtovάgέθAΩ²OΪZ₯lIΙ¬‹Tξ˜-ξ˜RdΩR¨@1[ͺ~Ϊ%Μ–‚€ΪO:fKCW[Η„Ω’ΆJh²Εσ°ϊΆ l=o°3d BJ^&cλoθϊ![΄ΈΫf>Άδƒ¨Ψ[OχΚΠΰk=>―Ό k?Η’kα§D΅¦ΚdIαnjNl­­Š§-΄ΦcΓkQ€©ŠΒΜΥz"žβX-ώΗXT-•h*΄°ZV¦yNͺ–n»$σŽW1Ό(}ΆˆέžS™H­ žEθπί–ž)ί/ΉΨυaYΙ<-Q„i£υζ*Ι;L‹:1―v›Dl@GiQ_&ΕL'iьu™Ξδœ‘Ψ¬³*>W‹P`΄ˆmΘO&Q(±«ο}B΄B)ΛZψ3τ²e„•Έδ’›†Eο(±Dy NaM~Υ¦\˜Σ³$\{=žΕίO{ +;λΔ1Ήο‰Ξ:ιΫ'9K½Fg+ΰ,{ΗώLn’i›ϊp­Ε‡Μι&EΌ…Ν’@w“bŒ2H‚ό›₯NτFiΙJ§“~Π+ά,Β·7΅XΑΝRY2uœœ%j»gνκρ»ŽIΞ2Ή|Z¨9K‰1BVAΞRžλPS§Pψd29‹˜Ρ-­eΣύe&ΪΞ#ΘY(ώLœuΊ«ά,΅q# λΨ,6}Ttdj=TY:4λΩ¬δ$˜Yχmυ‘™Eˆ…© ˆY7½eΫ5YΒ>½π²ΘA’κ Σ1 eΠ²Η£ Λ’lΚώLV–Ξ1Ν~±²ξΝFGFejyLRΦ-₯ΰd!‡ΟV=c²n―Z J–€ΞΦj’fB_>W–Y yQ‘E©κ 2Λ΅­h-6Υέΰc7|ŒΚ&WΣΛΏ&λnVξ•αXlDYπƒE"KΟ<ΨXΚ>1ϊ2KωvNΠ±8Ν*œŽuŸ–ιΛp¬«Ω†2ΨX†=&kψŽ6‘±F”š:KŒͺή'λπ‹Λ`,lμV‚‹Είηή&λPOQ/T¬CcB±¬±3&Κ}~Jl:Pg)"@yβΌΔj5Μ<,€γ}Lƒ—6iX}·to†au6 ‹ ”DJ °Xz» + =ΒκH½lΧδ`‘7š1X&`4!XˆE#‰ ,ύέ +‹3h· VΧ6nLώ9ΞC€…Ώ’ΈFβƒNΏb58F‚_©Ί(£―|άχ=ΙWΣ/ πϊR›΅σNξ•:I½’jžΥ6 WšωΫ(Μ+A˜Εpδ•ιaŽEΌbgoιΨΌRb\3'^Ι] !ˆWς€τ&$β•r’Ϋυ,β•²ULD“xeώθψB^  v΄EΌƒF αLΌRb\9Ν ^ρʚγΔ«}χ•――ͺ•ΧΤ,η^νQ»T€W²*Fΐ+YΫ ΰ•|2₯χ2πJ> ΠΌΪUμι'|uoνΙΐ+½‘pK―”5ΧΞ$€W*Qx0―dUiE―°¨x'€W>χι(ΐ+! T3ΐ+εdGβ]aΈ¬σ&ρpΊ6Α»ΒbρœΘΨΰDά—ˆ ‰w₯Cλ4ή•ΖŠΞ»’δsΏxWΎ8οJ²tJlοJ?νχ2οJ»–¨­ΡK—bρΞ»’δχΉο»ςv1Nz[Ό+Y―ΰ•ΞT(-―°*:2‘WX΄δςŠ?Ou„eδQηKbΌREiί@^!Χ¨2Λ‚ΌΒκ…uޚΏ‹γEŠOH­v|―0².Oΰ•n’βΌ’e;―ΌΆ[yk^±=»›zaxeΩΰ±gΰ•ŠνσZΐ+%'Tmΐ+₯ς5t3πjWΐ»Ό’:’’ΘΌΰε ’-―$|ΘN0€W˜(Rΐ+ T*.’W’³΅;νGt˜πŠ74G"^Il +nœxΕοžϋ8)ŸΊnΥt-βFuILβ•YΖ^•σ&πJV½₯Ό’ϊ–ΒΌΒb) ΌΪM ¨-ΰ•Ί’―ώ,ΰ―¨}V^©ΰQ³w―tοNΰ•u +•€W +[*Ρ€W*R·ͺŸ'Š[pMP'€WΜ*D ΰ•ΤyUKθΐ+Εβ˜ξ3πJ{ Ϊ0x΅G[H―v“ž*Ό+M8χ=qWΌ›¬A»RsΚc2νJΦΣ£-vOPΦ8Άcρ°tMx₯6„ΗΟ΄•J)έη\ΐ+YβΣ§ξ Q«‹e(ˆWx6ΒΓAΌR’Ž'š‰W›6‡_MMjŽAΓ(ˆW$§,+—‰Wl^€" nΣ–έ―IΌ–ZsH&^‘9³Έ ^ιΦ~e― –ΊυJΌ2κΩρJsϋ ^ρ•§β"™x₯"l½vAΌRSŠ ^CϋΉ*ρJi"UρΚG{_Δ+©Ψe&^‘'Rœ'ˆWͺqg”ρJEΟΌ™x΅ί‘ β•΅`¨¬Ρ‰W€.¬f#―t¦KAΌ’,€ζ~'^yΌΧ„ϊ&ρŠλ0Ώ$ˆWM^Ϊ=ρJΉ[ ֌Ό"ΫΥTξΘ+e΅ΨςJΩCW ž­Z*ν~¦D<^sϋάΔ+Tφ΄3ρͺifπD“B­άhUΝ9ρJMIΚ>fβ•υ7Y§±Δ 0˜?pΜAχΔ%ΰV‹ΠπJm;stΰ•,·Γ΄&ρJ bE€ye %­<ŽΌR—ƒ½„Όβww…lƒy₯Lρ㬬αYbσ+2τΚX½ZSzΕGΙΑ ζ—`szf^™υ‡BΌjVnzώ0™W sΫ<σJj—„σŠT¬9G½’t¬ζ« ^‰KN`)c―ΘΝͺa?ΈWz²tΥχJ Zo2χΚΥ6χΙ½Rΰ$ΈWΜΩZΧK]εΥΌμέΈW’λ'ά+Φtρ}φŠmΖΕφj{{₯’"܁½’{OD,ΈW»:;¬ Υ!Υt©]8χ +gOρΖΰ^vd&HΨ«{ΈΗκα†+ζ"‡^ —vδΣψ’AΌ"tΐKοΌ«ο0ξ/"ώgΐ])ήc5qWΚΏk0‡UΩv½dŽ»’αςΧϊ¬ώήΟ:Ό+†ŸŠƒw₯κmξSΊOο[‚w%•ςΑ»²#VxWϊ,6ˆΑ»Β €hπvυK΄QxWϋmυ§x¨E&pWL΄Κ˜eάΎ|‡ΐ]ρ²«˜2ϊr)³RαZΖ]±βKw#pWTjθfξŠwϊπvης’kαsή•Š2Nƒ%)G…A5q™w%£JΑœw%iœΰ]ιs˜@2π +εσ‹ A―Z³Κ§ Y5Ε‰νmΌ+ΙOeήUΣ. ρ–!Q—–ΡyWOΌ+‰Ίρ˜₯˜3Ω-ΚΌ+ι +jNΌ+Ω( ή• ,—Α»Β Ε>σš4Ο­YQ…ͺCœΰΰ]a`EΙΈ«&9ΈsZwΗέiWλοD»šΖ ]5epφ »B?ό»’„ψ‚]‘χ]`WΣPn{veι vΥ$QaW’iΟ°+4Τ_°+3μJ†»βοoΨ•lv%q »Βπ »b¬ΨKιΝΰXIύŸ§—aW¬Β +=Μ£ΆΝۏv₯v;m%2νJΦΓIV_ Λ¨πQΠή“ηί»ό“hW +w13νJ~?ΑŸ ]± UΨ-hWZ΅QΚK¨qϊ1iW2(%λ΄+¦0S’]a΄0’ΡΙΌ¬ϋ&ΥʐhW–‹5ΉK‹¬l·Ι΄νjWαVο…vΕΆ[ϋ« ])ΚͺΊ§]©‹Šμo¦]ɈW΄+ΛoY¨g³δj†]©}¦΅`]©ΏζσOΊRUœŒΊbσ­ …£Έυζτ8κκυΔ~ό%ωEλ„H¨+σ•#8κJΗιΙκ +ˍRF]ΙͺJ›@])hΩGb]a±8lf]±k²Έn°π|»ͺ@ƒaE”Σk ήXͺ=3±TώΩ½²U%7ψώΚ9Φ•¬T +֍²ΙΊΒ’ΚΓΒΊRO΅<š`]iΓ)U¬`]ΙrάWe]iCrΪ`]©lΥΙΊb "€ΒΊΪ₯Ιζ.XWΤ¨ § u5 ™t΅ŒžHW›»Β’°Μc[ΥΊbΓy]ΑΪΐͺ*ΉΝΆ šιυ·Υ.¬Kƒre?g3ω(›·θπΘ”+YUΐ”+YΙ +Κ»φLΉ­ GX™6Ζζ1\§\I†ϊ1εͺι=Lλj· ΗιU_AΉJ–TΠ°¬AΉβ+φK“_ōΆώ—ΜΉ’^‚‚ρσ8Β\·Ίs΅ ™s΅¬ΑΉR!Ÿϊ8t%βΓ Π•UV¦%¦ϋ£˜™gά1ΆhΦz–AW»Ένv7Τ £Έ‚―ΊΪ΅ΟΪ¬οf‚ŽUαQ€΄γRΐ7@WΚB¨Ο>“dέc₯"5Γέ.–hύUτX·zB])dͺΨ@°dŽΝ.ݎΩΞ +μJπe‚v₯ΦΣΟσ¬Ϋ{ό%—η%Šv5Ψˆά uu„YΧL* «γτv»ΰ\ΙiΊΪsuD_h¦\I=Δ§e|-Ξ:}*Ωγ‰ΏΜΈRϊ|·₯‚ξs’ϊzμAΈKθΪ+ΰJΪJ*/tΎ}IQ[&Ό•`|›§ ’ςˆ}Ώ)D:ά +ΓεΜ*ΕΫΨMfnξ1ͺe&ΘV;KŠξ|YΣ'ΧJκ‹› q­ŽΝ +v&Φj2ΥJΖk,¨igD#V]†œH+ͺjŽšE• Χ9VΟγŠh… €$PCύryrͺξέ‚f­ωaCΧΰpψΦαθ†hμU˜cEΑˆReA±Ίο(MϋhUŽk1¬δUWD0¬–%3¬’ΥVΟύ‚ަβ&Y}"X‰Dπ$¬Υ­Ξ}ρ«¨ύΡ,–θUw„©^u‡xHΐ« Μ?Ζ‡šθ*H¬—sr:–yvp! +εd3·JAδnclΥ}FŠάU¬ιZE Ί%ܝY…&Ώ²΄¬Z†Δ©YFVšΆοͺΛτξ—qU‚¬φtRwΎΪK€)ώΞ€ͺ°§κ6ύ™IŸ’Θω­BͺίΧ…χήΊR΅,ReV\Ά€TΩfIΉr‡O‘ +‘Ύ Μ¨’ΚxdcTΚOBΥιZ?P…0‘XTI ά…-₯+.ξΑΣ*ž +φšΝƒNEν—Ύ,ΰTa«KbS‘Gl*ͺΫ¦4¬zD™LuΈ€Θ4έ[|ƒK΅ K΅Œ’R5‘TR›έ "5™T\€ή‘`RQδκ’BRaΏœ‰T2ή¦8ͺνqϋL<*ύ²έ* 'ŽJ5 ZΈœF5†ι―MΥ2$Υ4ŠJ{}yλήSŠv•υ ₯ΦS%αΟθP½“z•Rƒ¨Ψ°Ψ +˜@T°ŠUΏ *ќχΎψR4Ω' •φuR7+I|―οp Υ²δΧ{YCΕK3K$ ±φp½X‰CeB8ύ^*•ό΄E‘’~φα +ƒ“BeΊ;. ΡΞΘΤ•rGz[ζa§Κγ―E‘’Aζ9χQ)Tfνa—wτE‘2Λ–;*M\:jR¨d±ϋι*Y¬"q¨”fzw •Z4q†J­ϊ­B¨τzΘ •šu^@¨€Κe2 B΅K5ΓΕ+D\ΐrͺϋ5 TΪri„% +•4οt³ƒBU,κΦ‰Gτ…Š§i&8…ŠA%‘RK΅φ” B₯V=³€Pa±νZ@¨–%C¨ΜzέB%έήϋ€PI(C +k B₯κš—½7Ι™₯I,·ςV@˜v֌cZ£Ϊ@’ΐβΌΏόQU1 H⑘ƒΕn˜ωηn6άΣξΙ *§7˜ƒŠ±UοοΞ ’Θ–>TxwΓKΩβ_#z»‚Jš59ƒŠwM{‹`PqEƒ +ϋ呃AU8ό“A₯*ΑΞ ’He]0¨°ψVYO0¨hσΧΈ3¨Ν†g£tQ(ΚηΊΕαZ=i*&>TμSh χoΝ;‚j5T…Ωͺ]Κ–Ηό·eϚWΔω1*ΌkxΫψ@‚²¨¦*-%ˆ‘\Š–}νΧw.Ίjσ(3G“A5…B΅D§PL9Ÿsr¨JΔυ7VAN’²είΩƒDΕzρ.;ˆJ_¨J™ *ώ­xβ’σvˆΚ2Ηη΅SZŠΩŽv'QΝΑw¦vNκ΄D5•D5ΕQΩΗχI’bέJQΡY§ΐ\ˆ +}žQ)zl{·DЧ&@T„C)δŠ]ΛTv•‰V„―3U•ΪfˆΚKOM *ž08p•||DΕΏ•šΪAT8j08‰ +A“w¨hezŒg5ITΊsμ֝D₯λΦ,fKž'ώ½q¨B + •Eγ³ϋ §υ•G†Šω“H`₯jΕ‡DšDΦΏ7 Υ£uF±<Χ0ε-WΒPρX©΅y₯b +Ε CUΜo$•Œ;e’a ·Α‘β,H΄‡ +±:eκ'•ΓνTΖΈθ5q¨τ•μ4q¨θg†TaͺυοCebί,D‰\0Eδ‹έ Ce­„χ:θξΦ’*­Ά©:Ϋ1TΚN&0TΦΪ­ŒŸc¨daΆc¨tγ’c¨jM„)j„δ΅s¨JfžG/© Υv՝CEEŠ +c‚CΕ_{2†Š€΅6ف‘ͺΠζŸgb¨”ΗΩ1TˆΊJΑ‘βsΜQ䌐2ΥO;† +-†ŠΪΕεC΅„ C΅DΗPΥΘν`JQΰ$Ψ*ιΆa7D…ΓIΠ†JνκΦβΆa¨΅;Ω1Tϊ,ό¨DΕͺOζ«Ξ‘šή0T‘…J»ΛΓS‘2ǜG•U?XΨylΟ*Lxj‚PM1 TΈΨΡoξ`8—uϊL} + +V„J]ϋ΄ΐ;ƒJ+ίΗΪ„&‚κι6́J —κ‰ΫψSξeBψ©ΫΚm+υ[> +Dξμ)‘ΗΒQi—‚- “§βί‰<5Ε O΅i·ζΰ©ξnψ‰;₯œκVWŽξ{¨ακΤ'Tϋ7γΐ:υ?κΊδb.ΞΩΔNI…Μ6U)μœΰ‘))%e”ΓŽ ψT?ˆŸi,θ²έΥάφT{7{sήO;Ž…Ÿκ­šYg•‘ Θ»κͺά€ν˜nΈV/”δΣ†D―O§ΜζΆƒ@PuLT.?&T½zυcF7~‡sΝκT»’™—FΟ{,UWN­c\“ΠlΜQZ.θ*‰bͺNfρyΔƒ0ͺ¦ +•uˆKIœˆ†\}CF‚£*†6oγQ©ύδ2˜ž©dΡd‡9ͺX^VΚF€*†VΡi»ζΑ ΄0&•J^›}VπE±V―°Ίm Ÿ―4 Φ6Z­ +΅X-Χκζ,wτHΔ1Ϊvh`”tΛRjY€€MνΞϊU~BΑ0!/±qŸ²πƒΟ§mRΝΦλ(ΰŸ|R5:UΣfΆ­ +ΕΓΒ•Ÿ₯Η³π{ G‹-Λc)…ˆ,Jψ©J₯XF*Y>)[4ά4vΎrΒ‡οϊnΧΝΜu8¦ŠύωiίΦ@UKͺjͺκR‘y ~8™©F;ƒ@©TΛ‚<»²ΥόώΦq κϊma—°ί‘Υ―όn[wΡ,ΊΥδt„‡ +A΄«Ώ €@†βŒΖΐX‘‰w<‚½z§5o€*?(­:ΘjΜ«εΫŽ«V¦uΚJΚοkŸvftŠ6•Oͺώ1Η»FΞ +8Ψα4+ΠδΊ΅‘pζMZο\j§X_₯oš“» ŽΗ +.ƒͺŒ!sœvœ} vK)yψ©ΠͺΊ"φlEΆκκuΰv¨lQQ|±Ϊέ?iE†ŠΥ₯ œ4…ύΫd-`ι—αŠ€ΥC/εQ‘œ”‰ΆϊdΧ]*]„RͺœΈPt’D₯δΜ@[υ§ψϋ₯'QΝa55Ι7χυν²Α8θ½}ΪͺγD₯‡^uۍΐ·*lxΑU°?Ωjœ Έβ)φ)]eόI&Š™N|Q―’Ζη`[ImB¬Š“L{ ³(v‘•(|Œτ=“S] +s·δSΏUczι—ψ{+α·Ί«ΧͺOΖ’[IνGρ +…d8ξŽ +ν­₯Twγš|+‰fφ«RΉ wΜΣ•ςIε|Ό°Ζ7(]ζ5MΈB\u9ιQΤӍ^Υ΅Y°Ί•ΎWΏχΥ’θλ8ŠGj0HδτπΘ8λςΊ¦ E~芢ΐvΫR¬S> MΙǚ=gy³­ƒeΝ±ΰ—ΒδŠB—²”ζ•ιSΥ„:HœœD_ΪΣΜυM)< Ώ«n0ήΒΧσ…†ŒhΚeυLu;4ΎRœ~ΐ +b*Χβ_-UKeΈΊ8ΫΌn₯ZŒšk¦bSΎ₯*9]Ηι#nϋ,†έ₯ˆ·Sc6ΕAu8? ;Έnνr]ΫΚητξ²Tv­^5ό©!₯]v-eœΙ—WAal₯₯B ͺ xn§†ŒV₯κλ7:oϋτPnzλθΑΑ§A1s@c’O₯ΦΕΘΪΤΗ:Tτ¨_”·¨ξ–ύΜ±)ΆψS$ΓΝ@νΈ +eBŸu[cΩRΚ½xY›:Œ˜ΥqΗ ς0fVWΧ`·φ• Ν‰dσt˜] EœZΫ/Y; ύŽΥ` ³ΊΊŸ„WΧ!PΠU†Q‡Ρ“tydaτ¨/τ,©V§l•–iπ―ΊT»θς” Ψ„ΊG€š9buŸA)'F¨RxŠ•eP­9$OϊHΌ™}±Έν°›Ρ‘žΦ„ˆ‚ "«Ywι4 p/k—Ρ€δEΓ(4ί‘2¦ΛA«ωmᐉΪυ3iΌΠςηwΣύ±:F*w%ι—)³‘RjΑω…ρBOV$έj Ά7ΝFθ ΤB΅‘•• ηA7”Ε˜|οψμξ–‰“¨5θdΑΐς΄lΩ ”J4λ2¦ΦPaJǞΝΤN?‰ς"L5 θDœΙηΘ4o΅—Ά-¬–TάΛθ/Τ“…Rλ/€A…΅ϊƒ­…Κ#ι6G­ϋ[<ό£Ξγ0ΗΝ kι§Ϋώ*Ώ!‡•(₯Κt§BΫΥ5€‰ͺͺR{έP‰ «0%'αΚ€‡±*Ξdξϋq¦_rΗΈ,–κͺsaˆρΚ*B†ŠΎdtώžΥg$εμy·_­VG–2:&œ³€Rή‘—Δ_―Ηz ,²}Ω™ψϊK ±A³=‘εΫ₯¬¨ u:'Π­ίέ­~*φFίΆ“έŽ{μ暯³‹©°ΟΑUη–hψό-γΜ‚˜IXσͺΕ,5' ‹o’· •Nk`ψY6\6ε5§Δfe¬…9ο*ζ]ΜΚ‘ΟΆou-J—f&ΦEΊ>`Ί4χ².‚ЧπώRΤU M-ζ’0Ψ«SΖcfšR‰b„0οΘ© +Š8ͺQ8ϊΈχΈ’?­Zd«ΐΐςεΣψνYv0Žη°zv +C<><”έ86δ‘jEΤEO™m©§²KUδŸΐ n•²uξπΡUF¦ΐ¦ˆIμκW·έ\…D ν2εΔͺ«ο՘]] e,¬[[ЎΗΪiγ–¦όN¬D%ϊ.ό;«ΛΓί₯8 +# ~ΐe3­ͺχΥ±θ.D†SDE7ͺΧ«™Cι‘ΈIΎTZΠͺβΉdς(Γ:\α*JQ”‰ρκ‚-=š~ΕU­‰”Σ–χΥ|εωΕΕQωΥ±yHHοlc[Π|Аm!WπνyUEΕΎ»ΑήΆ‘π{STqΔ&Ξ~α^ƒλ%Υ–VΚ™τΛΞδMͺΨAUS¨[£χ0μtΊp[J›Tϊ²ΩVΚ?BŽΩ,AΥͺt›Q½Αψ†κl=*τ·t}κCT³‡ΦΆ›r/ΐRUϊ’Ό£ΝΎ·cΪ{»}z „8ώfsŒ‹’mv&Ά+Ϊ΄iˆεQη₯έq.Ϊ—ΤjaωΣ"―R(KCaο Ρ_6Ξ Ÿ"©Cα ϋΌΒaΜͺMp+mŠαž”†0ퟺZͺZQ$ΊΆJ”Swσψ};ω¦Lά—TΥ”›Ψμ0–ώR }uq]X'γxώ„;¨“K΅ΛΙΈΨqά#}6λX Aϋ/`\―6ΏŸΤˆΘΦΫ—SPΣuD§§H†«RMoΪω«΄BΕcˆM°ΝΧAt}u>ΈS G«ΗΏυ?QFΪuΩzS;801ϊŽ8RtυΠΤ5»(N1ڎ;,˜Vε£mΆ©Sι‹υ΅T1΅{λκ‘eέ›F›ΖΓ6nΊ.³υ υΦT±²6«,‘ZŠ₯(ΐ,o{”ΘH΅ρρrA‚ΠW1Ψ +Ko•“΅Kͺ-«q@*F5™κ8έ Ϋ.‡b[ Τσ8WΉ„–wKαEˆwͺ·Oφxv»•Œiϋ]N‚θ}υ(¦l%σ8EM‰_SυζAMΫWΚe"¬)όύηΔ”₯μΏHR1ςC!ΐŽX1Εrƒ½,πͺή₯X₯K9΅:³ΤΥ°Ώy=όξΊΐ_}qζažK]B2xν΄\ςRΤ_Tη j9Νu»ΛyR“ς·,ύ‰#œ4»ΆέžΈuœ|ͺτΠόQπΧPάΏ..TΟό^–ΐλΕsHJ»Y―[ώ) ό―Ϊ…ΣΐΞ$ŸwΈρΌBνΏ±εYŠ…F{<°ΆΗΛΨΫόˆ₯œΛKC””Σߊώ7»:“¦lΑ#w©ΰΐτχoQ-ΕΆ)Η4,_b± +ΓF&ι\ €_ +™gΕΎ«7€lǝV endstream endobj 20 0 obj <>stream + Ο·*]s…νƒ Φ­γωYκαŸgΩň˜°δΤπךC΄7₯-hΤRΗa%μ]1]^±ί$a% κ”EΐTbήΆTώ<ξŽΚŠώ—i)1ŒΨ$ͺͺ'•γΣ έ£αJk2ˆ+t<“¦Ÿ0”jA`…«πΏΤ@K2O±‘ί‚Τ—<SŽ‘ΌͺGMωhQXUOˆ°Ae½κ9΄AWΤt@gΎmž#q;Z‡δΆνgZφcK™5OeŒE[*ΊΏ=6­H·ε#jύ>›‚y1 ¬›Ί!Ή)μTΤβ°ε¬ζo8;έ)'Œm€²"°Πˆ”±Η)₯β"ΐqŠ„K‘E +y<”Ή7x.‹ύ5RNΊ°r³υόmΘΊψŒΈΊˆ“†Ϊ«]ZEUΟ»<έ\Ά₯TŒΆμ˜ρA™Ηcνήνy”Ωϊa +w" +苦gθwυ… +φ₯[˜Λ0ƒz{­ΰ‘/N˜’ƒ₯VS)mJΟtΩη·jœ°‘DE˜€ƒ¦8t³·SσώΕ{ˆmκίιΥμ$>'lΰ$KN}Gα0KΖvβ¬B @NΖIr‚Ί™¦ΰμ£ψΞοΞ›ΛςΐΒD‹ΐ> “zXaΩe*½JŒD(‚…I±U†Ξ X˜T[uρyκγ΅iΪd|°T[―΅Ηu­I"—{:ι[P¨M “5*½τΘ,μ·ηG£ρΆbT3ΰ5[“ ΈΨ/ *κ Z˜–έT[¨jDeΔΠq*₯ϊŽΕ1Œ=\˜e'΄SaπΒ4ž]Dρ΄fΰžF†ΈΊ½όθ–LTφ&ˆaŸ^²‡­₯<*CAQ΄₯GΪg₯/‹WzU= Ί— NΪ 4"¨ͺQ΅θ‰'LHδmω(,J4¬λ±―5ΩaΪ‰Uξ€Ϊt53‘ˆSΥ +μ)Œš‰lKut―#“Κψ%IgAΐ΅¦E©‡{ΙΝΉV]—}~!IbœHxC©˜εj š­aI5 bƒz~T·ΪΜο­όΗ_|\΄Δ½”„ΡΊirΔΪγg©xτ±ζ›κ8₯e€όφώΝ6CΥ΅ ₯a@Š’ζRHO΄¨Εͺχf'Α’™pγ±o ¦=žΖή_³΅>1Ύ ΞQZLa[ΝΙ\2mˆXφ5#YόQ}Oέ&”Ι“Z˜”₯j‘NbώR¬”šΰiΗL* S¨!Ώ`ΆωG™~%{Q,¦R”γf6xΪٞΕβ +Ψς΅‚΄XΗ=_σPdη;v˜—qjέ΅ΑΥOkρδό«Gςν›ͺύ–B¦Θέ7’΄*_£;°ΩbeΒΕ΄ΓnL1zύ΅&$0ϊxε§Υμ+ΖJ‰€ŒΎBͺΟιe€ΐΕτέlsΡO ()’ΡA@ŒΕ#Ό‘\ͺ>·[kγιλ!}Y).LG]‰‘]θΪΥϋΝ2φ΄νδƒ+Dœh±υH§έ.λοΦΥΧ O,Β>ω^d1„ϊ£A]uZ?rdsJtZ4έ<φ΄W +²˜Ξ£Θ€}΄Ί^^θξŠΦΪή½ ‡£ΨuAZp3½ςH°«wμΥ]Ÿ4GMΌX χF₯₯ΉέυςΊέκΓΉ>άvͺ­ +˜ž°ίyl0’κ³f-{˜ŽΡέgAΖτM*%KχeΉLPTW`"’’#aTr§¦€‰ν@΅ ισ/Γc.6ξΘψ€+ΝhΟΏcγήIςφ~@ΩΥ#ΑX‡š<όΌhΤ΅ŒΟννqͺΒ³Μολџοω7gk-˜‰¨η β˜:Ψα™ N-­klΪ…D Σ£ΠpF3Q»f6(Ύ +.ιBΚ½ŠUεH9©N)e’R‰ ’Ζ_°I̐βΦ™0‹§gWοtΫF ™”‡ςΩ½kέͺΕ‰#EAb A5Y²ρΪ¨ΙBKdZΜτ΄Λώtcλ $“JXlΎ™Œ}(D“r3”ί>ϊΌ6Ί3W]™·W’žJE‘šδx–£ "?Tσͺ ŠΥA‡°€‘βeύ_ʘaφ‘ j ¦4’ε₯΅‘ιι·ΦlΎ§AΚT“wrΧVqA?{¬ΝΌ‰]g ιˆίπˆ +]6ͺXœ˜2 EμPXœQθΜiΥՐ Υ`E ©ͺŽΟge`ˆ¦ι:ΒGίψ²šWRh2ΑχΫ³J„ΓfύpΏζ&Ηώ^·»»«μakΩ­ˆ%ž_wT +“pͺΖ,S€Σκ`tj]:ΤΕj_GΡdχšΒΓTnV+σUj}²Λt’{wWΓIiόΊ΄:gΩJ0[±ZhΨ5F~nμσZjΗ1Ώω™ +@£°Πiϋΐ'΅…±ρ9ΣΦ| Μτα%pςf¦ΕR©μΜ;‘inw±^Z†Š­η'ӌ1ΩRξ§Υsι£,(%ZΤι߁ν±9ά>ρ+#ύΥΌg“dl»­2RO½ε“™Α·(€€ύ₯0ογΖΈ²ο $ͺςU«(+ŒΠaω~vŸR₯ŠνiQ“Κ3;˜¬›Ώ8+·(QΠSΆR:Οκ˜yIϋ‘ζΌ쬃 Πm:«αΚόβ‡ο5,[|QkŸ'z>fΥp΅rZFoͺπ½U™l»ύ«‚Ίt‰l»ˆ©kΩ …ŒU8Τ¨‰?νΜI?“z<Τ­ομΪ/sJQΉŒ”{Έ•ύjmƒΆϋ凂&cR F-΄^-␊r εͺ}~·‚„Fu0Huš‚ +€ΓΛ›ΏςτJ…J«EjR”cqΖDƒ£ΧmΰYT4©μpTiΗυ—+.‘Ε)RXO£L6š€H θϊp<šπ`λι³€‘T;f18S7SePN/ε₯jG\ΊΏύΝ}‘N—L'ή†ΫΑi—ƒ<ΉΒ9f|j†0Ρ—6|Γ€ΰΗδu„ΕΈήBβΔL΅q\Ψ4Oκ=7rš,LΩΑΚΝΨiŜ—υψOz±•αωx+«Qξ‡Ÿ©B'½†ZΩk’Z΄΅σAό2’kW<‹ORN¦Jα +νυΊAMS’ f\Oς ΓΧ$@j4s²μΔ'@EΟΩννdZ³[–]Ζ ¨ιd2ΔΤuPΏŽ ₯8R:³ϋΤάJ_΅¬κΝ7ε B«W•™mGRΩ)ʌƒAΌGΨΊ‹ςRΘ”J™ώκ‘‘H35eT-€¨ηρ ΨγςtžΩ@¨i:¦1•nD†ήsfΨ.3ξpΥiΰ»ΆΊ2ψηΥ2ΐ–y^9%…ε0τΫ d“Δaέ‚—EˆIq“Ζ’ω±O²€b»Ά"υ"²mRMMR PΚ–Ψ;ϊΩΘ―ΤXb9 ›ΔςPλeΑΠΩ·G!>ι>₯€pΡ—`°‘κn­k°ž!c­*0h¨žςͺE]k +στͺυ[yψ΄φΆjζ ψDHa€Β“'ϋ:>©ά«fUͺE§₯Ϊy«πω­X‹έqΫœX5κ˜Ey2ΥΆ J~h³IΏcσ‚³F +mXϊŽa@Κ„ͺ™zΨq«¦Μ?΅=Ν jzΞ­† p‘ έΓ›t―'TM9kVKzΔ,›v]6jέή₯6.ƒij³+ε°+‘β eΊ­Ψ;4œZ΅βiΧΎ`»ΝΪ@q'ΜΔϞ^I₯΄ΊΧΨm3ύ^½J’u#pgώ¨œ•‘JΑ 6šθ)*‘8ΰjͺ|ΎΑΎ[Π₯Ξντ©‰WΣ"„ +νΙI*+L(OZΗ.E 'F«akΥ„ ͺ°EΎ=†έŠ7ϊh’ ΏΣŽ…ΙcgΦύπ +ΦuθZ9ͺP―€­5, ε€₯"©D+nzN‹νΖΏμΏ&o`QΖP¦Σ†$˜k”1°{•’’δ’+]VRΐ@'aMⴈr ͺ˜NjBυpژ|D| ν.ϋ"₯άΓ’NΨ΄’tβaNΧ°c.;fdψ†xCj›'φφŸr=ΤΧeYcΖ"yͺΆΜΚPB±εΎT­Γτ ,ŒϊyX¬Ndxd¨Ά{xŒά&Ε˜ZyώΑαœς_"·e³ησZθΆN²Ώ[ +IΫΊoκΔ–‹yWΫ25ΛωY9Ϊ—ΥRK;M°·5Ωz―X ΈγΈI%ЉzX“)R#κR:%nΝ™¦XpG…ΕŸ‹Ε‹UβK‘Ÿλ2qG˜Σ8ntΫ™ΛmζτΗ‘[W!yάPYHΙκ@›κnž”X©W]47%s,ΔT‰RY !Αm τ3(ίΣύΓWΆ»I‡ΎΪ3,jk-•λS¬ρΉ™ψ‹ YΪ\΄ͺ›jJAš{tsΞUΝ«)€-ΘP‚κ†ϊPexy8FΖp7•hhΧ‚ΊυΛ] +Uπd@0ΞTZZ}/ήa¦±οΞ• Ζƒ.TΝΪζSΧέd[[ς²JM¨*^b§η6€˜gš,μΨιΖLνžu¦m``wkί7›8'ϊΚxμ³&ˁ΅Ο#ŠRe9GA1~nXΈέΔοΊ­Ξ>μk)g’Tω —kVK’/…\ hKυšΌ(ΰ”AΒι=εΎW~Χm›ι}?nf αiB7―UΈΤΛ\4ωQmΨ<ΣMUκ­κ4Χ’―έaΏ§ι„Όυγ_R&ΧMͺυTJΕ>Sλ(œ˜ˆΪγ]ΐ-Κ βΜ9:SΆ¨OΡq_βΓ»§Ωf"˜"j2/μντΊϋͺγQQτο—Dug[ή(Ϊdξng.+]8’ΊΒ›Šmμ}WAΕ¬ξR:¦<–L$‡b1šΗV¦SΜqqξ?Q‘ΛR‡gϋqγ#†MόΝΗώ佩 +"tρݝneO δLEΎs<4•τ•{e6Vθt+»Da°mϋμί<—*M"rλΗh%ΞΪF{DΏKI;;ύΖ5\ άΖUkLKΔθ₯gσ+djλf΅@.s*όΑiέͺϊ+mΏ{]Ά4ετ6ώΈύ!6άσ”»TMΝ`ΕP-ˆ¬ϊ%/ΫέvτV§9¬ϋhƒΦXζŽPέ§l)ς=ŠΙRiRU_` XQΓNάΞπ^h  λJΕά:xί¬BΐΜχTQρh(gmW¨τ’i<₯b \ώœ^³£•9εX0ΈNΤ•€’Ϋοvβ©dΡΟ&+|B~Ή›ε&αοζ3³ +δj4£ˆ=Μ%ƒΰιTμWvkΉG½π€?#ν|Ψξ{SκΒFmκi&ιΤαbι+γ+DzUΖ6ϋ²š½z:ξpΛ +m‚υˆ,…`Ξ, s7[ό%‘ξXKV§΄O%žœΦqͺ`V™¦š˜¦Βτ=;y»gc°ˆΆBε3ΚΌ«υBtšοs)φmK8ΜΖqΡ al·~\[}¨/=2;zjΎnfwygΈΔβϋOΛ.]J­,PœTs±¦Λέm?ΝLZΥΨ”5ι+v(‹§*O„ΤΜW›w/\΄Ž6Ϋ4q~Ήm(ήΦΨnχ―™*UeŒςÁK›R0n©η }’-ώϊU±²28Μ8y2γψ• [ε©Λ·Χ|²o+£•―ΞΨκνι  υθJavP sλSγK ΧpΦεTΗ€|P4νΪD§φ9+ΐ +eŒΕŽ[* ΊΔΨxΏq{0pΟ]Ι”(Σƒz=n«¬[/p +­ϋγ] ŽΣ+’Ό —Z~΄4— d4CΨg‡ς―ΐ~z'(½·Ύ›žJ BΕ―z`RΝUEΧMΑs Ix-~œy2ΡωβvC2Ή4ΗΕη0‚œrπνʌAΞ| ά‚4άΜNOεί}]Κ‹βΐΪ+ƒΣζXuI=g1›ξI3΅…Ϊ/?ΞΝυy·LΉBΉ£ΞΖΞ¬η°δ6Ε|vψ·”ŏ#Ξ” 2‘b‡‘@‘@Nλσƒ&|YφBNU4n> !7ͺΧ ι*ϊφ(Oίv-ͺΞEΩ-EŠ•Θsάσ  –―Ι½Ξγ΅‘Hy{RšωΖ΅°κ‹ §ξJmWς±ςΘx,¦€BπV“r_ΣNˆ›¦η·a)fΨKQ˝”Ύr¦ήV k[‘Γ=*dET禬e½•ƒ +#«ΈΒ.Εd\“7―²ΜΑ&INͺ·π]fʈU·YJƞCΓ>ŸcΒόWͺu^F_’`%.ψε6SμB+―2λ—aκυ’γ–aΊ3fHvQNE<ξ―u-€œT+5Dv\§ΜI6‡T†ίή•ΚgE **K<…h($Ή}»4=<ωτpυ\k2φ³:‡aαΡΓRΐ­PHDž[Ρτ:Nε%Τi3ΏΉΛ’;±[1΄ύΫvn—ϋ™ϊ1ͺ!5ϋ£‘«P(ž[ΜPΥX€  +-(ŒUΜ²`?'lγεΒυRΝ/αͺΟ +«π@ Μνjί|u©A}αΖΚ(Ρc\ϋRlvŒrύyξξΕΪ'‚M–ΓŒvƒK‡!/=j½ χ(ϋμΡJρΌ²,ΟYςiνhΊQ½―•FβΣΊΝ՚ΟΑΞQiE3Κ΅bβ6ΏΟγzΤͺ’xQΨTΚΉu›zXε=ΤΪnνΒί| =ά RGfߚ撞X@œˆwŸG‘E9κ™Ÿ—zΪΗQXΛG1@Q°θArλλ?ξ…ͺS˜ΩLBο€€"κζΚ‘œJ]΄ΊMξB23Xΰ™«›ΚŠιωŽνΈΓKδ ƒA.eυNfjt Nh>ο±ŽYƒe¦ςJ/³{ +œαΰΦ-υv:Φ s₯,W[ +dmΚyΝ9š" }x9ˆ,‚©²0εΩΖ Ϋκ„ZŠ70ʚ‘!9¨EΪ›ΨE‘yΠv½G―6Ί”L·+χρOθv*Κt»BΘx§Ϋiαρ₯ΫΥςΌθvΞφF·£•C·CMt;3-Ί―E·ϋŽΏ1ZEVcυυ¦Ϋq«ݎδόN·γΩ{ΡνZ”€OΊ=‘;έΞ7έNοI¦ΫΩϋ΄ΣνH”~θv³γqνTm“ιv؈}θv€uݎη?Ρν”ϊϋΠνέe§ΫIψν€fΊ”L·£ΚθC·SΆ?Σν>L;έξ{+ᷚΤα‡n'5Σν8.Ρν€|θvxΓ'Ί9Dνt;Ϊ…_t» +Έo§ΫUκ#7jΦˆ_Ί­D·Σ™ιv•v•σE·“ŠηΗ€Ϋ‘$ΊŽoΊD6s“nWΙGμt;”έNNhτέ;³D·Sαη‡n§p}F“nΗ’=Ρν6e£Ϋ-5θvu²¦‚ZΗ8π‘Ϋi Ιt»ΪάΚsν–²Ρν6Ρθvό€nΦνC·Γ:%ΡνPΪΉΡν8σC·“šιvΜN·“ς₯ΫQ-›θv˜ί%ΊέRvΊέ¦:έN!Σν΄ͺϋνθοKt»*ƒϊD·[ΚN·ΫT§Ϋ©Δ"ΣνpΞxΣν*Υώ;ݎ˜j’Ϋiψν‘Ξt;:gέΨݎΔK’Ϋ1½&Ίf΅/έNj¦ΫIΙt»†yυ‹n'1ΣνPέεC·«€?vΊ€L·ϋŽ”1]ͺκζK·S5ΣνT]”ιvςgϊν€fΊΞN‰n‡Τ‡n‡ΊΡν8/ΡνψμέNϋιL·Σζ=Σν”'ώΠν­€;έ7ΣD·cΟύ‘Ϋ±YOt;ΫΎοt;”έu§Ϋ!$ΊςM·ΣOΟt;}ϋL·[ΚF·[bΠνXΘt;%©Ώt;%γ3έN~™n§Ϊ³/έNΗeΊ,εD·Ίύ‘ΫΑINt;]L·[ΚN·[jΠνπͺIt»~½‰n'―½L·SΉ\¦Ϋ-e§Ϋ-5θv”’lt;U|ιvϊ™nΧFyΡνpωΠνPέ%ΡνΪ¨„n'5Σν€dΊ”/έαD·ƒΕθvφ¬ΌιvͺOt;ƒ}οt»M٘VK(<λμD·Σ—ψντXeΊ0ξD·Ϋ”n·Τ ΫΗHt;Φ⺝ƒL·c{±θvλŸ;έn©A·ΣeΊΥ<Ί6‰nΧ°ΣΩιvfMτ’Ϋαb”θvR2έNΚ—nG3Ρν€dΊσ’Ϋ) šιv2tΚt;ω }ιv˜M'ΊFϊL·[ΚN·ΫT§Ϋ΅ΫμP'άNς ·γ‹$Έ”·Γ ι ·3q‡Ϋq^‚ΫρΩΈ&¦ ·ΣΤ›αvKΩαv›κp»ΖV}ƒΫαω†ΫqCvΈΦ\ nΧ(v}Γν0²Jp;n'bΚnΗ.Αν΄Κp»₯€`ͺ·£΄2ΑνZnGEz‚Ϋ΅£½ΰvmR£wΈ‘n‡9Μn‡GΖ·Σœ˜αv –ήp;Δ·3e‡Ϋ™ς†ΫQ8ΰv( n‡ςΫQφ‘ΰvRάNΒngK†n.ΑνΈ1Έ] o€Ϋњ˜ΰvμΡ>p;2ύ ngΚ·γL’A;܎Ζώ·Sσ`†Ϋ™«Ωn§MM†ΫUPM;άnS6ΈέRnW1jήαvΐ½>p;=-n§O†ΫΙ‰δ ·“šαv˜«%Έ]₯½β ·“šΰvXμp;Žψΐν(1Ip;,Χ܎j άNj‚ΫIΘp;U‘}αv¨ nΗ™;܎Οώΐντ άN…5 n7…n7Ε€ΫUf·n‡‘άn‡#ѷӐ²Γνβί;ά.΄€Ϋi—αvϊς_Έ© ·³‹·Γν6eƒΫ-5ΰv5κƒnΗ/ωΐνPάNJ†ΫIωΒνH%ΈέJάε·“šαvΨB'Έ]½ϋ?Ϋ­z'sͺ·[Κ·[jΐνμ/μp;=ύ_Έ½\ nGΠ4Αν°_ωΐνϋάαvΔLάn);άn©·³€κ·Γoξ·£|8Ανπ›Kp»Nd n‡‘\‚Ϋ™­υ·γΜάNC^†ΫQxœΰvKΩαvK Έή‰·Σϋσ…Ϋ1 'ΈHn·”·Ϋ4§R)™αvΊ‘_ΈO]‚ΫQY›ΰvΌŸΈΤ ·CIp;Ξόΐνμ}ίαvR2άο¬άNί-ΓνT=œαvKΩαvK ΈlΥ2άNξn§'<Γντ"$Έ¦θ/άNj†ΫiβΞp;*?p;ΆΓνˆf&Έ]ω;άΦλ·3 žn·)άn©·Sp5Γντ7?p;β n‡?+«δ€Ϋ‘|ΰv¨ ngD–nΗΟόΐνXW&Έu’ZuOΈέ¦,ΈέnWI$ν(;Œ[>p;b5 nWΫσ‚Ϋiχ…Ϋα6ύΫY…uΩΰv,9άnS6ΈέRn§}C†ΫaΝψΫiψΛp;tάn);άn©·ΣΣ”αvzβ>p;τ n§hU†ΫΑ¦ψΐνhάNg~αvŠΡdΈ:2άΖΦ nGΟh‚Ϋ™νΣ·[Κ·[ͺΓνh’Ϊαv˜QΰvtŒ&Έ::3άξ͎8χ +·kџ™ΰv­Œ܎γά ή܎Η0Αν4βfΈ.ώn‡ΪλbΫαͺΨvRΎl;ξebΫIIl;BrΆ‘ΜΆ!&³ν˜Λήl;Ε3ΫNή ™m'Ϋ—m§(τΞΆS΄'³νω²ν€&Ά‡νl; _ΆκΞΆ#ς’ΨvRΎl;‰mg%}Ϋi;τaΫAΫHl;Ε₯2ێžν7Ϋς6ŽΆSwBΫ5ςΛo΄:Β3ڎ_”ΠvΊΜ_΄ΤŒΆ“’ΡvΧΠvιΪ%‘νP>h;©mGczBΫις|ΡvŠ|e΄˜Ž„ΆΤυ‹ΆSΛhFہςHh;]Ϋ/ΪN‘΄ŒΆkμ“6΄nΧm§Ή"£νoϋ’ν€f΄ΎyFΫ™χΙm‡ΫIBΫ‘$΄Š–²;َI"ΫιK$²]£ζMΆSwj&ΫQ=“ΘvŒ² •;َα4‘νΎqŒαlg™‰7ΩNΟS"Ϋ΅EOΉƒ Π?d»†­ςNΆ“’Ιv(²j"Ϋ‘$²”ΩNH&Ϋιe²+½ΙvΨ3َi)‘ν>_o²ωLμd»FοφNΆCων¨’ΫΙv‰lΗ‰²1™l§―ŸΙvί[ωΏψΈύν€žTfَupοَX+aΌl‡J*Θv(š9'َϲ`ΞfαΘz9‘νθLd;8²_™l§έP"ΫιY°;Ί“νxBdο4ΙvΤ%²]ορNΆCMd;ώΫ<ρ· ~ m§²’ŒΆ³νήƒ@ΫΥΐρνh;ξ2ΪN1 „ΆS ξ‹ΆΓ›=‘νj$ξ'ΪNہ/Ϊηϊ„Ά#,šΠvDX?h;Β] mW'7;ΠvŠc|Πv7ΪNJFΫ‘ΌΡvτ&΄Κ†Ά³z£νπΥΫΡvΊ\ mG$βƒΆ£π;‘ν8ξh;γ7Ϊ'ψ„ΆΣέΘh;Β‚΄"mΗ#±£ν”Ξψ’ν* —m§PPFΫ‘ϋ ντ„e΄Ρ mrκƒΆΣ7Ιh;ΒO mGIμm‡Ί£νΪΞ: ΪΊd7΄]­m'ε‹ΆΣΝh;•౨΄έw„ό›Σ5¦¦΄…_ΒML΄ύ\ mG%ήm‡šΠvΤρA ΄ !κιv΄–’GέΠvf2Ί£νj―ΪBŸίΡv”Qνh;Ϊ̞ϊBΫQAΠvΜ ό‡£νΙω’ν %΄Τ m‡’·'‘ν€Zτ*Πvxϊ‰ ΄ŠjHΪN2υKm§+£ν”/ϋ ν0ΆOh;3οίΡv8(ΌΠvJ›d΄ΒΝmG‘ωmdGΫΥ§d΄‘'ήh;Rz mG†nGΫ)_ψAΫΑΪΡv*‘¨ΠΡvfκύFΫ?Lh;³ΨΡvŠs~Ρvτθμh;`3ڎjͺΪN'f΄>7£νˆΤ~Πv€XΪN_-£νP>h»–@mggnh;}ψmWƒ΅>Ρvt΄οh;ΐ΄Χ*‘νΈN mW!.½Ρvόc@ ν¨?ΎΫ†Ά£=^kζmGψ3‘ν*€ŠkCΫιΛ~ΡvPηΪN9ΌŒΆ#ρφFΫQ °£νt^FΫi%υEΫαНΠv˜p[d;Κgίd; +ΩΞθr;َJξ7Ω1‘νP΄Ξšd;)V ½“ν(ζNd;"†‰l'εΦ|–ΘvΊΩNcT)e‘ν¨Cύν4re²οGίΘv Ύd;ͺ َ1<‘ν˜ΌZ{‘νP7‚l'…Ÿ2ΙvRŠΩ†ίΧ$ΫI‘Yi’νLy“ν8SΡ»IΆ«‡o\'َή/–;َς¦l§Φ&\ 'ΩΊz“νTl”Ιv•Bιl§yυKΆ³NΌlG'F"ΫΩ¬τ&ΫU8ﺐAΆ«a4;ΙvZ}Ιvld;V?‰lΗΪξCΆ#ΑœΘvδόΩΞVέ/²]Ε Ϋšϊν(5Hd;™lW―矐ν²Κ‹ΝV’x¨ηŸνPَue"Ϋ‘|Θv,nΩNιΤLΆ“ς%Ϋi6Ξd; +َ’›Ω5‘ν€$²„ΩΦ["Ϋ‘ίNd;)_²–*™l'%“ν΄Δω’νθ•έΙvδΰw²N«o²oy6²f‰lΗφφCΆc{–Θv[’ΒΙvͺζώ’ν쒝l‡βΞeΌ8œψΫIL`; ΨNό‚νΟ`;BH l'#Τ/ΨNjΫ5ˆP;ΨθΨNjΫq Ψε Ά#Ά°ƒν΄Ν`;Kͺg°Տ lGΦ&ν(‹ψ€ν*©€l‡εXΫmϊ€ν°M`;°D l‡ύλl‡YtΫ™%εΆΣ»Ϋαδšΐvϊαl§”Ωl'1ƒνLΩΑvιΔ ΆCM`;LνΨNΚlΧ¦—V€νθͺO`;½£_°υ§ lΗ·H`;λpƒνͺο`;ΨNMŸ°F ΆΓύ:νˆC~ΐvluΨFGΠΫ΅eꢁνyΨNojΫΡGςΫ‘ξ`; l'αΆ£Ω$νH}'°Κl§ ]Ϋ)¦•Αvd3?`; Ϋο`;Ί£ΨNIΌ/ΨΞΆ›6ΞΆ{Ϋ)ŘΑvJd°±“ί`;γ,ο`;2 + l§ΏωΫQ4Ÿΐvt!%°ίφΆ³ΰΆ³τΪΆγΜΨNΙ΄ Ά£C!νΪδυμ`»6Ϊ lG›MΫ)ΑσΫqfΫaΏΊƒνfΌ;ντE2ΨΟ lGžϋ ΆSR0ƒνHΠ&°iΦ؎"όΆΣ—Θ`;₯σΎ`»ΖP±ƒνt­w°­h°uΆν`;)l'ε Ά“ΊƒνhΡJ`;”7؎lϊΆ³œΫΆ£Gε ΆΣΟN`;rκ;ΨNΪΨn»'ΨN”Αvϊ_°©o°9Χ l§η<ƒνhOό€ν”±>Ί;JΓ!‘?σΞ΅λGrν”ΐN\;ξjβΪ‘Ύωpν¦§νδΪ‘1H\; έ_%H;Χ>FβΪižrν΄Θ\;½&_ΕN‰kΗΚηΪ5Zί\;h‰k§΅`ζΪικ}ΉvΜ~‰k§Λ’Ήv΄aΈvJde±ŠΔ΅ϋF±fŒόΏkG Γ‡kG CβΪQ±°sν>\»FsxY\;=œ™kG™Π‡km!qνPΧΎysνψΌΔ΅“’Ήv––7Χυgqν(rI\;Η_&†Μ΅ΣΈΉv*^ϋrν΄@Θ\;ΥΏdασidHX;j]ΦNΚk‡š°v( kΗg½±vbd¬]{ΞΦcν°e㱘DZ›Π>*°v›²aΤ–X;p†έ2`δσ»\X; k׏ϋ…΅Γύϋ΅CLX;”„΅“ςΕΪυ L¬]W₯gΒΪIωbν:Ί;Φ±#p¬έv¬έ¦† -Ik'Σb k‡ρ³4Ωτ[„<¨vKI·cͺA΅3΄A]T»ŽΛ©v ¬Μ©v X b§Ϊ‘β―T;ΦtN΅“ΰΣΣ’Ϊ!bT;ΪpOͺ”ƒο΅Qντ4Yά0¨vΊ™jΔγC΅Σ4Ÿ¨v¬4ՎΦΛΥ5Qν€dͺέwώg”ՎΫ‡jΗζ"Qν¬νf§Ϊ1λ~¨vζϊ΄SνPՎ3?T;©‰jG5Q툊~¨v–ήή©vŠ©fͺ]₯˜ξM΅Σ¦?Sνˆτ&ͺqͺj’Ϊ‘$ͺ ͺQ;ՎީD΅#Υσ‘Ϊ) ¨vΊ%™jχ½™ψ‹ ΉΨΥNU™jΗq‰j'εK΅CMT;B¨;ΥNΒ—j§ [¦Ϊiٝ©v +Ή~©v43'ͺUΊ‰j§}Η—j‡š¨vR2ΥNΚ—jG?~’Ϊ±ΫMT»6ι‰jG< Qν(νLT;νΎT»vΆΥN₯ƒ™j·”j·©^Ž€gB’Ϊ1.}¨vΪοfͺŒ;ΥΞ„7ΥnSjǏJT»vFΟΞN΅CMT;”D΅“ς₯Ϊ±KLT»v^™j‡Λλ‡jΧx}wͺ6™j·)[…ΘRƒj§?™©vΊΦoͺF‰jG°m§Ϊ-a§Ϊmͺ£(¬ά©vp]>T;+‚ί©v„νΥNϋΓ/ΥNΑˆL΅# °Sν»»7Վπp’Ϊ±ΝKT;²"oͺβN΅£Ο1Qν€|©vΔowͺΒN΅³#ήT;πJ;ՎD΅ϋ”sήΦ”ό₯Ϊi–©vf«²Sνjm„j‡3L’Ϊα “¨vΝ|¨vζO³Qν81Qνψπ7ΥΞ +6ͺe‰jW!‡½©vζό΅Sν”ψΟT»:!œ;ՎΠC’Ϊ‘$ͺ…'ήT;ΤD΅CIT;ώζ›j‡ΜN΅Σ ΙT»©$ͺ©;ՎdωF΅«=‚£‹jGUF΅³ΒŽj§Hπ‡j‡mD’ΪQ˜¨vZΚ~©vΛ³aWƒβT;S^T»)Nͺε4‰jG3Ω‡jg%š;Վˆt’Ϊ-e§Ϊ-5¨v|λD΅γΒ}¨vHΥNa€L΅£€κC΅CMT;”j'αK΅ΣΘT;)™j'εK΅#Β΅Sν,₯±Sνμ9ySνTΎ©vΊ™j·)ΛjSjG n’Ϊ©”νK΅£ρ7Qν°~LT»₯μT»©NͺώB¦ΪιΑώRνΘU$ͺv™j7•D΅3u§ΪΩl§Ϊα$ς‘Ϊ©Ί=Sνj4BLͺεmͺFžΥΣΞD΅3τΙ›jώ$Qν(ͺKT;ŽωPνjλ™jGηB’Ϊ)”υ₯ΪΩζe§ΪQP–¨v›²Qν–jT;}R¦ΪU ŸίT;ΎΗN΅£T.QνP>T;SwͺJ’Ϊُ|SνΨ&ͺq‘D΅[ΚN΅[jPν*1‡j‡υΪ‹jΗύHT;³Sή©vΰ€ήT;½"‰j‡m’ΪAτωPνΨC&ͺΚ2Υn)i$uRντJ%ͺΩ Ό©vfΖ΄Sν(vJT;¬ο?T;3€Ϊ©v35¨v$ΙvͺκH2ΥNR_ͺ©;ΥΞ”jgΚ›j§%s¦Ϊ‘lT;ώύ‘Ϊ‘ή©vtž$ͺ^ͺ―K’ΪΡ"š¨vXΘ}¨v –j'%SνΨέ½¨v9&ͺ]R¨|εΌΥNΫάD΅Σ‘¨v4ΫΏ¨v΄£$ͺ”L΅Ϋ”jgκN΅Γ{#Qν°\ωPν(/JT»Φϊ‹jΗΨϋ‘ΪIΝT;,ΊΥNoΤ—j'5QνxρՎC>T;\iΥqΒN΅ΣΖψK΅“š©v8ρ'ͺͺj’Ϊqf’Ϊριͺ~C¦Ϊ±_JT;”ΥnT»ΖόΆ¨vΆ„ΟT;Mη;ΥvF’Ϊ-e§Ϊ-5¨vZŒdͺVoͺή!‰jg6}Qν–°Qν¦T;…·vͺ]›ω‰j‡XΥΞ–”Վeθ›j'1QνΥεC΅ΣΗgͺewͺvͺέ*š‡©8Qν–²Sν–T;ϋ‹jΗύC΅£ι2QνψΣ;ΥNο/Υ˜]’Ϊ¬MT»₯μT;Swͺ姉jgα7ՎΈD΅“’¨vͺn-;Υ!Qν8ρC΅ΣLT;]ΕL΅[ΚF΅›β€ΪYΜp§ΪΑκψPνlφέ©vTzξT»%μT»©Ξf)Ε‘2ΥΞ:`ίT;žΊD΅£τ$Qν€0½©v†]Ω¨v‰jΗyͺj’Ϊaᓨv†ΆySντΝ6ͺ½ς;Υn +‰jgκN΅£5QνˆΪ}¨vΦ~ΊSν0]HT;-λ?T;ŒxΥΞ,vͺBš_ͺŽKT;"Ÿt);¬Ž*«ΤN!ρ ΅kΧσ‚Ϊ-e‡ΪmͺCν(νIP;ώζjGZ?Aν€d¨Κj‡ΊCνψ¨΅›Εd j‡uE‚ΪQ • v›²Aν6Υ‘vm&°V§ΘφjGY‚Ϊ)Ο‘vςJψBνP?P;}ή΅c•™ vSIP»₯ΤN{«΅Ζ΄CνXAΤNkΚ ΅3ε ΅[j@ν°dLP;ΐ<¨M" j§©:CνhΗϋ@ν΄ŒΙP;:y?P;&“΅S.CνTͺτ…ΪΡM• vJ‚&¨έv¨έjWι%θP;Ϊ‰>P;Ί¬v¨ξx†Ϊ}CΦ3 ώΏ8Τξ'Xέ₯θ€σ”&«ξ"Ώ‰Τb;Q‰TΗGK :-vžbδtp¨ΒY78užκf—91uκr8Ψ‹;₯ˆχc}}Ρ} l«V}Έ¬ΐžŽ*ˆή·’NΖ©ε²O™„:m +»wE,Q-`%ŠηeΚ‘_N§M­Vl¦ 7Θοό!νυ i‚ιp'Όξ?“KG±|­ K§]ώJ§ΝP£l2|:…kθ”NΫͺk\™I'±^χBI0Š›ιΨ{Υ²ιpΧβΡuLLΟ?Žš“ Η1ꟍFΗvοh!Ρ‰Hΐ9Xt!$ξΩ'‰N ΊΎsΚV6ˆNߜΚάy”ΖΆώ,h(ηeΥΐΛ\VkΔjΩ yc…μ]RΆQπΧβΗΟrωύ—ζeΛfΞ *θΈbHW΅Σy,› Tpp.ώ\cW»θsσί{.΄ ΟU|ŽsΚ)[ο:“;'/‚7!‹7wδ ~ό ΒάoR΄Κ’±YͺbρεNE‰ύ]‚/'#ζ\Nι~npΉ/N°εTίιψΉΕ–S<Α=/ -`βάΘrτ–XNk?Zϋ½D‡˜-5ρŽ‹S1)Φ *G,ΏnβI?υ3‘rv1h9žIb+ΧΚ©o©Ή{YΨΟ³•B•»π˜ήΔΙ΅Λsν'W΄~Κ3qr£Σk§Ι »–E“C1›§ΙΚ‘λ“irE%*χq.šœ”ίΤΫMNΚοΞΧL“+ZSΟ³hrE9ΞΊίirΏ™P΅9–4Ή’ΝaύiΔΛ‹–3£Ωe9ι ώ³³δΠ¨– +οzΐδ +ΎxΓϊR'LNκο–œ&LNΚo­γ +—Y ΊN{γ“+';ΧϋΟ„Ι¬Ό|œΊπΟ}όGάηφΨšXrRϋq<‹%ΗqΆt–\±ΓΘ09©ΏMΩ½`rRŽq•“+j­‘qr&W¨Kμ&(£_^:qr*’#€’¬ηŒ ‡Ι\Zfɝ8^_ %‡-\€γ48ΘξΟ±‘δ”o½ΟΊ@rΪ\Χ½8rZ}2FN½‡ QN‘΄ά\ "w’|»CNΦye< !'ώG‘°ή9MKΨrS ~ksάΙ w5›&=N;³r]KΔRΪ ϋQ§°‘γ–fδ8ύPAŽSαυ ;8ξ€Π*{ιC”Πό(Ϊη¬}ΜΊη'5N¬€Σqs+@Y9Ldv’ξe3ƒΗΌYPΝ§³R,˜C q(Tκl&¦…dB·²Z€ +&z‚χcΔlAcYbΔιυθ /ΑˆS­Ξoky/Fсvή™'υ7„έ‹‡E’ξϊdΔΉΈλ“q¨1bš•Ξ¬>ΞβrΘ§χV2%NΣoέσ,J! cΤE‰γ5°ΐ↉£ ιΊϊΒΔzΎ†v±ΓψΔΔ±ύ½ͺ}IΫω³!ώ3!qό›εΚ‰C=;,+₯5u‡y8I.(qφΉΞΡdr— ½υΟ€Δ-e£Δ-1(qΪ©ί,¬‚ώ&Ψϋ–D‰sπ~œ°‹ξ(GθWγο»” ‰+ΦU}/HHβήΟ³‰‹uΪ‰7Œ‹L¨ΊlΧ&$n);$n©‰Γφ₯aŒβπ·bΞ·%CβŠ*uΟσَ2€·± qKΩ!qK Hœ€MΥ¦¦³ί„Ψ–—φ<άɎcθUeΈžc₯Βψ΅cβPm’sLΚα89²P‹Ύκ@Έ1oηπ°@`βΐPΕΝ1qRlΈί1qϊn½:sՈ΅2Π½›M€πίμaϟ„‰wκ7–ν8¨Ω—ΝC4boΚ†‡ZjΔ΅ΕΓ>h£šςΑ}ά&NΦy?ΟvœŒ;΄Ν›˜ΈMΩ0qK L\‘ΟCJΰίΐ‡Χ«gLœV#σ°Ag%MΗφϝ·Τ ΔιsΈΠ“ώ¦hθοψ‘)qΚŒΎ« kGΏ%Ξ ‚ΉèxӐο(΅°½Ÿ‰cΞοZŽe + ŽηY8)ρUœCβ8ζΌ‰ΣwMO§@π£ŠΔ ΣX« EbΔ1@ΊYλ°awv2β–²3β6Υq έ¬γ§?yύ¦œ ‰γ‹ΰb8›ττ9$[!VΜ;%ΞTm +ƒΗ‰rš”8ϋ•|­G²ι1(qzUXMJάRvJά¦:%²ρΦNΖ#ζ,TΟ΄SβΈ#§€‚.’ Σ,8)qZ ŸΜ³;%S¨»—E‰£φΡ67θoκΌ΅ί)qμΝ*χ2Žk·I&%n)i˜jPβŠ*eθ( J\ύ©™v§Δ…ΓXΩ%ΰUμt(qΕθΛf"7)q…2γa₯Yšπ a'Q%` p–u”Κr(ΥD«eKs«€ΔIc( FσƒΏX='$hMt?fΙ‰™•Bπα$νv<œƒN‡Sa-η §‚.ΙΖ†»ιNPœdΈΣ·Ϊ GJ«o`8e½J³”ΥDΪ}u|'7,ά © Β!&ςiDtv&œ–$}τ…„ΣŒzjD8Α1Цυ§χ_CUΰΰ`΅{Ρΰ–°Αΰ¦,8*Ÿ4; +έf€§'‚]ϊ$Α•C9'ΚpWŽaοl"ΑI­ώvœ”Fh)Hp…–/HžΞοRΗΈœ§—U#Ό’<‚γ€ΛΛY¦UΑ°ŽzgΑ•ίΪη9έ‚šΰAQ`eԞAp…Mρ‹'…υύ$Α•rzθn'Α‘6’‰N‚γΜK h'Αρα,Uw\a_Sκ$Α= +oiQ$Έ)μ$Έ) 0…©L*oE16 ; +hKVΗ¦jΰψ­8ΗͺΰYΚΞƒ[jα +Ή°²@oE+£€Ψ΅QՎ›ψΨq\Γ», ά¦l@Έ₯Xim™@8~O)wΒ‘ήΨ8N +Η „“Ήb;Τ +‡rηΒ‘°ΚށpRm@8}Ω›q,@o…‚–§d ά“ηqΚΑ+‘3pKفpK œύ…«,Π›vΪ…Εζ„SP˜νη:N‘Ού—΄ δξ«‘ψε°ηΚ²₯>/Μpœ·”·T#Βα“‹GdUϋ€˜Sk"ΒI½ NΚο9υγΈ—VoR³ +MͺN„CΉ²J’‰3oo‚šDΈ’$ UδA„ΣU΄T[α–²α–D8½M“ΙD½•B³E&ΒΩ”ϋάK$¨‚@s άnIΞqRMΧ ”7†W#W΅Ρΰxδ”~\Η©Το. §θνοΪ– ƒ“ϊϋUeΑΰP†γα°`ζLrs; UoΝ„Α*lzY08)ΧΐΈ€Αι«ω™ƒ+JΣ‘I άRvάRWdύΤλΟ„Ό=5J,Έ‡Xπv”π=ΚCFAΨ;NνΜ–iuάεiŸ‰ΣΠyz‘VPΰπ |¬y άuΩJwέΜJΎI8Y±Ϋ#κβP ˆ*FGΐ-a#ΐM1pʜτkαίXΟ3Ρί”w.ε^π7ULΗ΅Ψoηi €„~“X£lL3ΖI¬ς\ΰ7†Jg©MξΫ©ύυΥφMΈΎβ —δΑ–° oSsζιž?δ¦NΥퟬ»ž§e|C½]ş•τφΩδ$Π›¬ΗZ©‹σ¦d½Ο…y[ΒFy›b@ήd’Ζ›-ΕLΫ―άT‘ΉΈœ^’dΗυ¨LΖΫRvΖΫRƒρ¦aΈ3κγM!V»0γMy7«Ζ›‚M­X±₯eΨ~Oςo™Y3βM4Ζζ‰xΣ‰ΟhgFΌiΗφ»|ΧBΌisωΫ± ή&«έΐj‚ΌΡBi‹―8$ +@ςΆ”ςΆT‡ΌYκmY<ΙΥ—Ν·Ϊ!o4PžΝ +Ь¬V^ξ,}ςφ GG ϊ?…ΌkWμςVΊ‡'δγɞ7)dΧδ­¨έύ’ž!oΈJΩRέ!oΊόΏ$Θ*“}PފYή‹ςf[νλΞ”7n§FΜIy“'τ•Σ@ργ¨=SήτΦ!o +š§š·‚ί12εI-η’Ό”οΞ”yΜ'Z‰εηΚ”7*όμε„ς¦x ΙIyΓ b•z,'Ό­P:/ή€R…2 o$ڏ„7Κ XDμ„7ΚXIαΝJ τM‚π†’‚β„x#½qœ‹π¦/aEux#WGiȎx‹γα™ +Δ[‘`Ήž ρV€=™πfγd_€7†R†ŠΌ}αΏΰΝr +Η™oΘ.’ox+O€vπζώY–œ Β›DϊθΠWwψ=5(-²53νxό3ov˜ ΜΞ@ aBb;ΰατκVΜNήNQ|ͺ'ΰMγωΈnϋVπ¦AˆΟΌ1%Ύΐ›†yΚ”ΰΑŸk€·B³—ήcJ‰RsD˜)‚»_³Όξ!(MoœI°b'Όi 3ΡαMߟ₯Ϋ$Ό}οε?ώβσ"ŸYεNΰMΎΧh‹οFρώwΣh_w¦»Il₯.Έ›κJƒνFYΤυd΄›VΗDƒμ¦ω›vΑg+†d& ρ‡ΝΠV°ujuΪHœύ&ά hYž<ΤhSΰ‰ϊ“΄i·rœ–SΧ=W.H›ΟΔg;c…x6­±IM/5₯';œMν)”œ:›ν9ΌH&Πlκr₯pq'³)`Γΐ`Ά§dkό%ͺ ¦|=ibΩΔQ&qŠrͺyάβ…0πυΨό•˜lψΩ[Κς’ršC@²έ‡=<‰Θf„p[Λ±…Φ2HOͺγΨ €Άϊž4Ά; +7Ζ‹ΌX˜fLAΓΠLΕ&,(―wΨTΚ{σΛά†LŒnΈ6ΊΚˆS―Q¬Šεω]½šmg°©™w¬@°)CkD Ψ”Ϊ­<’;ƒτ?OV@Ψt¦₯δΒ¦ +K/n Ά«Ϊ–u"ΨlI7‚­ϋy'°υY†λ6Β·mΔ·άωk£{IBΰΧ₯‚ΆY§VL)-–Γ;|m`ΈjΤ6IΡδΨxzm(kεgΕΖFŽς„½ΌΖώι°: +hU¬ά±k²ͺξΔό˜‘¨μy¬xΕ}<νΌ3ך8&rMΕύ΄ΣΞ©r€UG&pM"-Α[ΣZQAω‰[Sdy,JΉμ.n’0“΅¦ηkώ@­!Xϋν­5\«λβ¬)Νu΄Ύ0k”ϊ^W¦¬iI5$ kjφσ±F΅T"¬ ƒpίζΔl$¦D»9ž3^κ1=Ό…zβΥh+»ώLΈš@Ÿlƒ­Φ°Hξ­gϊ˜“ΥΜλ΄/°šB –&ήΈj€νyD¬VtΛ©°ZΑς›Wf«i.±!)ΐjδΟΖ¬f+ΰώ"«πuΥ΄|ΆTυV+xhΣοευΡz½Y*N°Z)>©&°ZVυ:›rώ™\΅EX‰«†JΈ4Έj(„Yƒ«V¨π?ν³&WMκ #Έj…BιΗά)ρ‡•bΝT;W­˜η‘7ΧYiΐL\ΉE―fr*zW UΟΑδͺI‘ή(Έj~Χi$Z1Χ΄gqΥΘχ «&Αbx;V­`gq] «&ΕCKžCΪδΦj%aՊ† ΛΉVMyž©ΐͺ©2¬©ΙaΗͺΡήuήζ€KiRο–j¬š +ζ¨\LX5efzΤώπξmiΗͺ©ώωαύά±j…¨e« «†Β\5ΞTT/Υ€ZT&ΘjRlΥYM<ιΑΫΙj”ίQπd5B7TΈYM4 *IYM*5‚“¬uγτz""RθnΪΑj™Μƒ«ΖE$Μ\5*I7Z!Λ©½šsΥ”K»« +Ε‚«V`ΒvοŒή, π§·―S£ˆΗR?WβJLvZ!φ^ϋβͺιLΪ“«VθΛΕfpγͺύ~³eB&WM=~DG&WM½{C±˜ΔU+PZϋ½Έj:Σϊ)bδ,f«εή¨ς °š~ωά;βQ£JΙ‹υηV+Τ²ΐj¦τΕUKηM* —ΰͺIOm‹«&Ε +wZ17§ΊΈj₯ΕΊ$ΈjzIν³v›6~;WoAurpΥ + ΰ~g€7«F­ΎU$QpCxοL\5 Φ’\5;^2ι\5₯Ωt΄sΥΨ‘TκM«V’‹frՊيύIX5FžΫΆDΝBΈ Ϊ‚ͺΡvq՞‘j¨„³ƒͺ&ε·! «&₯1Nμ\5ϊ3?Σ&-ςΝΟΉΈj(ριΣ¦HUωψVS‰όA€:ΐj$ΉΉ;XΝ’εNr¦E¬Z/κΉΐjΚ›Y‘ωVΓ²bϋε`5s.Χ«ΡbSέip‚ΥXwΡ`5-Όlχ`5Cχ-ƒΥ σ{ΆV3Jk ¬Va>•’ΑjTš7·¨5΅w¨Š°š!βŸ+ƒΥH³Ρΐ`5ƒ”ΆΐjœΙo«adB¨)ΐjTυσΜXŠnή’¬PΑFΈθ@ 1E›˜«•Ϋ+KX3ω›V+Dξξ2Αj…Œ΅{2N°šΎˆ­U¬VYΉέ}ΥH-λ©Md5…–*EYAV£₯ΐNV3,Σ•ΑjΤ­? +@ƒοm£Ν«)hp™{Vƒƒ1<f>R”έ]=ΐjtoY3τV³^0ΉšŸ‹:Ε­ΛόΑ{όƒvšT‹W&"ŸΑUCΉΩ6Αjδ―‰CYΝ’]ΊϊAV£±ƒ^덬¦ίέZMo5VSj”΅Fb«3nš³ΥτQZM_ ‘ΥLύ“ΐj +ΣΡ65Ρjz­b(Πjττ‘{ίΡjΤ­Σzl5\‚Νψ β}Δ°vΊZ5wέ±πjά[ά ―FΈ¬ϋGlΛΆn]ώ―¦Ÿ­M―¦1άζϋTzΥ(γ7ΌšκBItOΌš¦{ΜξvΊšΚ.ΎYΠΥ +$χφεNW+Γcαζt5%d- x5Γ#–πjZ[―eΰΥ΄ι"π9ρjΠ³ΣΥ4:άχ½ΰj—Q“­ͺοΚd5Ω:jΥ9Αj +C¨ϊ7°jŸ σߌ`7PΥ¨Φ'죝ͺFέηPω½„²ͺ†pω‰k§•šZvΗͺαzEP,°jj ²˜ΐŽU“ΪέV E₯«fΗ\ήm2«Ÿ©ΊλX5)” ¬šͺŒV­άn{ΠΜ5°ŸςÁUƒ1Ή½DU«”3Ÿ–+&ž₯!Αό@’ύ™D5Kφͺ¦W —”IU#FΖΕͺQ‘h4OC‚M’ŽU£Ύδtτi5~Wq:ΪΔͺ‘RΪX5”v~Ν:¨υYŒ7;WM½BυέΑUƒ₯U7\γSΌΤ«†1XΒͺU6;VmS6ŽΧR«†ύŽUΓϊUΣΐŠγΡ:ͺD<Ο±jΨOί°jˆ”ΊV eψ +‡`-ρ¦ΣΛ”fκ…Πκν-Ÿ8R*’n£ΐͺI1cνͺ¦wΐZEͺfρεαι§Φ7a‡ͺmͺ» ΚˆΝΌ©¦ ΐ—©†νόΖTcǘ˜jKIχbͺΑT3cύ©QμΝTci˜j,Ώ?L5ΤΔTCΩ™j΄…Ώ™jˆ‰©"1ΥπΕ}3Υτ(e¦šn"ΙΫ K3sΤγό“˜jx-θ˜Ηi‰ΑŠ8 jt*šΝUCLsGΞΣΓ–UϋŽΏα„ς_‚ͺ^³‡sƒͺΰ<έRvΜΤ +Ξθ›P5ζΪ§ŸͺF +.ί€ͺ‘w[P5ΞTp+AΥ€½ ¨ΤΛΫX-Ο‘rϋ›ΣU#βx»ο©uXΌίΆS"F¬: lrTMnΆ› ¨kfTβP5šΜHwοP5TOUC_³`Σαι䝩¦Δ ‘%GͺΡƒ‡―ΏΥΘάτκJdKΛαVATΣύ°ΥUΥΎwςσiQ‚Ž&‘¨VΘγQwλD5ŽΓ΅)ˆjRŠ–`‰¨V,Ώw/’ΡΣΦ7€š οH5Ef,ΐH΅αΪPiς—²ς©Ζκνθ΅ +3ή«} ‘© νεΐ³‰TCΕG+jRxθ&RMŠWcnH5ΊΧΩR}.†hTCχ•‘jD(1€Z5Λ³jzΎ±dHH5Ftκœ©¦b½ξdmˆjS؁jKτͺΜ¨• NZy"βΌσΤ0E½‚ε"•zΑΓφ=f[­τf§©-Ρajφs3<Άρϊˆζ—¦†JQ{ΐΤP΄ +š05)φέw˜ϋΒΪ―E«τ»β—g05άE­Ueƒ©UήΫavνΕ’+§ΌLmSΆ +Ž₯LMr°C L[ +Z.wœ†8œΜγ0χ¦šίpjKΨqj›κ ͺ―1O­Pœ^ΑSΣ™V?<5"v<œqΕ΄!΄Ό§Vπ`·«A£’Β… +ΰΰ©)ώΛ’=ρԈ +Ss<5φuΤOtΘs TC-NK£ςF +QΰIT+Έ=υ’‰jDn HR ₯;Π€sœ™©¦ˆu§`9 jŠχZΊ( jί±ςoΞΫέ«3S­Λθϋ^D΅ΦsTξ~•xjγτNΔΐ©1\uΡΤ†·Ξ&˜AS–΅ΣY§εcFΈ;ξ(5rύεš$5%ΈνRƒUEUεΖQ독Ά'Fm4.E ζ#Γ ’¦Ό‹₯ᝑ&αr4ajhJϋ“j4Y¨IwΤ°―?F}θŽOS(˜&•ΐ§©x”_ΠΣBHπ4D²SnD§έ‹ͺ[ΫΨ-rΪ}yXΦ$­ˆΰά΄ηρžο›φtsΐ€ϋ±mΐΠξbIΚΔL›Ž!ž‡οdƒ˜vš§θΞKsiTσΉ0`iχ%±Ϋ&ΒΖ~-TšVN樴₯쨴₯*νΉ££ hX\Ν/γΕs"E’­,LšVW͐΄Ϋ£δ“‘v·xœ‘v73Χά iJβ[LΠiψ»4Cv‘V„ρŽG#€έϊ€£έΡΒ(4‘76šjς)4šH–5v2Ϊ6‹v?ξ1Έ3e€ %ΉQΡ€ϊΆν(Loμφγ ށhMΪνŽ?9S‡ΨΩkf‘ιFWBΥ’Ÿ†ΙB›Jb‘™ͺ•[°ΠT7α%Ξ8“ύ -S; +MΤ§Ύ‹Ρ/0Ah§ϋ,%šΪX˜gƒ†/½Ϋšβ$―ξUšxv +šΜaiΕ šŒaν9MGXMΒ†@;Γ‘:hJpi +ΪΈύν΄αΎ,ST<Ž‘9πgKΨθgS4ψΩp―Ι>SΝZ;ϊL_ΐΠPŽ>“χDxΛB>“ΐ²yŸ!ήΟ➍ΫτΐžρΛΚ•©gΧκ½ θYοζ•7™gSΨ‘gS βνήu;.υοΝΉœΡΓ{=fφ«χ(xgre"άyg‚cΣΌ3hβ₯-Œ™ϊ°ψΰvΖώΟοPU5βυ&N;[ΚώzOuΞJ½WΙtk 'o·αΞΜUˆVǝɧn¬ΓΞ +!•²ν°3σ1r[(f‘0N¬3­νm™‡ °\ΰ;μLϋη,=ΓΞLm‘φˏmΑΞLΉBΉ£ςΕ-Ί&μ 0aΰΞP¬ cݑ—~I;ΣΏIgLΪ™VΟGΝ¬3΅X<0XgΪfΩ|¬3ŒΠΜsgcI΅Dg°Ξ€œψ댝Ϊ v†!! Β€%…ώsNΡ’°3³±TBΝagκΜV‚0XgŠŠ[‘Θbi›Β=›¬3)ζ-¬³MΩXg¦^χbιšZ*!Xg˜‰0το¬3 +~šYΥΉΩ‘χίNΤ™Œ‘y‰κLͺ7²9κ ιξ 3Ϋ hdow&IτΎ8GI±’“@qŒα‹7Τ~+€Δu¦ šj9κLE5Vϊ΄£Ξ€Zα_ Ξ€tʎu&ΕΒ‹;κ Υ]!qbq8…|xXR%•ζ'‚ΪA:+”™χΖx2‚;ιl€³Β,Vb†8²:+Šͺ“¬πcTΜyΧ°ςΖ”tΆΤicFeΜπ;`GΏ“ΞTzcWp§kE½I Ξ6ec-5`g +<]†|sάY™yƒ w†h6K<+έ;©x¦M0mοLš5π ₯”Ε;C ΉσΞτιφο¬`ν~^ d¦έΉ•‚οΐ³YΦ3;/0 ήΩRvήΩRƒwf /ΰ™φΙ€Yvή™Κ’ŒŽͺΕQŸgςΞ‹6³‰w¦―…[ƒwF$•*΄Ψη,e睙κMπΞ( e{Ό³’ Mwή™TσŒή™3qvή©±w&Υmζx†‚7sΟ +άGG§Mΰ™n₯υb:πLW±yΨ—μ6άYh“vFŽ}0ž;Ε¬h΅¦β©D;cϊΕk}§κΛcG£-a§Muv)JdfwA1Σ8xŽσϊ“hgΫ1ϊΏTUχψyͺ†³ƒθ‚κέv4΄ŽΡΝεΗ­«Z% =B)έθ1:ξ°bέδκ₯†μQ­+ΗΧλα’a­“Ϊo’ξΪ-Θ/AMεBEυλ^\4νPo/aΣ>]ϊΡŠρs»ΐq ¦Ύœίτ‰jl΄ίτYν0g£ΛKΩΰhΕ?RŽ¦Ί³q‘8MuƒΝ>+ΘΈ‚† +ΡΫ5―>_ΙΏι§ίΖdΧJ_Ή_7g όΔ#αΗt/zνΔ– ›Mε^Π₯Š&iφjQΉί3gŽ›Še~p[œ4!PΥςΎŽ>ζδσ₯΅σ°MK—}qΈ’Β}»«‹ψ=ΓK)„†QΒW*Υ=RΙ:J­Ω£IΚψέmS˜fωψSκεΔ΄³xRί֘iSyκFM[κm>ϊα–)Σδ­)FQΌ£*ΤŠ]Ωκ֌σ8u=&§ν™§ξHˆ—ͺlˆΪ»x9κG·šSW5}ΰΤδ—Qύ%U‰3†.fWΰ8ˆj¨Ί„ ζ―^³ž’Ή‡†™³-¦*oζٜ½­’_ΕOQ:AhκwN;3ϊkeώRκi愍Ϊxl¬¦έ3·6ΞΌI3žKνPœ1X ’‘πXC‘3ŒPυ‚1djΕ"ΕΎϋ―Η”<όΖTheQ=β]q‰¬q«Έͺ”Pαžώ£ˆR¬ϋΜηιΙ“χαP7£[?HSόqPe~4>3±Ό₯νιW^R…=AXΣ[Βu—J{₯½MΓΞ€Ζ@J;ȟΆEXΣΝϋ5ŽΗkύq‹^=ΜtHιν=Τ<‘ίq γεhf€ΖΣ?š /@φη1I³ΑXCό­/‰š’0<ίφe:NݍρX“Ϊ.žϊΛϊ&₯ΐ;F± ­ΈΒo'ΐ™‘%λjΧP9@g)z<ΌΡΏ«7Έq6nε?όVw1G!0žu1Φ€φ£xŎ‚?wGŎ6λR*I]ˆ5‰X3S:$_h)Ώ‘ϊt₯k^–ΐ }|£7£h^“„΅z-ά4ChΫΣ±Δ™­,ΐZ/·…σΧq³(©Q[%MΨ2MΒΤPMl703̚.σI—bγq»lΐhβ>Φ;{σ›ν(,‹dA +“+ +]άRZσΎΫ9ΐVb*jΔuΪΣΜ™OCΟBW΅CΔ9fπ¬Λ¨(9£–UE—;NΌΕΜζhd_в­[ΫΤΫRm]4‹‘[«·C%)Œšk¦bSΝiΊ“λ8E +nϋ,†έMιΊΆ‰•Jx~’yQ(Cί΅σ|NG―!KŽDš5Υ©>E­<€ΠaΗ™|y/Ύνξ΄εSρTθΤ΄αΌχψϊν§4-Ν83ڍ&¨ΣΏΫōӀ£‡ζv“ήMy€m©²TΦ¦EblΎ€’ ZΤ•ϋΨ[ό)ΆΕPΗUP"ϊ¬a-vKΉΗΒ°mj5[ΗΫMΥ?Χe Ά.“P₯ί”¨‰ΞσNpώ4³B»@*Rζωœ—¬Ζ»p`œ,ΆNΒANAˆ΄{Τrτ7κG” ΛL3_"XlRY£ι8ζWmΑt!ρ9Σ¬F©AƒP⁠©Τ>KΕ OΚ©1 +O±RςΔ’(6‰·f_>ψ―F‡§YK&ŠζΩΖjΦ­\Ί\˜›£jTΡ€‰Ά*νŠ|Gʘ.ξΤ·Ρα'‹m(ΐ8$ο-~7ύwΡ««€’hhΑ΅c<[RK©κε¬HΊ―15ΐ 7ΝFθΙbC΅‘•• ηϋ–Ϋ›μωl-ΈŽΓqΠΆΓJ΄YΪnœΥνSί‘\i†:œυJ›Λ ~εN~ιΤ‰˜ΘΟ‘i(~ΛK«b‰±0’“J\Τυ  hmΣhÏԽTIχšBΠˆ·xψG‡Κ.TΧs¬ΛΚώ°Qκβ7δPͺ‘ΰό]ώ©t/ύΉZ’l–Τc8δΝΞ*ŒύHY₯°K +…3œφύΈ5½oέβCΕΞ2Ύμu,›ŽλŠeλ½€d¨ ƒυlŠί Υ]_χ΅ώ¦ΡΎ°*p§)b’ΨRd7ׁFhΎSRόφμx ΕΦρXQŒ ¦‹o-‰ˆ°Δ +.CX‰jΠ]ψwV—‡ΏKqώ"ϊͺΡΡL«…*Α}mΞ‚Ε†hΓιmMΟ¦0Iψ»eJΕYRišΣΚ ,”qΈΒU”’‚?)“Θφϋ{Ώ FϋwUΊH9m¨Μ†R>ivqŽ e³5{—nTΆ62Ϋ<~υΨž« f߁έm˜¨ˆ„ίλπ˜’'6i„O?Ί―„T–VRiˆ0EΏŸ¬j +tΪ[N8[—Ϋ’&†Y―tμΥzλ¨K‰%mFωΑgΣ†jq=*τΫ(ψ~ͺJQ'°Άέ”±x KΕG!1†ˆχ«*0m¨π€ΣΝ9σ*vχHŸΝ:VB`Ϊτ ΧϋΈ)ΰνΰΩω,9¦ NˆNOQΞjήνLo +μΡ© ›Ε}lσuXt}uR\«§ΔbOώoΟD=gh½ΫzS;8ˆ>ϊŽΨrθΛ?‚«MΕ.J3ΰΤvœ—œ+ΐd1Α₯”Εg[jζŠΡΗi3~ygΣxΨƍη5ZΡPoύ@UMk³*…p%Κv&ό”Ȑ ψΘηώ,=$Ώ,…\P΄τΦ6ωlRYVλ«ΩzJ,$j Œ,¬T{ΛΘŠ=n>P―γTύMBIφ,ο¦ΒŠοT΅dxζ_ΰΩ-V‘¦§ΏœΡΛj~PL™Mι:NQS‹__+¨ΙΎRΏiΜ‘ΰηπ°γ–‚¦—ήFΆMJ”M₯Χ…g[ͺ +‡GT«%ΝT©₯0Σ­΄‰g“zsγ€ՎΓ5…[)…τ•Ίš—crυqƒΞζΫςzΏ­ΓÜjω α o”αEΛ4kΫP©»·Ϋνs–ςŒεJ,<€•ήiί}‘"GŽ”ρπ+ŸΕhΣ΅ωžΓšOuωš5(b±δP:ςη ͺ†oΞΠ|²ΣζΊ-dƒ;i*vo»Ώqs;e‚<„.0mš’Ώ†½ΝΟΒ7uΪ^θΐλ%bH·'ϊΘSiζίS&ͺ­ƒίa7Hm=PkšϊάΎΠh€>ή‘˜k΄Η .jr47ŽΫι©(_:Ϊ?lκc]u}Τυ“žκγ»xΗšΛτ9 =\-ΤlQ•Ύr»žκΓΆ¬'-₯cɊΚ=Σ/g&Ρ±’”RgŽoΉšέ nΓTC©Ϋ䊰«Έ ±mʘ½γ7Ρ‘$ωCΏnl6ΉΜ³bΧΪ}_Ϋ]ž ϊ\ͺͺ3βuŠΰ*°Ÿ₯ώτγYt1<&˜œ “Τ§’…υ{-U ˜£•6Κ'֚§4¨σdmΤV½ˆ†?Bωk»Ϋ3+΄P‡5•9ŒΨ$ͺ²0»Π:c4q3νkΒάΠγš²MN`Ή«h ͺ–`ž|#_©›ήΊ’νδ —B6J'ΩVPΚ\<Γ|γ« +°ηOk­›οΩ;e±άP{΅[λ¨κqόPζ32bvL Θ5¬‚cΑ¨¨ΫιΗ’ίXN*K(‹ε¦wθλm$qȟb³Ίς ΅ΚΦ-ΑΦ‘ΟΟι >.υ2wž2O%8ΛΡ.―6·’³nR½Λν<=Ξ¬λ Ο-?I΅›'½φˆ/άnœh%47©6JXkδ›νπ–£ΰ‡‚k¨οž+?XSΉ%ŸΫžδΡd‚‘χFZB#Κ/SΰG3Κδ»ρŠ0+K••N"œώR,—Χθ²m&γ U–TΚ8ƒύένWxU4œ¦cεZǝ5\Μ¬πˆεέξ°°‹6>0o€&"Υ‘°Ζ±{'±’ιΝ"Ή,Π›\ωv₯Z,‘ΙΑ{mgωk#6³V&θMKμΖ£Η‹δΫΛ\Έ@kX†ή“ς¦ύ,Λ@ iΕτ4,Ώπφ> xYΌίca†δ| 1ŸœζW^ ­γΘσΤΗ +χ0ŸΞD½u,­ —ζqΧቻ·η8εψΒ”\΄7½a_OζΑ³ΑPͺcΝ4Z1vyZώˍΐ7]I-έ‚™x ψαt‰΄X<ϋ†4AΕkΪΑΩf6π\fͺ[±ΗΚέeq„Sώaw‹Wφ2φ€”½aΦκB-δszm]§‰ΞΈm΄Κ#δ9]+ Λ¦’«.ψΙ_§gSΙ₯€›7)]Ό</2 §;΅λxcX …\>εφ7ΚnK-»΄μC‰aT*.TΤ8ƒΝb:Ήιψ―βœΡD¬AΞΊm₯ +Ž΄ ςΤύ^ΣΈ¬%bΘJ”Œ5YΤƒ>u]3(I©ΓΪŠΚ™Σ/Uƒ“Š_AͺeΝ«;™hRn†ςΫζ”p½JΕΫπΧIŠ₯’ ₯’N2ΥεP2ιΌΚ¨Β<ΠŒΕ—H*–L@…Μh;r•E…ΣhhΑ_ϊ\ιc8εt,ڌ +§υκΕS[Ωύςόz‚ΖτpVe&™n*SΊΙζ·εUN&œ>E–(Xg€ޞ”wx„Tƒ9€J;Ύž‚ΑF9ˆ!ŽτKz%†¦ˆ?ž•#,'oš7¨V*ˆ―όeq,b{t>³Gα6Σ:AεvΡzH±ru’Γ8X8Κtπ(ƒ?‰2΄Σρ»S†<_yΔ&N;Z:ΫŽA—yŽέŠ7[ΞΪ‚s-8QΦΗ³N-Ž : ωžς@£πμ7p‚j–±‘Ωӌ>q:Έ½HΟX„8ύ8V€$;S΄D €Ϋήm2xΥ½ξtηλ€Δq―΄&γ·3κ>™Wκ΄*V]λcΒΜΡ BƒŸΕΏ―ζ$Ωξμi©‘ϊ' (eΒβπ€’ΒGίΰKoχ1γGΝ’ ξεGθPŽτF#U…ρx[dι“ŸIμν°΄ζ™ΊEŽ‚|DΡΰJϋYς„ϊμSˆόJΏB' _‰~kbrmi³¦F" ρΥ—δΠβ`”νσDΡG‰²Ηςi½IΓ“ϋVy²€sλΥW²ξLL—HφNu½mR”Ζ(…Μ6)–MGcΕγœ{xu&½°x YίpξjΓΓ}ςO{mΛΈΐqϋaΗΡ’’Z懲dIF5GδΉθq΄²γΛHh€3<Ώ“Wα¬6C,€άε> bFΣ 39Ν^–ΙX7†œTV^ͺ‹ΰώ«9½nη…HΑžF™9¦}RΙ FΆžŽI₯Ϊ6‹%7Ό8•xέ'Œ·­¦#Rύo5'žήίVV +ZΞ—ώŒœ/yδΗy[ΔΆN$’vψG¨žF.DλΑ–“J£TΛ~VϋύΛsipΛH‘° %ΰrR-ω――|ρΊ‰ψ\t,σŠ_!ιœ‘\J(φ±t–zš£τvœfΫ[d½{Νd”₯Ι’7zF—#rC6=ύδ―Pn±CΩ΅A—λDͺ}NΆΒ»Šgr¨ΓL£dOJ±<©I—λτύΒΊ-‘dyšW†η€RR#΄FΏ~,ΊœΦˏέν¨FΉ£$Ί‡οIΌ'εUœ[E=-Φ}Vkh¦>¨4RάΜG ²ΎH5"ϊ†V—ˆM±}ΗI—CΕΚ!ˆΊ@ˆphΤ•b΅ †™‹΄Τb©˜š¬.μrϋEχΪΖWM‘K 4‘„j#ψeWqvΟΐΒ»E™ϋi‹’I—Γ­Nΐυ΄Ξ.”ΰυ’AΎ ΥΫςŸ‚.§a€Σμ4rΤΊ{Iaž{|ΤW{ϊ Λ±Ψ‘SΑΖΛ“κlͺ”IΜΔ₯fMΝσ@gCYαΓΎ9}©7akCŽYbύ\0‡ͺϋ)š‘Oυ†Α!z£v‚MCΙΙ›A8Vό»‘5Œzφ„’›n0#)FgIΝZ«θέWo"D2‚yΆυXp9sάλυΤ +>1Ιεάώj5˜ +δΑ$ο.ϊ؟š1ˆ™*CGTNΊY2H”„uR•ΈœΒŒDΟlu¬©I@ 졬”έ@θ —ό‘Ί δ8/χFηι5νΤά(Z'θ#ξε­\ŽΤyΎBυ°ΣJ‰Z$Kφ—γjq³I‰Nm즂Ά²[±D*²“ΩΣΪcŒ—S<ΝZΊlλpϊψ+¬arΤωHΤQ5ΰrςfϋEετDΗ~[LN!K~‰„ΔΉ'η”?ιΒμ•άŒ‘ηΓα­OvΒεt!f«(eˆ^ΥΝύ|R¨- Φ­wVωOΑ–;!~by(FΛτ―[ΙqDZ±jE7ŽΒ=2ρΙ²RL +ί²Ϊz2Ψ<Ρ0\ΉjYΤνΆΌαTͺ0 κΚ>7°Y5ΔΥI‰ΈΝΗ¬ -–†¦`oϋ/t‹VKRi‹ Α^ΪΆΆΝtΘpΌVν%ΆqFξ?<ΌΗuO +[ͺυb˜|9eόΩβ@ ƒκ5U8ΞTs©Ως’΄Ϊ ΐœf³6”$©‹Πΐ@>λ¬ι>i.[­Hrζd!Π7·›*ο•ΓΝ—wΖn—ΥjπPEa˜(Q#αE bΚV―Σ& )0‡zy #;₯σβDYΈŽΥ]ˆ7ϊλ3ψϊώ/sΥiρj1\Ž;q„ϋΗ=sgdφ­νXOΰ†o^w>0ƒ}³©§c3ρΙ5z{žΤ‰©ϊίφS”†ͺ؊šίαέ)dkλ1!ηfdΪI€mΜΪΓjoφVΜΏ+ΕδwY©ξΙ+ΦτTΒ'Υφδ‚jŽ‚Ώ²¬γSρ"X’NJΎ& Ψ$Cr }Kњͺ*OTηvθ*6ˆqDw‡-JTΊ+dΏ‹—"ισ‡cζ7e{K}ƒΜJ‘Ώ^„ηα‰cBζτΝ‰«’οαq¨1%d™Cϊ3Ν(„ °ίžiά'd‘ ΅\†ί"Ό€Ό€9Ψ! sz<€U sH™;ώΑ}D MΊ$PΠ„”€νΡ₯CžΒӍ¬k°Ϋq(©|ΝΫƒθ›gn©Γshž€³v\ξmΣω|-М–Ό–]ΉΆ‹θΒ0τ¨ έ²BWΰR»΅ΡδG±—λŸa»EνŽb•kνžtq§Y5ƒyhΒE„―Y±Δ`Ν±P¬§©Φš…’έΛzώΙK₯‹πΞjχb͝|Ύ—-1ΝψΤ"χ…~ΤQweOΩΤΓSεneΥv9ZBχΊ–υ·½³ή‹gmψ“%R4·…^ϊτIOυ4‚Ω•ϊJθuZŽ{›54gΉπ§΅³›#Οέωμ·KιŠαМ 9ω#,8~GuΑU«+³’%Φw‡ΥRMΠbKϊjή\U =¦24Yq*2ςx:Vpζ‹EIΘξ‘ήρφΎ£V=§rοΪ±ΜJΤΗβηιvuECΌn^ΫΒ/eBζδΉm‰h|ΰ2 hcπxπ=Pώ‘σΆ¦dK₯—›Cζd =Τ¨ι˜Œ>λ―,‹Ϋ>ήα‹υR«ΈΝŠ*α«[»³œbΟξ…r–΅i±ηŸΗNΠ.Ρ­ύcΝ/-ξ`’ͺW`_–ς§‹'+Zsœgw«9Š΅Σ“TξŒζ‘Κ³ϋ@Ξ‘`lίϋ΅˜s8(I'ΝβΆT+σΡΘWΤ›ηGc¨έΧZ’’;rϋ»rΖ`žπFΚ*BηhCbcΥ]·΄'^φανιLΉΆρΠTΒW݊˜[£$E—πήΨ(gσ^*5 Ο­oCvΗmΞotrSΟNΑq6·Wο·Δ('Ε―–ΉΝ”,– +'œ½B₯9†uŸκn>Ρ€•Β~όS€}ž'αЈ &NδKμ}Eoyš§•ƒΐ)‹λρFeKQ+τ@§,•*UEοZͺΡΓ ά8kΎp,¬€ξ+sk»½κΌFNeQ1μ©5lΤ]‘β]אŒ2μ=Ρ2‘œ‚‚Όcaιts²h‘I–’*±ˆ’K!š,χ ΟD{Ξ›ΈΏ›ΟΜ5’·ΕΊ¬^χδͺK±_Ω½ζ^ͺ’ΊvΎϊή”g¬–J|SwCΎuλι{ϊ€ψev‘9»XΩt=mwDϊΗ?±₯ΤΕ©[*Ύ‡fs΄DRR†Ω’Υ‘σS‰χΐZΜνԚŽ49¦2Ζ‚Υ™Z­ ±'*_žζ­~)…ΦΕ2A§bWλ,±΅]TCΨΫ­†Γ¬η^E©tτΦδΥZΖ([ΟΫΔ p‚Πωs/dTλR £uοϋιέ€o›uΩΖ¦­{Qλϊa­Γ©ζ«ΝΛ(σSmݜY<6SΌΡ/šσB%«ŒQΎ:υi)°’­ςR1~t$ŒΏ³τȊU/zŒ΅E―γ:KA'ŒBΎ\4ξΕBΑ We9°Υ<–X?‹|oXBrΰΥ`vвη9—Gξ αz_Ήyb8)€ΘΫv½•£[eqDTθθˆQ₯€Iͺsv₯YγΈ½ƒΚbΩi™kν7'«²ˆΗ\Φ δςœ±‰=WMΥ•αΛBU5ΠΝq)eΑμL½-Φ–BG4©Pgξσ1ΫΓ¦-vfG†‘ε@τθιΘςb21φVOΌΎ ΩIυΎn]ιΥf‘­94μ“Ώ©m’ϋ―T+ μFqβΓ³¦Œέ3Ψ΅IΑΏΪ͎ξ4˜OJ‘g;άή7”~ΊwΜtYˆάχ{xͺ!ͺwnθ€9©Ο!™ακ}¬cE +**S΅†!IngrΟ&ž=Ϊz.› r:ΫEΗBέclνβ½PHΖ©[τΪNι%δi3Ώy›%oΕn [ϋΫVnΓšϊ6Κ!%zέKxBQιl™KΜPkσ.@"B±Φ Znλ|ήΛpαŠ|©ζ·pnF»Ž‘`#ιΞ­'Oˆ@:θpΑϊΊ°P"@‘l?Οƒ¨ο2“RKκj­0CΉGυ™±Ž>|d”>kψ_=ž€R½δn‚μtxϋ„υ…cIL'έf‘N†kμμ±Η=7S!0ΉlKΛ½)ά—Ω‹>TβsGœΰ΄ΔcitΦέ^Bxΰ¨Ό΄Θœ«œš Is —uΪ:RžοΩi₯dΰ‘ξ±+œ΅$ΌΝεT’Mnxy­w’VI4¬S +*E/w¬]pw=nŠΝ=οΩ0cx{=΅.±oQχυ“dΠ}ΤΖ±C ―΅b0΄Ζ׎–o=ΗNOς +£ηp|Ÿ4ndϊΧME(–πίNQAπ§uχž†!φ‘±z«ΫPμϋmήΠ>T’=/o%JBΖdβΚnSΓ;©d5Jˆ•#CΝΚ`U΄Κ|λh{9·Sφ Q™+•Α²P iΏηŒ;eΡY€‘V¨έήNcαo‡šπvRΘ3›x»χψs‘ed5HŸx»¦ύ„·k΅eΌ]£οjΖΫ΅pNΌJΒΫ5£?ρvM©2 o'%γν€ΌρvBΪfΌ]«χήξλζ~ƒ·krB$Ό]“Y•πv­Υ7ή1ανPvΌ]‹>} o'5γν€dΌ”7ή©N#αν˜vΌέϋQώ⏺)Αώ…·“šρvl—πv WΗήNbΖΫIΙx»¦ϋx»JˆoWɏܰu‚ΏρvΒ/gΌζȌ·ϋzΖ”Ix;©τό˜x;”„·«κSχ‰·“Θbnβν€dΌΚ oWU!―ΰν„AΟx»ͺ,‘OΌ]UO?šή +uΒΫ-eΗΫmͺ‡εκ„MΆŽqΰ…·Σ@“ρv•¦ΧcΓΫmΚΒΫm’ανψI;ή*«κ…·“šρv(νΪπvμωΒΫIΝx» +fΗΫU:_~βνj«x;Aΐ3ήnS6ΌέRo§3dΌ¬Ί7ή + ’πvUF_ΒΫ-eΗΫmͺγνͺό2 o'fψ oWΙφίρvUάή’Nϋ‰·«Šk%Ό]UUΒΫΥ'ϊγμx»ϊτΌ]UK’„·kΗρ ήNjΖΫ5Z+οx»FχκΌΔŒ·CIx;”ήώΨρvυy>πvο‘2¦KZDΌπvϊn2ήNΩEo‡;γ…·“šρvtvJx;\-/Ό9`ގύގcΏπvz‘2ޏUΒΫρA|βν¨šJx;

πvtyανPή%ανΪYΏΑΫIΝx;θY o'卷ӡeΌ0ξ„·³wεo'\VΒΫν{ΗΫmΚ΅ΪTχΒ‹γρvΊˆ7ήΡζβHΫ=x»₯μx»©NΌ]£,eΗΫ=αντdΌVήnώ™πvK Ό”ρvrήΎρvŠsdΌγZΒΫYk’Ό]ŒήNJΖΫ1gΌπvΈ1ήNJΖΫΩ6x;ύwΖΫΙqρvmίx;†Θ„·£?SΒΫmΚ†·[jΰν½½VΖζΰ1Ύ‘Ϋq!‰ngΑF·£'έΞĝnΗ~‰nΗ±_t;‚ƒ‰n§%Σν–²Σν–t»ΖR}£Ϋa}νx ;ݎΘ]’ΫΙ|Σνhd•θvTό&Ίj…ίt;Vp‰n§eT¦Ϋ-% ‘NΊ]SfO’Ϋ΅r~C·kΗψ Ϋ΅#r•ƒnםθv•΄θnWq•|Πν*½ 6Ί]UQ’ΫΙN}ΡνέΞ”ngΚ'έNj¦Ϋ‘$ΊΚ‹nW Ht;)‰n'αE·ϋ²”?θvU-¬έΆλΊ]ή\A·“ιv¬Ρ^t;©™ngΚN·cOΌA;έΚJIt»ͺi6ΡνδΌ~Σν΄¨Ιt» +«i§ΫmΚF·[jΠνj$qMΊ]庝ޖL·ϋz>θv_Χτ έNj¦ΫIΙt»JyΕ'έNj’ΫIHt;ΆxΡν*ψvΊ]ηέΚ7σ’ΫUVΡέNB¦Ϋ}ψίΠνPݎ=wΊΗ~Ρν*+žnχefΊέvΊέƒnW™έvΊ]½ϋ›nWŸ–ιvRvΊ]ό½ΣνB Ί]%œ·Σνͺ ¦έ*Χ"Ρνμζνt»MΩθvK Ί]όΰ ΫρK^t;ΤD·“’ιvRήt»ϊ΄ΊJ’Ϋ‘ΌθvR3έN›ιvυŽLϋn7ꡝςέn);έn©A·³3μt;­Ύίt;Ή”3έ§i’ΫΙ§ω¦ΫΙχΉΣνπ™&ΊέRvΊέRnΧΔ‚ήιvςrΌιvR3έNJ¦ΫΥΩ‰l§ΫIΝt;”D·cΟέ>υƒn§›˜ιvKΩιvSt;}‰nWΗψ†nΗ4œθvr eΊέRέnjK₯ψg¦Ϋi |ΣνxλέNŸ[¦ΫΙϋ¦ΫIΝt;”D·cΟέ5Ρν*©B;έNΚ›n§kΛt»ͺa’ΫM%Ρν–t»:ΊqoΊόz™n'Οw’ΫU9^t;©™nW{„‚n'Gε‹n§ΝvΊήΜD·«³AώN·«5Ÿηv΅}Πν–²Σν6Υιvς²fΊ]e¬ύ ΫOt;)Ζ€ΊΚ‹n‡šθv+Ρνψ™/Ί‚™n'Ÿ?Vχ€ΫmΚ’Ϋm’Ρν*€e'ω›nW•>•θv΅=t;₯ ΌιvRίt;Ο`΅α0ΑδLt»©$ΊέRƒnWΥ.ΡνκίΠν4ogΊ–™n7•D·[jΠν4hgΊ\΄/Ί"|™n'oU¦ΫΙ5ς¦ΫΙ—ιvΪσM·Σ’/Σν΄>Νt;uώ€ΫQ3šθvΦφi§Ϋ-e§Ϋ-Υιv–‘»ΡνhFύ’ΫQ1šθvt°Ot»·7;όά–nΧf}ζN·kεό Ϋ±]’ΫIyΣνšκϋݎFZ‰n§›¦Ϋ‘φΊΰv¬ϋάΞ–κŸp;že‚ΫIIp;\r/Έ^‘ ·“Ο%Γνύ?ΰv8Xά—~‚ΫΡRη·#‘qƒΫΙΫ“αv4δxΑν,Θ±ΑνΨl‡Ϋα!ΑνPwΈž—·Γ·ϋ‚ΫζHp;KιΫΰvzύήp;ƒgμp;z‡'Έ5۟p;ΘO]l;ς‡wΆ]#ΎόΙΆ£%~bΫρ‹ێvI/Ά ™ێΨCbΫY”ρ“m‡“.±νPΫΞbŸl;ZΓ'Ά΅»ίΩvΊ=oΆ—ΔΆ£Α^bΫɍρfΫΙ‹”Ωv <ێvL/Ά‘ΧΔΆ#h΄³ν4JΎΩvςΜfΆΌŽΫNjfΫͺKl;^l;rΫΞ²vΆΚ52ڎIBΫι"ڎ`ί m'IFΫ5R΄w΄]†τ‰Ά³‘rGΫ1œ&΄έ{ Ž1όCΫYdβm§Ρ,‘νΪ€§ΪΞΊ†e΄΄ŒΆ“’Ρv(/΄jBΫ‘$΄сO΄ήϊ„ΆS( £ν4¨ΏΡvΨ3ڎi)‘ν4ΤΏΡvL mΧ¨έήΡv(/΄]£©α†ΆCHh;v|‘νdΔd΄.?£νޏς—?πu‘}ϋFΫI½ΖΉ‘ν°ƒ{ίΠvR€S$΄*vk νPڎcQ“Ό£ν°—ΪNω1 m'‡ηm'σ6£ν*ŎΆSrυeίΡvR ύmGPBΫ±>δ„ΆCMh;ΞpDιΆCϊΊ*οl;%’dΆ­ο”l»zΆ7ΫNΩ$™mWIφΪΨvU­ΫNŽόΜΆ«ΉŸl;­ήl» +’dgΫαMl;\¬/Ά]₯`gΫΥIΞΆ/ΆލĢ“’Ωv(Ÿl;‰™m‡²±νμ@Ÿl;]WbΫιv%ΆˆΫ’ϋ³³νπ8ξl»ͺxμ'ΫNϋeΆžFfΫΙYϋfΫΙυΩvΌ;ΫNρŒ7Ϋ*ššΨvςeΆ]½Ϊ7l;½a™m§ceΆ]U˜ϊΕΆΣ•dΆώ§ΔΆΣ9ίl;ԝm‡Ψv•δΰΔΆ«WΛl;»[;Ϋ’όΙΆΣ…fΆrπ°ͺƒmχ"ΘωΊͺJυΕΆ«ΰΎϋΖΆ«Bξ%ΆΆy³νPΫ–Θν ΆbΒ‰mWωžκΖΆCIl»ΚΧuΤ‰mWαΟοl» +Ολ\l»ZΩvUFΥΞΆ«U>ΩvŒΙ‰mW»οl» +rι“m§Α―ucΫ‘€|·m§·£ygΫαLl» +ͺbll;]μ›m§)%³ν)Ξl;Ř_l;2vΆφΛl;YRoΆ~@fΫUμΔΆΠv•_h;Υie΄ƒwBΫΥZήh;Δ„ΆC±œFGΫI!k&‘ν€f΄.5£ν€άΦ9i«kQ©YBΫ–je‘ν¨Τz‘νŠz$΄]!5Έoh»ςάί νΎNύΆ«ΚHIh»ͺ|άΌ;Ϊ՘˜„’ΒO™h»J7ΒγmWιήΎ£ν€P­4Ρv¦|’νΨχ] νͺBrZΉN΄]™©Κ;ΪNN m§Ϊ&ΪN΄ΚΤήh;•ͺe΄]%SzGΫiš£ν¬oGΫιfg΄Άy£ν*€wΉmW£ΣμDΫΙz£νΘ4ΨΠvUοCBΫU:’ν4#e΄AΏ„Ά3«ϋmW‘8Ρv2Ωίh»J σm§‘ £νκœΡŽΆΛ*ώ˜΅DŽΆ«‘S–Πv¨ mWΗσΆCy‘ν€f΄β©m'卢«΄œάΡvd"$΄ ‚7Ϊ5‘ν€$΄„Ϊ΄nGΫΰNh;)o΄]₯ΘŽΆ“’Ρv2qήh»ͺ±dGΫ) +•ΠvΚt{‘ν¨kKh;₯ d΄ίh;…‰2ΪnE)m§tξ7ΪαBέΡv(ήΊŒ‡?ΙvΩNΒFΆΣŸo²Ή„‰l‡)‘ν3y“ν€f²Π“DΆ“ς&ΫIΝd;ξa"Ϋ‘|’νa؍l§ΐ^&Ϋ5ΈΌ™lGϊc"ΫUZ\νd;ς"^d»J,`'ΫiΟLΆk”4’νZ©d;•6f²Jίd»)w'ΫiΟLΆk’~’νš‰l§žΙvΚϋ|‘νΪqνLΩΙviΗIΆCMd;)™l'εMΆk³™VνΪQ>ΘvϊFίd;Pَ«Hd»Œω“lG‘ηNΆ£ς ‘νTυω"ΫiΘd; ;™l§<Ί7َ₯N"ΫΥ( šd»ΆΊΊmd;FžDΆΣ—šΙv’ΌΘv¨;ΩNB"ΫIx‘ν¨6Id;bί‰l‡ςIΆS•A&Ϋ)γ?“νgΎΘvζ·ίΙv”G%²]ƒ―υIΆ£ g"ΫΝ>ΞAΆ£^θEΆΓ Kd;™a™lgπδO²–w²±hv²]ΊυIΆ#k>‘ν(CJd;φEΆ³ ΰNΆ3dΔNΆcΟَ.2‰lG‰B"Ϋ΅φ$²8‹DΆ£Ξ&‘νΪ‰/;َ=Ωα)άΘvψω'ΩN’Ιv Λm'Ϋθώ$ΫΙm•Ιv”G$²Q±>Ιvdα'²."“νδ|x“ν $²τ‘lG-Ϊ‹lg₯m;ΩΧP"ΫΡ²θEΆ“Ί“ν¨ΡJd;”O²ατlgA·lG‘Κ'ΩN?;‘ντ=$²B΄/²έDvO²”ΙvΊ‚7ΩΞΤO²\;ΩNοy&ΫQŸψ"Ϋ‘yίλΫΡ yΫY]ίΨΡΦxΫρTΨoΫ l§o!ƒνdθe°†ξ7؎€l§TΦ ΆΣ<Ϋ)λ)ƒν”υτΫ5Rψw°‚Β l§Mή`;ΩΒl§εVΫ)―σ ΆSFbΫΙ³“ΑvΤaΏΐv +de°ΎŠΆ{{±HωΏΨΗμ lGCΫρ{w°Β lΧ¨ίΐv4K`;•9½ΑvR3Ψ%νl›O°ΗK`;)l'ε ΆkύY`;ϊ&°Ζγ7Ψ‘‹½ƒν4.d°AσΨNίTΫαMK`;ό#^9ŸF†Δ΅#Ω%qνψ]/jβΪ‘$ΗϊδΪ©τ)sν@™%γΤ‹kG_6kμΫ±šΧn);GmSέcΐΈ[F¬½@Γˍk§Ρ5qνta™kGϋοObβΪ‘$N§ΧGlβΪΙŸΉvRή\;}™kg^ιk· Χn©Α΅S'ΌΜ΅S,‘YΩζΖ΅£σ³4V8°k·)ϋγ˜j`νŒmPΦ¨wpΓΪa_c”Φ+cΗΪ‘Ž±aνP°ιkG₯ϋύd¬’e†9ΦD ξΐΪњXΦȎ΅ΣΫd~ΓΐΪι9f¬υ§ύΔΪΡcν”B“±vZΛe¬=δ^X;©k'%cνXέ}`νθ䘰vI±ΜWνχΒΪYΠ k§‚τ„΅“ώk§•PΖΪIΙX»MΩ°v¦ξX;έՌ΅£ηΚ kGzQΒΪ΅Φ?°vκ½ύΖΪIΝX;zt'¬ +ΘίX;© k'!cνΨδ…΅£-MΒΪ)j—±vΚΰycν€f¬”Œ΅“ςΖΪ‘&¬{&¬Gaντ2Φ‘q°cνP^X»΅]`νσΫΒΪΡpύkΧδΓί°vR2Φn);Φn©΅Σ0cνθυπ‰΅S’OΖΪq³v¬έ6¬έk'χ֎΅kŸΨ±vˆΦ•#cν΄Ζ~aν$&¬BΒΪ‘Ό°v:|ΖΪ΅>°vZόΏ°vk„ž›Υρ΅[ʎ΅[j`νμ k§΅ψk§τ§Œ΅ΓY»cνδπ~cνδGΞX;œ΅ k·”kgꎡ#ύ4aνšΚ9^X;©k'%aν^X;© k‡°vμψΒΪιI&¬ξbΖΪ-eΓΪ-1°vΔτΦΙt{aνlφέ±vdzξX»%μX»M ο€ς©ΦNƒΰkΗ[—°v"2ΦN>γΦNbΒΪ!$¬ϋ½°v¨ k'%cν€Ό±vΊ² kG±όŽ΅[Ž΅3uΗΪ‘€š°vxν^X;ε„d¬ύ€֎Ί­O¬xΦN&GΖΪι7Ό±vΪ.aνπ|κa­Ž,«ՎκΊD΅£ΰ Qν6e£Ϊ-5¨v€φ$ͺη|Qνλ'ͺgΥεE΅Cέ©v*Qνf2Y’ΪQl‘¨vdC%ͺέ¦lT»₯Υ­–Σκθζϋ’Ϊ‘c–¨v„ϊՎVρ/ͺκ‹jGΉάF΅ΓΚLT»₯μT»₯ΥN9~‰j§Q%QνHΟ ͺ™jgΚ'Υn©A΅£'c’Ϊiiς¦ΪΥq}Pν”p”©v”㽨vςJdͺ•Ό/ͺ*Β2ΥNNΈL΅Sͺ›j'i¦Ϊ©N&Qν¦°Sν¦T;Ueͺ +XίT;ͺ¬vͺ]Uέ\’Ϊ½]Φ€Cό?Sνώ9T»‘f"^šP»Γ‡ͺl½DHŽδΧ£%’¬£§”΄£ˆ—›Ή*Ϊ<κyv"uQ\8;hίO[4;Άθ}‡ΩιH'«b‡ΩώΎϋbΩιΥ*£e”έ­μ―žΒ©’Ρ³βνσδ`ΕΪG¦ΨiρΛٝa§’‹Ζ‡`;ΒcOΝ;ΪŽ{μT,~Μ];ΎNΎ›F―ΣλTώ[ϋF―²gœ#Γλ$Φq/v ^ΊNΗι΅μδ:Ϊŝcλ:έN―`©[ΗqΦ[Η²πh“Z§n$€Ή΄n +; -Δ…¬±/’'«B ;±Nέ₯”Α»ΆννΟΦ‰{3λ$–z/^έ³-\"΅•L«SΖ’§7[‡K«αg‘κT…ί+“κ%½Οkκ«ί…©‹ΏwHέΤQ'D#"Θs +Π~lΤъςΨψtΗΣω†Ewψ—$:-φK»?@tδhˆNΑί +ΒͺύΪ(t5>œ€Π)Τ9u BΧ4 ^ƒNnΘσΪtΤ)–lD}Q Γ·«™&ΈrMυ%%ΣηπωΧMΌ΄šΠ”λμΉAίι΄œγ„Γ―ŒEž£Ηφ]xξ5DΖle)SEv‰½*w¨¬ž{άΉ"“ω)ΟδΞ:’Ž;W,A»,μŠ΅cqμ\!mΉ>;W,cωZΨ9)_St[Ψ9)_«΄š±sε€:γYΨΉ"ί\‡΅ιΨΉ―S9<-cηŠZ…‘–αΤΉ"³ηluQηΚE₯q‚Ξ‘iˆžΠ9Ύυ ΞIωΊkW¦ΞIύz$Χ’ΞI©½_‹:'εΛT2u\€.ά‹:Wθ‘t-θάϋ9ώΟYΙοϊBtNj?ŽgAη؎c@η€TΌΆ;uNκΧώ^Τ9)Η9Κ’Ξ}½‚ςDœ™;W@κmΨΉBώbίxrE‘ΪۏĝS2™`!ͺGέΙ:Φ©s—†π«eθœΪΕ=χXΜ9ϊΗaNƒΓEζ™‘sδη_uη΄rγ^ΐΉ‹¨Π“ysͺY8΄jtܜB‰Χ9mNΉ;w 6§ΞŒε΄<-œΐβξ•ΓcT»Oa'Ν-ΡeΨπt–p~άh6M$ΜάGb,‘ήΣ—‡u ‹1·4CΜιwπVbξΒΓpH„9*έ2€©W”Π|+Κμ΄ΧΌγεΈœKGp,Ά2ƜR’έ₯ '3_ψ3'Λ‘‚PΜιƒίi WnЁ•ΣZ²γΪuZ·cxΥυEyΑ!ͺMάIΓ‘rSΨ‰rKt άCqxτήωϊuΙ€μgηΙ‘cΘ…;ςhα^·[€F{ερ~”“+Š&-&WŠβ¬§­‰Y―—:lŠM09©˜N&Wδ+=δ ˜\id Xo½ ““Ϊmι}ψ +•ΊΓJxS Ν’849©χα qiΡ€ΒG49r–·n§… C·,QJ…4Κά—… *½Gΐ˜•λrΩXΆΑδ* ξΛX09ετΤζε!VΊ/[ ]w†ΙUZ‘•{Αδh₯ΔS˜-—nοq9ar¨1bZΛνY}œ₯b΅Vk%γ䴐ύ²{ž…“ΣͺωζNNρΩλr/ŊεΛ57†9B©Ԟ_λόΎ†V»g‰‚'Η2yT« 1 η“&ΗίΕ+5'Mυ8’Εͺ S)ZLœg<989ύt–g'§‹zιeΏ‘μ8Ή%NN+ϊΓ*0qE~AΦ-;NPβΠφνθšΦMEs•L“Σf_–Ζ½hr°‹™ηƒεz`§m49ΈΔτΕ U7Γ–kA“[ΚN“›κ€ΙΡ¦1;%X‹ά’irePϋlΫ‰-Ϋωcδ–²Σδ–4Ή’υ§ΥΩ9'N8ι/KͺύH<9]Ιu<wΐ;ΌmT =:-WΏvžͺMtΞ“C9œ;G΄ͺΨ λδΈs>ΞΣά“''₯ξΝyrRξONΧΦ«ΓYαΙΏΎ›M€€βμe9Ÿ₯Ψ½UD§žΫvࡇΝCloΚΖ‘ΪTχ œ}9dΡF5ό½υρδΙ*NŸgΫξ©ΆΜ›<Ή₯μ<Ή©Nž\‘DJpβΰŒΧ±‘γβEΐ’ž›ΚB·γδζŸ '·ΤΐΙι8v£'`όΧφgΖΙ9!ϊκΓω:Χ½prΦHθJ49/.ς₯ΐa^›n=ψ;9θku6“ϋπ|žE““ςΧX49ΆΉΖH499";ΣSΠδΤCιQζβ€Δ©₯₯‡;L‚€ͺ}ίμτ'0ΉMΩ`rK ˜\%β*»"hr:ε¨₯fšΒ§49)§ά[A“£ύσŽ“3΅Ž…“cG:ΤNΞ~%—΅αδ41™Q89MΎfNn);Nn©“«,ΌGžuš.’ΓΎαδx"—α.‹Y0prj‡u1Οξ89šGέ½,œœ†‹γΡ˜Έ"W#ίqr¬Ν*Ο2ΆQ¨Fk*VΚSIΓ@¨'W”Qƒγ-prH¨;NΘ&Λfβδ +­Ž1'W Σά3NNΖ^±20Εάm‘γp©—K±Ηπ|&ZαqšΧzMNš ₯“C`~𠑇ΰ(u6» ¨9INXΪΙI(d­l9 oO7ά™&Jj·ρέ(rΊT»% "G}ΣSC3ϋ¨ !wΕR{'ΘϊκANΡ±ϊΘΙΔΤ[•ψq—Rg/Δ½θqΪ ΞS9@?ϋbΗiF½κ΅Πq7έ-žL޳¬οō‚$Z`γ–°Qγ¦Π8%ξΰPf\9ΊΝ;2No«τ‰Œ+*%~ΐ592(_ίlBΖ’όG[Θ8)M₯‰Œ+”.xβςl/υKΩΑqK tœ–k£•E„+J@HŠέeχΠΣ.Άγήe‘γ6e#Η-5ΘqΕRpΛ$Ηρ{ +5¬9υe‘γ€ΰpœδ8);Ά“γ€2NrΚ}\‹‡"+;‘γ€bAOrœ.φΦ86‰p…Δ—gcΔΩΟτ1ym§ζOr‚·”·Τ ΗΩΖΖ‰ΣJ»πΥμδΈΒTήφνδω4χσX~I©†ό—ζ!utŽΟAΣGΗ-eGΗ-ΥΠqEE$Ε=²Κ‘’Oƒ©5‘γ€ή<Ή@ΗIωzOϋBΗ‘@ΪΡqRmόtΚ}χ…ŽcΟϋy2:hΔ€U\ γtm₯θΈ₯μθΈ©Ntœ>ЦΙd2αJ‘(#£γlΚ₯ΉΊ«ΎωΎΘqSXฐ&π‰ΆW”§Ρp4b^6ŽWŽπγάN)wYΤ8yoΏξmΙΤ8©_Ώͺ,jΚι9Z5³g9Z¦Ζ‘^Χ³¨qR.a“'eΑ‹SwΜ» G―Κη\ΌΈ1̝8k9ί3-N-ΫνuQ-ήπ©ΞŠ›ΒŽŠ[’“βδλcqβ΄n{+aβwf JœbŽc,HάuΉ΄3β$r“§γ0!Žόn‡M@άΥ•΅ήN\Ώβ…™ΔΑ–°θpK38αžE|SŠϊφ'vΧαΓsˆΰΘ7&œrxWv$=ΉzΟD8΅₯h₯. œΖ‘Jυ—σΰBH8Έ) N{Ύœ(΅ΠXρτgδβ ΝΕEβΪ{fΒ„ΑM%Αΰ–08 ÝQ7`pr±ΪΩ`pŠ»™_-`pr6΅ N^/3³fœX{; Nώ•V=σžN…κεϋ΅bΫΨojΙΫεXM48J-ΝψŠνθ•DˆΣΰ–²Σΰ–κ48jξΫ’τ.Wf]U’ΑQhyΡ΄!o!†h™4Έ·;:Υ–W¬¬±g\ιαf \±Ξrχ’ΑI!Ί–hpE!ξA•›Σΰ΄Ά½ΜTwœnΏ'Ώl48T&ϋΐΑI±€Iΰΰ +eΠγΞ88'#fΰΰ€τΗQ~…δΑkΟ88½E€R P1Hγ4§ΑΙUkζοŽƒ“kοkΐΏNM΄kwψ 8Έͺ^Ο32N^δf'88ωkpLNœ\ψŒZ1@ΰOnΫμvΰ +}O•Χ¬t„ƒCUΨdςΰpά~$ΐdRp<'‘ +³“gΙp£L\Υ€«eyβΑA¨Πτ8ΈJsώr-΅Ξr{ξ88`&N…ΣC~ςΰΑUΏWΟ<8•Rό<8~=#§ΫŒΙ±Σΰ$6ŠΌ'Oχ„ΑΡκ}=Γΰp²iυ=ap(υΉ Ew-Αΰ€>άκ€ΑQΞ}£ΘΞωΨ(–`pς[ΕΟYp`-ΏΪYpb ~πwfΑ©Ξ’/|²ΰ@_#,8έW„; +Nn0Φ +Wι€rCGΑi$œ—Pp…Oΰj '_YQ8/‘ΰ€’…2QpϊŠωc' +N +FDBΑIeΐ›(8-2& +E‰Η‰GxC/ ΰt$ΥM\¦pgΑ5§δ +\!±Ή^‹§!‘V; +ΞΖΙΎHp ₯6T8 ξ=ΗψύΗ‘ΰ,¦p\™§l …F‚+O„vƒWˆn(8‰ +rΠ‘4G‡TP{ƒ"Z3ÎY?& Ξ6³jΦφΣ»ΰNG·€wβv +Ώ‘ύ8IpΟΟqΫUM\1ΐΛυc’ΰ˜’pί NΓ4είHpκD;hyν-I^’΄sΰ”»t;cΰ$b¬Ny₯#-j<™'λΟa ΰ4Ÿ‡oLŸ»šΖΥ£g!¬£.ώ›ϊ]Ι šψ· `OΟτ7™ύyόMVΔγΐ6ςχ΄ΕρA~“& `‚ί.€ηΏ©ϊ³³ή™ω&/ΐsyΜ·OΊ^‹ω&D§~{‡Ύα—xžΆ oRpMθŠœŠ‰ϊV¬Τσ^Τ7”§Ά ΎΩ‘Žš©oΊ²/Ϋι\Ψ7έ1’q}Γ—`‡ή°oςετΗ!r`ίp^$΄φ­¨ΤΦ– ϋ¦ύHκ›ž‡%χυνy|ΎCίΤQ°Υg1ίτBh­Θ7ΟVϋρ€k-’ψ¦‰ŠτΜΰ½=1΄μΈ7MΉνκ‹φ¦Ξϋ‘Jž°Vω»7Φ½•ŸΊPoτ¦2)wΞΫNΗΌιo"AyαŠuΨ†yӊ‰›ζ”7nδ€Θήθž•?+ξξΘ⍖$AiΈ‹ςΘχGNΓύρfη»]Πβ.πnJτΎΟ0„ΎŒΌΎιm”Ψu¨@»Ι·mmQμ¦bΆαDηψ¨Η‡—₯ΕΑmJ +¬›"Δ,œ­gΨυΫ–›@έΰXQ—eL7βšΕ§fPε%+&1«TΖw*=n—ϊœ9•mςά”xΔ:͍ΖΓϊns“πTΒzɈΉ­PŒwFωWg±Fί1)ΞΊμΐ³™ @'·Ρ9njoΗΩγFΫojέ6Œ›8 ΉΖMω¨mP;η7εΒ}­;Ξ;ΗMA ³­‚γ&ηοM†Ypά +«³ώrΣΰΒς"@n…*J²αœδΖψC’ζNrS@―Χ$Ή9;―1Inκ7N«H›)·£xJάT‘z\–‘B_ΐΗVŸ δvΉ‰69n:$±‘ΐΈ)©“Ζa;ΕMυ)”&8Δν9,Kf2άδ?bτΫnχπό£ Έέz«Ζ­ Πό4Μδ· Ί£PβεU΅¬§·QIx:4/`ί³eωPΩΝι°ΫξΓ_žέf,q3ζXC B‘7ΥΉmj‹₯Υ¢ݞΉ9©mPΛKYΠ6XB²Ζvf›^ν£Φ…lS.ο ΓΝϋ•©Y£wf^›>ΖΗA‚΄τ5ό‚%AaŸ“)N‚ΑΦ|@Œ ’Q‚Υ¦-/Δd΅)Ά[qfXρΫ›ΎΫβηˆΜ„ ΅©>Ρ²Φ6ͺ­Y'«ΝΰΈηb΅u_6ο¨Ά>"1ΛIm…Ιn PΫιW™@mΙIN›„«Τ…i³d”–)m'Yϋ‚΄ΝΌ“Ρ¦.±±W¬lΤzžμέ ΄5ŒK€kεήΚΔgSO‹Σ[6?ΦqT}|¬Φ&Xά9Αٚ{8&›MΩύ²έπΞ)τΨκΘd6‰γΉ˜MLyε'—M½ΗΛsg,‡{AΩΤxΌRνL6„š‰lΪ‰*θ²)Ξu΄Ύxl +ΉžΓπ”Η·ΔOBc“irΪΟw›₯Kν(6½rχm-› ΉA½‰΅FgΌμΝ|•‰ΓF]ΩX6A5·O[£—rΟ 6ˆδPKΑfMQϋ"°ΙΗΐ›Ώ؈Ϋσ!9­Θ‰D‚DΨ +½Αωd6›ζ†€I`#€Φibη6³€ϋ‚ ίYMζ³Εͺw›vΆ0kΨτy›©ΆR|RMΆ¬κs6εZΆYX ΐ†Κˆ6=² `“bΗΐ&υ2l†Ψ +™Ο½lR¬šj°iν½έ ΐF@ί"WήΛW39)½ ΐ†ͺχ`Ψ€p6 _χιL6‰§Γ9€0qίψkŜ–-σΧ +ε[c,ώšχ-yIΆΙ= …lό΅’α‚ ‹σΧψ±wΚωkJ kT9lό5κ»ϋ\ό5Εή-Φό΅B'9ΚvώšB3=’ψφV\ ψk…$πϋΞό΅BϋκV …ΨAΨΨ“Zٝΐ&·ΜD°IΑj0›ώΌ(ΒΫlJ_τp ΎR\ΑV¨ΙoΏ!Ψ€’$8l…ΞWž‚KDJι6‰Lζ`γ&βςŠRIw[!Μ©Πl +¦έ•ςc°ΰ±½μ6Η5€Mo‰εž€μbu;€­ΰ|―}Ψ΄§εB€­P&E—Μ ΐVϊi‘ `S‘ή‘ `+<=­kw[ηΪο`Ӟ6ω€­¦gT™ΐVHEΣέ›~ω\;Μ¦ΐX“ύΉΨ$RV2 l¦τ`KϋM*†KΨ€œrML[1ξڝlΕΪ>Υ`+Νν’ `ΣGjΗΪl€lΪψν6„Ϋl…₯{ΈΨ(y$Ύι6’υq5€MυGσnI`Σ0@Vν°iά1o\Ψ”•fcώ`c…BwΨJ”ΡL[±ώc™ΏΖΘsΫ’¨™W©mΡΧ¨» yg§―‘R ψ5)υ<ΞΕ_“'vοi“ηηZΆbTŠ+Ψ”–?˜‘‚ΐ¦ωCκI`#‚ΘΓέ lζ.ΏοE`£¦ΘΊU9M3"†‰ΐFΓHb”A`³–ΓeLtvΖ”ΐ¦¨Uq“ΐ&ί;«ŸI`3ΖοΡ2Νxΐΐƒΐ†/ŸubΨ**KΙ6RΝω +ƒΐFε3Y،%ŒL`«φ΄Η"°‘Ψhγ6φ΄NMν(ΝΥ6ϊygƒΐFJ7_ΙN`+χ#\” P™B;'°)²b©%;=9gΨ +ž;2Tΐ&π²Ο¨MbΆJΨ*–Ϋ݁Ψ2oνŽ`S4’•6Υz˜6UF\ή@zΊ‘ΈώLz€ά±Ον£MΨT•`O|'°Uΰ.Γα«{mω}F`£|‹jθΐfΕ`uΨ*ΝbkΨ€ψ6›TKΒ4eMζωtΚνp·I`#€M… Ψ,Ϊ₯»6*;˜7›~wkυ\ 6}–„ΰ 6ΕFΝΦΨ!l—&)Ζ!l:FO0Ψt 6μ 6S3M‘vκ¦&ƒMoΊ-)‚ΑFQΉκ;ƒM‘b3˜ΒF;aλ[βΆΪά‡•0l +[γ„ΰ°ρlio6½ΒT!%›ΎΚό'‡MŸΩ&ΑaΣnσ}Κ5ςψΓ¦ΔP"έ“Γ¦ιވR†MωFγ8­ [ω^,Z71l²DH+˜6EdO«0w[‘OΦ—;‡M6±[‡M‹.s|‡Mq<ͺcv ›Fžœ>DMLΏ‘lW1«sΨδ†PΌ3ψk/'σιΑώWΐ―‘8P«6ρk$π–‡Jš_ŸγΧ†οΈfpj©Ifwώš^JΛ ώšŠέ'°E$₯6\7Α_CQξδ―Ω6ΓΛMfϊ3N + +’Ώ&Ŝ²Α_“Bšqβ―©Š…LθΗˏ&~Mƒ±ε νψ5Ν +fi~MC™‘³ώYιb€α%όš¬Ϊ€LόšRNΈωΏ¦ŒJσ4$0I“Λ]„Υ€η—ψk¨δΆ ₯]}ρΧ8VΏΟ `Sϋό1h€p‹πρΐΉj•ς[¨'b‰ΏVYLμό΅₯μΐ―MuώλwώŒ€OώZΕp>ΚΆUq^πΧθSMΧ…Ώ†Hϋˆΰ―‘œΞ˜ΕY+[!ρΧ€ZΪBπΧͺœ;T¦MŠζ€„_S[mjEƒΎ&&ˁ ―mΒF_[jΠΧΤξ&_Soϊ7|ώτ|Mέδ3|mSφg1Υ€―Yώ Ύ¦gρ‚―AHπ5υιΓΧP| e‡―IxΑΧ| D‚―IyΑΧτ*eψš"ΑΫIUƒ5aΩ(Onu‡£cm'‹8θk”*²4Ϊιk¨§“Υhέ)Εά–A_{ΏΏ;‘ό‹θkΈΧμεάθkrrScΧ +}ιcJd±E©_™ΎFΝΚ|Ύ†rάmΡΧΨSΞ­D_“Šχ2θkxP‡Χ±ZœC₯NψψwϊΗΫ€šSηΈ­!Ο€―)ΟΒϊδμτ5΅Ϋ`57ιk”¬‘Φτ΅b/α•ιk¨΅ή‹Ύ†r:₯͜M‡‡“wψš3„½FžF±@―Ήιudτš2¬—…£Χτ<ΜΊ +τΪϋIώςGΎ- +ŸZ•Θ†^SΩιC&F ΧΨNO{’Χ€™` ½†ϊ΄{‘Χ𞢾±Χ€0y'φš<3^βμ΅’<j‘‚©¦Sžώ±-Κ)ύm;£­—χt_²΄ΰ(ΓΙh“½†J#­`―Iα₯›μ΅J·K%Aξμ5ΚΧΙΧφλάξΕ^C9ο‘ΩkxΘ1φZ΅¨έ³ΨkZχ\ΦHkc―Z†Rλαμ5eλuGpƒ^[ΒF^›b€Χθ.€6€j IΆ>ήΐkZεZ"c¨$ ΧδΩί=cΧ–θΤ5ϋ9GYΤ5 §Vύ²SΧPΙjκ +‚ I±kί©k¬ k #V)x₯žQΧhCjΕ6κZε»U΄%¨kZπ›Ώ"¨kKΩ386Υ©k:εΙ +-xjΊΡV΄sΧθXAT`n'/m2»Ά„»Ά© ‘ŠΧ―j–’d€Χ΄'ρχ ^ΓcwήΫΣ‚ΠΚςvπš<“”)wM^α‚8ΐkςb΄'π^aΛΉrπλ:Φ‘^#ςάg&―‘Ηͺ‘y#ΕΌΐ^“BνYB―αΉΕ!μ5”ξ7\ΆΝqeψš<֝ΠFΠΧδο΅–3A_{•δΌέ#=s‡―iΜ`κθ΅Σ{ΟMςΪιν―xMQ +Jƒ»†Y5κ^;›¨kcX–5¦½.Κ 1γνsXΉFΪΧΥqL5²*7ΰZά΅Ό55f‹΄:pkΐ!ωΞ7ښβ.εΎlMΒp†nrhJΛ¨5‰δziν„΅8k:°Ώ³¦†¬kƒ³v–‘41kSΨ)kˆ£/ȚJΚ­mό΄ήΟ…XcΈs 9­qF`M3"Eί;`ΝϊΕά p?Ά² jΪ]-HicΉ«­‘όάxϊθδ’mΚΖE[jpΡH·ιύZ\4Ξω|`Ρ·k?±h•ζξΟ³°h(‘v,ͺŊ‹Ζ±Ό­Λl+pί±hr[§Λΐ’‘‘Dτ)°h›²aΡ–X΄Ί"KŽ;“λ9+f”έ6xOU^xς &MΌšpΓ’‘’±cΡt<λZ`4,M2œ‹6…‹6Ε ’ΐeλΚͺ^ΈEΞl΅Ώ΅Β°€’™ςlƒϋL5 h΄d42N!8γ…RŠVΟͺP4λTm~Dσdz“ΐΆ#ΡΤf‡BŠ ’©PΔΞCSP@C»=9 gκŽIυΒΞBcέψhά¨γ\$΄)μ$΄) ­EkΌ‘u'.$šj™ͺ·%H©–eχΉ(h/Χρι—ώ#νoώτοώτ_όΥέώΓΏϋ‡ΏσcθοS‡Ώώ?ώαΏϊ₯χ׏ύ‹Ώ0ωίώύςuτνώτΧIrΫΏόΫσ―5Žσ_ώυίΣγΛϊ―ώtόψ«―ύϋϊΣ?ώI©[)Yλψρί|ύΗφ%ύӏώγΏύρ?ώOǏΏΣΦßώβk’Dta…†Ζf}©ΏfYΛ45=ύ)Y~‹o”ΨυηχGόω§ΰΒώ»?ΩE•»6)AΡ1‡qΏŸΣd’ώύdw<Š‚L¬—΅˜'σoύ- Α³W{QΝήωμΓΏμβ²Όn{TΗ¬ξΰ|J€όΨ0α]ή‘Ιm’¨>ΝΝ?Ϋ󹆋΄ύοJHΎ­Ή'€ΊϋσϋOcγaΓ‘²ε¨δ.“χkάε“OEOD‹ΘΩ{UΨ€ΣΪ³/Şݰ²±xSyλxΜΈ/}dϊZϊωΆŠͺϋ¬QρΆ¬ΒfώΕwύωύέ2’χυ€?O΅ΙϋƒωΫς~χ±ύ€Χ―g:ι&§£λ6τΫς~χ±γ€‡Ω€Ÿ']ς~τk Ώ%§“ΎŽζv›ι~Mޏl£ί–χ“Ύν'ν—΅1ψ8ι&§£—Ν όVήOϊ>v˜ΨΟ4ƒχ“nς~t:‚ήΏ'ο'};›ΨΜAαoώαώη_ώο~\i@ΠwψΟϊ!Ο£Ό«ϊΏ―«π•-—\ϋ™΅¦χsΫχ;Νχύfdΰh4ΐ! `τ€O\δ―©ΧDL¬―:Νηœ/EEAόW&χ†σ˜6y_Ζ«ΰ1ά™Φς_ΣιλμΏθΑύE¦>Ί[χΏ†\©ίS•ƒμP»JίρFςλ ?ύθδΐυψ‡£ϋΡ=€^ΚŒ›X{&Β€²ήνπ##ϊΕ―c\†i=Λ;©¨½έεS}—ŸλŽΣ γ/cφzγ6QŸΰ7:ψ!ς4—οΫΘτωDΞα"E³v€‡/—Oϋ}ς=·Ϋζœ6}»8z€¦Φ¦ƒ/‘Ζ© +ΪL»bχ°~Y>ξ―ώΰnβΆyόυc©ΐω½ΛΚjΌ·Φυ«ΫxΣ4OςΩzυη¦ζxρ΄qΨΝQ.ΥγΫ*—Ξ[›_m-νρ«PΊn|σ+wμ,~Λ^ΧυΛΌΰSν’μC’φW—›ήPd˜,?CΎΊdTοψUwl{ψΣ|w=Žηnώσu­ψ3'¬V1ΙwήβΨυnώΊSζζΏp4 ±jγU u Ξ[DΟ,σϊΈ°uΕcžξ[<žιEW,؎x5Ϋ "S§S„Ε·|βΞϋά>ϋπ«θ‚όέΕ_ *ί^Α/sψ)O|γ΄Α‹αη9„v[l8†‰ΡοΨZVkȎ΅Υ-P†Ή{~2ΐΟߞΝ/Cm%ζIχΆ_]¦_Ά½‰JŸ2ρΈOΏΝw=Δ«ψ{u0X'|< ΙΆmwκ˜wω>~ρkΠ:ΎHU}{aλŠ?NWά­―_ρ韱υσ”νev±Η!Ύυ·~ΘόΞΞΈχΠ β%zόͺ/ΛŒΧώ²ζ~4ΪjSύ8†:΅Ψg`γ€^΅_]&σΥ&ˆt”rΏ©tόύωύ1βΰκΫ‡“Ή>ρΉ£hβΥνώ)ͺU»‹t{kӜψΕ0|^'‘ή7υΎήΊbϋ«Šgcπlε(sΗ¨§BϊAxυΫ_oAΫώwζW—›μ oΗγWQΫγβΧ]}~οšσ°m\ρ3Ύ&—x‡ί°Χό2ιQξx»TτΠ„›ΖZ‰Mꞡbb}βt” όβ°wvάγ™O0†ΛώI)*8Jˆgϋρν…­+¦*ΓΎ£―—π7N؎Ψ1ϋLόϊ’b W‘«‹'ν0%VMŸ'6=bΣVΗσ:θΗu­1 όΛz«Ζ@»…5ω―>Β\δWΖ­ˆm»_οΜΡη™/¬ruβwσ‰¨_—k΅}~_ςΖ +χ1ζ•χόZƒnΩn.ιί^@\½ γΚ™ό5δ#>κΉ:nkΏϋΡΉΦWdR‡όήrΔ5X\ΔΕ³ΔΔ?wώΈ¨υ~\gŒSΤ$Δ}μ–ζΔ›ύčlO˜L>.ΞίΥκ6%φΪΓΞPοΔgάέφό™W„d?WL~cŽ\Bλ|{ύkB|¦½„Α’ε¬aYVΐzόΊH:7qΈΙwYajΌϋγ £ορOž$wŸͺΏVͺ1~\ΐ/σ–Mq`+ε9lθ―ιpΔkj„ ‰}Μwχκ#ΔΆnιέveZh‡8πg}ω +ώμ₯•Ή(ΣͺmœρQ<ηοΏ €xzχueρΣΒ›ς;Ÿε9e’&~oz|λG?§Ι;nϊ_¨MΰZcέ1.wyβΎ=Ί°ζ7ςΆώ˜qaΝgΉ*{9Vιχ2’Ddb/Tn/χέΦ;(Άρ~[W~ӎrϊ―ˆwN«Ώ3zάηόiwL„_ΣΙvoΪtΆs[εΉΥ:¬ άΔ΅ͺ¬ύ ίίr@~}u}χrKpX 7ΙΫ·k8§σπγΦξ6XΜηνιΣ»¬Ή#ΞΪ3ή=ek”k›Ό§ό ߚ–Ζ!gσ°Mğd‡ΝU·eΕ|sΫβζŽ•uFŸ‹›ΣXb_CKʟί$f4>υι~Θδa„aˆ_·&ϊε³0ωφ?Ώ?ˆ]ρΟ‹oGΈλ‡73G¦pρ§Λ'•8ζ“² O’…ͺw ϋφΈ~³”‰co9Ύ˜ IΠα»Τ_υ?]vλA‹ωΣ̏λ‰Šၢχqύ„ ¦kη g‹ZΟ%uf&εI΅/HΪ5]xgσιP€»Ξιπς;ΔaηŒxί^—_09‡_†‚ϋ­$»α67«‰ŸΐxTKtGεwΈ­€Ί@–cM»mΚ5ΊΫ³†Ψ{ξίGυΛ:ϋά4\ΦΊκύψλ—y0T_‹—MιGΡp©Ρκ§Λ‡'|„Pή₯‘q>Ωψύ>Ÿp(/ή”>ƒQ_ςeή/9,J ‚ώ]uΚφ«›―XΨσΫΓϊωH˜°¦›CTΪ1ςγ1s’ Κ\;ζ oŠ ΟHΠΛΰ™¦±Ο΄tΏ³ρψΎ€υΩEΘθΪB8ΒTΞUswλ\DK_«ςς‰ΊΜΛeυυKwzS/7$Ά°ιάͺ|_@ά³s /£ξW—Ϋ5Χ¬έ>$˜Ώα;F ±>Η4Vbα!ϊx ƒ9F‰Φ7§Aΐ߽鏖§UFϋQέXdΉ~|ϋψmύP·Žϊψ(Hρμ―!χ{£Še™8ŽΣE•-Έh&+Ξz -šlγΓσάτŠM±ωΎ;Ώ_X9fθθ2Hγ―.ΧQέα.΄c*!κq"νq£•φvΏψŽΉ °5Ί`:›/"iί]AΈ Υ9pΞ`3rχΘbΗ‘b“Ύ©+ςξ~·σ/ί2¦V₯ΖZωΏ†μΉaε†.Žπ­πΜhΠl1]ξ 8E–Ι―1£¦/αu~{~ΤnώΊ|`ζώώς(m“C KuΎ“+ϊμβ/q€6ΰ^'Δ'Ά>ΌΌΰ—ω€–_Κτ<ΫΧ―L₯ήe|αΗyfΜίCΰρκtgΎ}ζΧΆσγτλΊΚΜyŽοQy^ ίdoΞqŒb}"πM˜€δΗΣ|zŒ·ΕΆaάΝΓ›―+X—vΞ„Z‘Δ₯υ5΅·§ΘοxΞ^~ž΅ZΞΨvή H΅ΠQΛυϋƘ›ͺšΓ―jf­|γ±Η/πUε±'φώW—›gO(šo ‰ΕVCΟό½t +½C,ΎQy”Ήabζ’ωψΓ_qЏ Γο‰6ΎΥ{ώ:εγ Ω^4‰φ²KμΆΰ•x>q€v†ε§mG ω˜°-‰§‘fih=~_—GτTc­'cΧ}‘‹-°k”>p_,o;Ÿί?αsΫ»ϊXKΏŸίŸNΧρoώ»@ν5ξ˜LdΧύκ²/<•N qδ§ΛW΅e³dL|Ό(ΌLΟ»Žk¦%i†Ώ|.‰‚#žΛΨ.3Ε%GΫb°‘&₯ru3―טφΣεqΔδW‡½-i`N0ωœ"ιχ&φpΉ ξiIzΔ΅ΜβΕΆf•Ζ…αӐ#π—ΉΈ:―xwXWξΠJη΄wΛ%7šζ Ισ«’υΆΛLΊΌC«=MΟ_€9~„_½–JΎΈ; ½Gύ%ΨQοωΊ[`S­‰ύΦͺV.^–v…—%~Γξƒν†i ”H,–§ύοΨ²πk\3aN‡=c₯+ΜU—ύtΧ +'‹§Γ„';ύΈ`zγΈΝ‚Ιzkϋh–Ξ kπ·φϊ²χϋα―2Q;€œ'ρήι½ύιͺ{ώuΨΫό‰4UŠwœwX’ΚΙͺ νqXu­ΆϋjrpΕ%Œλ2ό:j‰i4e“K©%^…ύdL~&ͺΏ„‰ξ;­^lWΰ‘hL}=LlOˆt4ΡΓM¬ύΫϊ ,sΦͺΙnΝΉύˆσ0‹Z’ί…bn8Ολτ«½η›pF ή€Ψέ#P$’ΨœrωH°]{$ξU§^ΪΎέBuυΓο΄rμ'ΉΦάƒ Ι?Ί¦ΪtΓŒΙw ΝηόhγŸs…m[ϋό@}9«˜A_³γ™ ―aŒξρΎΥπΛσ}šWυšΙW:™›y{¬W€ι‚·³†§hΫoFD2―™¦ωχ<ΧΚ°¨§:ψ›QŒΖδ―‹-oUwvΗηIA;€PYώΙ]™PKžcΑο»X•!>3Φ˜,.ήQ©ΐ΄§ΠΝ@Sυ“_©‡-<―Ών€8=‹Ω½ϋ!"iκ Ρw“Η4ΑOχΡ0βz1rΚ«a6 ω¬ρΎΛc―iζ—;σTGεΑω7KβΛBŒΨ’G<~Σ“Σ|A§Τή3+ΆξH_Ρ1Gx”›WΫ!-"–n ͺHΦΧg·W˜Ϊ1}±ρ¨ πZž€™,ΛiΤ=Ί+ΫόŠϋ½'Λ'kc4χ΅ϊs‘‹s4Η`Œάe§OΠΫΝΔϊΔ/Έ|Q£¦7mύ‚Λ=Μ:@œk1M}=μΈƒξ‘fξ’—ΛΧuΖΧ5}q§šœΏ+²z¬m>A3ργ›Ÿ/Ζ–%ωβ&ΝlŠζš|EδZηs·<μΗκ·†e‰gΜ^Έ‡‰΄ξώ5ΥΨ²•xβ§Ok˜& sw-?3Ν[ΠΣι‡ `βεβaΝΑώΦ€G\,―Χ7Yκ0·Έ‰ύŠϋBυςΌ€‡%$ϊ3δήΔα‰`ϊ g\Χι.<•–o}Λqά:F™ΔnŽμMhώzΡrŽG±p>v”EUZkŒg₯ΔAO+χ`i0οl‡SͺΏ^mζΣϊJΫΔHμ{Φ<«ζzsΰ{•Uzβ}–8θΥγW‘Ÿh^fσ¬[X…SŠ£^ώhͺΐ‡ή(+9iFΣΟ†ή [—βκZv…!Θ(cb€@©nά-ξ.Ώg½ζώg,»/UΟ#2šτ…™—α/XJυq…HuΒ?]>gLΏk¬ΖJυecρ{kJw$ιs‘Ί'\gΌ^n9χ;ςξt€cνΏήΔώΔωλQΓa― k<™˜@ϋmn9»ΗζJ5¬[‹υZυeŠNy§‚Pχςa4kΫ>W>ΡušώϊϋΆVZ]ΑΡΨ––ιΎm k―{‰΄eW|‡σÊ?μgι[ιςι9 Ο4m΄ν5‡jζ± pΗ΄„ΫΣζq«9›ψκlΛ;~±ιi)wBΐ±HΏϊΌ3W„ƒτΒή‘τ ˜1?ζzJLΛwά0 1OˆWXL"ωz¬χq2β׊v>FPΥ\¬0iλίΞγσ5Ρ5±X§?ŠBμͺΰZGώqΌœήbͺ)z}μμj‡o"6πOίvE7Εθ?‡ΎΛ <Ί³ΗˆL¬ΈΨ:ΏP²Mό2ύWʏZb€fž±@ZV― 8?κ\ήwεTjζ™ΔZϊ<@;‹ΛΛφ–όŒσ]¬lœC΄8ΎD_κEˆ©’·(βΓJnσ°_o‰Ν‚*Ί‹#¦ΦΘ/”’Υ°°ζΆkAΓΊ»{ψ]u¦­‹gΨή£DθC‡½¦Λ)Ζ3uFΈΒJξγ*jςW_―W:™π‹ψΉέ€‚šyPη18³ΔΓΊ(Έω–›0cW˜ϊ§'‰.nΎΝZΦνZn–b­γηˆq=²uΤώϊ{ΔAΓ :Τvν™ϋGυέͺΊlΟL»Ν½nb;#^Ϋgf’€g#žΨασΈΨ’#>ηp[θ¨σ΄+²)$ΧXς‘ωΙΌ HNP{Έ׌=Ζ:‘6g·>·a7ui›ζšψξhνaνtK9β#M«Ž;f jC-­ί.Ώ,RGβ}€‰ΣΕcΪΤΥ„¦ωbΩ'‘-ζΈ™Κp£†oJ3D[¬x}[εv·UOD€Μ<“(ΰω«8/ύ."ω²ΆΞ&»ΙΡ†ΊόW^g§xα\@θΨδϊ–«½ρŠBΊeqm1‚―iFΝu%ρΚ°»ŒLΌ;¦ΫμτωλωΆΉΤ<³ŠKΡNΟBΣ :―ι*1jα؍œžσLWF›V+We~―Άr 3Ψμ-|!vJ\¬W»e~λˆυ.£y Fσ‡νε‹Š}—i›yFGk–”oίλΛή—.Gri>ήd&­  Œ+3rψ‹ljdΪ%™(i%Ϋ]£h4‰!.MJστίηξ‘‘™Υͺža7 +,±Ϊ‘‡‡ίΗhζ €†––m™D!ΤlB–b΅tSœ’3BhΣΆg{ C·ίY,[S *?Χ@ΪΑeh 5<«Ϋ5Z΄i_ΑΥμo\‘ΡΧ˜“Βυc9Ρι4΅ ΣκγΏyœ–0Τ,RΖ^ŸΩΚT;ψ½M:„ sΉZ²Ρ‘\Œ­΄oψXχΦuφ9Kq ’ϊsΠ1ΜΥΛI―˜ͺ˜ΨˊԝM`ΠψΫ±ζƒ5ζ ŒΪ™ΈΑζg +Άœύ,sΨUnγ3₯ξ[79Ϋ: a€wo^]ˈd ±Υc#©μ6Ξ4¨_9wΙΒr οκΕρΩdGγsT ΎυIK•ƒΦoοu( Λ©8?š0I„­t&ή%Σi<κ›ΤFSί™‚coΙ*£ŠΙ~(Ζ 1ڝ…΅«‘½Ήe|/U‚d kςSίμG€£²?-aXx__έΨΫ•1d!½\­%Ζ 5ήEΘΈcuδ7)η–M™kΒB’BΞ6ΐΰ,­>[ΒNnbΟYΎ]€oσηζ:C[Γƒ~Κ‚Ε °τ3¦ήOHη,ΩΧGϋš$ͺτ“[ܞ΅8\η}u‘χ»ζΤƒI?yM' –`Οqk΄#¬ φλŠτ6@¬Q₯(Ψkqnjι`,X DgΧ&G 1Š©‘S"vM₯QιΨJbtΥs§΄κΗΣI9‘5]h¬ €΅Kί-±Ξ6€εΉbφ>3p΄°!V€P²ξ-aΟΒτρdΝrιͺ0:σ|0¬•[Žy’”Ζ©€†Ώΰ*Ϊ'iΖQyS°‚As6@Αs˜*|­5Z±rWίdKπ­3χιΝS?SfήW'υΖ„™{»‘vhoΤJ5ιΉ ¨7iͺ³ϋΐf³*w…še*ΗAjHgϋ0q²Ύšε“8ΈE’ Υ°|½0ΤXΜ$όML΄ η(-„OD€―yή=Ϊ¨ P%fWΜΕΖ£T!˜ΪΨI{ϋͺρ˜U±.Ω€c—μ$³―A;,›‰¦^Y~UΞ¦³Y £*}ά `Μ†RUT~Kπ +b=Ηΰ)³‘3|žržΠRΊ³h’Fm΅Αr'{‘Α°>ΤDHv1=Z­E£’ϊ°β7)Τ@]W™[ƒ˜YΔE‹ω‹N’! ΏFωιdfWι§z>jιΎ&Dσ[Ζ²‚†žX³)ψd΅Λ Sξͺ· ¨]†ψνm€Uψ―>ΫΧ,d3.₯šEΠW₯ΐPgP%[ P“#ΩFJ€©ήσh€iΥ$»šDώφΐζ<˜{#N9f½ΈaX£]™ζDž=²22K¨ky ©Ο“•sͺ―’ι»μ`Β—ωβπ  +Iƒ¨²φ~,M·XDδ©>€YIΝv ΚV­ΧpΝ&gŒaΣj‘9Cήα³€%E6Η³W½ˆ.0^'cΠμ;aΖv΄†šXͺn°-?u<…ύͺΡmΗΎ*i&˜’mcmΕ(;λm•2PΫ΄7Nμ,ΐ"ΥΨ"ΰWJζήυ>bsƒ9x| dξkΞ+tš ?Ψ“VoͺfΗ₯φ&MA{)U8P†Oφθ!;¨‰„)U‡M/_¨ΧΛ”o­6$@;Ω$¦žϊύ¦jRόζŒSΊ\Zτˆσ5kήφ–/ϋ₯@ T9ΝΔG΄ιL +κψͺϋV%Β }ίψO’ΊΔ:«Α*»¨»!MΥ–@«βδύμ’%Φdα€Aλύδ6}z"56€’s“ΏγRΥ§m›Š8`ÞQ*G‡V DMα`ε”Ψγχdζf†άh<"iŸ«’ίΣYc€kΌƒ…c΅3Αμ§Y•~ΗZϋ£·’‡ΖΫΒ²κ–‰Τ?‰NjΚN†jeυ_»j‘3>ΈuFˆΘθΟτ!6†Žl‰Ή€Φ\4z} œ³Ι–£9€†¦ŽQ.ِjPΟpZ“˜Ρ ¨:Ζ½\&φρ΅ i}8SΝƒΟ¦€£ΗΟ°,ξ€6E5;©ξχΠd©NVΗφΞ ²Œ²œ.«#5TŸ(zσΤb„άΖf4UΌ«΄ΰͺͺ ΙΥg«’b· }£Cl3ΘS’Λ`©δ™EΖυήxRΙή"<°gxφgμ"φώZ†½U¨θ•R‘Ώ΄3Σ«ω9³—‚ψAΒ΅ΜGˆgΥ,¦Έ2Ό½&τi`SYεΟAͺKΤχ“qQ9Spξ&¦'–Gτ‘φΆ«ΚζF–§Ψ‘œj’ϋPυΰ<4*TRNΞUdλ₯« ›ΪͺS‚m“|0H5/ΗΎ~NgF‚UΠh~τ*s&£ρΜ_Ψ°ήpΤΚD²΅‘bΝ}F»6ΤƒωϊΨY k£Α`N“‰²Λ–'aυ^₯'‘½oΒ„–O·UCΝΆƒdr¦OOυiΔV=vU[$]€C°Ϋά9‹+B©ͺŠΣEΫξΡΤ=«Š„'+I’^θΜiΡ]#]Α΅ͺ‘XdF' δ2€λ¦r­dCΣΕ™‚5@Μi7sn¬ς“D™£%\ofΚq¬Ÿ«·——’*ZΧ9³'XZΘXƒ¨‰€4²ΆLεn¦3Ž“=`°2γ”"©QaΤs䬃]N δΓNλ9ιυg}υIŠH+@ Πk"8έμͺŸ‘+šνji’ˆqgŠ,oα,jZ$Ψ;‹fs!f}Vsςb°)_&7"οΧL*“μœMVŠ +`΅1ζ8ΫYΈ–FZŽΊα +Qϊ΄bΒ`ta6”άˆtκΛgV¬¨¨HcQ*g +N‘U2³ΐ)Σ€–ΕεX#ηΤΪGpηΝρ/ Ψ[E<Λ’g2ƒE?£  Ι•˜Χ…&’‚%™ SΙΔH Wo΄ΙΦ½­ͺ$#³F»€ΑYL"-6€―Ω +ƒv{>Φ°Δ/QΙΞ“b§†ώŸ†4β + .Μ ³3Z₯.L&ψ€^ŸU{3ΝΣ[³ΒΨ%3΄Ξ(«ν8˜RΠ‘&μ‘I˜½―ΙΊΜΞ΅­@ηŒ]ω)ίέ8ǚ7$ζrΊ·Αlϊh š,o†νSώŒaŠY‘h:…vͺ“kdί αŒJp ή«8ˆζ€5>Χ’ΖΎ #΅’78v΄œ?ςW+«2JNΌwc²Š@|5ω€·;Λ:Ιn’”eπ>‰!hD9:›¬iδcͺ©ά£8’d€h"ζΥYˆrχ* ΐu:¨Πbφ‘±†²‘ΌΕ‰σCCθ,\sPGτΘFΈH$9¨#zΪΫ0€LήfŸeJ™˜ηŠxeί¦8’J%ΡBΖ   TΑ,ƒNωo–7ϊκpΒ€,dldσžδνcζΊEήΤ(lc*1ƒΡΒ“€Ϋώiΰ±3K C+Ύ9KC'Ψ›δ› -„ ‹δ, d3ΖN;ϊςvIp”‡:&;~ ΠUd…@ΣSŠΞh{₯•₯‘S8r•ΗZ ”ΧΗΞ +‘Q„I{Ϋ-‹v…ώ”m_­2ςsj€[oΖhθpΙ{ŸMύr5xŸy'›σΌάΥΐZ: tΤΞ‚αŒ8@/¬1©5ڈڒρUKδΗόkˆwaΫv°§Γϋjα”Eμ-ΆΨjθac₯9¦ˆβ“”'‘{_ΤΤΌ§$si-bYrΉŽt/±%¨}k~έ™‚‹"ήf§ˆ"kN’a¬š4cκΝ“‡¦Θ“Ξœ’ρ―^“Kς`]`­Q"Ή―Ι5• σPε'ΕmεYuv(1”ύh΄˜!‰ςΎΦ/”ΓΥ–ΉCrϊχBKr’Χ„£ y²0τ•%U?roυ2H δΘ3Γ‘jŠΌ₯εZά“y£Š^ΙΜmΨTP‡43^ΝX•£Ω„$τ<ΫSM‚(ONi»C Ώ/`ζ\½ω˜*‚ZΓ tmΟ&ί…Ξϋ:€«ρΎθ”§‡[¨doΊVΰ »'Ϊ;(.«Tkδΰ…k†Hl6€`”ͺΧ―2ˆŸ6έΊ‚δZΏ˜ΡγΞ¬XU$Ν£DΙeoέg˜~άM¦)—μFY f5˜Ωb– +Pi&ύΎPγZ¨B­ECΓhgy7εR@nΊMΡ²F²3Ώζͺ ±}ެ>·΅ %‘Zό\#h[*?:v»Zz-g[SVΩΉMLΗͺ45ήI viΝ›A0Rš1w΅ϊΫ ΨΗ4.‰υ$φ;ΰjν…Ξ’[ΩΪ½ +<53w¦†YΊ>;ewh€¬¦©^±ιβ€ΖOυΰ”΅tγΖ;’ΝD›«T_w€fKοθ΅μXωGΜΚ7τl2[rΉ―υη‡Ρb.šλχ5ΖΧ7Ιό« XAΎ‘Ζa‚ζ7 +Ξ’MH›Ν™?₯b ±ϊם‰ŠiΚ―†δ0¨όVΣ,!yTa?ΦƒΕ¬*e©6Žς¦‚Ν ΄»P5―ΦX#ΔBC-l-Ύ>³ΖY©έυχ_XλX fΟζςƒΔwcΠbYš«‰Η­ΐTƒΟͺ$ πh1+τƒ QoέFjbHg‹J&—0ψΤΐ5ξ~¨^W+Έœ~ƒ«£kΒ}kgθ4½…1WWβH±PΧf%­©ΎΨa˜—v5κ i§ͺϋ‰@‰.U]<χ΅β₯ΪΤ›\--Eυ'οΚσΧxB<«tkξ}¬Υ3h*HΦ/ΑJ2jΌ<ŒΒΰLVM$ŒήκGn¦ΧU3ύP`ΤƒήTirΣ¬΄‚²Έœ)E³Χ:clΛ„kΕ (ό50Υ4΄·eœΕšŽ¨Επ1@6Σ₯9ŒΧί·hω­Α]?υβš¨yώ[κΑ«λ[₯[ύ`±΄Vδ~JdpβXί¦¬χόΠτŽͺIλyMEςΥTι²h9΅HΎ³θΆ_`¨™%ύ Θ#DHΦ~u{sΖ“ƒQΞ>΅"‡Φ¨‹΅BmΉŽλyM;μk KΚωΆΓj6fμ‹ν€&ΧΓU3hR‚ZΦΓ<Θΰš­UFίψ2-dŠ£œΏ¬cŠετ1‡€ΖJΉdΐΕτm]}qΔΩbε-uh¨1$’h ωP‘Mz‹‰CΝΜ ‰΅ΐ«ηο‘9―£ΥΓ[Ν`ͺκ—k¨mm 2Φ*}­Z ΰhΡϋΜ(R I’ΡΌΠ΄ ›‹iΰ{WΓ\ϊj@\~Β«ιšεv&Έd•ΟcwmͺPžβ]Œq6¬Έξ—jΙL ­ΡdWKm²Ϊόα=–?Σ»š“©Ωƒ¬ŽiΧΕΧό{$ΰΤΩYθ4η`™oΞלšωΌ^L5>ηΫ„Ix\“R|ΝSχ![RŠŸzv€~š˜Y£r kΗ Ρn¬3B°ae•&Φͺυ€wvNζ{Η ―UΨsγυe³Νƒ+V§ΞΚΡί(X5Fœˆ³aΒdΙΝΥŒδ͚όj9{Θφθ¬ΤEͺζt|n΄:σQ œt’°lDΊ:6NΜD>_S•΄^ō‚]-cωΤ£΄R &τÚkΌ2x+α`9Θg›Ώ6mœεmk!!ΫΈPν—ϋj;#kΖ¨¦šΤa;4ΥD©₯‡k%`Z:ƒ °˜Α‹ΚήΗΡ²^ɍ½ηlgšΗz¦τ_*5ΜƒιdλAΞj‘τ-žΡ’V(=x³U5ISy0Sδ‘‘&Φ”Ρ0Y'ι7`¬TΕ Άd)8Σ]Rο§€Œμk-85ΌGm&£zŽ·Y-V0Υ€_ŒlK‹Υ)Ss5b•kΡνΎ«š–Ε‘3…Γͺ™E­Γ`­Α™όΫΦυJΥS&!σDo<:λ€3NŽρ©}‡ω«6 q¦c{ΡeB1Έ1pνΠV~ΩθΪ‘ŠύΤ|Š|+βuT―»Ÿ:TΣ²Ύι[VuΌ·,eh 8ΦZ•N24Ξ \•Y“gϊή46˜FIˆAΰͺ:‰œ,~±ωsS—ƒœΝάWmθLj‘•Η"$»Z1ΕI]¬³ΝcΨΰ±τ’qs£`σ[zI’ XKΟ fhρ5FγνhRmch_ΟΰΕ’Aύ±U=‘Η|μfMλίΪ­ήu‹vυCΩ;ω+&G5KrJ'πΩΪ€¦ιUഐfΈiΙΝ—ΫνΙθλκY{·uΞΎί‚λL§Q§-—~ρV"Αύς¨―;χf‹+El·›δ‚H εcσφCpα©AΐνiυήΡ"U–λ Ε:;Ξ°ƒq’εί£Tβ( =˜λ·,ςΐ·"Ÿ.2œ¨rύχωE60IΘ€2š±ŸΧœ‹Ση~°;‹pT›UΟςεn>υAϋ4NΛ|q$`²­iSΪϋώφ½ύηΚ ”­υβΘ&x€S @ΠεΜυ@L"±wz6)vIfGEεZΗν‘G΄)¬Ε€tπσΩ¬XΛ »hK0Xlšν†[9P3Z- ‘ώ©_, ξƒ~Œσ%WBβ_, H†[, B, Ά_3ςvΆ¨~~œ/j=ί­οΫ9pπ«ίίέώρώκφακφ›““1·8ϊύχψ‹λδO_ώυ·vu]†9ϊuύyό―GΏώΫgΏΏ{y‰ŸŸ_]<\έݞίσ]ψδψ—ΈΉΎ-:)ΣΊΏϊϊΝΓελ_ΛΡ―?½Ώ?_Όϋiˆ$xΈΜΕ—§Ό¦―^>|»υ’τιΎ’»―γςβα³»7·/Λτ>»ϋΗΆΛ{E|+>Όήz‘³w>ψR·?ΊG6‘YΡ?žτ:ώΉυ:ώωΦριοΎϊτϊϋoΟΏrΫηκeyς‘•ΰ™ΩbΖO…L>ΌΉϊΝυενΕεΆ» ―ny°φ£§]Ϊv=_ŸΏΎό·ϋΛχ¦lΒφ»xλƒ―πφξΛ‡«‡‹G(ό΄ΚΧ|ϊΟWΧ—ΫΣΛΩ;|…~Ϋ₯έΎΉωΓΕΓω;¬¬}εƒ/ WnΫ΅έ_Ύ~s½½dboCή2uχŽ©o¦~ SΎόσ–δdšσ;Ά ŸΛΥν#θΩ²<ϋΑ±μκvΫ΅ά}yώpwΏυ‚¦>ψͺΎΌ{sqωΫϋσοΏ½ΊΨώ°v8«xy^άέ|χϊκa‡»σSΜƒRςΆSψυη—―Ž?9¨€OqMπ TΐmTΐψsV_ݟYψϊχwW―Ÿ™Έ΅fΠŸ¦Έυ½<θ€π tΐƒxΠgΘββ3ΤwXΣ~θ€'ώΉ¨F»¬δΙ+GŸ]ώpyύε·η/ο~όy{ΙΎΎ~σ5όoמͺlύϊαεη—?\cB;θ νKIF rά$„ίžΏyύϊκόφ³Gqς) +Ψw―^½Ύ|x|ξΟψ>½άžξΏό„ϋ…lϊ_~ ^Ό Υή—Ϋޟύ»χۚέ|yρζϊόώ7ψώξφςvϋ›Ώ~ρΓKζ».ςΕένλ‡σχXδτβ_δΦ‘5―ίάΏ:ΏΈόςβόz{cρό₯Ύ8μοޜνb2ϋil•—_*O‘§NΆVŽΎ [―~ψΐ’­ςˆ)₯]H| yδμΪ…Έ°σϋ«‡oo.ΆχοΛΩώβlOΎϋΰϊκαηWY;φy"Άd‘ϋ£Gοξ§Ψ—σόβςώ›Kμδώ‰D»g|$?έ<G‡ΐ£·­Ι=·ΐ£ŸQςΙIΪϊ잸]x‡›υ΄­ΒŸώξ«wwןέ_^ώηΦξ˜η_εN·ΞφΎ?yυfϋ;gx•t§σάRHyωςςκϊ|{gα>ιΥ[Ρ~ι‘Ο2κν‹»ϋοΏ½»ΎϋfkŠώtΤ–gHέΆO’9P·Dέ~ϊό²§J4ν`ΧnωO˜lΏ’}Ή('Ο&y‡\ΜύΈςϋΎϋ\k|½΅dφΤΙX·½y¨vπΆ5~άj[Vο[΅ƒνoΩΎ°Ψğ=αLϋ\΅αΣ­ΝΑ/Ύ=Ώ½½Όώςςϊςb=nύβGΉ?mm½ίE_|Β”βιΗ»}ύHΫώΘΫ―δ@Ώ?τJΆ>šΧ»₯aYώΥGbGŸ_½ώώϊόβςζςφα‹σοχ'ݜ—‘Άv'ο…΄[•Ό§LΟΆ^ΙήΠ³νyΝ§gέ±ύίρκ§›ύάvΕό΅½¦dΔ€Λλ»ϋ/Ά O‘μ}½΅ϋδ‰ΔΦ+Ω"±}vϊV|ف;=ίμίW;E½ΊΊΎή%xνϊ#λυΥνεωΦ1ΨEh½ψβnϋ8Ϊζ…Ύ²ϋK +ΈΫ.νόεΛ«‡«Ά_ΪτΒ‡7d>ΒmΤφ5ŒδΩ/l½–―Ρm{sΊ<ύα½θΧ?žsλ5^υp~Ώo“η?‚{ΰvϋ»tqρζζΝγνmj^ωΰk۞7k΄Οž‹Ψv™σ·ž δαn{uωξ)ΛZ―ξοnΆgΒ|ψ#i&η·W7;\™Ÿ(GeΏΛί]<›°™νW²/κΡI>„Νεyτm+ϊ֜ιΫΦ‹?Π·};Π·½’oΏΉ/€ƒψφ¬ΘΫ%Ξτ@έΤν@έHέΒہΊ¨ΫΊ=7κΦΊΎΪ-dγ™Ή­ίβοά+/αανp‰†Ÿσ%Ϊzρ‡KtΈDm +twœΆΡ’ei‡(­ζ.’ύŒΊmRψΗ«\^ρϊόŸ_ν–τϋΜθΰύεΝέceKφ«&ΝλοQ•fΫνSMš«Ϋ——―nmφΪ†π}yώπωe\š7>ψϊžqΝ·}‘šCѝCѝCѝΗΦΆ₯h΅οwά±ϋΔwΗ.•νŽΛR~—~Rώpό<3v.dσTD©―wiGώΔ³vYΛΎδ |X•£ΨӟesΙύ)υžŽŽ§žώςμ§Wκβξζϋ»ΧEΑϊΓ›GΪώ‘ΏΨӞ†v^ϋJv$ΨO*lmJϋξ‘8€f%xτΓ«Έ[/δo\»ψ€ςΘΩ΅ qCIΏΏzψφζςa{&ΊOŒgϋ‹³= ψξ£T‡i8賫Aω>βΑΟ‘•ξϋγ½Πu_Žτ…xπ?όΟοZθ“π?οV­υΰ~βώηηΫεΰž-ξΰ>ψŸώηƒω9ϋŸ)nΒν»Ov=>η§gΤ?ψœ>ηξΒΨΣΙ~ϋœw4Ό~ΉS εΩ;ηώyy}}χγΆλ»ΎϊζΫ‡ςχ“ έz‰Λמ;ΰεΥ«Wo^_ΎΈ»-Bήνφqυή_’ΞΰΉ0―­Λ Ύ~sͺ(™»έΉωKOύ¬φ…9䈈§Β-&Έƒ ξ`‚ϋιyϊ‘οςγ«9˜ΰ&Έν©όφΒύΎΫαDνωδ›ϋΛΛΫOŠάrωIαWίά}ςΓΥέυεΓ'χ—/?Ή»?Ώ}ΜΟ~0Π}hͺŸ·6™žηΥΝ›‡G:AΆ8iΟplμ·^ΣεuωΗN6­ζfύωόŠZρΜGŽω\T―3₯u{xΆΧŒΏΏΌ(Όδώ7ψΎp­Œλ?‚uΧUξl²YΏψ€σG¬0Οΐςφ¬ 9†C‡τ–ƒ1η`Μ9sƜƒ1η`Μ9sƜLχaΊcŽZvhΣ9sžΈ.{0ζόŒ9ƒ’όdαΛΤ—ͺKξ―iκY¦ΰ?ΟΒΟΨpρKΫ—(Κ=.Ο±kxΪ“§ Ϋ‚8”ζxbAž‡“υloOΌ4ΗυΥΓΟ―σ8ν}Φ­dφ˜…Ύ—`σΤΩθ‘ΒΥSc£‡ +W{ΑFŸM…+c£Ο endstream endobj 21 0 obj <>stream +ΊΥςΑΟ‘…ξO ΐΞhΊ/Ηy¨jυόͺZύΌJ?}ωνωΛ»ή}‡žc²Φ…ΌΙώOŠ£μw²έ«W―/0χϋΛ—;ΟΎά«­žΎάΊί.}Β y„Ά ωΗGXΘs¬%ή£Ÿ•Žπώ€c_υ=”…§r8ΟΪ¬}P➟ηBχ‹mρτΫΛ]"˜κγήj·_ӏW/wψΣ§?ψŠ~Fͺφ‰K[ήφΧǐ·vYΙφ2πǁ'σΗΟΊμυs4τσΗ^ΚbσΗΣΎWωΉ˜?Ά_ΘΑόρΑ©ΐΑόρ IϋΑόρlΞε`ώxβ揟‘b %ξα|‡@΅η¨Β½Ί?Ώx8ΏώύέΥφi"ςς–gl_ϊΐλΊΨM1ί%iςCG†žn]ΜηλσΧ—vωή\ή^l/E/ήϊΰ Ό½ϋςακαβ£c«xγι?_]ο+>{ηΓΫ_·Žξ½}sσ‡rΨaiν+Oψšν‹žzρ1C Ÿ +W8Τ_:Τ_:Τ_ϊιΫ-<£ςK‡rEϋWhyqί«u§[7±zΈΫ^ΉΉ{Ϊ +Α«ϋ»›ν93ή—jJ?‰%ιΟoξΏ~s]nΓޚu`φ ‹pγИ‚ί#;ν`†}§ΕΰF‘ν°¦CΪ3–otO;mϋu<ω΄IXωκ‘* ΟΫ…ρ°₯ΠΆ_Œξ΄;ΨύοφΫξΏu¨ΠΎ™ύqε~rΓGe:ΰA|bWθ ξ4ƒψ8ž΄ΐƒxΠŸ—Έ΅Ύπ΅ΐηΘ֝n]oα >M5pλ<¨5π ΤΐƒxP[•)=C5p‡5Τΐ'¦žΈη’ξ²’'― +ώ―»»—ίܟoΟ(Ÿ£ΈSVσOύyŽυ5ΆV†φ·ΎΖ3Mχ}6ž exώυBεRί΅C½'V/δCGο_ϊ©³³/τλΥu‘Ζ₯ψΏ~}}~ρέ'ΗΊϋώόβκ៺ƒaυΓ?―·wTθΣνNύ–ΉWκΏRGη©ΫN_³Xα‹ηD4ž§9ψωΛu»q=#φΈΏαŽ ΐΎΌ8߁Νήωΰ¨φγ·;$Ε_kψ“-΄Yας΅oHίZ½^Π/ξn_?œ?Φ­Υ5–ο}π%ξΪΕϊ‰s­Γt^ΏΉu~qΉΫ•›ΏτΤΟj_ΈΦGΦ}Ÿ ³[#οω^έΌΩΑmWŸΰgΫo]ιςΊόc'{tσΖ_YΣOWν#‰ZŸ_‘ νβζώ‰ͺ|.΄ξLE€=”ύΆΖ|λ‚ύ›|w{Ήƒτ°~ριJH6םE€υ‹Yχ 9νj£Ω½ΡόAz:HOιι'”žΒΣO&<}©δn₯§C”υޘ՟1o}₯¬κOΝ φτιΒΦ\ώ»GjΡ4+Α£Ox!ΈηΫ…Δ§¬Φ~χΘ“νBάGXΘωύΥΓ·7—;4bΨ'Φ³=ΎmOΎϋΰϊκαηWYEφ>λ˜έ=f‘ο%Ψ°Ρ§Άύˆltϋ‹s`£…ξΊŸ#έSυ‘©δ–ŒžλUΫΣ~’O-žk€C!άΕ*χ―σm€·m™ ύθήΛ½΅ŒfŸk;ݜ—‘Ά-²τύ·εΥ׏Gκμί Ϊ6μ|>4?ξτ6ύͺm—Λ_Ϋz{ό#κ‚Χwχ_lqŸ"αxΞIe?ƒ’"Ο’οwI‘?<ϋdΝ“­5―§^…γδΩ”αxΞFΉ}-Ηρώ”ΰι»,ŸgD Μϊ8―?ˆΖO]‘Ϊς°ΗΡ -Ύm“·/ηΆοHΌψϋЊ}ΉRϋ-γdώφκςώίυθ)Pρ§rΞη_oΏϋ`στΗ[{DΈφΏξf)›½σρ +½Ή½ψΣώ•g‡l§Γqwόσ@·ίΠνγ£›ϋΉ·Ο>r  +υ!TUψσύωνλWΫw»x:؞Ρχ£ΙΗ2šΘ=Gϋ}”‰}QσφΨrΒhΌO――rtΫuθύξαΎΰκž†ώsxŸVΏψτwϋκ7·/k++€ _ύώξφeρ9πg—ί\έΆ8ϊύχ#ʟΎόηΝΧwΧGΏόνεύΧ…ρόκ¨;ώ΄όί~•ηN†Σή§±όπξΤΗΞΛSnLΗηS}θ‡γ“tΗ‘+?άxΪΉόˆ§C—;W ω4₯.ε!Η/ΚϋSηΣρI8ϋ”Λ˜.œ†.€τaΐ8ξ4&ηcH‰o••Ή…0%Oc(3ΑησŽΧ+yqτjΪ8wκ†~θ±»έiŒΨ7Wfr8vΓιπΟaLγρ_ΚΊ+›Ι9Œ"ΠΉ!HwκϊXNΈ¬₯S(+3μT–Υ•qSxwŒ½Γώ”οπΏG!―” ΓΙ•υv]™Ί§ήΗίιϊΓρjϊX޲Oε; ;RώγΚΖβ0‡Σ.ΊrJ„Νve±”b œΥΨ•ΛΏu’ΓƘ‚Η!φ|aΰ +€lΗX g9Ος–†Γδ.' ›| +εKωԍ£ΗKa&sωe»CŽε<†ΣΤLj‰Η‘O=F ]πDκ†{±^Β™.xξβάπΘIΩΠΑω±,·ΰΫXf +Pp‘όπΨ8ΰTAŸ2‹rpcωK'θ7:‰–σξ»'&Ε\φ’ Vη;’–O~ ΐ /›ΒΧBΩφ‚1~||O€\šSŒXLA›θέ(Ο„²ΰς₯q(Ο@Ή«ωγpσi™JΩκ‚Ε±|ΰ–A€αŸœ ‘μIωXπ.Θ νΚU)ΈΦΚςΊL£ ξFb9v/sΚζ”Ν%€¬Αc+†œδϊTΆΏΌγkΎΰ?§SFυΐ:€ΈΈςdŽIθΠ•cώ+YŽ5\Ω,\ηΛ*€ΠB+V‹²SΝΐ†§ν• a_<Ι‰+‹+;P3δ ZSf”c4(Ψ&“/'Η‰}7FlΠ +nž*Γϊ‚XξΣΛRψΏ]]π©/Χ3Θ±4π9zμCω¨Ν)ΫΝ©•Ή§²Λ8»‚ω'ωˆŠεlϊˆλ]ΛCΉg„•ϋrΌaq;~\σCˆ‘3qc.–ψα²οˆ‘εež[_ΠV(«Σ³/”L¨FΕ>“Μ•5κŠ\ ™4hΘ8v>€$Φ δΔ«ςZΖιHΑι,›QΠ–B +qΚηB—ωάbκο8ρ2ΞHœ*Ÿ"Ω“p:‚Rςδ1]ϋŒS*άΖa‘ DŠΰ#»\€‚x@ρ‘0‹aΐΑ AΕ +Zd!λΨΒ :μfλtτΠg/+°“*h°ς‚ϋ…¬ΛΦϋŒ3X­όβhγώ¬χp±Σ彂Ψ=.7p%Ίw%wΧΎΠ0b¨°Ο#qωΆ.ΩΦ }ΉδgϋΉwe· *DlLΝ[ώ.$,ίLu ΄ΐΟ;TXyŸ928#ΎZ(œ“£+Θίu"D”ϋΙι‚|ŒΎηϋ ,„€ΠƒΤ:μI’#/τ5ςbw]4‘a$!-ο ›!Βy».^ͺ PFΜ€πεx³s 3pέP.2Pμk)Ψη(X¬ΦχL-_ΝWŽ$ΉμΆCX.²BδšBž#ίύ;³²+#―]β©–½θ’ε©!ηnΔΔΛΰ™ύHΒΜΩυ ωCΓ@2›)«Lo‘–V"ΥJθZJfœ$‡έγŒ|Ω“0Θkrͺΰ§BνŠΑ;WQq™G*C+Ρ-[—³|}ΎoοcNΘJG’aί—‡ε„Ν˜HW@ΒάP@ŠlRP @bΌ@H‹ΉΩεΐχΚ>zΩΐΒά)u@θ +’ 0–‹‡₯D.k9‡w"'ΌτŒBlφ#>ݍάΧBIΰ`šqγ^mΪΡΥ/NΗμ–Ÿ&Κ'‚ΝΘ·Ρ’ΌRH”Y‘/Θy—‹,ΌΞ _)ϋZϋi9‘Βιεͺ…4PjLΊ__σ…&―χgN™W:€―•- ΑHΚ ε; doL- cΞͺ‹™_Ωa,ίΗEθE +!ޏ|ΗC|-Bη†@δξc!FCD€ρ˜H ₯¦ϊJ1*»±OdξD°ύ1p+Κ~e<α#δB/<‘Oε€=ωM$nώ n_2$b!9\ζzžιb“^Ό“"Ν‚΄˜ΐb†‹5Sœ§£ψŽe‚tRBQ΄τ« ΰ±Ύ…^χ†(ˆ“O ±‚Ά +%A6§…’`œ"“68λ‘ό*mڝw\³"ς@Ώ$φ•»αΝcαΐΨQˆDVˆ5ΠΖ"Εΐ Θ΅eE©c9LEPI –xχ‚z”³)qΩ^Uς§QΎ4‚―AοΜEυω«(ΣΩQσσ£ˆΙuœp½1©XΉ($ύ6ΠŸΜˆ ”Κϋ¬ψ¨Q: .wβοoǐ"Ky\š¬h^6-SuαrSF"œ灘ο6Ο`5ΛΥ:k½ rR­ƒ‚•Fα ΰ~ΗεΏΉ!υ |©ˆ(e!ό’㕦φΜ/•ϋιcΩίς쐠q”ως<γ.τχ±4GEλΎυ‚ϋϊr€e + ΗνΖ jۘοΤ»P±ΰsΰ0#w]p±\0H)ΩHPΑ2PςςoŸRtYIωξ9ΦDS”\ πλΒΈ­e²”h ξωNξυ-žBXGŽγO„ΈSΈ΄}TρL°`”›žzGŽ.β-€Ν’›b[ Hθ_‘—„π—Uc DΈ‰½­ωΕ†}Έ†Ρ₯,²X$/n½‘j―Ω&’PΡϋ Š:θΜJϊΓΡŒΊ²²-±rο£μ]!ώpΐθ]ξ}αϊ€{0φr7nΐ*Θ `ρΙεΛ™ΒώN•‘πƒhp-h.Ά@λ©°±Dq9š@ +§ζΑγ»ς­φΌ8ZαΨΩf<œ­π‡£΅=ze±^Z΅y@’ Τ + IžtQ΄7οΜ–I8SCΔΑD/žΧ¦fήΫ…9zi°^΅IΥ<xt ΠM˜³:ΡΑ2WgυNŠ^Nd * +S!4ώ'»σl“ΉzeΤ>ΫhψžΗSΦ½ +΄”‘‰‰&_Ύλzςͺχ“4r†0θ’Hχ΄0™νΗekEκ¦b +s#iΜ„,±G=ίBλε[8xΈ•Vςv™ΕΓΰ–eWΠϊζHv€ΗΣQe+£ΘMͺΜ­&ͺΆ˜ϊ„κΠ¨:0ϊl–sΨ€ ‹ύ‡’ΰ;‘K"A­/"u'b(ž&HU2l[X,ςΒhkx'Ά¬ύπ;τΰݞΆW2±Ž’θΐ[$χμο²PFAάΡ5꬀Όh‘Α‚ ‚;Oq ¬‘δ₯εB–[BŠ%ΩjAEZs“ς<₯(Ύh,„œ:ύKJx +Q(‚?€n]d9ͺ<φ!)ΪΐG™r€•Ζ«:κak1χ@36₯rυAμ‰ =y Ž*“’/CZςŽS[¨“wVή•rI–˜₯‹fνΖy±αΈΞήEεΧ&~υ₯,KgΑΚ₯pA­M0o0σwY•JAΠ;Y ©©₯΄ΰP&Ja§π©“Ž&+/X’xJXθγΞ6βεr;~8Ϊδ#[ϊΡ6x€6ω­VΞ­ލΝB±Lœ4P7!Π…2χ₯§ΙƒσjSηλu½£…Ώκ‡£^­΅ηkαdΊs·P!~Ϊ§˜lΪΰξΉx§9ͺ²:τs ‘σΰ͞X©w^ΰΕ«— δήΈ—œ|ώtX¨K`ε’[hιψZ;Ηޜ›=>s·Π0£tΤ\驊β9QW(Ot«M¬P )£-a‘W{Όη_1oOλ|ωp’Uΐγς§@γͺ“]L½*³`j*0‰8%œ’Z­„–εςΧIϊ„6²Δ@–σAύ^xΌλ’ψEΚ)$šβώ„7‰NOε>ρTδa:ϊ謉GYΡ +S}yœ»ξ Υ ƒ!9 Rqb¦_­™.ΓεΞ¬wo΅Η8@Ε9βFRB¦.*~”;hX‚‚'hˆΛ"–QΈι r’Λ‘ψGZ)έ©žqΆMˆΣOe1ξŽΥ―ι€\£Έy3“±“Υ©ΌS&uΠU³ZΑA‘AνjeΪ4ߞ]”οώήΣλθFR"ΫwAœα”2ZH!·ˆ-Mά–…q†˜+h'!OI=£l!πŠž:Cβ¦$lb½ς‹£ ϋ³ήΓεF_ΠΩ½žs!sβ…·X)ŸQΡΟEH’πθlάM­rŠK§μG\·kχξΚIJμΛ&Π( ΜζZζH«σ|·γoε½)Ϋύ«‘#Χ?Χ@’m›ιrΔj &,AOŽFΣr“ΒΊ…ΑoΖ† 8³B«9ξ½Ψ€ «U“ΨŽŒ-ΒΥ¦¬Υ¨DnKΒΜWξι‹£ Nμ•›{ι +Ώ [Dw₯9’:}¨­€$wqΰ‚Sρ}GTC±λ$˜« ΊŽ6Dή­bσ–.ι‹£΅ίzνΪήΰu΄:`βD‹k Y tq΄ΑίΎΑ'ΏτάΏΨθί_zh8ΪθΘ]9{—aΩ•…3zν°ήδΦΞ**˜Οp€ˆ‡HΘ „ι§(”ΓΜIՊ–H#S’™˜¦€‘ΜκhΆbψμ²ηb’ƒρGFΨpίρΖ‘†?O ’GXv™l±Αqkb=΄Κrϋ‹άAό„@EZβi₯θl™ΚG28ΌΥ΄›Bs7Sδjο―[ΜχDž}λ&σ¦/b}V«½8ΪΞ° yXωΤ…9,οkίό/Ύ¨cΈƒδZBζ‡z&Π%ŒmθœGhSω"ηόaΕ‹ͺh•·₯lg’.² X&iЦMePyΙW½VΓ‘Ί--ŸβΞƒwtNŒFs|y4|„β=œ°c‡ηH­¬μŒh^8[H\Ύ Ψq?ƒνγ –nΘp •zhe—›A›QE†c*A]10ΙύΐΨl ΫSX——ˆ Aζ‡ρΖ#DΥχTκ#Μγ$^τsΓ)₯L +ύVδY‹}Ϊ2ίϊΥα,Pb€ΊBο{@€˜ ω·:1(@―ώ”l‰N)|“‘U—±Β3ζα«ψEŒ‡Μί\ I8ˆkG3ƒ~h~Κ.Δ΄jQ‚a}–HͺFςΐ‚ΒuΡΑάqW΄ œvξ{<€› ζν:9Z’Μ +©ζˆχbr.V%"Z.'‹ΡuŒ3π2`DΘBQ² +8Y„]IX„f¬‚7 πHκŸΤ0€ρ”ώΘ¬έ fƒ„‰0Ψΰ™%gƒ°ƒL;‡λ>GrτΏŠ΄ΠΡΩ*JY}άE a<;δ +rf>¦&w$‰c˜0`*5°h‰οΦE6E›¬β0‘?-c)V±Λ(ͺ; ±ι½*β š}―h“…«Ιj;ΪmpοΥό—h)δbBΠ€ο¦7K΄Žl§WΉ­Χd€r)A;΄ϋ$ρΓ‰(MNUwδ“=½ΜΐEΔψυAP3XΦς4η-θΚU¨9’¦@'Έ§―,Βx$Όdκ³ +Zα»ωFiV”:ά0˜—’ύ0iϋ™ώ:ψβΈ΄M»ͺ‚(Ά`d§Έ΄Šι‘΅sφ³ + Ϊ;€DΒ΄O±αpΙΛmz»@^ξ”ŸE0%9‡λ<Φ#ΨG΄3 ™όΫ1k +nJ^Q}Ω΄»ύˆqΤΡ ͺηGyŠ2έ†’U˜Ρ*i¬t1e·£Έ9ΕΙα5ΨʄTώ"¦ηŽΔΊάθ%οεφ"x&#₯6 +»’τo€ŽzΝρj―ήITV‘Pε,vω‰+ai"“AMʜ°AEΎi1ŽbΩΑ 8λQ„ΥŒ.Ž6ΝzΉωα{±xH‹S—|)ˆœƒ#adϊA<•Hψvp=q\?­γΌfa`o‰ ΪȎΧAT£ήh?™ƒβd% cηŠμ΅·B’©Ό–­ftYRΩBΎΥ1ΡΧ°¨Ξ„Bii# +jXρτΓ¦ ±ETΩ2θl–vQVαm‹ζ`•έEˆ…/—W^G›BΑ–‘bm0Ω‹UΈΩr/xΓΞΝΫήMυ»&[’X―zfˆnΪΕε>/ΟayRˆP‘€G–‘Λ >qˆqwn›vq΄Œ^[·Νƒί.B’y†J JG|’šΘ T’&έ&tΧ—Λ·ŠEcLΚzρ8ΊΑ%TΦ`Pω ± +Λp†UΌΓ*&β’\5˜q”鏓… ΠHμΓσΔ%ŒPuZ8“*‡‘½pύƒ/Β–ρB ΌΈŸ©U”53~ ζmΪ‰Wπ?ήΉγϏ¬ΒΫ²šC¦‰ ‰-y<Ά€ΘŽGΞλ»‹£uή†@½E8ήZ„l­‚ΊV_ˆ<^PΣVT;4*³ΕΑK«pU@Ο"Ύ†qσœU”Ξ +³p2Kδ[aηβ`πNOŸ±X` +€˜p’Wj™‚wζΑ+«θ–M!0›eΦΑ4‹0‰‹£ Α뀋ePc9ΤΚ t%unξΗη+KW:`ι’‰U0)©Η‰R?½K‰qsiƒW™jΚχΌφO―ΌΨ9@Ϋr.Gρ8»N}W’Δ\›|kν\ϋHΎ3qm.Ζ}φjoβiΦ¦Ϋheη•W–Άΰ₯±xnOζ;e!γρ€Ί|†zS° °₯y“η΅0n0’Ξ­e|Iθc‹U(;Γw“JvK_Yؘ–F¨……Ώ°±l°ΒΜ­Ό]#}ƒ&ΊΠ"*00?­Υa š©ΜKz‘uΓ€²Nκ™gύ¬2b.Ž–:ουΡF½x‘;―lΠF/„ P₯ͺΦ5€Ήϊ½na.5Π…²½JtY$ΒΜ΅p‘Ή^΄Τ›–:•ΉΦ°P*²λ…Y »h0ιΨβμ’ϊY–ιΕΡZf]Κ΄sŽΒ,‹b™e±)c™©±Μδ˜₯z0Δ™ΒCA‰ΑoaΨP…―¬*Ά,KΊΜε#D³ύΏAŽϊτϋ"H}Όa@aʍ%νΛ‚π/Ά§Δ1#Γλ€žΑΟ0ϋΡ8Ÿ„hx^$ +&BΕZ•ΓΕ αf= ζ(γbqιƒϊSP‰£Ο qΩjU—wy†JΣMJ0—c™‰~Ζ@JOλθR'u +ͺ‚JͺΩžΡΆΘ€γ έKž@ί2”0Έ”ΰώ>;ͺAXQsNΞ&bT5#(+‘F€^POeΡΆRž")λˆdYίT±ΐiN£—Έ4*‰E„ΙO”b¬IŒξVΌƒKaŽΑ“ύ‘”Rž{Έ±vR"q<ΆisρdΔΝΕ©8Ζ—AaΞ3Ž0Τ γΙTgΤ3¨ΰ‰ι‚2MΔdH‰iΰ†χšΓλ₯QΰKΠEGΎΘ Α υ!ΠJ₯ωJKD…φͺ {yΤςWΗϋ_ZιΚϊΡ}ΟB1E,ε~Ν€q9±ΞίTΨN― R„Ω+ώL›dŠ€ΥΡϊPA->c£T€~‡lM ΰu=tV"Oηa Pc™OΩ„mœΕŠ4–5KŽ­…™1ΤnίwυΦ 0@PΊ‚ΠΞ’ω +λ¬βό…Š8 +³>τNΩ(0m€ABd‚ Œrβ4'¬ΩΙ„*Θf\Z¬‰[@Ϊχ*Hμͺω3f¦*iξ Εη³ι1˜§…FX$“ Τ«œΦΌXŸͺγŸmψ&π8Π’λˆe@άQ·‹vVŸΑZ#«rEυNL€jz˞‰5H~ω-1d”‡2Σ1šΰ΄Α‹˜$HŸυ1/φ[‹Ž‘n 5/؟mΨ³υ—πyθnN’μιθ{) aΤϊBeφ$¬gΩυšl!ͺh £4λΪ—§ηκWΞ6~›sςvΝXΙV„3j†Β%Ď³ζ9؊$ίΤB* H Γν«φ˜}αlΓWΟ$Ά9iGαMΡIhσ(dΑ©%α¬yΜ«#,£χΌk3XΡ’ϋqφn}N?qΆώͺN%0'Φλ28 rFμPGξ_ŸBε"eΡ‘1¬‘έΞζE{ΚO»΄ό’NCΚΉ™ΉƒQ!COυΆΨSNNV@pfΈUž½(OΩπgλ/rπhˆQςFθ2Ή †<›ž + Ι₯'¦0Ξ@΄½4οΩC6ϊΩϊƒœ…cΕ$&@Ρ<Ξ»#†'3RMO™6J܏KXGŽΖ™Υ7λcφ³υ7…Œ°@…L)U?bηδL; ¬;›žƒ”υΚ9ˎ˜Α†QDΫϊ=V?qΆα³g,B Ζƒ w7“οεκœΥg€€"Ε•[ˆΨ”§·μ™Poχς[ς}/e&Αv¨’Ρω'‚™Σ΄³ι1―±ΦίyΝx@Ι¨™½XŸͺγŸmψ¦HI£ŠG9ϊΕWΏώτώaV†χ_}RώΏ>3•H•β¦ʝώξϊϊΝΝΥνωΓεΛγ?ܟί~s9«|Z?Ό½ͺλζUPαη†Ÿ|±Σ:€+"s•π_Hα‡uX~H Σ+r²|υd=ΎCΠ^Ÿ~؟Ίι'UΚ,‘Σ +Z °ι3Ÿ}]φγ—ΉE1Ϊ—ΗίܟΏΌΊΌ}8ŽώWܘ{δšnΑξψ³oΚ¦ ¨+δΞgrΜ€(£Œ? ΩΓbzό·<:ΌσΡu­pΕΟ.p…>υp ΌsΨΟ0lα—ƒ“ίςμ5­(‘|uά φΌνY„xσΩγσ-7J}ΐ|!Η}φΩΟ;\χΤ±Κ8Œ[!h¨Wˁ{Ίfή9Όψ3Κόόp% ͺœΌ WN YNf{:ΐΘ#UξωΡεΔΰmO‡u„‘Έγƒ{tlž-lIXΫ[žί-ŒΤžGΖCn~Deπe―δidΚΔξ­cc‘ΖCϋ‘UVT―hφžIΡ*ΩΎ[²7I₯}Z“ ϋοIΔ¨ΜΜ5ΉχY"TdΒι]Ά_Ν9ϋγΙςν“MŸ8YMδd5Χf%/ŽώMέ±UoŽΦΘ½α¬ψΕΡμ6ΙlΠΚυΧ‹£Ω-­·uzyΣVσXέ΄f%/Ϊe‰Υ”&₯ΣΎ=Φ™…i²©‰]`ςEΑλΤΑΈͺRήωχ9vx=Η_A_ϊ/ΎzΏΕ—χv]ώ/ΎzΏ ψΕW· ПޒηΫΕνξψןέέ]—ηΒΟ.οos‹ΖMΏ}sυRΊHόβ+krΡ>τοοξώ¬ v—ΫxwqωϊυρŸ./ŠΤ~½Ϋ»ΕvΦΤDεDΑΊ€ΝŠ’ "ω"½Τ–€[Άψъl&₯W^¬ $€,ι‹υ€VJ6(ΰΕ!]ͺ3Bθ4U‡MiΆp.°™4ζδmΔiΐAγ•dΛύ8{«|χˆx[ΤqLR&¬iμΩ“Βš$bS„;ΈtΛ ήςhί!60©pηυϊΦguXύC샲ωΩAΞƒ> ―6-Šo}ΆGΨσgΟ·hηΆ{ΐ°χΔ0QPL&΅†½ϋΙqktΑ s] 5΄λ€=[`Ι³Ÿ}»™TΏ:ΆhΌΚN“γ|DAκ«CU!ηΎ˜κYnVΦησΎό£Tιγύ>ioNξ5Ι§ήΥψτ–½νaΡI―8κ αν۝4,¦ώ­cΰ{ϊ‘yTϊ±ΠΙΈk"ϋB'kΟ” bš―¨b>œ4g؎q¦Q NQ1·Ύ)nœA?φaΙμlHηAΥB*6NΘtΡΧQ§Am¬ ά,‘³ΰγΩλΏ9š’S¦k1…iωΐ9Ϋx'uΐv^,7¦Ρ« QΧZΥ_–"ηRy€d +ΙωsHΖ³3„±:Εt2ΑV'Ήλ¬αέž€§«―Ώ.ΖFΩύO5pϊί—[*R<*lhB†³ ,gιz$E›3«„πh„πιŽfzGA&E/<Υ#ΜΠKL:υ#(ύ¨εάEΨχr@ΈybςF@Ν5@0œεA+ƒΑ5@μΑ<:I9Ί`AZŸα§H$v=“ŠKλYβyΘ D EDΑb†Œ4›#.ς)©ΨlΜp!£δ}ΞHLΟHIqQ Δΰ₯bΑ KsJ2ζ)bžV½ΉE5)­μA‘ŽΘX¨‘—bAΧvΨb χκΈgΨD’¦r²"q!’ΘA’Έ`β8ˆ'Βx3ΈΙXΜXe‡μ„ΘήC’Lδ’gχ¦Β"†Έ‚pμrΔbOžC $ΒέΨΐ ۈς—ΨXV< R±]’Ύsκ‘<; Έœ +²O"+>%d–ιΜΰl`jΜ$t‚Š…~Σ’8J5¨ΐyΘ‚Έ½Ž:SΦ4pT¨b»Iζ—†SICaqΆ¬ώ9 ¬–h/Ι `©tΗaYγEj ²’€’"ƒŽq %wΓρ΅Γ™0JŽ•²$§kŸ(Η:Η+΄.’&΄ρβ ˆc±oΦqΜβν΅ι³!NΪ‹xΟυ’ψFΥΪ‹ΠΟr΄’―F;0nb—ϊi=Q!E«bx͎Mˆ νˆzB ‡d£—„,hq―…_ΰ2J£τυDU Κ”etφb’”·NΨ8ϊ,!Ž•ΥK₯w(ΌΓΜ$ιΝ(ΔΗ+ΩγNφ,NJμWv§RŽΥoF"_’§ŽύF,³w’ƒWΦ6Θg„ Δq‚ίA‹Ÿ!Ίgeƒ‘ΫΛ= Ό'NpτΌap'y% Ό}bšNι’T쀘₯Ls—"«YΓ<±mZ’% Ɯ6?6ΒˆΰFνΫ‹˜ΰ΅ζ<΅@„k–eωή+]rAŠ`vŽΘςoUκ”μβj0³Σ¬&TΊ£mw@F€" ] €EΒ +•c o+λ±_-‡:J1)ֈΊv,Β!Ωσ²ιp”ν£^½"άΰ”’T·K¬OdτNC₯™ηΐJΈŒλ€’Η€΄>IJ} ©Τ“뙐'^kιu”²C`¬“Κdκ…~²c + 3²3QQύΘς)<žBiQΠΉ€Έ L#gυ/9v@D)tΌƒ±œ 6 nλ;€ +@^D%,؁VΡ§"’Θρ:OEq§Z:iΑ i^šoJ'ᡬρΚv*‰±oΜΒΐΒUΆš΄Θί`όΗΎ3η¦χΔΪ‚5’ŸΦKΕ‰AΠVT3ι; 壐šˆΊ7 ΰΜA`ΥJO"ίKA„•εЊΥY},)¦b%p{ΗΊ('Η’4ώΊ€~ˆ$ˆδΕ1ΨωδΜ Ηb‚‚,1cελ&­3ΏΡ%‘ζ JIνWζI‘’!ŠDξkίΉ"ϋd+GiͺXx¬tY £”dw12g=ITΤbΗ )Ž#͜H/$EΦΖσpx/©Ϊž=3±…Zm‘Ε6  $ΎL5s΄׎9|^Θ7λM e#ŽΚŠοt‘“₯6πΰD|KΘͺEuCρ‘‘S*€Π©Z“T($"’2+=A€3„Ξ’5W©wHBk©$ήQSUΚ--<€¦(EΙ@”ΙIz/σrΉ0”Μ –0² Υ;e•wiΟ`2»£¨€5ΧXœΒiΊQ«Ρ'>ΖΟΙ*°ΟόTΩΡ‘ ΐŽ‚ŽΜEaˆQρ·?Υ²’pδ`+.¦’8Αš£ΝΕ—œΈΛ½Δ‚Λtvw]ϊ!©I5Jš œ΅>,x«°d*σAκΓκ}IIƒf2sCΛ‚;­A΅Ό έοEfνΔbΐΪρR# •ͺ£€Ξχˆs–’hs΄#.z¨w"'Δΰά±$ Δ#hTΡ3τc ‘±ΑKα$=(ΐB«’T`sHΥι½g-9ΙYΒ}θ:«,Ο€ιΐΤd\qφ½†x“2SΑ˜ζ˜"Θ<("b Ύ—ž‘9JΏφšρ€žΑŽ‘AΨp―kω•χ$mcr…εSPΖ@x ’ζΪHΔ!SL΅c?Š€κ‡‰g)@%C*9*Ÿ£|“@I°…,;jk¨ΰ₯<ew―'²TaΰW {žΝώZ›ΰͺvd € νaβ©%pW;°iυμ -)޽VτD”<1ΤΌΌ*»ƒζ<:/ˆaΓ–Ίϊq0a€EP)6τύ_Dό­ιL +#Ν‘2*Vˆ£‘ΓOΡͺ¦ŸLήυŽaO–φΨή›ΖšŸμ90C0d`{o>h~>>pΰΐ”£e`{o>h~>>pδΐΑՁν½ωhΑΝ>>pβΐn:Ό0^3šη?Έ¬¨γΊιμšΑ†Ω―ΗG0κtnӱՁRϋγρ3tušυΈκ0n˜ύz|Δ#ϊΊ‘Ξqɏ³_:&ρv©QJ: nF»έgώΌΦŸϋ―υζη¨ •ΗzηeύςΗώγϋ~ΰ΅€4…Y4Ίœ¬‰B‘Ύ™P QV/hΥƒmKLΑ™@QBυΥ +μ“}Bzζxͺ±‘εOΡψ›—7}ου Rσ Ι 6wSι«Γ¨y|Ό|Β–ΐ~U‘ZN²γl. KΐD­…σv€‰XO­’6 Β":»‰Rν ‰"Ίυ +΅H€΄ή˜G»ŒΉ“uI}1‚ WPΕόθ—Ο±F“„ΌYΊqΑςb‚t΄€θ"(¬ έP7©΅³νM~΄oF=Ÿ'2δzέL’TΉ¨Q^u•¦IΊ,zeέ€Qχ—EdΛ{MΕ~oh2—NšAv^ρW~efΪ)^ΉSA†…ލΤ>—τdX"Tœ5 gK… ^‘DJΗ;κtƒƒ:KZ-HϊͺMk:X:(©οςΡh—w¬Σ•nx σβπzr!Ξ©C?†8έ™g‘ «—φ•nΣ3& ¨«˜ΖOΚ㣃ƒ&=WLTku™ +`²«πΞψ7; •7?­νN²ΒΞΨMVˆΚ3/λ½iwh²— ~­@>X9λx$7@Ψ˜"@~œh IΡ¬Ι,Ί‰ƒšβΘΠ€κε γΤ©DZΉg/‹“ŸJ“„1q*ΉN…Ν±eΚF hΜηΊ†qIc₯"捏IŸ6€:₯ ¨ω@kμΪ +ΨI}0’CP’9hΤ‰`ί€Œϊψ1L@[;ic90ϊv Ψ―AŒ0 LXΚm’α‰ΙHbZ¨ς£ ½Sd ¨€ΘU2f1AšƒΐNlΈ±J)@ƒΙ5 )Tr)&bCvv +:·AΦ”Β2δ'‘*ΝT³Wσ0Ž‹ρΑ(σpyWυΙΘ +ƒΉΉ¦ vν°OΖ±u‡h€”Oz=©ΞΧνΝμXτ΅‡Η» +²΅Kc½ωΙ g‚ΈΠ•^κ7Hh ζo’4#ˆžR€€n–_ž ΰ+α–ΓPϊU‚’H{+€:e ~Μ@ϊͺ΄έœ=ηέb,/KπΥ’-βΤΈ˜?²€^ΰ³β.jaRϊΣξˆτ³šν]”‹»ќd•>ι™Ε*œκεκvœ* +KŠΣ“ήΘsoδIΪa΄Ÿ!'>κά‡ƒ7Έ΅IXs#’„ΨΜ/Sλπό:Ε k§—λ5©_FK³[5όš—ί„FNrY&ˆ€]}…υΊα’έΠ$4θ—΄+JTn{™L<™Ÿ2φ2Eι•΅<{φP™Σ`”πξ†PΊ|6T1†q˜‘~΅“ΟYDdψ–“Τ-ŸΨM ͺ\©*σΒ`Κ–ŒΓα££1εFjC6`Λ1£y7l₯+˜xr½9-OŽ[3Y΄α†νKU¬…xᜟIQΘVֈ,m΅Zώ\z93!MΔ4ϊ‘ΚP*-1ΐ0UΑ©ωΩο!€νό] :θt#jΒ&£‰Le@‰ΟΏ«DIΊ +¨a8}ξδΥ‰1±ιAύ +HOΨεlʏ F·Ηό£ΤsͺυA''-―D/νδ³±iΔ0αGί>gψζΫ'„ςφ’‡6ŸI<•. +͌£ͺΝΊkξΜμνMΜφ2²Θ|Λ£ΖS6G%·=ΐ(έ?+¨e{»žΓϊ!NDIΪ,#“/Ί +τΰ;K οΉεžSδΘHΩC?Q +ŽΖ»„΄τOΌ5m&Œ:=ΣμβbAZω΄‹hΘ³-iA­œ^•IΔ4ΒτzιΒή;iYυݍ³I3”‰LŠ[΄X½’Βe™W£‚Z―Ζ4Γ»PGl°#;>™œQΩΙ«α&βf·«‚tߘΪ3?ό A”j&-‹\“›Όƒ΄QέAZˆ€Ύƒ0Ι“[-z}ΞY˜‘π>‚,D'©PFΜ§η΄ω_;3½δ«‘~Υ„˜ir8Ε%τΊ©l`KΥ7³ ]ν¦H‘€Εφ ƒρΛX₯z *ŸζΦ†hμ·:6`ΡMzUͺ―½7ό4ΗF j0ͺ'Μ":ΓΟΎΧE΄xΜ’s|*Χ[!ΞόٍŠͺΜT”\ŸφεΨ\•κΩ`ͺξόnG•Τή­F9Λ<i=f’D 5€ _Τ;ΦJ’Μΰm/Td>Νμόΰ…σΝ‘κ«2ΗΩαC!χ~AŒγΔΧZ λbš‘wήσ0γΨα~Ι+’”QiXJέσ±ρlL Φ΄_Υ†ζŒ?Mž ΗxΕK΄μδ†uͺ«a―QOiΖ›λΥgΡL†h_Φ2.sφ/IΖ 1a ;'€ΣγLθΌ©ΝMΌΑ\Œ9›βOZΧF Υt‘F +)ΧSνΝΟήΓ6²σv³X΅‹Π7šIah€5Δ¬κ΅6ψΟΡΐB5wf}:’€M@#€s²ͺŠΒ".ΓΜΧ%]5g/³y—|’ϊˆ₯–Π0ΓΝ@―§l8Μj²0Γτ Τ܈ XoŽDtdΧ‹Aa˜]Β yKCsY5{zh΄ψƒ T΅B?ΑlυΤΛ‘Ν}δl­<²}šΑͺ H₯aΑ)Μhέ(/6$‘Ί3@•nVHK] hZ”rB€ SˆY/sm ΊΤΎ°~τTPeh›: ½hU0`u3)§}93Ζeφ ‰ύΰT_ •w«Ÿ_*{p] PA3Ώyšƒ*Sg€:¨ΔΝ-Ÿ“†ž4L6i„ΞŒCΧΫΣrθ€Aε³—ΕΠΐ»dz:l 4i„ +ΤΘ1]ΝΜ4’.Φ?—eΞζf)η›σΌi­H *Νnκ°χ ΔB5₯A“Ac4ŠQ €1hT Ή)šΑΨξ}ώQ†™YΒ&§½aΉ₯]UΒu η«’πΠWsD:Wρj₯)ef‹ΑΕz&ЊrΈ|νkdq±ΝΔhΆ:ίπiSZ₯¬G΅¬P:w¦& ‘›[”EΟn}b­ν­ΚέΉX 1˜@uSZ`E(ΙζjΆΨ2dfGΤΈΨ™YVšƒ “(EP½P œ€³_ngF3›Νπ€š΄@ΖεΞ>,"Εlz¬Έ\†WΊ?­–η{2š½›€υΞͺά„“Θ6Z0Ί£&΅ζΩΙΦ%Lη―%ζζ%&ύςx”U + λ…4ΒΤ]9•ΡJ1ήsz]%³Cg«G†Yz|jAuOZ`%δ6˜mpσΝιšΉΩyΑΊΎ ήšΥ·(hω‰‚Γu liٌ»Υ@Žyf˜ς^Γ”χκ¦dΧζgxŸΔڝ?π~>­9|Zrψ΄ +δπiC ‡OΛ@ŸV>mδ˜?ΧΩάζ>mδπiΘαΣ*Γ§ >-9|Zr@ϋ§ΐ δπSŽ­hψ΄ +δπiC ‡O«@Ÿ–Tτš erψ΄ +δπiΘαΣ†@ŽΩs½nξ2ƒ‘iΘαΣ*Γ§U ‡O9|Zrψ΄ +δπiC ‡O«@ŸV>mδ˜='>­9|ΪΘαΣ*Γ§U ‡9|\rψΈ δπqC ‡«@W2ΛΘ8Μ9|\rψ6ΙV9|\rψΈ +δπqC G΅8 "·β*ΓΗu ‡«@WͺˆίηΕsΘQ-“ΟΗu ‡«@—>nδπqΘαγ*ΓΟσN%ΓΗU dΖ‘K3TΓΗ >9|\rψΈ!ΓΗU ‡«@6r̞ߟ«@ŽΩZ-ΓΗU ‡«@7rψ΄ δπiΘαΣ†@ŸV>­9|ΪΘαΣ*Γ§U ‡O9|Zrψ΄ +δπic e +7hΜ<™”R^γΉΖ<#¦δϊΈ˜©ΧτKΘJcφ–r=l©1ϋΈAcp‘1糁f³gσμeјgŸy1Qr›)›&ά,¬­5ζiŸšΑσlΟMcnΞΖ4ζΩ ŠΖl Vc6ΨυF΄i5f³εΜ4ζ%p0ֹИ}ZiΜf.šiΜ.4f0…ΖL‹ΤRcp‘1σBΞ5f€V3ε·ΉΖΜ[5ט t1ί”΅ΖΌ +οI+™Ÿk̜ήRcζ2ζ3;טg›s³Ε¦1ώΒ4ζζΘLcnΦ4f5σ 'Tc΅ZiΜ‹Eξ[‡qX|X₯‘΄˜Λ Ζ<[­hΒ³=™@+™{<טysΩ΄’™Ζ<;ΩΊ„₯ΖΌ@(јgΘc:γ8¨Έ»Τ˜›ΟšφΚι-4ζΚΕ&MΈΑ§΄˜›½›[jΜ³shζΆΤ˜›Sυσ]kΜ ”εΨ$Ϋ%p₯1¬I}h5f7UpSυ‡¦βC«Ωξ/ο8ό}φ”AΡI[NR œ@U—Σ©ˆς‘jː²ΎY΅ε€tΙΣ–QW‘<0Hœ€Δ€ {“qX³ηΔΩΝΑΤέ Β©MΓd§t8Υ–“Κ΅¨Ξ;š“pUmΉΖTί”Ίq¦-«Θ€-›βΓBόn°ηœ€&ίέ§-š€ͺ-cTZ‚iΛI+jΈΠhΛζq‘jΛK@Υλ‘t“²Œ³ςiρ˜u‘jΛIc+°¨ͺ-(oš²\Ν‘*ΛIzT•們°lέbη"n0ͺ²\@c/£MΚr¬Cσ`n@ΫqS‚{K* ²\½νsR*ƒŸΫ OΑ<ͺά] +UΥμ5Yϋ¦ΊrωFWn€¦+χ5½Λ”ε^ΌP>΄κΚ=:φpͺ<Ή~«άkΤ²σ3―ε8Θξ7:υ(·΅Qφ…ώTue8νδ>Ue9iυ)ιo g:tςΗFYNͺ °Ί³έIΛψ¬Κr|[€ͺ²œTxP΅e8ΪΕ/]΅` tΞ¨"ΎDE4Οέ―Ϊr’&²Α՟΅’·)ΛI;!Vͺ,7@S–1–ξκΚψ’Ξ«Υ΅εŽ―Ίr:•‡άD“P₯FQΡ•`˜ͺ(kίN‚ͺΕe=nτdk:`g3“J ¨J­¬΅·|kΧθΙ½]αφ9Ά γhͺ'χj +𭕐?LOξ‹οe©¦'7 IOΐ`zr―&ά=Υ“{‚PG}3F½έ¦'χv‘κΏ a˜τδ²%΄R6Ο!! Αλ+Ι–ͺ4dC]Εz1%ΉPυδd…„CΥ“—¬t¦'G ¨p~B§]€Β,„“ΝMA/Š +!ο&ΣΙΌF{7 +{¬Ϊ£4—j«0’-:/α€½<η%œDd›½άSum ')Gιζ%œ4₯Ά-αT9Ξ”!;š Κ X«8i/Ή¦ŠSoύΪ*N}Vf%ΆΛ+₯ŸΚ8I豁lύŠm'P΄oΓ±x6@1rΉΆP―TqRͺϋ.6„έ΄,Υ8έ’“&E~‚΄ͺ§2NΚ|š*N}ΧΙ4Ϊ2N½³7k„ΆJ|m1&σZΜ’θΊΤ7ΟΥΠcebSSμh’θœνQE'Y ­–#Ι­©SAmέ΄(:Ρ“œo’θ$ήΩωY3J;EΡu…«j<£ΐœŸΝ”»tΜΦ€Z aš Q›€ gβL#”Έh’J^$ηv&αtΖ Ϊ΄@ žέζΨϊΔEGωΎ1Ν9EέP]hLΈͺZιQ‚˜‹Γ[?™p•χ…Ζ†[ΝE“ w56ά ˜-γOJ?Ν„ΪΘ:5 αWΫ5ΞꜲ7ΜL”Φžfs9ΌξJkΝπ3z5ΓLF\©*Χ\|oΊa{σ½φRonΎYOΉZ³βN ΖŠ;λεΛIευɌ›P7Vά<špGζΥOΩ¬—vndw*.pωΝD¨Ι'ΰh’@νύΌj͜Ύ«­΅ΪΩ)˜―B{°΅‹•bΣ³-™@ΝΦMΐJ€\"ΫhU‡«N/]dη[Χ0Ώ”š!Œ!έ‘$―b¬ΚpΠ8ZύhηΜ"[]0ΨDTrκem©ΥiΊsΣ`ΣφΦoΆΗ`Qkκ‘Ίΰσρ•š•·ψPEΖΙ!Π[J6cnM)CΡΥzΣS5h³ΧΓKβNjͺ_όσδ}κΎίWv ¦JΦq½!˜έB ͺŸ½χήO^Ι‡ίΰH!βnH§¦χήC€$$ε”οΏk%ΝΈbSΞ9{vŸΟξ>μρhF£ΡHσ©©ς c>eΟ(G,Λ¨gΈ=юX@Sjg‘€‚Mh§b½ψ™­μz†mρ«μ©2]άΔ$+&h¦K3“ +(΅λ–3;Ξ0!K7JΟ°RcœΚoI)1ΙTeΛ|fˆPd2ŸšQe’κώ>)«n0,L α]΄BΌˆ‹a-UI2.­±#ΝΟτAδOœx0Ϊfτf‘•E£»ΡŸ”EΡ½NzŠ‘ΑΎž,rΣ|f ΄7=hlz1Š85ϋηξ‡tΓgœ”γ$+slDχ=ΰ@5k†6Κp† %Ξus"ΫΆάNBpR‰‰Tlf_1ηrΪΪINϊ0ΗzCΧ.SΈύϋ/YΜΆ¬!™Ψπ$˜xrnWΎ˜š%WΰoΆͺX κΧόegρΆ&΄’F΄ξš­½lP…“P;㗝ίΫ›ˆφ>μ30ΩΎcNbϊmr1SžαœL”UG Ε…Ε έ±τ)ΗΈSΆq›D`6!"0ϋ _vΜœ`ύ›ŸΛ² ‚9«‰βθCqb&όY‹$zHbΙ࿌p•z§ίƒhIv"Z²λΦeλΙNB½ζ’Α^*΅±ƒ<Ψ‘eN/mΉ¨―—>τλ΅q€9¦‘9ρα’»²s!ΤA +½€β"¦^rs£cqΨαeA/‘ΈΘ¨—Π„θχ@rΙ―E@Šω/ ₯œž»ρjρ–Φr‰=/§[\΅„½[FWΰ‘˜™ΥJ’a’ΐ.² xwΉ|V)Φ‹VυhKοŠςI±Σ©΄κ©σZ΅T9/kΥϊϋv«Zή―ό9]‚fjty·ήq4ΆOλβΟf…5„ώ3FZͺ'Υ?*΅“Jλ­RκœωύΪ¨ελΕΧZεΛθV΄΅6ϊeMΆ»Υr₯mΆrΟΡl΄:ΨUψ_$›ή\GbΠPxΞΧΛ &ύVž30ή:2w#j΄’0ΗοΚ<¬Wώwσ{€kܘ +Ρw³΄0Όω~μΑŸπˆŒbΡϋG!Z†EΎ9ΓΓ—‡$54Σ1%\`^ΖI3!―Κcς“Xή„;¨‘ύΩψ*‹g‡Qžˆ@α.ΉΜ +OdζŽα†–ΌΑ@rτ5Β΅$«ZE‚ABΡ©ιθ¨GcŠŠŠμ s}˜/˜†;VDA=Ž•?Θ­i˜5F€S,“H­€$UΊK0;΅Fή©τ™LE«Ω³”L 2‡fδ Π§’\R5ž,:A,E!κ‡ν”b˜k =‘iFQ#ό#`π…NθR°Φ/€©<»=~ γΡdφ-6’Ρ$YXΗ[tΨ"Οώ‘₯XΎ ,£Hq;ψIJMEΥd‚ΑH¦DΎP“<'ΐΗ½¬Ήα7F<«X)]Γ0Ώ@vA₯η†7•ΧeΦπTπ7έΒ0φ@Ÿΰ R»&±G*R½ΞΎR2=(έ7N*₯Hμ#ςˆΑZh42‰GnhHv’LT£z€’°‘©Θ+UdΪ°V*O3€j¬”Š9d‘œϊΒ:σpQρ’F…>υ„ Ub|ΠcdͺΘ.ήθ欩 +θ\‹½²{c, +#Ψq¦Π²ua€ŠΔ²Δk ‡HSρώ[Ar`™ .BΑΝE·εΠ=Θ6@T +Ϛ +KR ‘ž’ +ru-™Ι,vρJ΅Ξu#“ŒΖ½©ρH%G[E1§1QΗΜUCΟ=σM€;ƒ2©³ψχ "„γ +P’κ”(Uΰυ%T#ζž°ŒξͺQΜPY€#ς>™g1•°dvͺ +ΔόΨ“e‚wΓ£ύ©ρ‹\ + ΄?Νάw ?ΐXδFG"θ₯ζF7ZS`”,—Oc­μ—œΔ©΄1΄ιD8ΡΛMd·ύ€Μy‰ΞπH72λbπ…Š©K(9§Ξ|+Tτ +Υ%:1’t…dΚ·—b>υ*^ORjML‚Šσ +ψDX)hDJ’ΚιŒroy rTˆ˜P\A7cΦKg ΘlΉ¨•i@ΗΨ©ŠΞΌvρ#ωαQ‘%$j;π\U€Ω±)βŠΚJβ')¬` ΒΑAα…Ή’±‡(Ψ :η" π;ΕΘ΅«ςdeΠs‚G*¬X}j’ρb•"1‰7P \μ,‰gΚDxD Ρ‘ƒ|£i,Ε‡j$ΣEFbό–“$ΊΨeΡΕo`‹‘¦ς²~Kσœ™ν&άCΈ―U}"³΅šΒ}Ε±€C€ŒL(Χ4 +@x_Ž μθΡI’bΌΚD΄o‘!!ρκθ.+) fB…»uΖξPΝvάΆπ@Ε.:UF RPY²VSœΡ6ΥYe Σ?#`z  ΦΑόγ^/°T5Ιψ¨‚WώΤ ­³Δλ”τŒX\3|€‡ήiCnj€(Θ£ΓIΡXβ>ꨨ)£Ψ―Fe2T†1€\guΜγD•DFŸΤ­Lϋ!©;‘paνu™εGŽΘ*‘ν‡Κά3ω8ΕάΆρ 1N’ΐώGήΜϋ&YWΊΒ*=±ΝMAΩΔ›SQλ·±:ζ7pΞ1 +₯„ι°uρTx’qτΠ)η ž³*ϊž$j£' πα06%kΜ›˜)μ±”τ©0ωOV˜°€aLκUc©4Pk€Α3y9~#³ΐk<ƒΚΔ䂆ΜN†8¨ΏTΊ [θ*†²'h<~Aζ5χTΜΩ.Y³1˜(2Vβ€( XM’*PΈΐΈ0be +­hLB‘€ (%b <’@ŒPΈg£όΡ ΨΉ9xŒυK‘ ­ΔKk¨žP&‘©Fx²ψΛ‰Š•NrH\Θ?H£œS2e%!ΏI ³5Q’I ‚ŽΤahœή8P&ΑΒEdβ<‰ΊΔΛΰI&³c^K±΄ +Iϋα§TT>Ι\ΨθT”IΈ%'<ρt©¨P<2}ΤHΧΥΡN'ξ@%θ₯„ˆQ¨:ΠΕOx,5…νλGΣΠ€Ο&Y y³‰O‰΄ίtLq'SR’qΧ KΐιP±ˆ4νŒR;IίH€˜Ξ+’Σ·‚rϋMαθx0β1„ΏACBBXΤ»ŽςC* +δ‡ΩΗα—¦΅Ή L Ηψ½dS‘’šBρl ƒ$ω‘ax%q ¨νJLΜJ"‘‘Iβše’'!”ψΑŠJ?ΖΉa ά.Jγ,ρR;2ΈoΫ#‘ψΰέΜι 5τŠSM&1bΆ$PΡ /}¨’L,@iY•xιiΆ1hϋρ*€’AΗͺΘcρ‰§ͺ`ΤoΞ€$ιό¦s[P=@·fe\†QΚΈUU +›’yξ:|@UΚd3‘·16“2—&(»]’"₯#‘€³Μ ΩJM,O2*°51™Ϊhw!‰)\Š”lI0ͺ*ˆ,PyȐŒ)R -%ΥΤP™2LkΙ‚W©LΙ!iΤΞAo=ΙΜ³bjC6"¦ F mh(,“&-SD3 q]”ψBζρ$ˆγ£’Θωπ %EzqΜ€ ದx+9Ε2―βΡoP‹|£BΩ*訆!³bh|6 +Ώ +—μV)^£MNJ%„«XbήeυgΘΣR$Ά’P·I‰ͺˆG"£Β„0‰ŠΦ+τ@ΓJ2Ÿ‘ωA&ΰ&%J΄dΠX~Ef§Ϊ»ΚOΒη”%s+y§ΙΨΟO½lÁΔL%’‘>Ϋ’es–9Zdυ¬ψ,&ΉPΆ'’|˜’Βτψ[uKάΑα²3AŽn-Ipΰ!d?GΉL”mχf2^¬0 +;†[Yb—‰(EF“ρEgΧo$Χΰƒ$ΓΪΊPB’%^ KΗK(ΠΠΤΊpΌxDΖM”fψπDfξUΨ%,»θ%ΠI–ΣΌžΓŠ»e1ToW°3αDM1ωi ;fΑ8hΎr§ϊ»όͺSfΑΏ +Θ»R¦K2―JQμHHΜ0,“Ω€²™ ΜJΝX4ζfΖp’$6^8Ϊ,Uw(•k/4ˆG…(2CͺΞs­€0€£ωx…18'Ϊvy~ŸF¦Ρ₯ +ρC¬ν© +Ϋγ(‰%U‘O1ΆŠ—ΛήΠγΕ Ζ¬64‰… α!ΐ"Ι&£Σ•ΐΒ%€t‡h²Ρ ₯ƒ²DP{`k(…8ΪνdΩB +ŠΖl- •jΣΡA…ŒUPΠ:?Ω½6^\’E`~Έ(…6ΩYVLΟ—$3 +ΫRF¬ŸeŸ0y'ή{κ +»n—θJDa·0Tγ–Οg΄ύαΝΊ¬£ύνF)ΌFOQL%Κ-j¬­Ž7‡)ž t§[1™`\LœH"wUΠ©‰ΜΌtqL"ŒWO2ΉL€h.΄™θhB2²«  Ebκ0e’ί”s3ؐ…3‰ja +Ή…”ΩhμG/:Ξθ,ΟΌΞ%uδΒVi}€2-κΣz’νJό^ +8i€zdIšΝR&a@&,,Ξ-PbΒ;e΄!βy{«‰έ›αj/1Ω‡\€(επ‘―ι> Ϊc"v\Yd¨π†Μ +hCΣθ,0Ϊσz”Ω +Ι +ΏL_FΣ.’#ήώΛΌœ―ΖλАńPˆ}°T +q\ )Z„ΥF» Ι†xAΑT]…'yΖ‹m2­ο%¦6TΡYD‘½Šš$ή°αΥp’nΤIwΤx&>4JΠΞ57*Ϊ‘Π O@ΒAu ;ΦΈΕHFΉY™•”Mdέi<[žŒ†.™ΎH)Θ§α2:€θΔΠ½‘»ΤœƒΘN³&Νε"$G‰gΐ₯ |‰°@~’ΐnι ”π7ς …έυ!η’E +Z‚π'9ΒΩiΙ T&ΡFΖΫP]’#\Μ«Ώ)O-q «²°LvDz”—²Η!ι₯! Δ§~‘“yRb5Їr’-s–RdWA›‰HV~I§όάhψΐ“ž:b¦XR +%‘YB#YUS<ΥD•ɐ¨τβ*ˆ*;ΈΡG@ Γ!₯1«oŠρD‘nJ£tν‡ž:K–aX±ΡΌ*!‘kή²jά Œjρ`C s„ΜM,"?"KΘX„ρξ"m’Yγ4$²ZΠ²$Τr(n<έ$b^†ΫA’Œ ›β‰μ g‹ήy2ffΒ‹~J¨Σν][1EΖRΛΠ.ΚθŠΜμ― άO?“Δζϋ‘ΐ4@EfjΩ£h›3‹―Θ3œΥ{Χi>€T“)ˆ$?…g ’xιcTxT.jσ›dY”'Aβ>bͺhJxΖ#t"ύ qͺαPΔ₯zΌ»C›΅iEο7t^ζY"Ο@ό&ΕσΗRς +h‚g˜dfA}PςSΈG’˜ˆcXΕpΗβΥήβSΩ"ΌAΐλZΝ,Q0k wέ‘’Š*?zDΓ°Ÿb―z.m²”("Ue*“©}GΠΜ…ΖF™2¨'£):‡‘eΑήH±θu‹i£U£Βͺ ΰ”L HžqwOWWI–ΛΓΨ`ί‰;0Αω ώN2&’#'Ž@uG0-“Jg2Y™H˜Ρ€»D)₯4ŒU€+-κ`/Mί]ζΘj¨%4–‰HgYŸβ%Y›(«žω:·Μ’3J‚Κυ3R+!›Av 떝Τ‰έβ2α•Όω¦GΖ½5/Q#R*ZςΓJΩ†£‘ρNeζiΌΉΰ#rŽ‘ά( όBΛ (Λ‚σ=}ΊΛ Zˆ–ίΝF·^ŽΆ?ŠΝJτ»QΆϋAϋτ€‡1f3EŸrΞaεΠqkΚ(zό§Ή‡ —{ΈŠ?Ÿυ“V΅ήΩΕγμ19Ϋ_DŽšψ&ΙޜԺπορλ'Μ 2—.7^+ΡL«ΫώˆλΕχJ+zά*WZσΑο’μeΆX«Uί[ΕζG΅Δ[^ΐμ—£j΄ΩIDΟpΑ—{ΫΞGγ‘9ηbπΞΖr΄I]ΐΗΏk}Ϋ³ΎέM©‹€φ…Z±c΄<ΓJ}8Ϊe©‹b«Τ(Φ’ρh‘-*­ΰrΥί€ΜFΤ§/έNt§ͺ,ΟGlaΩk8 -Œ“x|°Db_Sό‰‹ŒΕL‚‘•Žώ4Ή‘@ΛζŠ`y€©GΡ"KCΰqckˆf™’ςόE@ΝΉ"P‘Ζ5Τh²Žέ«Λ[kbΎγ€C―έγΚφlOx(E—£—υzρ»RŽjΛQγ?ˆ©εhΤ¨ $Ž΄`>γαΫί5ΦZGEk8°txq ’ zDjhΧ&εE¦eβuœΘφcXˆpΞ±ψ *Ώ­£Šσ§(φώfΛ ΰ2Π Κω₯ΨX¨σΟ΅J;²Ό_oό^§ ~Μ₯λϊ|tωVŽδε4ˆ&ΏUŒ·ΛY.Πͺ5=ΆR«Φ£¬{:ΟζΒ›,¨Έ|UmWAΐ{{8οK_τ)Ά«%Ϋυr·Ϊ σιj$Ί|Rlu l…;Μ‘wŒ/ΉgA›Ο‹ί*;Ο'ηΣV£SμTžs•χV₯v ’Uy«UJ[ώNœzχ;ΫhVYK…?lVλ'j½γψΊ]*Φ*Υz₯wWΆQ8@έΜ3|±¦ΤΓΥs‘ˆ `½A±ξκ©X/7Ύ«WινjΗΦ:λ8ߝTZ₯ +›ƒϋε•ύε/‚ψEΓΔ?.WKαδκΏΧΓ@WώR›ΪϊαZeœX³/“_fFu<ώβ†ΏŽΗ_ρŸAόρψv:Κ‰Qΰλh1Ή<ΖΨ‰~'€ΚH‚—’ΊΔΘTςo6»ώbˆΏβ_ΞSDς5ΕVώB·‡$—ΈYhY)Ž«CΛΏΚ/†ςίΘP~ωQύ• EqH(².ΙΔPdΜ©π―wΓ#0ι/₯ŸΏuυΩΎ¦ƒ_Aή[΅jρ½ςΌ}ώλφςί|{ω7ξNƒfζ9»4pƒΉ'[42X<Μβ’Š9Σ1#¨(‹˜P_S΅ΗhσοίΦ3χJ0¬όβ_9’ 3&eFo~ρ°_<,Δγί“ *¦θ₯bΚ£ͺ˜β/σ_Γ€O€uˍnλ—˜ω/gΡ*#‚Ewž’ͺMι£L*ώZΔΏdλ3ΒuBΓh\‘ίΗ&`‡_΅5ήMΊ’ΩF«^i΅£R΄ω—FyŠGŽ!ŒλVΫΥι€wΫ­ΐ»νύ9ddκ}3υxΠή0”ώeŠΓ/ΣδίΘyξαi±[λ<ΪΞyυ»Y3Ž{A†$[Ά<'ΐ©:ΆΡPŠ·|½l%xλ›%ξ~Оh'―–}NŒΞέΫsΓ>βά΄#ξ§‘“’m2sΧΥNΕφPΔ‡™°ώΠ01Νeoχ£g•²ΩΨώόΆR«5~§W’λΥ6hmuσ`{“ύ³hΌ/2΅nΕoqX|§ΘήαιŒZ)2„a“uxrΈŽΊΡνzJˆξßΖh©URε}­Γβ`‹Ϋux΄Ώn΅Βδ…)G«$uζl₯š€&*6A¨φ6²Ϊ9&’/pl¬ίΌΡH²!t]xΌ„jo£z·ΡtΥ³QR5̊N“ §fK§„Q™γ ώ Ζ)š§‰2Ω›ŸΌnΗεŽ4œtΑ€Ψκvα »£fˆίžΙΨZΡTh΅¬V’1Α„‰σ<Δ ά«Άv"ΛΏBΨΪ1r“°₯€ZΣmƒ³¨ΉfΆ6ͺΰΩFf$.«ΦzΘVo²j_6BΫ,Μvͺ“4iΊ’c+ΰ\%Ρ©Ζl“τ°„-{K…―W‚#‘Ϊ*Ψ«’°U‹L<ˍ‰EΥάBš`Η‘j4ΤΨ(XcƒFqξŠcΈ +olb651Κ‡ ΫQjAw`T6†΄W6‡tŒΧ€Ξφ…šjliΩήXηλe5Τ­]¦Ϊv6Q{’ώί˜nŽ@gMYX&ρσ₯(γΰQƒ§{_<;[}·ŠυwxΞ™zΏ^\Ν­~ + ½Φί£η_φνΓΦ”oœQμžύΌΫω +°ΡF―ͺοu<ϋφμ% +Όdriξf[ϊp ₯ί֚ρ’ΉνVρOR2Nήν'/ێR°ŸΧTύ'₯τΆK9›ιΠ*™μm–t6Σ°7½·™ξl¦b3Αif½-Tg Ωgτг™δ3zΩΩLτ½δl&ψŒ^t5SΌͺΖzeZΥχŽ΅b–X΄nρY·  »]υhd@φΞ\"‡νTφ>“mG™u€πcΜ}€hœE ˜²@΄ώ o4ON2¦HjHžƒd,>αΣ.e{κϊ=7lŽ"<ξΩαFΰ2χφΘΡv˜„Λ’ΐ^±*ΨΝ°ZR₯έ†–:ΐνj˜8ϊͺ‚¦zo«ίψ­ίΥz±κ c‰σxSRύ©΅υՎ>Μύ^ν|DSqͺφπ0ˆ¨ΎΎ6@žΫ΄^+­βΌ»†ƒξ? Žκ\£ΤύΑ8Wμ±F…ρ›ΚS8΄0Vό@ͺ”*o«"ΚΫΡ%[5Œl«ΡL·*EfyqΎƒ!ŠQΔy₯ΣmF`Ύ]X™θI£Ωm²φΊj/­ρVΓXρh«Ψe1ώCίk±V¬—8ˆε›Γƒ£FΉβ9πΥθάί΅:ΌŽCW­κk·c”ͺXN·€Ÿ²―ώβ.ΖΠΏ­Uι£Z+·@?’6F¦γ-ώΣ1‹mΜΝΤΫΟΏ[νU[&?{Σί¬u€ηmŸvθ²Ζšρ‘΄Ώώ₯Ψ©7κ•ˆ©5J_ Δ†ΐŒΡrL„9μΌ^«u”Δsβ€νxD“θ??{λ1-ˆ˜1jώU¬b†πϋκΏi£―όz«cΣ˜’qz₯n»Σψώg9Ω_G‡+ν"ρ<†-–ς}qŽ9sc†ςί°KΫoΏŸΖπ6h£ ϋ/_eΠ ±ty#η7׏ +κ‡a–ΨhωΟ2akλ²Ψo^ΏWΛ”ϊ¬ο΄xΓvVζύΊίt^8vPι9…ΎZ3³ήoώΩI&Ε„(H}WξPό柞L<)cάΎϋλΟ0³ωσ?βτ'ΆwήθΆJ• Z:ώργ©zί•N± Π¨γH8Ž©2·[„!'[cb™’"%M“F*Zlu^ΕV9ZjΤ­¨}5ሾ͜{ί“Kl³S,ύ}oUΛΡ6χ uκLE›E΄d·«ίέέε²&šͺΚͺ¨Δθ;έΏ†kΫ2τέΎs5[φνΣΒJίNmC59)›m kSΆX­Ψ>7ρ#ZψΕθI«΄~«D/*t’ωr΅S|­Φͺ?{ΫνQMγ³Ζo•VνkνΰJ΅j“JΕΦ*"ήa-ψsχ‡•r΅ϋ=«΄΅.Ώ‡_Ύ¬WK@\ΑyΠ +fο4‹NΤΛEΥ4Ω!Φ+νθΩΠͺG„`ƒΖΎΗΗέN³ΫισMΘεΰ”η•ΪN±c>h”Š5[›ή{qU³-,^₯΅›³·΄ΏΎ@=‘rάaYμ„`ۘ_ιέB·V30uUi΅a€πΆgsˆšmyŠυN5Z¬U‹}–±ΡνΤͺυJ΄MώCνήN½w€΄Έdh£dΎz8κΣnI.z€ζk77₯ησf£“Ez?lΕ…Υ€Ή\'0Ηf…ŒXψω eΕό“ Ή—ΙΨz°…άhω¦δ,&=P³r³špa₯ βΝ4cΝbΉμκ fe)&ιέhΊΫi˜$Υ"(>Ωη!8vΑh£_υFι p ¬ aΨ‘}šV~‹ +π— +ΘΜΖ6λv†D7›}Ϋ`Ό@Z'Ő1 Ώ}ύQ-}œ΄oΥZΕ,½lβΗΡ]ξ`ΆΝm#xu˜~­”Γux’+`Ÿ°'¬ΚΪΐŽΦηέWΰ …°¨3άΖ½Žτθy·I£ŒoτΨΰk=»uΞΊ²ιΰrρRΐΈ:=•Ršk"֝WΕδ<~¦F Ή Ύ°v,§σςΐΪχΞeΉh4mk’οΆkΧbν¬μΦΆ}IϋΑφν*Ύ5}Κ\ΫΓνrfνΔ Ϋ4?}vsΞ• {½Ρ”Ρέ²%‚.6^―ΥΞwWΗΑ}ΝYΪ›7ίΏΏ―8νΖΫ[‚©!όΠυmώwMξζ’ΗXœwΫ˜2‘Ψ<Κl~qΜή0Ό²ƒ™ΨN,xνN-Qf=-V8»š ξ?γν-Ω,Μ7Ν2Vo―ΥCͺYέ93^š_x-5l@ή,`   ‡Ξ—U”<ΪΩΤk=εΫΚn[π&)hTύJNΤ*oαvΝΎ£c-[π€1²ΆvςœJƒ³΅}ύ3škΑ‰Ρ +^μΕZWΟα—\8σoΤe¬«―8Φ§3W³ž%§V$ρϋ·A.Q΄«οu›˜/ω4€½ρΚΥL?B3‰ ™ΪیM…Ϊψ•c9zg]k%ΎMqΗ―E©Q‡₯ο <€li +κ―ΜΝΙ·m«œh΄0/G±Σsb»ΎTΡhύŸy(yΆj6ΪΥ>l›A}O’oσ[ΟyοnEα}F_}Ϋύ<Ηv©Y+ύιO(¬M©ή"ahΣY₯GβꙬR­Ψμή.`μtXrηUΟΕVmΓ#Ό/έRsΖ£­mζ ψ†qπ‘ g ίq μΥ'' +8‹ϋ΄)΅Ν>Mšΐ]«υ·FŸf-›Sx? ¨­Ό[ν€utJύΞGγŽmJύΪΪN˜"5Œ­c[Ϋ0ΌvΡ[½“(Χ‚kΣl½5κAά›΅Aθ744―5jΓDM]ΣsΫ u’œΨ€^y/φ:ϋΈ•ότŸžvpΨΤƒϋͺ‰%|zlvνbΉͺ` U:¨¬ΧalζΒxφζl₯{ρω?š ‡W’₯>»Z΅άb<™jΌZΎ{ό^νψhYΌθΛjΗLΑ-kΥ– Π\BΦ;GχjΨh–Έ +5h¬85(wύΕhΠζŠλο¨·2œQΝΥS°@*·ΪύΟjυΦ­—(Š΅αf"ƒͺϊ"τM±^7μ.–Ε«§U?’τm¬ζ.η‰θuε5šmβΓάωυρΙΓ|τ7©χ rŸM8τZhƒj˜iFπŽaM-}$™Y ,λ―iY"C.ΖH₯ζQΛHh·©––~Rύ£R;©΄XΡ^s'&PP\»Ρm#G[±^ζVΤ »)ϋΣCDΣ-φΩ•έ9!‰ΡόΙωΐ ΨWύa¨t[ט›ζ π,·aάέςΌ^ ήV6#5! Θ0m[ j›EΓx–ΖΟμ†q§­Ν‡h€M;ΨNOwΗάζzn7ΠΪ½J©³A.so܌Ý4œ5Θ[ͺՌϋ‰p»Ώ4Ύ`ξΏ››ΐ€€fkΨo4Α­Ϊ_Υ&hCυ€=‡ΝΠZSμτQ[ N΄ΪD”ηΖάkΌξ‚„iΫ–’kMŽύoRRΡzΓΊi‰Vλt“‚ZU“ .ΜC±?ι² ’vYγ°Δ‹mϋP/λΠ“|ίf=gΎΥΔ…Nϋ`-6 βyρ·Κa·Φ©ΒΣNβΆίXΊŒŸMΰ*œϊxΰϋIΐ1ŠΊP£ΩaΈrς ’θ1{eΓ»;7°½•u―Χgγz‰Αˆ +Χ³—5= ω6’μˆ‹ξχk½X­˜Q, εΏΧ™—ί~΅^|>sσvIς’E}>ήE#Zϊ΅aˆλZΏOmΆρπΏΧβcUϋΌaΒqQλΏ­βŸƒcΣωΥ`Θt~;.ρˁQιϊhLβ—αyΨ¨7J­ΖwΕ J :ρ[”(‘ z"&θ 3μc|Μ…ιΔαgO1>ΊhUΏρ‹λJc€ρ«αY€Οϋ½Ρϊ:Ά ψ~w6,ΐ‹@Ϋ‚οgϋާj|jέ ΅`Μσ“ρΒζ{2¬²εκή³£Αβω>ͺ}hΧ›„νώ>„3„ΟŽ ηΠαƒΓ>ξύΰωy„ύ.Ψ<`ν.¦`₯K­Ζk±sPό³ +£Δ>#Ep·^ͺuq+Ÿ4jΥ ›±ρ?0Π.1ΘgΉJ»Se7φOϊΫ_…½4Ύe΄‡N*υŸτ}`>Ϋ­ΐpίξ–aΥ·jΘ‹Q£žέγOΫΠοm‰‰’ΓίβzΪΖΒΗς-ΊκCЌƒ²mσDo/˜UΆΨd>_Uc[yο‚ŽL?₯Ϋk"—ν +bΆ ‘ ‰Ÿw@·©;‡Μ^W^―ͺ•ίω²^|ΐ¬£ΐ¬£J”_GΣβΔΫΡί?*υh»ψm±nONEόF‹m|l π†#M" +“ΐ.α_gg6ΊΡ&¬hΈj…α—@³ξή1εVΥh) +ΐΜOλΧ; μ’T‰VIΧ+FkΕ?ΡΏ§ΨlΒZ3Žέξ–>px»υ]{Zέ0huΰό]]γΝ_mG»υ/Lδ“Ν)J­j³οΉ Pcξ Ρ™`ϋQxoaDͺ]ϋŌΏ$`ΉΊ„m||γβhk+ϊκ+™bŸ3Γ6†jυΑ-Ύ…³˜< βPΨΉ™’VPΏ.¨ ύ R³iΠΑjtž1ι&k2L±fͺ†Άš>Οξξ&Υ\I_*›Η3χ‹kΧ볫ś₯=yζ8žΩjm¬ΌΧ'φ +Ks³Ωj1ўΦ.wςΪΤΚΦεφΖ‘²Ήrπ0{ΈΥκ–τB^:LΖDE™„vξ3χΎ$Lo­>%ΆΦ–šν­φΎ΄‰m­L΄ŒF{ΜϋΞιΑ֚R9ΟVΧ7JΉDbφ½ΤAωΰιΉBlEΏΫξδ>3Κ]|)ύέ8h§wΟ;‹ΪT·S¦―3Ÿ΅ΩλH,χ&μ½zv6­§ήτ«Σϋ‡τE6qεΤήnεqkν«πΈ΅N|/ζ–bέΒάvω-#d^ΰœΘ½=^λ™ΪVνfε-σΡΙ~θw’/3Ή’x𳡢9{Νϊ!·³OοO ψkζ'·[ޝΘΔ“ŸΣισψTα¦XξFb©ΟΉΕRΎ€žΞe?”ηΥ΅tLžYΜ-½,neg/ ΩJwaγjoκc΅T*~α_ΥΕόΫΑƒ, +ΛE½U~Y©>ν•3΅ΨζlΌ΅ψΠMœΟόΰψη·Vχ>δHL[½zάJΧK³ί‹λ‡«ΛϊχΓzUΧ—ΫorΊUΪΏVD³ΗRn―}hΣg+ϊ΅,”WͺΩε"¬―xΈ>_ͺdjϊΙ7›ΑνAl+»»6u_J©mX—έ{mjCΟ6žΧΚχ+λΤ#u»QΑ„6΄…)\’{νZ;­#ž62_σZœ“ζUω@§sΛΕ΅™ΒΔβ] ‘hψβ‰z‘&‘˜π:Ή«Πί‹…5ώΧΪu~Ÿ5Ο.ε_Xg­΄ €{#,nlδ—€άζϋ:οηz}m΅όyτD+iϊ;Ξ¨ +4Κμ™x΄ Ξ­Ÿa£ŠBΟΤ‰Lξ™P Μ}SΡξ΄ΟRϊ"χΉ˜{[ήΙ‹³Σνυς4u»ΉLg3'Ή·σκΟΦΟγΚ{$–Qn/ž2ο΄ς]ώY\ΌΚ(7ιγBξσϊ9[ύΤ–WίΎcο…μΫ‚άxΡυ³rΓ‚—<ωήO,μrσε}†ьφaυ;ΝΔιβζUρ‡MhCK·V/:“ι‹½N·wj.ΜΪπ`,ΔMkΒθκvΞqΆ‰εοΚ±wιem3'Άd"΅—΅B¨cai1ΣH=ΉΧΚ‰YϋΒ Α(gσ£έ%,Α\μxΪ;ΨN?ο‰D1k‹ΝΥ—ΒάΫ~"-¬]άIσΣOkl Nthέ³T₯07ӜΟ~hg_ωΕƒDΑ’TΨ· δ0ηω2Rθlͺο˜ΪΤ|φύ#ίΦWK—giύNΊv―ΑΙNνΚΡχδv>ΎτšςZ’ΤWe?‰₯/Λ‹ΐa6RΉΜΑν—Χh©₯­έφ­ώ›&/ ΆrΨK9“ΒόIm΅Sο€Εν—x$fΝ fUz+δsͺžΡβΗWΔpβΞΥΝ-Ώ42Ÿςw¦VΏj€/>n¦‘‹ύE³ƒf~©q$fβϊ}ϊμνc>{œΙh‹Œ[Ξηήfw4mγƒqΑόΥ͎ΑΒΐώγ…\Ψz_ΏA’{U>Σ—±RΫΩn&}vq_K~ΦβkΔΡ¬ƒ Xο{ΒZζkY-¬m‹s6ή~wΆP΄γΞ³…Χn~nύηΪ:i\o’η:ϊ; ―rήσ>ω²ΈΊΫ~Ž]šR3b·vŸ>ΩΛς·©τΛΦΪN6M^€ ΜdΔ»ξsϊΌ{‘Xo©1π1xπ½Υ*­Μ°Υ²οΟεΫ΅Νγl]?{{Ÿ_Ÿ.ΣςΜΔti:+ngΆπ― ao[\*―+›β\vΣ|Άa}‰Y-ι)ώΜ +Μ‡τS;?Nρν:ϋڐΕgΦYz-^ΠΥxξLzΎkζ±Ι5ƟΉHΜ^Yύ0(ΟΩΕ–9ψ σ‹Uj‚£9‘!™ΣMΣ@"1š&›0J?Ω9Όΐg«Τ™…Ίp£Θ²(ύ4ϋ;ηPΜ―ι›U|OΣΨ΄PIΝix ‹υχΥSη„Oʚkι`υ 屴C,„k8φ "ΛꛦAxr’cfeύ€ΞLΘΫcΨςœΛF%aC¦ΏΜPηOFΐωύΓ—,°ρ9+‹T<‘E/€’{‘΅ΞζJ;Η@ΗΊ5gl|μ…TΧN5ΈΞ0ζš&αdΕΩΕ¦s4Y2£iPjlν: dk΅«ΊaQ-5GL€=ΆΚͺ9Β“y0"₯|οS·ƒ£:˜^ε„Eκ™Σ˜€©™[s02dKbξ!Ζ-iŒgZRœ?¦Ώϊq4xόηΞ)ϊ-€/φλ…­ΩΚHϊo’ύΐH₯λpVΎ^oW + 8Εp^I㴏Oƒδ’ϋΪΊžΊ|ΟVŸž·ς₯―Ÿv”ΩΔ ΅sβ―ΞΨŎΕkRg@s*44Πά{|~“‰~'»σΦηΠΆ„©­«ΩΉTφ£{v—ΫίΙΨ'”y€ΟκΉγ­σ§Φ+H°΅­oΡ e‘t‡•#‘φΌ)4άo—'ηοA ½jζKKΛmIŠΫτF1σϊž«,δw,Ω +%₯½nΚB —Β’Η6ΥΝ.D€jŠΊmͺVhΌ1ρ¬§ƒ>‹7–Ο8.”@ZWοFQNB¨&()¨œ„PMΈΤgRh§ΖTf‡ξϋτei(ΙZ’΅ΓΧΰ2φΕε£›½ ‰±ž¬ώ»4 R€ }jη!·ŸΡfΐόkζtλ~!s{μ8Œ¬Bχΐ“]!²ίΠφΉέO½h‘ 4 DGΊΎ£_Υ.Η—ϋ@ξ°;qZρS*>74mΑάΫ™šφ~O$fΙ½­ηΆΏbΨ^§khΤ(Α_Kνζδk*΅Έͺ9»=πQRΦf‡ΩNŸΧΆαλχ±tΆy,m]N€Έ¦z±Pd})}”~ιξk*ϋρ0±~~6V1ΣMΐήΟ|.‚"rς¦˜dƒ§Μ—΄>a½0‰]X)Χ\¦=‡Ž¬e +kω‡„Ω‹^xz\˜*δλ]Ψ•R,υd”΅4½|ŸΤK{™Σ“-8-nΏψ@»·±τιΡωκΪΖ‹λO™γΈ1#θ_έΧα ™¨m·+-dΎ+]°Η 93I²°Υj}\*+‡Χ›`UΨ\}Aν.+Ό₯²»ΆΎ›™ŒΝβe{Β±χOιΤκ~ά|q‘ό$ͺiΕςK[­Ι½ΒΒό’μκτ›₯rN§³Bαy~βg*o­½>Υ·OgV>Ο«pψ₯>‰ΞmάΉΗ€±Ον΅^υRΜD~ƒ΅4χ―£³p»W3t’¦ίώ•-£cπξ΅ w/¨‚·l΅]ΥΠͺΏ?φς?YW!΄|[·§pr»WρeΏFMVΔδΘό…ωΫ“NzV,³e\ί?*ηΚί©%ƒψζ&AOίrٝ)vΕ f`Φ³λuu₯ς2SαxΪ9YΞΤg"tz^'±#c.“ωη§Ψ= ώ}bλ'σ4gžX&έΧΥ¦c€‰Τ.ž9οωΧε»ͺS†!Ž}OΊ;?―ήAR―›ηΞ³›΅ΤΧδ|%tόϊ ²Ι*2œ·ω|iQxH+s©S`ΧI& pπςΤΦΪζεLnχ»zŸQ―nιΣ…“χτΩΕ"hΫ±νG=σ%–[vQ…(λΛΉέϋƒ6Ξ¨ pη΅s―Α'/f¦Ο ΟS3·Ή7ΐW¦–œ^ΚνΝΝΟ‘pcξ}’$ήc_@©ΙΥ·ισ  +’gνόβ‚φf?ήp­šΟ™§­«ιNΗ„|Kό>‘u +g@ΙκE"ξx5;!μήo―ρ.Μσ•,΄‡Ÿoo+ΥΩΣCι–…άνΞ‚ΧΤνΤΕHlυ±qΤθjA?*­»š¬VžζΏΘŽΆrτΎZΝ/5ξDΰŒͺ˜>W Ϋߝ…Ylχip˜*šjΓYrψΑ™Mνf;{”½ΪtΡΏ½hMάƒΨόs‹Όυc“yWBΠ{݌ΔθΔc °?χ5m½π³³–«¨–Μρij"χvώΘV'§U lε8]ίΨmxΡ έq£ΤLΎ-‹ιγ•όώΦj¦i—ΌωΘΦζΆZρTyςVZ,εήR/Λω»JgΖ…ΟΤgkφΞύ§Ϋtγγx0ζ$S\’ŸΦΰaP›»6*ΩXΧd/I}₯σi=uFbγsξν΄ '2c|΄;S…lϊρ½έz?Ϋ™^wΣ©ε―΄w“τΒηΦΥΕn±°–λΨFœxjrkεΊςΎ•lΆžΙ.Ω ΊZ+ ’“°3ebž³—΅νΪαχβ†Ύ½ηΛΟέκ­ΉP20Κ|Ντ§@Ÿ3[Wo][ίΪ^7—8+Η·VŽ>ΏlΒ9όs‘MκY~υbnן4j―™o8ύ蟭-Tž^ TW;:vŽ»Ή§v;·τZΘ―ΝOΗ.o2ίΗj/½œNΒρυu‡’ͺ8|N‰¨v±œ{»h²'Ό}Ϋvΰnϋρe;V˜ΨίjM=uroVΒƒ`SpjΎΟγέΞM!ϋΆ)[Ϋ‡λ/(θhˆe"Vaϊζ³*HκΧGn{#V#₯1lικmv»Z˜Ϋ-_£rω€<β&WY{BU‘»h)€Ζ-Ό07ŸT[«Χ m¦ΕŒ jφζΧΦΪFsΚΎ 1ώ*/Ϋ°(΄—K%ŸVγϋ§Θ(Δ^(ԈϊT.<Ο€ΙΒA=_Rλ9ž˜χ@ΦlZ??,ΐܞ€ι·9o(€ωύ€_s = ο+‡‹2œ€3‘vͺƒμΩΊψΎi|:°‰/κiAΪ,œQ½ωmKΝmν4ŒΖK θ4FHΫ·[5Ί8δΕβϊήݞ ;pκυBΚβFϋ.e1Gΰ–8₯υΉΣω[ΤPŽ–«S+k\ 5žkΛπH­Ά₯ίΌηΣΙνv―Ύγ…Ή½ψUVΌόn―VVfΎaΞgσvΘ?ί$E"Oή,Uœά²›NΎ6ίmG1ά»ΣβΘz aυ­[iΉYoc!·lϋΒΌ&’‰Δ΄1uςφy‘°υD~ή½(χ§_”^Βκ‡@>ΧΘ#k‡ισ₯-X—χ…Ί +gΎΤ|N'γ‰I5yΑqT―d”―rY»Ί|ΌJκ›ΩμΗ}y5¬Ι­΅Sω)·ΏΏ6i^»?y¬PœΙo­>^‚Ψ©Ÿ. +O ΈόέœΉoΝτYM½v0αβΝV{ώf2·Ώ'ΩOeš^ ΥΈ΅?ΉΣ/ž»υH ZfΧsοͺ6ΉΆΤ}¨j? yΠ‚~ +k…§F“?™¬ΙΰIœ΅ΉRq2³ΈΎ₯OζΘwς˜ΥΟˍ5Ζ›ΣOqΛΈΉR.—.V€βΒI¦/Άoξnκ°.ŒeΝcMŽž^»…—Ηξz[Μ’n―/](΄φΕ°@[·εψ5,όε\Ίώϊή6y›£Η'ι›Ξ@›…£Ϋ+^ŸΊ€ΐΫ°΅Συ–ΡΨuϊβRΏ°p—ϊΪϊ<€™_;L–ˆε—k8’šB;-¬5m6QBVfvν"·P].­-έξgΙ₯]μo¦ +s‘½j +D~˜7‡Kxy¦2₯τρώ^—Ύί"$ǐN'αp¨ά――Ÿ ½.η?c…|ͺQΝ?έ|\Γ‰ίz4Ρ.ο?9‡9(<ψφ]˜ο¬6ς%m^ΝΞΟWυϊξι"jβnkτ)œϋ‡…Y ηι»|ό6ωžQεΈmυ«OKοι‹\{AϋΩ/nƒn<Κ՚θ„gφ²°ϋεuεk=χX½²šΩ©υpζ|ϋu!Ÿf?ΆΚράn-{ν:ςιτaͺ0·ŸIΒΊœά-5lσwΨΑ5“3TQTσ―yΥβŒΘw(8μ”Ι`mXHξRdSAYΚN›ΛJΎψςΉ”oNœ^ζ%ά Ή½‰7ΑžΡχσΣκξρΞ™Άrsω +s©Έˆ€ΖΉΕžπ«bή<x°Ϋκ΅•©ΗPEjκy1Έ˜‚]·Έ{蒝/mμ@W—3ΝιΤeώ~:υ~ :2Œlνς‰§τΕG©ƒcόfμŸ3R+G©­š‰ΞΊ'Ψ«‡‚‘tΖ»Ήύٟxϊθ-n¨/ϊβζΥλ²°ΌxΈΈΈωΡ‘ρ/IY;]‘Ν§ζ_τbUήΌθd@βΨώΪ™:[/’ͺ°aΎ•ΧΟ΄‰yyg}"Ύ<{‰M,n|­MΜέ₯&–>ͺπκε-1±Ψ]9ŸX:ΌΙMΔ…CIX^Ώ#πκDvώTiKm8θΤά—²yό²!g’rΘϊϋŽμdDΦ[aηΉ’ΔZ­υΧτRσhok?ΥήHξ¬]' +;ε*ίzΈrw…Ϋ‹Βzz½$‚DRηPδιΣΕl|α ΰh~ΣeJΘ©iΐXO£ƒv«΅ΪΎ K»Β²rΞ¦a¬,t€§Ζ׌Pž ς±ΥmλQh―AίΙξβΖφΔ MœΦ%χ•Xn'·•δΟκ'όάΑΧ·9'Π‡ΦγαΓ©7ΠmύI]Ω}Jx}š>ωέΦͺUχ·cή@Χ&ζZm1Φςz">(“Κ‚4³ΐΆg—γ>@ՏΉβμmή¨2°Έ&½{Οt²π€DbS—ΝځΧ\…BfΛ¨65]oΝ―ϋ½} +oGηPςi5ΑnO¬Νˆ{Οž@·w€ _τJw/hρ5ο\Σk δ‡ξΖ‚ο]ΥΉ[ωΎ&ΞP₯ΡCJB†=™uUΥοη¦Τ’dφΉυψQΏπΊUΤτΒ΄θ τiσεΜθN$6-Ο­>xΟumβ±=υQ9σzšίψ™ώ>πΊΈZ[Ω°€ΒΊ8IiaσnλΨ¨r{+RΒ‘'ΠΙΒ»>}φ-{­ΊπψXπ™«6ϋͺfύ€…ν₯—+o ΫBzΆ2§ίΠH̍ΰΞΤ&zŸs!xσHYηθΝ?|@οΦ„=."ΠΠH¬=ΉSihgΕΈ`υ¦›~ξοŠ>@΅)ύ«\xςšSiΜ5Χݟ•­ΟΦΡ™'ΠσΥYΩθ~ε\Ό€"ηWξγΒωσό€Χ\Ϋ“ϋ;•£ϋ»ω9O W³υw_ η§/―4λλύΆp΅ί\σz Η. [kλή@›{“^@'#Ψ«ηνɎ‚λΝύœ7ΠÍόσΣιγ£'ΠΗγ―]ŠηKο\?oΥrΑθCRxlΧβή@>›ίΗ©€μŠ–ϋΌ―ϋ"Έ;_œπz{)δ«ί{ž@“GρΙ‰­Η8π1»ςγή4έgύ™}•η]›fώξ Έ@@₯ٍΉηL„—…•4]²€ έ~ώL½εΪnΜ¬s ΝEΧL'Šχσ hζVάu2Β₯Vϋrc ΨD/WڍΣ\hΆΣΓ +w&5tS܏»αRS9b'<½’έ' …ƒn΅Š―u*Έ€ΆZιJΓ ί½ ΠΆϊΉΒOšΝ•Σ„ ½“ΚΛE„Λ•β³ζΤΞεΜScΕχνν©ψ}εχφCΨy‰u­·=œXonΖηkXƒ™Ε¬1ϊξz«%Εη ώΆύ•μΩ•ZύcςΖλ=cŠ'»+Ύo“ΒًۏβΣ¬‰±ήχiiζδϋφ`±Ύ)ωΏ}=~[΅ήΊ0¦MO–^w|ΎNξΜμ¬]ΆΩ۷ٟ”λΫΛΕͺ!œΎ‰“+=»|έ;―{½g\.·ψΥς}{{]žπϋ[Y70ζρώ%φ€OϋΎύμœ4w|ί~]I™SλmΖΎΏ +O~_ÐNWUί·{’²q㏱X©ώz~ΰχυΜΔΜξΓ‚οΫ|ϊπ΅βϋvOڜύ1–ž¦ηW|ήͺ;B~}Α˜σΚάͺλνβΕi{“ΏΝ&Φά»rηβe{!m½WΪΚ™SΛ +εΩϋ,η?/±Ύmru΄π¬2Φ“i΄Ψ_>&u¦QΓΜNΔχR· a~^ΰ? |V˜XʝeρŸkίLνρ―x–18_kRš]?‰s~zŽCۘ’gαΓ½oΪ¨ιΨvΔςa²> zμMXλδ ΐ{[3αM-WΧ_η;Mζ[έ—DάΑn[“‘˜–4 Ϊκ9χή@•Ϋ;_ pˆ|Š.yΜ>Wt|β‘WςZΆUΞAGΆMeΞm@Λ33SP’ώM ² ½(ύ›3έ9€Ξί’φjλ@πΊδ ”€  ‚τd…Ή8ζϊθ άVό’το 4CωΓ{k‰  ³Ύ@I¦°€βήw€E™βΒ±ͺ•”žώβ 1Ÿ½+‡iχΤύΫχΎOKmκη)sά·ϊΑιŽs‹ Μω!ΝΉeΟΦ}™ϋFμœΩ 4…n‹3—™σ-ΧŽΗ›€%럍ζ\ω‚+λΘ“˜ΎΏΡœ_kš=ΞQ©ιOΕFjϋ>Œ«˜GȲŚ8ψ|Œ³tΨΰH6˜²%Œ&·ήd\Φ'`{™εJ.fώsf—˜ΉΝμΨlœC(ΫφιΎμmr› ωςΜ @Ϋ]0°ΓδvΎm38™q"Π΄ΈΑ€…=5£ ―Z’Χ ΎR»AΩ‡τܝ=\’f7›Νe$”·|μfφϋ!αƒgΚΌΗόf'|η‰Y3€|WΠXΏσΙώλ7eΞoΣ˜Χ Qx½ @Vψυk}2Ν"$²:2Ÿί"aΘέ@Φj| Κ²θΚq"3ΚΪ~ψσžxαζŽSςȘ—2w©½`ΌGό‘εd=σ½¬η)οd=²/λ‰τ#έόΓnˎ@sΘΞ0Φ㍻'Œό3μ3ž₯όϋ‡γN¬{γξ6>αΛΆύv%Ωγ<§v;9ψΤμ§MNήΌΊ8μ‡κνύ~›ΰ9ά’kVφSΜ6«ΚIb†―~Ν”«Ζ@ςβ0@; ΞέΨpknC;ΏΜΟΐΰnr>Λ΄Τ‹Σ³;4fη1‚)ύΡX\7(ΗFΙdΤρξL Ϋ™WW„wΫ-ΟBοΎ+Βξ»ΰ]geqς¦Έ–Sβ₯Έ„ά/Ϊ.)zΘ8γ\~ίk9cφΕ`A-Ct/mΐόL.ΨKΗ§ζlγ’ΉtΆ=GΆ±ύΪφ›δ–Pι\.χHa½Kbi|‡‹½KRήξ'……e=_Ιv$ζ{0…­Ζ Νάw|₯HlυέFœμ .=yνύςΆ“O{ λ°aΌCκlξωž•Ηg|&ϊπ1›€ν½+;›“cΫ•™›ŸιΑevΫ³’;xer`α5ρΑ±s;9Vω0eK7v6Ϊζ±ά׌ΰ-‚η~ιΏLν`Ο5NΙ½CιΓB Δ%[‡“>Ϋή6¦#/ϊQο;hΊΎ@'g—’N'#Σ·GzlΏ&lmψki>?£H‚2Œ'ϋπΩ »ΑbG$6Θ ¦†dNn‰[ξ± >–Γ2€]‹„Υχύη7ε‘pHwΘ +ύνnIή²υ}ξβ₯ήυ8ˆ*Χσνm‹38|α<hCKŸόΖ*Yα·Έ―ΪCZ kΐ-ξ@–ΉΕι y:υ΅μάΰ{8ηχΤΊϋ[—€j'ΓYH‚l {n“¬{4A&Y—…δ{Ο)Αϋ(ΕύM²05ΫFβ«?°™dύÚ7L-Ι=”½σXΒΌtπ#Ρ„ΘS₯g΅Β―•λLυ±ϋDbAVΊο=Όά½Ιξƒhιoλs±{ bG EΙ6Ύι°44’τVΧ-Jψ9O!L#–χέ’τ Έcς'<ž°φyσRŸuQ„Mθ άwIΒΓν—•Σωΰ©υ§σ}λπ3Ο—!¬ΡΝ}χΉη7‘H,€vœ‡ή0 `σ2¦Fϊ¬y8Δ<χ1G\GŸ, ΨqtύΞ!»,Λζb;κπ²jΦ³‚gaˆΑwΧΩ(9 γI fσξσΝΉΧiηΌ } ωΩ[½¬­L³π³·bgl>o} 6M$6ς%­Zπ‘ ݏS‘l4όNœυ3κd½˜Ϊ€Υ‹Α“ιgπsΟΤχ=:sάvˆ:οgIΊXšsJœYrSΛ C–œO#±ώΫ0ΔqƒI‰οψ|„τε\…J›ψΉςγ8Εά­ύ5ίΓΡΪ_ξ ΌΝΣB’ΔlύŒΚΡ.-Žfh―ƒHπξΞϊs΄HΘ$μlxŽfξΚν«Ζ8¬šGxοC?ƒs΄Ϋλgtކ½Œ~χJύά-eζΜ[œεHΜKpBW Ϊ~uθ-£(KgNKΠyzlγψlΤ Xγ|y›ύρgC!%³,μσγŽΧffψΑΨ,tv51“Δ|ΩμήΞΝ|EΊ΄CF@Us95ωq˜ώύ„ν}{!; τ3Ί υβ£P»nήϋχγΌti^φΈM ΞΖa«fg!Μo₯ ηiOγ£Θχ6"-Nž΅GΦψnΓZ³lΆ ίΣπz ω>Ψ‹.ί?όx…ƒžbΈjƒ›΄zO1μgωήΦ‹yŠQ?ς½W/¦φκΣOΨΣ0ψ,$σπ3ςiθ8 ŸέχΔžŽΕ ω§?+ΞS–†―,πά +X;*—BάΎέ܌b«vΩω‘³Qw·m\{;ΨΧ:c‘Δ]c%ŠŸFk™΅ΟnO³€Ο«εΛUw:א|)‚|{ϊn/χΑ”MΔ{Ž₯lb9”^β`’27e_χ<Ο5}F&…CeˆΝυΪŸ·-tζ{wcZ{Β:ΤCgςτκώΑ8,$€1}0ΓΗWς9ΚΛ:σΩ췁ηŒ""†ύ>Τ BRDΟζβ'2ΫΊΦyΆ‘Φ=5 Ύ-Χ~ŸˆΧOŸ'–žςρ΄ό„qsy―:–Ήeτ:ϋ)ΦAηŠ:†.8‚Žxςbθ|Ro΄ΰ€1tΑtφhΑQbθ‚#θRί1tΑtŽhΑbθ‚#θ’Š‘ Ž £hΑ1ΔΠ·γ±Υ#ΗΠυl\G©YŒCAGςX:‡Cr@„ΩΙlΑKΪφχχr9»„’§₯7Χίq{!\ΌTΑ₯#ν ›sKΏƁ°–ήϋœσ΄lιlw|9·ΓΖΠxZ]p«3VΤ<γηΒƒU>+WύŒ(Ξ;Ύ Ξ‚ύ°Β͏l}ύ"ηBΟΟeΉκέ/α‘Ύ<ψ|"ϋX‚†δ2‡s(h.―Ι»\A,ߞΑ¨:Ή‚01OgΑΝΖ~FcΚ 6²½κ6><΅HΘ`7§'δ †A’dXσQ-Ζ,ΨΝοΪΖ©%υ vσΧOƒ/lά2θ βPMϋ©!yW4ƒ#R8\gN,±χΖζUϊιωŽg )½΄+ύΤήWΩί…r SŠ}; uΨ_·dyέe›ςX―鬟απ+Ωt™IΰΫKO§Ω!n¬Ά}Ε.ί(0›€δŽλ+v…Žγλφσ Žο΅_όΛ”Γhεšζ,JχϊΐΟLω jΛ+DΣύϊϊΐ‡φ"(o;-˜žλ6Ž/ΩκD Nοtμll’-λζΓ/2eΞϊS|xŒ9 ¬#b¬o˜hψIZm(Œ9 ΏRζζ6ξttΪq9Φ{Dr…“e{lΎ½j–ΉΥΟΌν–Αρr.|:ψštžΘ]ΌHO"ώσΈ»wB({¦ΖΧGΩ{ί ­μωuΰφQ’‹~©Q`Ν¬αBε†Z‘g‘ωbˆ4ήΫCάϊ"&iŒJσQβzΘ>(F.'Μ9Δ•'M(8εI€G½ +#WΪ=όsΉN”ΫnFό(ωsw0σއͺΔ$₯>r=\Η?"ͺγyš!ν†έρΦ~χ•Η>w3οψ‡ΩΉ=ˆ†ΖΣGKCΔ₯Jψ“ΐ€ǐρΘ0(iσGΐœ›Ή)€'%쐂½ΣϋΕ ɝ»#α²²€qXdφΘ"3’—HΒΣ!,2όŽ―OxΞτJbf‹ŒMίίέ"Μxw †6ŒE¦'Zpt‹ †‘Ή,2~©ύβσ”,2žvώ½α9α‚s0D6\JηΎ‡₯:§°Όo Λώ~γa„eyσrq*1Η$6χΗγΙ€λ²r:;£LmeOo˜0΄!Ψνη ω[—λq]πŒμW7°Σl―‡*ΕΥ…τΧ Œ«³…ŽD +χ7‚ξ&©²ν^›lθͺw›‹Ÿ…<茘w?Η€ρΔΓ!”qψΤΗΓ žl˜x8//θ“οqΗÍg1@<\‡κψβαΠj=β η‘Τ7ˆkψx8‡7”ρΝμΈγαάyGYDάΈγαϊf K<œγΖ*„«εpρpn]ΜοZ#ΩF¬Ηnl>‘Π•Σ'OΆ γyΥεΩoο·ΏδQΕ€,9HŒNύ,υ[ύύ„‰#ρν…ΙcΤΟ"Ήz<|ΰϋs4 σ7ˆυϊ;ΫjΩψx<Οώ,τx<ΟώτYΧ&τ΅φά\² ­ΰ#›UaΤm¦•ρβcΎΫπΆvHγˆοΑτEOBO6`κg°ν㏠ύŒ%2·ξλۏJ`ŸlZ~nΦ½)ϋfCsZ₯]Ωη—zmX|œΨ©―BmF€Š“Γ:ˆΨζμ—Xx¨ˆΤβδsˆ ©ΕΙΧ0&ƒ>‘~c‰H}ψOD*φ3ŽˆTŒ="{GD*φ. ΄K%φςλ£ βŸ4u`'£ω8_}η6ΌyΊBαΌωΨΈCαȟ?Π£g‘pžλ2φPΈαν–NŒλξθ•#„ΒΩsQ0ά_ +ηaUψ BαΌνc!υ³Ϋ ΑΠΞ +μω“ƒŸ>|}UΓd„wΚcΩD΅(¬£v₯†²(†0 cgώ™ν”az’ zΉ`‹FΏ y…”XΉΧ‘gAιά쎫{πM‡γ> λ¨Ηρ`ν_¬·δ―•Έά8ώΨ]ŸsSεnΎšήz*\lœδ·–;³ΐω ›ϊ-• Οέε[[ινb/›I”²ΩΜς>!8oΗQ¬ζ2·89c±Ό’ΞPKβ1JχώqgΙΣ•;y9ƒέVKΗ‡vγ³ ¨ϊ±[›hψEΨ)·7AΑnεe_ Bα"a;ύ€Ύݎ§l@έ±X+‹m›Ξμ¦ά|˜• ]!`“sAΑnbΒΤYoυΫ/ΒN›šϊΡΊ~ΑnχAQgίΑv‹ _ 3•²ΠJp=ΎΣ ω£ϋm_τNΧεΥg? §Ξ;ZUΨ°|Φτ§σ•νV½Ϊ1«‚£₯ςpͺGeώ„΅γGηζ!ˆZF‘[s¨AΆγ.·N v±ΞζβΈ#:™iŒ'΄§Ώ‡ͺΫjβ_Ηκ'ĐlχbƒκηœΪΟΟƒi―γ¬$ηUvΔ#§JλRP%Ή¬pχΉΠ.’}’!)'δ~}ύŠΘϊυ…§§>Eδ|ηηUχ­_±‘°σλ_k 4ϋΥqεR‘~\ψύ²]ρ/DδλξΆ]°₯w˜hΊαμ0ƒFΣyιF-ΞρEΣ…Μ3b4—MΠ½_F¦σŠ₯6ςΡ?šΞΛονi?J4-|Οzζ)šΞ««>B†ˆ¦ςD0šΞλžΖ<+ΗMηKgΧχΗMηK·g€h:/[»Q}|Ρt^«K–ή±FΣy 7vίΡρDΣyΕωd›!šwHSώ’°Ρt^Βi$6ξh:―υσπ†1šΞέUߚΒCEΣωɖ㍦ ±Q’ι\]ΉοΔΗM7Ζަ Œ±[4wlυΈ£ιΌ:(cަσΊ-qωΐ!šΞ‹=8΅ΧqDΣυΉS4]σeΡt^Θ°€ρqEΣυ‹δO4W,o=ΎΡΐΈ₯:κ‹ ”ΊΙΏŠWo‘JwmސO?}6»ωJΓ―–Νπυκz†ΤΑ[žqΧ«σ—.Βα©³8;ž,,9QΟ~ƒr ),+Q]Ξy15Ԑc0¨Κ. ΙΫ‘Β—Γΰ) μ²ΛΔSΜ©mŠ{m—F$O§š} +›[ζΜjYA…ξF.sgΛsR$¦ΜouΉύP±J!ΛάωEr… € ε μŸlΊm­Άo›aͺΜZ©B•ΉλkQDČ\ζŽΛ0Α…ξF.sΗbίϊΊ wyΤάCž+yσR ^ΔπqϋcsQjξ["χΠ±<0΅υω°τι{Λƒκϊϊφ£O £Cε9Π*.ŒGs€„‘ΏGθψB€ΰv8€bΗΧτη€δpΆςΤ¬;ž“¦ϊΞΩ+7”ί}ΟφΙχ]o( ͺ>ώΰ‘½‘ «Ύώc‘½‘ ³pέΑŽΝΔϋΖω8ϊUV HΞW?d?‘j»zυbσμ:Η€^z"Ω=#…ϋΗ²Sg‘kύj@ΈkΟ뽁΅ηυρeΔΞΖRȘh F†™ΩΟ._T^x‘²o½Χ κ…ή+]ŒΔλυ ΤΔύ|¨+ν―±D¦˜™—$z»:莫‚!Ό8ρΏ"½χ/*Tνwϋ†…ΧF'X/A^τ3†,¬ŸQ«U³^ŒMθ•αp0_Υˁ έπΞ/zlΓ« ‘,π#WΈ3β+ύjά ± =œ+†­[=X…» ΘΗΆ‘AhΌΒέX*ευ' +W)oΤx"³RήθΫ0 Β3.)L|Θ0ξ‚κ½b»Α+ά…ΝjŽΡO£Φ>όXbŽŸφ:°:λ/ζDΒ:¬6έp΅ξΘGuTϋΖz†C–ηŠϊ‚oφδˆΐ~ΖΟy(„ΣΕϊφγ λ +bŠτK3Aες‰oχ +b²ίŠ"ƒXκΩ†+s}"„]Λ¨ϋ2Œ)LΣμϊ“[΅ba˜œ“μc;΅Ί2ΧΕ7Œie.T„z ΪnξΚ•Ή0»2LΣμzέ-|«Wή ΔδηA„΅NΪΑΓΓ;BV~—`θ‘,ρζ–Υ€GŒk6αŸU υ—A+ Tξ‘Pι/έŽ/5Υ-έΎ)ΖυΦ75Υΰ2Μk{ r}*ε-γj۟¦Fˆ¨ηώ10€ΠQΟA1ά„ q {Γ3D?ŒxΫYΏΘ}‰ΩΜςήunͺ²w‰ε6Ο/Φ/‹ό΅}BΡ}…›‡BYšέ˜Μ±ƒ‡L»6Ϋ1Λ„w΄yfκˆ‡‹ΔΪSW·'vS•³ΫJφώΦ'nή?―Υ}Y<Ω†',ψΕώiSΣϊΩό£_ήƒ/P˜Λd‘)ϋΞU؞Ί»τ:»ϋšxχ«Γ6o5#Ή,Ÿ¨’ ¨34­=«ΟXueW”γόάζ}Ν h$†vלs„αέ±vτψΥ¦bΚQξΕ²ΑΊ#βž€nOkώ@·O§ξΌ€Rέ·δŽ#΄ τ,¨Žΰώ•?Π|ώ²ΰπμ°Σψ~Ιό‹avΦ—«οΣNΞ +Ύνμρ•ΒΛΒJ:D‹+Nή:&aΞ·Š[θ4/kΈ΅ΗyxfμΔζAmͺΞΣm£ŠYΗΙg3τ½ξlκk!ρIκu­ςR² ²aB›ϊ6΅ΗU™… Ί}*³„΅$ε‚]«|—§2 8Δ-(κΞ•yr„¨΄>š K‘pτδΊτt~¦Υγξ²θ3€/-χ~ τΌ΄"± AωΫ‰pK?->žίX»Κ?l,8/―σ½5S†S% οέ©―ϋΨ`ŸςγJήxŸ—α0D4R y9μ-ΟS~”L΄VLbOΚΈ‘‚έΌ―¬Κkύ”²μΜ’‰Q€£&‘υΚη/ΦOkιΝ yΫǜN#W¬ΕΒ@υό9Lal:r±ΰζ0Γήz³€;Ώ}L7VύΛΧ9FζΆσχ7ΩQ=>_«ŠςΣγ@π•l .ψΤ~š]ΏρΏ,¬§žΕeΩ‚#™бJ ”ηΐ6$WόKy;ΘvάWw ΙζͺΟo«m»vΐPΐ―ι‘œφƒω†3ΖjΠ(ΐ°1€¦Žx]?oβ Μ 5D]Ώώ”<ŽΊ~Αž!¦εjΔΊ~ύ"ΉΖdΠ ¬κ‰ dΠυ­λ<5—νbθΊ~ށτTυ’ˆg]Ώΰ yy¨SΧΟ31(«yxΔ„Ž”υΜ=D]ΏΰΜ_ζψˆuύΊ,bc¨λl(U@]Ώ`UΧΣ zˆΊ~^a’ΦΦ­ίbήͺλά ΪωΗQΧ/ψB%ΊŸQίέ©ΓΦυσ5mUύμΥ„κϊΉΆ‘ΰ¬κηΘΩ5pxŠ`Φυλχ:–Ί~ΑUύLJ±_°Γ΅-"u€Ί~Vό–-Ίς\ ]Χ/$ΑŽ‘_ΐ^kΙcͺΗ·άKθz|}ΚΙ…Η7R]?³Ον3h4GO]Ώ€Έ‡ΎήΆ•AλϊKς˜ρ`uύόΞπ«ή›Δαβ·BˆσΖMbΏmΨ―_π}³Σ‹`ψΊ~Nl»΅Εaλρ ζ€α_o ΫΗ¬κ7z=Ύ0ALύ²7τϊj VŠΟ‘:Z]?‡a»§ͺ‹½Ÿ*TWtδΊ~ΑbŽ \Χ/ΈͺίΘY›x]Ώm}!λϊ…ˆ{C]Ώΰͺ~Χγ* +ΧΕ-{λϊ  o«κgƒ2R]Ώ^S²½ͺŸ_–³Aλϊ»wΉN±‘λϊ;:ΉlJCΧυσX[UΏΰΌpαλϊ o·tblπ˜'½r„Ί~γςͺκ7΄χ «_ EΨ*€ŒVΧ/X0dΪλθuύ‚bω‰άy₯>XFEΧY OύM»ΑŽχ°E54fέήl¬7νqπΜ6ΕAΝ9NΘDΓBŒ°|\ΡL|94Ρƒ6ΖΎIν 8Vφ&…ε›/5Βxͺ‰ιÍ݄0WŸX.έ7Ήυ±WΨ¨=¦N/ζβίσ³™ŸŒ°σ~”žϊιf΄‰‡bY†Ώ^ΆbjrugζπψηLύωΊ½Δt5‘”’‡…›Δ~’5‘l+/™³―ΛΝςω‘vύqQ9Rζ*oΣΧιy%χ9yqΆ΅R[»iT6ηκ?ΟϊO¬΅U׎&6g§εΉm-φvΏ»;ίύ˜ΊW•Ύχ)Άsγςβόj"±ψ΄5!½\-Ι³[B!³Ÿ +o₯=a[›9k΅^Rs­vςz·=υ€½ΆΥΧϋ3ςbq}9~R“FΨΫηr«ύΠΐbs©)[έΛCρ₯«wΟ©t鴉 +΅YλIv_ΔΨBzλ`Ο Y„ ˜ngΧEžžπ+E4Ξύ΄}ϋz_5’νψ δj{λ.q'!€i  ΝΠ8\Bς3œg?Z«ͺ΄΅m'ΐΜΜΧέω-ο­-©J₯Ί©τέ₯?|ώ³/?}ν…_άzΡǟ=ςΓ…p’τ];zαΡυίγ?―φώ―<“xαΝ[Ÿ~zqyαΗhοψΫVeύΤςιCϋπp:4·ϊ[§‘u±vή<Ό–/>ΪΉxσΛ[?~Α 4Ώ~ϋγ/ς?x‡―ΌϋΖΑŸ?Ό|«=Λ‡o}ώFψ¦OΫ――½}ςΩ|σvΎπ}oη³?¬YΉ>σ²»φKΑQΖ»ίΌρςΡ…Υ›χ'ΏωήηŸί»φΦg_άΖΏϊ€?<ΩΗ‘έλbΦΏ–ξ> ε΄<ΌŒl„{E€ύKφ/w™Ύγ>#εΧώ³\ε©ί.pήω½|υ:%Μσ—ϊ.φΥƒξΫ‹·n½εί―½ΩΫΛ΅›Χ/>Ίuωφ;οΈλ—ώλώ[ΗΏόΡ–ƒΧΚvϋΪ]=t/ώό݁λxυΪτ‡ο^8|uη’ύιpoύ“ΏρεΧνοŒο½7oο…wώΛ&ζWΊΘψνχφΡsί μΪϊπΞEχφ7ϋΗγO{S;oώμ@υ£τ§Œξ»ΫωΘγ§—ΆΏζβhϋ£kςΘχΏ;hθνM>Ψό₯Χ.#έκ£}yθ8’$‡=pΗ·?ΰOmφψΛ―œκξ­kοςKθύτ:κ―δ—~°~Ίo_YΌPςΙΕ··+;–Ο^˜νύo―iU@a†­θ”ί§7{ Ώmtηβίmv™šuΟωΚ΅;/?Θ―έ‰x³|ύΓe¬?άgqεΛO.(ΫάύΚψ6ΌπΚ+ίήΊwε«χό•G?όb“πωυ•tώζνWΑݟοΛdέός‡-ύσψƒ€:Ήγ%ί²ϋΡWίPUρo]ωξžώΛ”ΠD’&ξ}ωZόr'7~σχNŽyχή£΅νo―|1ψξK?σ˜φεώ=ώΗϊό~Λ·Ÿ_8Ğσ2>Ύq²ΣΥ7?<ώΧΡΝχήΉπΙ*RFXηpΈ ^ܜI4v#\|τΏφΡ―8Œπ’ΏΩΫπβΛ_%ύΧΝο~Ο}ξ³ϋožξΝ‡Ÿ~½sρΦΝ“ηŽίόψΣ^zλϋ½7>ΗΆύ +3ΫT +<ό=Λͺά*Ϋpπ‹ :œIΠ9o|•‘§$θK_πΫε·>Ώρώ»7œ<@Ή‚|ϋΖ[Λώ§g%θι ˆ/qΰ}ν_}³²\ν[βώ¦Γψβ—kBΥ_|σηrπΛsϋ??χα‹α…vα²\ήSY³ΛM¦„ΣσΪΖ+<πμήϊηψωRΧϊ\ίE^ƒPΌ>ΟώΞg.·χ©α! gŸ> ˆ#ψn<Ζ»t{9‡ϊs{ο2ς`pΧ—_Ώ5‚ΎwU€ΙυΓ‹ίμΊbwxϊ½Ξε³Ϋ‡ίώςζωz΄,ιϋχ@†χΩΉS_$γ? Nύτ€`ΐέίΈΙ`θ|S5·― &ϋΖΫοΘ#˜¬ί8yξΧ[ξφή-‡ά$soΏώqΰX>ΊzJ<_œ΅ΗtΪ±²ξΧΫݜ,ΥΏςκ'oύ°όpρΧ›Όzόβ¬ΘπΦλWήϋ|θ·ύα§ίΗUσ$†+ί·Ύ½xΊGίψoϋ­D|ρKξ€L»πκ]€J|ό:θM­‰£?Q©ΰΓΉτΫ­Σ „wΎΊOλUšψd{w―H/έΚoέ»δ―άΏQ _ξŒφΣ>Ώ’Ψw\Uμ—ηυύ}μϊΓ&ŽŒeΤ¬Ί±^‘ύΖηWΏλŒνVΓώWΣΩͺ&ΒƍΡCιόšϊ&θΒΫΊOξό}Ί»-Βqy₯Λ~;xKΤΌ7ξ~e^W Ώαγvζ‹oŸΎ·ΆΑ:c.ΰ³d2γŸ_½ˆyΊ`εFΪσkof;¨ο6o„k›[ΔΏ΅)ˆͺ[Žώό2έ&ΕΒ 2 7όdLΒ?W₯ϋΪˏΎϊ`LΑ©β'ΧΧ)ΨΉψΨIo|tω²NΒw―p6ES ½0“δμτ±œšΉΟ‚άγΚ{cn½άΏο<Hfž0qωΰ—Q‡Δ?rσ$πώγψΰ’—~ϋŸ>:ΕJm`²^/ɁοΗqγζE(Ζo_;―\ϋO5Œ™ža“n)›ΠίFί‚~98E•cU>a—gjόžΎΜ3ΌƒsO3lbΚσ†aœόϊKΏόjM\=u!ϋεu&žΠ‡'I'2ΆΞΨrϋζ'ߏ²3ΏnŸΌ"υ”€„Ξ§7αο~}Š8λs™Ηf©ϋWy¬o +ϋ± α±sVό3ςΨ<‘Ηζ™ψKMΜ+ώ1 i97q†M§εϊW¦ς2ia3φ—šΈςTσΠυΣΔ_”ΏSc½χ±ό%j\Y©ρΨΏφAκ\ξΕί‘ΏΐDΞ>ΜΨ³c]\O1 φaη”ΰΊς8ΑυΤ}xͺωΒ₯›όH›π~³mβκ_\ŸΣŽ|uεΛΗΞΔ“ϋπΨ}h+-Ÿ0Wη}θ―IΛ«OΓ—OΪ‡>™+ŸFZ^υ7ξΊw¦Ÿ_?|ιέυgxα₯Γχ¦Ÿ―ί9:?―Ρη9ΡεΪΦΫ~M=¦γ§€kŸŸ°ŸβϊZnϊu U5ζž]“ž1xτγΏ<γy2‹ΰί{·}ya―ξ}yαΪρών Χ?Έr~ž†kμφΎ… Žς4–©=/?>|£Roή₯o&[τ»ξS|3—^½›ΜpfνžωSω'~ανK#s8έξfΚ­G'‘ΌΙm±Δ‘œp]$?χχ΅£ϊΪΑκ&―φϋ 3ΗγεαξΌΏ29XΫΓα€|οΪό‡£kΓ΅ωήμΪΌώM‘χΦο}^xω§7ν{Έ‹λΔ¨σδνW―ΨμΑνφώτxpνέςο+ΊσβΌ&>€―όχ£ώ‡ξ\μœw‘Ύ±Ά}O*ήβ|cAώxƒfbI­Η>xΠωΰ+ώzΐ/τŸwΨμUqΥ|ψU ο”ΆΨ§Χ½φό+Ογο`ηύnzί=ZέΛίΪWΎν³œΏά»yπέ+/ΎτΣ―—ξάzε­ψοSφ'bjΝ ηgέψ£Φ;ϊλαίiv9{DoΦκr²Ω+ο֏Z}ϋΦ—~ότζ;?ΌzAύ0wΏpΖ6ŸNNIεδήσζ^ύ.Ž)ψεa#ι ΗΎ`αυ |η@]ί±ΈοήΉυ•SŸΩχίψΧΪ;έ2>ψώ»`ϊ!²%ρ/³½=†σϋΟ/,Ϋφΰ—―ϋΧ7nτη{ιυ£Χ”•~ω!LψζBΈ§ΎΣχΈ¨cωε~¦nΤP_ώρ›+:ό―|냝‹7Nκσurqi"c@΄ώ—δ—[Δrππ‹ύρΡceš‡ί,ξmχΖεώ―οœύλ?­—γ.4>ξ#|ψοx¦?ιαg·^yνεςΩήsοίϊφύ‹MΆ/ήϋ³,οΎ} ~η―³Κ/–ηiΟ―LΙUζž“Ά˜ϊ0χ<˜;sΆΫšSΌ£³ŸρΓƒiήQψ0Oy0ίk;₯Φ΄[JK»?:ωρΑ~ώιη_w―οΌΌsπζ;Ξέωυ‡ίn=ψρΗOόΏoώvόθώΏ>ά}iχΰΝOίy§¦›?φÏ»LΉJί–u«ΤΞ*_ρχ7”Žό7ΥήώεφσΏϊέΝ-w_›–ƒhUΏϊΗ…λυοΫ;±©^Όpύή_]Έξo}rαςν?―γη]qΙ¦znψ—θκσ7|pγΡ[Χή?ϊόTƒ>’φν§oΏΊsρ­ΟoόψρώτΚΑν7Ώ|οζ—·>ϋ䍃‡Λoά•5κΊΙq˜bση„ς»fππΕ W^ωGΌ°wpι3„τoφ±Όp³\Έ~ε7€Ύ{αΪGΟύγϋώπϊ…½7ΓΏΕν Wxώ‘u/ϊkΊΤΦΝξΦ½{ƊώFρΊ#Qnwύ§Ÿ^cHCε$–£,Άμψ‰——υ_ώ‘κΑΥ.ύ‹nn_ӟ/]†νφ"ώ(jΊσC[Γο,kŒt•ΰΟp]Γ­“;p]pJUxvEA‚ΥΟ¦*<»’ [峩 +Ο(μ\|ܞ~ι {ϊ³κκ†yΪ’z bμ)„Ώ£ ₯χι„Ώ£τ±<₯‚πwΤƒyΫ²‚πwΤƒ&?VAxrފƒ^zάζ βκΧ·:υ±|qαϊgίΌΥ…βη_\Ές//«ά|τ‡©έΨΊςϊ§ό|ςΪ…½_?ϊ'diΓΎπΒiKφκ]u}ΡΌIήΥΥHϊδw}θ»?φ,=%^^ΣSFFΙ%j–ΧTZ~ψβύYZκ~Ι_zγΒΧ$;€εαώuΪΡώλG―ΌsπσχEαψωϊKΧRμrμ­wΟ;ίm―ΌwŠϊψÝώ•ς`­"ΗΎΦ%pJRsθ"=£ΟξΡ6Ψ²j/³ΑχφKWΐο33ŽnΛ*™ξν;—λΠ^Tzϋ§ˆϋ‡€Ξ™΄]˜―»―Ψ§‘Œά„SΏJςά[ί€όθ”³Glω½9Δy\ί;#}xωΟΡΔ‡gc€Wίޏ·ίΌo‘Ψίμ‚©M0wού)˜{Ήέ ›`n~ώΒΕ/ά|B4ψΖΑΤ€»υΕێΡg9ΐ}C—}ηt*λ?Ώvη-*`΄ΧΘη†}φ‡awόόΑ―ΧΦ$²ά&UAγsβΈϊΊ3AJŠ0 RΎκ§₯ώ¬ρΉ‹§"t«#νi}’§ŠηΕiαP|κH­ϋ}LΒ7σΠ¦Sπε<½7ΫRΏΤߟ"Rϋψ8νπμ>)dρ$?ήޘύ¨ζ$’$O1―>ό›ΑκΧ_ϊπαSΔiη`υ鈽ώ!9ΈΩθΤJn<Σ―ž{Ί>HμΩ&xmΦߏؒβŒ=σ0ξΌtπLQσ³«ςz{xυοπ4Lιk§Π{Ϊ™€ε½χŸ†ρέ+X_Έ:εqΧ?\ΞΖSN%=ψσΉ·oίΈ6.ΩΉxυ«αιΙnξ_Ρ'oύΫ];ηjεσοξ]ϊ›<Φ”ΛΗŽβώΪΐcyμ‰M|σΖςwyμ]ώ{<Άόzε1<φΤM]»ώdn€ƒΨςΨ7eοP£Ϋσ―œΧ@η±§mβν£ηώσr=Ώ-…ο©eίω}ψfό©DθκϋΤθ +ζ\ρOκR­ιοQZν“§’ϋΛ“†q{οΦ³­3}ΘGp΅qϋυύθΓƒΧά΄#ߎχοΌ25ρύ7ήπύOΧَόΔ^<‘Ώ»Η3Υ©>θΪ?έ‹γΚήίβˆγ½WχΧ©œ€εΨ‰ζ&ςαΉKό±}8+-_ηυωηνޘ~tηMM‚NNR?Φ+ΥΨΧΊwα8ή|ύΪ½/n>ϊξν£Γ―ίε!ρ0€7VΗΣ?» ωß49ΔU½&TΎφφη4/Onξ·Ύyι΅ψ>ψρWυ€|ρ˞Ώwϋ‡λ΄Ή-ώλ?‹Fͺ˜αυ;Ο‰5mή₯η/±LγrdDΤκ¦?£χU~~ύητΗ]’u£~lL? ³wξθ)‡τ‡­ΧϊΓ7’Όονoπ]fk2ΪɐǞ 9φ?t2δ±ηB$ ϊθdΘcΟ…¬…Z/ίόŽ|(δ쑐Ή½‹OlρiΞƒ<Εiω›ηAžβ4Ζς7Οƒ<Εiω›ηAžβ4<Šσ<ΘSœι«rœΉšζ,ς^™₯ ιύ_υΕ~Ό*³xιΥOκ Ά[N(§ΰ–XTN}ώΦwζλλΚ;3).‹k°Ϋ¬Μ³XΣ.όΝ½―ρ Ϋp+ξρ|*±αμΊή~οŠ–™K·NΥ΅;‹Ήα·=S5 εϋΖtωςK#y‰ΓΈ<ΛδΧήΈ.ŽAž―½s0…+χgaΧM%υ李΅t>Πpε«W-NΫε–”l]Žν‰yχϋK”]ψŠΊδΒ0ΛΪφk±³‘ώΏΧv^ήΉˆhε½·~ύaŽTξ\ΌΨ‘O~|ψθw<ξέψρ§Ÿ=ϊξΏ|°γvε—ώψοv―»>₯ώ#=ϊ~η2ŸέuWv~έΉxοΰΝoώ|όπηί~ύξΑοΎθ‹χξΌssχ₯]yφ^φεέΛ½7Λ½ώtΣ„GουήΫYvίμωβτΏω{ΧΝώŸvνΓ/;‹φ§?σίύΗ»ύξΠΩuΛξϋ»_}½μώ€χ?ήΙΞο/%ωέ½άώRύξύκφέβέ +­PJiiΨϊκΉΰϊςΏΠέήΛύβbqwΩΟΕΥ’πδ‘2_ϊ€z―|ύα%ξξ…šχSΘΉwΛϋΨΑT'Π»²½kjaΏϊ6Cqρ*nχxgέ²Ώτoξzί;Z+‘Όί Φ:TχSφ Pέχ5ψέΓώΥΆJ,ίΏΠ‘\bTφ›oε[Ε77˜s.ΘcyρςΝ₯ζ&PŸ@}xΎΟΎ™zœ˜ϊ˜ž‹ϋ.³k~?ΕΠvοφΗB•|‘OeξτΑ¨BΚQ —{xnΩ―₯\ΪΎK‹Œ>ζ*‹΄ΧΏ±(ζkvόjΛA›«±Ο/ΛϋQϋφCΠ™+%5ι^φ‹γΐʝ@~ N'³&OΠiOΒ²ο‹WΘw¨„ŒZ)ςΥbs{—]ΔtφΟwUP§—ΛuΉύVb&%V°OJŸk©χ©3Nοzτ^ΖΪ‘²Ÿ— ”ˆΰ‘, k.ς9Ÿ+‘ΤΩ0αΥN―«°‘o^^νLκΑM‘uFL1 ±&ΦΗέΟv0ΪB0/}ˆ>t*‚s EΟiŠπQ!ΙΦλ.•Νs8΅…Mk₯/―%M_ν½‹ύ« WΨθ]μtΚ)O£θĎC σhϋs©a‰―s‘θKΩΞ]5Wζ9ŽQεΘJ‰ Z)6²ΑγOZHJ₯ΙXsξ/Ÿ8_πΥ>Z[0Ή”eΚ’„λ—η …Ξb}Žwf0u–-ςX$c%΄ 4–ϊ#1}¨ϋ –©ΘHΤΎ —lβ₯ LRκK¨ 1Τ'$υ±,Θί₯ ™$ša«ΰλ4(K™₯γY)zά…ρ£ΨEsΔfοyς%tρ +"…LJŠλ|@ιE4NP§tλ½;ήY±.ΐe7ΤΪΕ†;9Bg‘!φbί-ΈXw0ΟY€k»ΑsΉσJζs}.Ef¨/ ǏΠΔ[g@ΉaΌ1φΉ„ˆ ”)…bߎrο‡Φ₯G#dngΡΠroΛ&φIk±‹Ό»;˜ΪT(›½RΏ ;‘=κk~)|vn Xώ}ιβ·³fh ] ŐΫλBΏ-ϊ\Ν½etΕΧΘ©+²7άέιΜΩΐΓksy\Ϊ™γ]όtaΘ‘ΥD©ήΕE.­pBΛ~o ErΑTι;Gαΐb]Rτ‰rQ–—ˆε—N©B©Ϋ…γRͺΫΕΈ"›_ιαΐ ‚0)Ή3άρΞvΊƒ΄",(ΑjgΛΊT5ŠΔ)}ŸM’θe Xφ—°’’―ΌZ:ak-|΅u>μ²§,ύνΒ/eˆ«άeYμͺ¦$‰<Μ½έ‹tωJ8Šϊ - o5˜ˆT‘ώ±.Κ¦ΔW²fΏΟγτX_c”3S[Υ*φΐυ›½o k‰"rτ-c³eC§4Ϊ•ΖΖϋJΛ±Ξ3ˆ‚`žΉ˜An6Γ±·ΡebXΙ0!+΅Vͺ··SηŒEΨ¦Σ>χoa¨T)dQc’ϋG#ΆΓκ„—bθνaό%0uίΘά’κ«:PΈN`ί*Φ Œ΄A.αΰύZ—ϊφΕι*f½ˆΈ ΰθvu+Δ@ ΣiΩϋ[zΧδPW?wcίξϊu\ΠΑVh•if’/ζ$S³ +Θs)$μΥG’\c]W3δ[}£O”³š’e’Α.ͺT[Υυ-‡KJTEύžrΆχ‰Jšs‹ͺoΌ%g!\g‚L(»κJ}!Ϋ«"‘z»­y~ΐcΘιFNφ&Εα±t·e}.ΉŒ/Δύ ’|ΞHΟώIŸs­ŸΛ{]ωσ­ Wv>yψΰη_Ϊ½|γΖ›Ηέώϊψ·‡ίαΩΙώAW£(’½ ~χwnύ4}υΞL3(οϋή“uθ¬yŸXHTcΊΐοκa¦¬€ wqΔEθep˜Μ€’ O΅r[ ͺΣ7£Œ™ΖSάn υi―ϊjςΥ6-P˜[Q‘}'‰©(ζV’κ~ΜξV +2nΎoJ€ZτQ{‡uyv Ηη ώ‰΄―ΎΫ*υ)iίϋž“v τ™z2ퟑι'ΡώYšyDc‘φ±H@T,5φvΰ‚AOΜMŸƒIBZ,’n/`χΗlφ}}κΓ­mw†ϊΖ3šoV™σ*rα˜νRYŸσŽŒ3ϊη’σάbΘ"BΛ#_΅-_MΠ’'βΎ›i»η υψΌρ?‘ώ-weyJϊŸ3΅O 34ύ$ϊ?K3]ΕξͺΊ*vΠΒϋΛ½“΄phuB‹sΨ]y +ζ€m‘ XF%p}υ7½oGτbM(gΝρΉ%Α4…ώΊO(@‰ Δ9’W‹§•Τw«άZ~4δδ–ϊΞ3w­χ<…ΖW±»”$`ι?wε@Ωί;χχ΄{ΞPΟι_’ υι$λΉSϋϊ?CΣO’³4ϊwuG;™Έυή'¦ΦNΧ,ΉωB‰mI5}Ν.E³ΑCXΦΗ΄RW|€aΘuMG>K§& Šr2SkΩι«qpXκϋ1?AΣEŒ |Pюΰ)Q{c‘ήΰzƒBΩ‘ζ“ͺv>ηΌ{v€ΗηŒώ‰Δχ ΖώSμΌ>φΟΠς“h,ΝtΪ»Ύ¨<•² zυ}£§³¦Ÿ>°,k«ϊΎλGτEͺL„Du^ZoO–k#ιΥΊΙY••rίZ”—Δ»Όj`Wbο +έ'­κ ϊn—ΛW]Σ§ΌZ?θrkRέyXoΝΑ":;Φγσ&ΰρτ‡η¦<ωιΘήΤ>ŽώΟΤςcΙl­<’c"ψ€σK7ή}‚fΏw{ΕΑœp}ι;ͺ°!‹©ˆΚΉˆƒn(q2#έLΔRίθ  /VDDacAδΈ,‹Ζ•ο‚ι ή”«Τω± »ξH¨ΦE~ΞBω/Ά¨₯(žŠ""5ˆcεΤ(Οϊ“θή ˜ΣSύœI}<ݟ‘ε'ΠύZΉ³Σv/_ΩύβσG;0ώ>ήYh({ΏΫ—ΦΰUΔv »lΩ}oΗνΎ»ΰ + }N-@Œιo؝󓝯ΊΦΡ/ν:ώο.Γ6ϊX”Ητ΅˜«ΔψΪϊ\Χ,ΏΏώNφάΪι;ˆ1|τΕ;yŒ„vμ½³Λ~b0闝.ΏΤΞ^‹‡ςε;§΅FU€ƒΑgΏ (9Ϊͺr°Όσα[› DfΤw΅}³~¨j„ΌsϊͺOβuuπΣόΑWaϋ*%θsT…q‚ %}t,_@^ϋP²—·\v:’ Y^\RΰsQΔ―$*ζ$¬?²ίρ:<_.2GId2Ώ€·X ±ιGBmϊd½Œ€‚Έba"ΆΨ‘šŠΎ ΕT§²ΟΈ>W—₯ΚT:§Υš ‘>Cϊ½?Η$ΰ’₯½,Š# ΤψjŸ(4νΒ·$‘Bά[΅Β,eι°H…΄dB}σΣ7c’vƒΆP§w:ηΈ ¨«σϊXΚ'u$WΈBs7;£π±ΎVD›OS*w³ΘqθΤπbψ’τ©J’!\"$θΖΤδ-DWœΎ©`ίQα1ΤΒ*PίY₯κ/νPuϊjŸζΒέ»u™‚­Ϊ[TP„›Coά :”α΅ίLQ«γW‘‰}΅e/σ‰Χΐ ±(E›D<;θbŠ&O † J‡\ΰL€K2₯νsα9{.( κRΓWα™Pζ^οpγXi:)Dg Ϋ`τ9 iΰ΄‘Α ¨Ϋω:ηΠΐv}Χ]ͺJŸ.Θΰν―B‘©ΝhΓ b‡Δ –ή»SwΑC~5aON‰tν=) R…£—Αƒύ£F/‡p₯φ$߰Ɲφ·FώVΩΦθR–·2U³ΙŠoΑι -1ͺ IηΗy“έPΣΗΊϊθψXMφ¦μ<œσΖl„„=$`·yŽaM!ΐ"λ½ΕρM΄!λ½*―αz­Yo‘L΄δڲ­%‘ηo‹ŠBKN!ΊCdψt p΅θ4V±tΆPGά€Ί$r’δ±ŠΨι|ΩD,΄­»έ ΞDλDŠ%…²ˆπ>φj%9ύjϞ£Ve‘)E-Qf7Σ‘R‹„8…,^βθ€—»ftΝ„]^Θ΄θnˆθ­ η’l9Mˆ α³μkYb‰UγgΒ€]‹,‹¨θ‹V Θf…α‹+u’κ²j…A°!T}S€n’`.W±JζΔ ]²‹ΨƒΈ²SΣM1&¨O|ΘΆΨWP&Ε’;| ‹ˆΛe‡Aϋκ[3΅’ΥΚΗRΊρ/‘ΙR―^Φu_JΑ–΅m¬ήθή—ql +ΡHζž,¬CtΡ鞬#υ^γͺ-φ[€q.u‚t‰.eϋ"'Β^"Θΰ5לB‘ήMΊχήΥ*ΟΥfΠΊΦΔ[ˆ‘–’ ¦3€N’[Ω¬LΌB§’μOϋ ΗQ_ς*ϊϋμDΏΡ·Γ₯(­ΊŠZΒτε…¨ψ‘μr*7πD–Ÿ*wΞ>zY~Ιθ\1Αηh£ŒΏάκΪiaϋψGόD3/wΫ=¬˜J ίοR=՜–‘Ήε΄K2…€Φ'ι&n(Sγ97T’(ή=@Lχ!Δ­―z°‘}5aτ^^B2^ύ}£Ώς¦moI΄ΡŽtMίNͺΉ>θfΤ'±HɍIb^’gάΤ uΣ>Οa3τcζΖδΈΉεΤsN―181ρ³&•‹ΤύρfΆτ€rUsjΐ.€`€š”‹dΚ«‹ +fωB1θΉμŠ)΄{ΔH@ώTαΪμ«eμ‰Mβ[(Z‡gPwέ2xY=Α#εDΝBy³κ^ΡGθ² uIτσΓΎ@Z‡*)‰°/šΎZΝΣ_„€‡Vδ}©IPτΝnΕ+’Υγ2” o2{ PζE’Α’6['Q‚Aϋ²Φη4+φŸSΩ*Ζ +Έ¦ƒ`Ζ ++­ΖOˆδύe¨­‹cvU_+5 'ΞϊFχ69z :,J!„&έpιψρ¦©HYΌ„ͺ9’JΑ„o $>— ²“/LΞ«ΊHg;g)D3[W[ ζƒk PWŠƒJCΪTσ¦*―*KΫΆ +ΘΈΑ.κpπq£ΥΩ5eΠ΄C)oΕ<³„Σ»/hκ6b΄wCΜ 6δhšΞλG^]ιt&aAΣQtCkΌjnœ€cאβž¨€†ͺe!™α›%ΖΕ2φ₯’ΔΘάΣΑccBvœ—b;a…$YI2<εU&IŠζ_-—HΚu${’€‘’_ΪPkι|FVƒk₯³.Iπ“ςΛε`Ύ`}Ξiš‘’μΪΥ\}•Ν-‡Eϊ€(φ½!0:Ή‡D{Q2jΈΥ§ !Œι‘½‘“ΦΩGφ£ΞS:C±.IίΤ" †$)ζ6tΫΞ'(Λ)‚Ýl’œ»!&/ێήΔ‡B(؎΄τ]J»R³mfβοοP—‘ŸU@Jš }σYu° ϋΣΟu{8­’$=―ž-n‘‡;[°!1ζDΪKΞφ.Ί‘‘\±”yΧ?G€‰ιvoΚzΟE]I4JξοȊo¦EδdN7qα Η™cΚ9 }cΈ(£…θvcPι6\ο>(δ*§Ν2zΖ,0b +‰§€Cζ©ΓY€΅β’nX1ΫΆ“ν«I¬j1Glˆ>g]y}#Oΰό¨ΪMhΎ… ͺŠ00y­Ϋ±ΚP g{Λ_K₯ΪRΧ6>(§'„οͺLΠM‰Z’m|N΄pε0&C>(G2?žVAκS1Dό0~δ'zφ'βΨa«ΈαXμ­Ν4<Ω ‹ΘZrΤWՁAΠ‡½΅$‘*;΅ζγ:IΨʘLΗΥι,jO¦ €ΧΩ&Ž›·ξ›*Υ5Α€J*fΫͺ]gΰ[ΑbΪ4?Ν‰*ρφΞτΩsΞ£Υ‹³p‘ΡK¨ž*žΊ?ƒ’γ‡(4gΫKGη΅4λόuΘώι3Τf»~Ξύ=ζLKλg\…ΌC‚{B +ΟϋΨΉCXοhGΞ,ω]e_>±ί}ΊαΈwJJX₯kcˆυο7κΒŽώ' jb9l€νΙβeutΤn ΌΘΌ…SYˆ)‹λΘQJΙ.λh6‘³9κMΏΐP% υ¨δ}9z7A}ˆžΑΎY™ΞdΗΎΩΎΈ@ε,έ¨Ε±€Ω] α„Œα˜*ƒ—€§ ΪQ«$―2ν~ϋ\?4ϋ₯΅ΎiΧJ]μ«kWΰ΄#β…Ž |@3tΰ†L€gΖΨγΐΑIGγεs‘$Ι›ΚJgO―œa™ƒ³Ίr'GrpΡ=oΠεζh€‚€|-ސœOΔ™1…€U'sŽCƒΥ˜„βζ !Ν(hMφ3ΌΪΈB1-B™†άumΦ ͺj‚BύΥ.WΓΚό,ΡPκά-]‘σϊΥ6όC£wκ27Ξcΐεšu¬<=%Θαη–°Nrψ=ΈfL°ΌJm™ ³’™ΤχσΌόΪα亜[ ’'Ν_ΕΙ'*lsο‚l°σz±RGό:'k‹iw9πΆαu‚pB„6B²hοτξJ.@έ€ςYŽ0ςOΟ“¬­ fšΏ:˜ntnpζ:cΰy ŸΫ„L«Α¦mZ5λτΒΥ•Ϊ† 0¨šPƈ΅ο― jΝXδμZ5ύγ•p5Ύž²ζ$ΰμΊτ²±ΥΎγδ c‘& HbΎ1#g2YΗ%_ŒSο/¨q:ϊXl²œͺΙιΞd©ŽφFΠOδΘΉ_ πŠ$I¬Ο5K&X[ƒλμΜW›9WΧή5ζ\₯y Ν©Ο{k3―Ζ:'δνVζ™λμ3,―J@ U;” ―φ5ηΔš۝[s’Ά7Υ™j7χΞIΠxΓ"Ny¬‹ψ!dšΪP<Χ6Οά"Ξπy†‘ΖΦhBV)±Hm₯Ε"ρlε3!a ‘ζ9?Ύ*­Mά΄~uβ:λέΔ›6†‰‡Χ±NΌns2­›Ήiε¬3 }Φ§:S‚iFy&׊L yΒ„ψSSΖ"gλVIv8 €Ϊžjχ'cČ ˜Λ vΕ +'‡œR~ΧρȐ4•ŒΠΥΫkžBZh³έΉ€Μ\†s‰ϋ[Ρ#ΆΟv Η0R Fυ [£1±‚€θ ˆΪΎΙ“$$TΗcvΎ#G$Υ‘Θ,ΗaΛ1-6μ‚ΎKI[*Ÿ/ _ΈΉ% Z“°†εΕE₯““Μ:BKP!νγβOA9.™c_ΑUjA΅ΣsΑYι;KηΙ„0 +iΦνξOΰΠaΊ‰»έ7ϋΗƒU€δ Α&Αk»Ξi'ϋўΔY‘\ ς’,΄x9)Κ-Cφ‹Χ³Ό4d`'’–RTG^ᗍ}‚}e'Ύ#³&$lŠWFΦv\νp‘cP’Ϋ5…$xHܐ`<΄Φ­XlσΟPπh'ڜ3Σ˜':(<9 -Iδq§}Ο22o–a2΄ i6?TDsγ²ΩqφΤβRΆ™¨’ςV’š–ΆΐT΄<`λYΪC:Qe—π<#τ©¦₯%ϋΆŽ} Ρ‘FγI„‚[3§xntΝ†ΐ/Τ±mαάb3„άΠp:• —ωιI3KD<­ χfΒΌIώPŽ&ΜG&γ’Ήά/$|a†DfΖϐl„4%JΝΜρ’6|˜ˆ’€<δ•δS8ˆυ±υ¬ ?Ά₯ΠZ`ξM[MΒuφœΈ²uB§Β(5LvΆ²tΎ [cέ„κF\g(Χ5ΝHΑ Υj4λ& YςΤ’i„ βΪ]jΡQJθŽj˜N&―Ε€ +–Δ½0gΆ’lY4ΥU’d΅iš€We?F/Ή”¦¬¨ͺΟάM&ΠL&°AΩ<‡lP[ΊQ8ΚΤυ$;™2²ςh4ySm~’†iP Δ«rh1π₯ͺ΄I”Opή-}VWη™δ’P£B’γΝ’Q6κ™]+š,LΪ.Lo‘(ϊ .Θόqς\v¦τ&ψh6νΛq–b1{,v„Ζ˜BNeB1(ΙPVΑ-#ΥHSӌj,W‘dΧΙds“₯μ-ΩD“Μ-@‰ !A/˜Ϋi$WέλςH’‚•Δ—υ9o™fhk¬:oξ}Β|-˜ΧFςŽ˜ΫT ddάM%³<σ+Υη«ΰ‰€χ‰»i Ε™+ΗNo#‚ΐ»#54J-Κ ™–Γ‚€©³M)ošΪ<5ΜFΥƜΖ6uzςsνEΙK=8ΡΙ‘²…α(Ν]’N‡δVϋρΙ>iH&dS«” R³Ή$„³ Λ δα ωέ€±ι«!·lš­AΊΟωMr0₯Έ”('άπd±μ‰Hw{Š2C¦ό#·%gέp‡ΕJ}ƒi·fΞXˆΰγY6I_6•K&‚*’zU3a<&Iu„Ц!ŸZ£§’8Ν‘fΟμύ£β+θH°2΄‘ΐΣq<2΄yQppE²Εΰ]Œ +iB/ iQ»lιέ­Ω‰’bQ~³΅‰N5ω>‘ϊd’vd΅v™Rλ5ρz³j³ςK1ΜΖΜ¦ =»HOmHΥ–Σ.νύδ3A€w—Τ'2KΨςtB6ν<™ηΰγϊzQiνek=’β₯ΙmC<ή‘Θ³Χ―{ΖΑvΦσ›έyMMύΐΫ `7τ9ηΑi©Qκg"ά&ΜK6ι‘ζφ΅ψXPή>:§Εωk8 ζPτύ œ=‘H ++ξρΰκžd—ωΕ=‰Β9ˆΣLξΙ€£S†¨w‡θλΖ9pΦ¨Ν6g kޜ“(Ÿΐ’MΓ7‰Š+8ƒ1ω&Γ(³2ω&QŠA{kΎIT4Θ!ΜΎI€©8IWZ}“¨x!Υ!&ίδg68;Ν3 Ϊ4_LΌO‰Ύš…ΐ΅&d–A:ζŽ79 )ŽHΚ‘ˆ­¨θΈcΥJ­Α93χ!L"φΏ «ψβM–ΛκξŠ<&5φ…2C˜ Ό 3Γmƒ‹­X[‘ue=Δ–ΉτTtDΡ;£ 0꺁މe‚•hcJšŒα‹·η˜Η*΅”ιtθ"ΧPWΌtά.fTRblNWͺωŒ;˜•‘œ”¦•BΎfΒ1ΉσœmΟβHΔ„Wo~*ΗΉEή© ±ΰP)8{s4hςoτƒ‰=έ³ { ΙD*ΥΚΨ„E‘—ƒδ˜₯˜Έdƒθ€R6Ν\š6¨ue‚Β8^™qνtγ’i-Z*\l+ΰerKC’ƒΫ˜\±ΐ8“Ρ€" Pτ²‹ωaOD–·3Ν¬&™"5½–“ˆˆ―ΕΑ0­)A³2³Σƒcΰdu‹†Ψ)AνZς"X«₯ΑΞZͺΊx§‹EάIC.$+΄&LΏT§ω‡»2•'ml}F#Ν\*eΊΕ‹ BΡΦ¬¬Ό1»iκ„ 1―ŽBefβ4!Μ²M&Ŋ +kλb™ξ₯κsΉ h^LiξyD"Υ¨"’Ξkh&ĝΐDšηΤT?Κ\Ϋ·ΔW‚bΈ>O‘*JλΕ<½ΌŠ8λ‘λφ)ŸΌ9a₯τΈΫa0u±€aκΨ‹ε΄Ψ*YLΠge?©Π4yYήδ9e™4fφbΙV ‰0V±8(E?`Ϊ ΛŠͺφΡ)wΘ΅"Υ9 ;lQ +Kάˆ½Ι­ημΖΣ ζΘdDeB>ΈO¬[κ–AΗE™FΜβrρπ¦±Zύ1ίl’ΞM©Η1hU+₯³Gh—§π**TYΠ–>@še *ςθλτ…ς"%’ω$-•+€¨œZžX€†μΦΊΆŠΪ)άΤ‘χΗjΗ:֝=l6)ΝNO¬Ο΅NΆΖšZ?™FMΕΡ3”&vΖψ΄Œ]ygZ,uzΜ*K1ξ1kɍ8τ:»  Zž©œΥq΄JANΞWΨ«rÜ[ƒΒΆΔΝGύΘ₯}γΆNΥwp{ΥkήຍαζΌ»N°Ϋ“+tΡ-hν²&Λ mg―”l― +ιι΄’*A±ψ’”©!Y"Ο— š œΤG¦Lb”±ζέxƒΙ§ηΚ°ΨGkΆ`6_-C½›έxͺΩ2Η:–σ:'cΡ―37„Γ<ΓCˆ¬”’F‰5δΡLΡ!·VΚαΆςΗ$W>X-ogΌ*Η3Wά@Ζ½h\>΅Ά¬t+yGΘZS0Υ†•θΆΕΐ\)p²Φ==4 +Ν€˜¨œr 4«ζ-Α‰–Ψ‚ˆZό'β€ͺyl†Uxφ\ςΆΔͺ'DV§ΠΔb«σ¬¬=} yΆ΅΅6§sΪWΫ šυkΒ·°Ž -Z9rgZ΄"Γ:X_‹…•dΦX~DšκΈλ"Δ¦Šlή€VΗƒ’2}gŠΧPQ !Λ+4ƒoϊκ"‰`sο5‰ΣΈ–ZΞΆψdΊ]BN!ΝqRι½N΅_mš–<τ­‹mTΠ²ΣX B°<- ‘A4*z”ΖΞ" +G€u©ϋDyΥv "©Δ`œuί½mέjWνN»£=΅¨#}4UΖΩ¨ι“<Π6]+Έ%lP4j²h±βλ„+²N›­Άyz# &…™ ‘ϊ@š‰³»žˆ:-|#~΄κθ+‹raΛJΡκXYŽΠšT +Ζά@CaŸA•ˆλWm9œJ§άŸ y(eφ_ޟΐ9J °YDΞ’”Έw!YœA’”)ͺ ΆF)`ΆΖβrŸΚή₯Li° Eyύ‹K„Wσ8 9žΛvD~D)S‘;’φζ(e*j·―QΚ†+ͺΘK”2•)cQΚTυ¨ΰ₯ΔuκΗ°(eͺjΎΝQΚ„ ĊJ‰R¦:‚r₯œ5JΉ%ξΕΖL¬J”MΑ₯DηB±$_ΰΥ_{k”21‘Xw‹RbFͺνωβΒΌ5ω‚E)1ΏΑτ S‚Υ™—‚aJP+7λ-) «~“Pθ'œ~Ο₯A SβšμκVΰ=sΓ7Β0ΨΛ97ΉKIΩ€9L ތ“”0e‡˜;Έ·†)“·›Γ”)κy5LΙ«‰‚N§’k]7k˜rZakœrטdςC‹<œ g—ςˆTvRI]χ9T ’&γ@£(λ>οPebi9εy U&HAσ4Š›(α¬Ώ™βΫM¨Œi―Z¨Ό0Ύ ‘Κ”†ƒάBΰ„~±PeJVΔ|}ΥΜGk U¦5Κ²†*AcgΟ1T ;λœ(Ξ izΆζ-T 7';›Ά¬hŸC•$GΎP~" Ύ¬‹Y•ŽPε“PεΔ«δGWΥYBŽΌΗ™O™Y€ΰˆUb ΊDΧX%&$˜:¨ς3j°dUbvλ8,£ΑJ,Ύ°Ζά«SA> )1\Σd\δ•–ρ }.k5X™ςxk°2α|¨}U‚•ΰΛfξW+SQΝ¬—«VoΑJξ +E! VbΙ$›% V&Τr4ο³+EΠ¬ά@¬œ@ V&ΣjΦ`εΩuzz»†’–Ά»u^TnΞΒ {­ο>+3―Δρ§žŒ*²N½^ςpΠk°2' “D•&kͺνΈ~|Δ*3K”œ +j¦vN‹nxkΧPε™qkάκΞS§Ž’ΐΐγλZ©ιώ βδQΰ©m\ +¦΅4Ξω›uΠΧ +cΣokώθΌo±6\Pcα+'suŸ`jk¦E.$Σ‹;X§©/=ής#Χ€¬υœ.ηZ$΅—υ4+Ύ*Χ;̈ΓΌˆ΄ˆZO=Ζ‚sΫΆ΄‚ΙόM»lκ[ί&5@6F€@ρ +αΥ WFnŸs,ΧρΚ1μ\FΡ{+ΆΔRΈ@υής¨!ΕΖΌξΰS )€ZΦ’5€ψ”U”=e‘θ/hέF©Ώ8yΥ‰ηNkHρ«Ξ˜°†nAΨ@dvyuy–­y«Ε?ς«Ρ +f$9JΘήΙ…`,"•d¬z9Ο€†Jh”iΓΔΐXΏ\kHαφT} tΚk )N―\t»Φβ_‘WV½°“ΔBaAhš­y-!ΪΣY.` 'EΤΈχ»ZBͺ”³Σ΅€‘ΌΪxŸ”β%»:‘ghe{””œΠr ן !ƒΡ@)!Υ?É5€œ½Κs»k )Š|©!Εωž!©!΅ΕθD €ΝβƊR£R!©'ƎD§EŸxΠ‡έ I°„T7“TβM’Θ›ΚΠVAŠχs)+$9ώΔe*+a­ …Ι­mΤoδMBHE Λ¨ …+qε\qa‚”€r™Θϊ\@‚‘>—…‘Έm£²k~|lZAJWΈήhΕ*.Ν+œΕ’xΙ1Ω~ρmOTJg)έLHω2ΛΉ<’UΥ +R5Ο€(2ŠM'‹½p}Hέ «Š*£`q<©Άo;H˜ +HρžΉ˜·€x{Œ’φP4Φ2. ‰rͺ…l-Ένs¨Ηk%ͺ˜ρΕKά²,(ΕΣ·μ%υ£DβΏ+wg/Κ!!Ή²±Mυ£x›σƒyΤW„–ƒ€GXή€2ͺυ£‚Ϋ΅KέΦςQ‚ε’„ΖC2 kΒl°‚©"Rό¨Ε:‹^y»–Ž"ζΫ(ΕΩ–ςq{£ΎoΥ«&κU)hΩ-ΣsΜ•;βZΠ6ΞÝ-Θ„Ι‚ΡI΄U+G±'e-₯›ϊ©ΝߜȀk°ΊZ9JVzΆ28(ΚΛ•ΎXΑ&ϊΫ£Τn΅ŠPΖΐQ*Ώiε('{4Oό­•£ιύ³8ε<Άθͺ5i΅p9=-£peU-εωuͺY8ΚΛΪw*ζΤ3Η΅ε¬ΈkάΙZ•Ϋ§₯p”ΛQŸίBR8j‹ιvg.δ¨{}‹V%IK"I'ŒΓδ{A΄εΉ,Ξ/ͺ7-Ά7qΡOˆτ VΈΡκFΙΦT™`€D^ΥeJ+"u­|ΉklΩ5J:Ϊφ±œ5eŒšœ!U£’νvN„«Fι6ΓjZ5ͺˆζ'ͺχfАoπϋ+z©«FEaΘ*Ι]¬΅Ψ«mρ:εtiRY£Χ n!­5ƒπG‘I.ΠͺQ€j’’=Z5jQΩΈ]C[# +wΣFiϋώΜRΝτHΐΆψ 3Y_zg.―ΓR>Ρ¨:ΖόœAƝ΄Ψ δZΒ ˆ£[‹·%6Ω— zc„q/ΊΑeΞW±q‚h=xΥΫ…Νλ}Ν¨ς($k^!ε#'Ύ}y“εδE‘ež'½…wo!~9ά™@μƒ°MT+AΑ“ΝͺYΔ­ΞaxΫ¨2nγγυs%θ†Ι@œLJ΄RΟ er†5C[λerΑ…Υ’Ό[›}.ŒP‘jdqSή“•d„q4»[Ο„s!΅¨έε`\Hb{σ6›ΪtΥ„±Ι՘tΥ€¬3Β !―XΞ6=Q‰Pε[eΙ–€ΈTDuJδΦ*Vq` &) o¨p­NF ¬ΔβOA{«Λχΰ2).ϋl%νye Ιz Ε^-j%$υ‹„0ΎτŠZ,hQGV["Œi»Υ€’ττaΡ¬‹k²|œn›£>†OΦM”{,£¨»£y’ΐnΡL\0δI³ζ˜4Mή΅]{³<]ŽAπh{ qOρ± ψ΅–O6 *+ρ6ψb*7Ίtf»ϋ Β#[Ÿ²xyw£ψDK@XΛ\΄2ͺV\tζ}ZgΖJ7cOT‹€ήΉSͺΊR QΡαΜrΠ})‹­&Š•pβ +Y}ϊκ“<䬲§*ϊβπ‘4Ήκ‹=SC=«5‰ώW󒈦Ib›γΖ.$†(]’™ p’™΅ §ΆYν’:5δ·]h 7—ςxFΨxGΐ―Υό +ζAQ \ΝΟ©TbkAv3σμMλ+ˆΡ.CZw=oE–ε&_/UΏ|HΆ_zΉ΄u_un\Σ&ζbU•Y½„:D5νY΅TΨD¦~%ΩfhˆΜ¬’―/ITσ-؞oϊb•‹LΪΣP¦±ΓΥ*Μ*S9b±eή0&xπx²εσJX ΥfI$q=Α³¨3»Ύέzg7=731“ (ωΝsp<.ΫΦΞ¬S6RΆ«yιιG½Oω!²CQacJuάψό£3οάδ1Gn΄ͺ#γΉEjΞλώCΞ}΄ΊΒU5φ¨žΩyeωu½,Ί»©ΊΪτd"mKΧD4»sΊκaw@ζ5n¦zT)ρ£τTΊ£"³ωΤ©φΥuΗ«Γ«TδX½ΌΊ‚Qδ9κ e“²·γh’,κš kΙjΦ~•‘ͺ‘ΞKtI&Δ<’ς*SΕ†£σ7.C$uέ#«|Ρέmšί*₯KΉKα£ VΜ'ή8₯2oy<°έσ’–z“Φp!ΩF\aΟS?ΟToΔ+ e\N‘ζWA#N‘¨^,8 Hs3‚¦Γ!c~F REΤόŒ8f$,ߜg_ŽΪ Q£ΟysΝρϊOˆmΒπU‡ΐ]CM/Α"―†αKnjΑy’Q’\zάΑΐ‚ΖšMΌλd’hΟ³8Gz ύ„'Ό²² +Δ"ΨΦ=™‘/2νΨΟx‡—GH$‹²€“8Ζ L•εΔψh;&\š€xw«κiΝήδEtΒξΈ7ΖUWΆ-λΝlD\Gj!ρΟξΜ­-r€jϋΥEΞ7Ν½ƒPΨDupΠ$Ω +[ω%ošœu₯hzλ’¨!f.'εYž·ς:η5Pζ6ΉoTΦ'£:λ+β=$aLVπD@ε {·ŽPžCθΣ[œάΨ»7{ΡVlu’SUuu’Ε<‡ DβΫy‡ YžmhϋκEC{²kιE‹ΥΌΓ‹λδj3/Ϊ^4dͺ&“ς*Ύα7ΜΥhŒ½ UGέκEC}°-HΜkδ›6»φXάhQ/Ω›έhQ/ήά[έh˜gJ›ΈΡ‘―ΈΥΦΑ€A)s£r‰m‚V7Ϊ +ŠΫ,&½BώΤΟΙΖ9CεΥ‡W™,#R Φ― δj$δ“ΔΕ²?V1SN6`QήU=)Ζ“6€τζ ζ*YœΕš&ΒF«v΅'Ει1UH*‘mΒ Όκ-*6?§Λ[{@1Ϊ9k‹τρj0°θ«zω# ΈbiΨtT±Ÿ1e‚z_Ο†c,γG-cώˆΝΞ2φ²«/#ΜΙ2φNžΣƒrEΤf"K˜!™ΈυˆΊ>η6ε3±9I Pν­Ίxξ:"uv5`3qϋŠMό€ͺ §yD±©ύϊςcΐ$g‰f{ 8^?‡•'_1*σQš” ι““ΥΩα!$fΤp'1oχ¦ZοΩ·ήRed• š$$F&•Ϊ‘C9Κ‘£jO9‘”ήΈ'ΉΠΨΚ–<œ» +αM˜ΤΫNJ©kcE|XΫo9ΐ:w­uf  š±6΄žͺ{Ω4mͺ¬Σ‹Wqfَ›‹ ŠEμΌVχ¨tIL_;<ƒ\§skj|Ξ_EΥuρ‹O½SΒΝcˆr,e«Τz‰>ζDŽbσ6sR7>ˆ1Γ’4­_5JH4 Œ\’ -cPu@ΒE‡:žS™ΪRFΪ|rMξ]‹cΪƌ{7 g'd] cΪΦ53Mo˜ +Ζ+ΒtΔ_‰5Cƒ¨+8ˆΏΆ6XδΜJŠ+rG½»bΒθ}™†qDI΄ΎE#ͺ£~;­h—9ε‘>ΞzZ*<[­~# AΆΉŠͺΐ,IΓ£ +=  βΝ83½’U,Ω ›ηΚψͺΆ–υ„χ櫚!5χhrCΡ̘ΝX‹δӜh1“yβfy΅ZΒ«bikΘ Β#z;έΕd© 4(Ύ‚Z$}nΝId}ώͺη©wZ™}Γ’IwΣX—α˜ζdΡ·rΙhmε¦ι«+׍ޭΌ9Ζ°ςπ4ΦΑκcJΦυ0&n]7Σ[=œ‰Qν‰\+4‘u•όkkƒIΞ¬ΦSΦ‡sβ•^΅…ϋ8U΅'XF ©jP2œPΥΏΪPG εDT¬§ ΄Šjd‰bo;&œΡ…qλSσήEh[mWx(5‘ιDΠt΅βv,Χ| ψκb‡Δ,²‡2›ΞΞ‘2– H<­Rٞ]qγ8Κ‡s1;79ki{NΖbΉι,ΘΞ=Ϊφ‘U6 δΞFh”a!ˆ-ΔΫαΞ šκlVΛ>ΞjΰYjΟΙΤ‹"_›Ή?C•A3Υ<ΤηƒU€ε Α0Υ’(j¦΅ͺ§ %λŠΛ©κQΡ5‹F±|˜©,nTŠγ’{Sυ¨Θ[˜«3ε9"_F/y [R^Išͺω1GΖ­_βJσz+ξž”,`fΜbž9–?@/’ΫS­x43eΞΞσL„8|V ήά'hχ"kυ(&,-v “ `ΜPΖ\±|%Λg/rS1σ•ΚZ>ΚIΎ’ιΎE¬ΊcM…7Íuy™ΰ¨R8Ϋ$ζ±βσπδ"GΠLC}L―υ’Ζ$dεSŠHDώ‰•ΡϊQLIΙv*68&Κΰvλl%°-ΉYZ,λG‘t,v¬–!λο endstream endobj 22 0 obj <>stream +#ΑU“ζΣHΥ"€·ŠUI š‘Q?j jφz’‘1Ζ»R#h:νZ7h‘m}υHΐ―Si·ˆ»77¦qύ έXΎ5Τinyέ έ“ς"Σ«F)~™½Q@Š ™Zψp"E“έoπm- $ΫU|QTAύHmͺϊz•uȝ՝6X* ρY σ=’ΤκΥ§Έ7*H1M-Z݊‘6½žn” +R’όk•ε\sγ­„i·ŒrӚϋ”Ζ]"c‡‘eŽL°Ž +Ψ{˜{XΦRQRDιΔ%4Η B-!Ε„Σ0ΖΞψ€>T_J<0IqΜ%ς™Ί«ξΞP5Šς_:ΉͺΗιM"(y±έynΖδi)&5·΅‚”εΕYΙX[˜ς„guΗ[L_*H… hηΉ%Ž>$ƒTrΖτfΫ-Βλdρ2—b'NWΕΧη΅„v¦Ή•‘§„Sˆžiέ‚:!š‰»'%€’4&!V#rlT’ώ‡δ΅‚T‘Ζμ8ΠΈi£―VΉNσtˈ―‰Υ1Az”ΩW/*₯Ήχ$„ΊΤ΅‚”ΫδLΣdp^J³ΆΦ§4NΠΖΉ—lωΌμΔX‘ulΘzΨ(YΚKΣ›žΈhΛZ-Ϋ +ΡŠ%eΙςΥB+:·MΉΉŽͺΑΡΩY+έ³ˆ”²ψκHaȜO™£†σε F΅ROΜaγ2ςq}—‰jηlΛΗSδ2ͺtZ)bγKNr[‡Jγ½Zξ|Oj%hŠ€³|ε*BˆeV΅U‘ξš¬jΣζδΝΑ‡Œ•1gX‘Ί/L€]K/ZδμΈΤTA―rjΥz˜iΕΗ {»΅ΈeK –e?vdΨζo:R<¦ΊRšZΐƒθscQn/έ|3YžΖΪ΅4ΊΗΦδΑi i$¨ IzZb5(>ΖcrΧΪ ƒy”OSJε‘Γ84³ mΚ1΄ŠρMs‰ΜaΥp$юLOΉ‰*e^'‡,μE«&IKjjΚ §Ξ_τ#£ήϊ%ٜŒH:ΟέΫή iTΦ}ΘζBΚ­³%‹\fuͺl4&ŸFj…θ˜q +%΅ΗF9₯•βRviŠ;g8‰e“}ςΆˆΩL5ψͺζ9+† #fΣ―^ΒΑΪΣcΆ¦Ζll>κΗΎ?:g«n‚­ΞΝPέt~\§D—ϊ4o&6Σ놂3ΘΰLB™Ϊs1?η Ή +³‰1–©ZρΰD“μz”υMS ”'d°μΐc―M-«ΈάJΩ5Χύϊ£Z σΎ€ΩJdζ‘έ9Ό”49˜άΜMΙtb%V4UKσ»lΘq 9™—Ϊ 0C«£b”&•IΎΡκh\9kυG2Ι½mό‘γzν©1K™ί|tx₯­kI3‹FοΣπ»McLβšη" νiΜXR‹{Μ¬Ό*)3βΎhςœM3™!Sn6 8γ,wYJχMWζ’™wΣGυ­L[ΤfωZ-*™Τ·3F#·Χ^­Υ’τUΧF½P― †i$`μ«4NΙΩ¬-ΑE”4qKӎTΉΛšί6Υ’$‰ή-Yϊ^΅£ λMmέS‡·ζO™κ0ZΒ M£VT²|lΛΡύBήφΈ]zου +Ν(υ–Νy6Mn3gΆΚ6sλ₯ΟLogΩVJ9ΛΆœ)Ί.ψAyΛ ŸψΓiΦ†`ΘlΩΝΩ,9!ƒs'L|ύβXgΡ)o+σοΚ¨1!ήΦJ•€δ™]%Λn%ΣΛͺ[6;7Ρ&+ a@«{Υνšι…/3^ˆμšVg+Su΄ΆψςD–3,–εΓ²Τ“Q­Φ²?fj‘εQj•(ζ)I: θι™sευxͺ”Ÿ‘xΤΓ‚£H”€Ϋ˜›=KJHΠγJR$ͺX’WΆθfΤ +™β$Ί>!~νμ ςΠ³4e’T’XρIηΝ‘¦YMlMH΅ΓGR# +n πΆ½@kDq>lίŸ&-­%’4okivAΧ€Π Žkη©€‚RΜ\fUZ}JSdP›{YKDYςΥΠZ˜fNώˆΡʊ¨ί j9 aAZΥ²ΒΔΨj΅ͺ̜_.›Q€ϊ.――²D:―%’t“kj}ŽQ’-λuζ„\ӚΡcψ‡›Υ₯ΰΡΥ pΌΐ΄Εsΐٍ~vŸŒΌ>―燀τL‘„eo{œΣ 12ρhΨH‰(Y’ϋGφ†n!4nΥŠΚ‹d―kΩD'Ω“r“€”ˆ•"Ίι ‹Τ 'ΈEǘ†7μT’‘πΎžzŽ+_[kš'η–Q"JUΐ&—Iοš$β©Ί˜‚Όζ,#’mΌ8QΨjο°B'~$™±y¬Τˆ:εΕρψSέ/Γ“%2}BΌξ—ΔΜ ™-Ό‰τ:tΊQjΝ™–ςPEΣΉUΠ…€AκκΥ‘8*'’ŠML£!RΚ£έΡΔ%*Ώ[,ΖΖL^4«oU±°‡‘WNXΖ'τ9§΅iFu(&xzΣqmj™ΊV‡Β† Y”¬#8ιΈ&εΜ°œ>―<$Υ‘’δ­ZΨK«C1GΥΩDŽ}½‘`oT‡b6χ²V‡RiΊBS~π'D“ε‘ΞY£§S2γ8Š·nΣQK3l$σmΗ7Ž$?rΔΜΖ“š}ϊυͺΫΛλ J™3Σ|ΞχZ +$M·ϊPΜ=T±8=Οk1g¬5ρθΌ‘O±©ΌHΤmέϋΠΛΡ% •pΜn8\{‘Μ!ωpz݊"=Τ.m_?ήΉKη‚σλgΗώΈY¨š΅μ.Z3Λν~ρ1οΠ)Όg2gXΠ™χUÑϫ΄Θϋδώμb˜m•Nr±•‚<εΤχ\b$f_Ζ±`¬dΟΠάΈΉ©½xΨΏͺ0`‘7γyS γ>td l‘(Υ,7υBΛό&=Ν„p‡t‡+Eƒ›˜ΈνuΠΙwΌ‡ ’0£nCΈ+·+y~ΙΌΌ=Egx(‹nή彁•Ek3ΞP’”žλ›KP™πwε§E1_q«&γ%A›£γζ.―™ŠΪDφtζδN•‹/PL΄%₯v+&€ΐΐuŒ.ΝP3jq–•3$AΌά!ΫTν%½Ί*'8΅–Κ‘F‘8¨πŠ4†C2”gΘ)HΕkΜR_%x•UΔkᫍ5}s¨b/J&,ΟΒζ€ΨΒΎΠηob7Δ>cN‘ΈG3’χR K"¬9Κ1ψiEπЦjA,qͺΗ ΜΣ›±Ά…NκφΝή7Τΐ¦°φ-5έΗ:₯s6•ΖΖ³•·3HβήΣΜΕ\$YzαX=:ed˜•ZΨΜϋ’²$Wν³ϋš*…,jLτ!Υ]Ι/ρ ‘dS‡²œœ &ύ©ϋea#ηΐ +Δf₯‚Z—ϊ"H_\ΡzœͺI‹ž€₯€ι΄μύνOu\#CΜ7‚ζEλŽγ‚ΆB«L›0}1'™šU@ž#HiΑ,κjl· τz|Λ#Χη>A)―Ιΐ™DA–¬Gh9\RT -)g›i%Ναny@Ό΄‘„λL eW½@Z(ˆ―Š„jb|ββp#„ά@9Ω›‡Η]Τ‚–ζP:cDψœ‘Ÿ7|ΨοΌωΰα͟ώόΫ―ί=ψοέ—:ty +L«Α]Ω=ψδαƒŸύiχςo?ΊρoΏΓ³Wv―χ'_ξ‘Δ‰’HΒ³ αwηΦHΣέDωiζε=DΙώΑ’zάhq)ΜάJ™²²4θ΄ ±›b©Κ˜Μ€’§0Ο¬VNΊ++–Y„§δV’Β³ ±κ« χMΘ¦ +s+*²ο81uΙΟ€ŠΤ½ v€M6ί7₯ΐŒD΅wX—gz|ΞΰŸHϋnΥ;WŸ’φ8ۚ΄¬ϋDΪ?CΣO’ύ³4#gετ%Δ"Q±ΔΨΨ΅@¬j&ŸƒI_K‹¨ =Ÿιΐ˜7LŒQ«²6|³ΚœG‘ Ηό¨άσUίζ~DqJ³ΏΜFΤΔy½nΩψ*³4g(‹Ÿ7ώ'ΏαjΕε)ιΞΤ>ώΟΠτ“θ,Ν<’£ͺΨ5I³Ό―'ƒjq’‹ε« r&ځδ›)λ±4TΙ£‹σc V.v7τ?ήΗ H"Ό€―ηS=­ƒNφ"ηS₯ή{αρ”&'/΅kύU+oƒM©k<αΑH†&ΡάΟκρyγ"ύKr‘>d=wjŸ@ghϊIτ–fΙ‘ι$t XIώl֎ΣzΪ<€“TΣΧΩΤ2 ςPˆB~=bEPͺτπΎͺπ^½-ˁΜΤ΄>6O΄‡I₯υΕ.‚¦1οσ@Ÿvdσ±žϊ’ήΥAήφΛH,SŽ―z9|z€ΗηŒώ‰Δχˆ_<-ρΟΞλh -?‰φΟΜ#9κBχ1¨E½ZΞ•(ΔQ§; Ι€,8Ξƒ{Dp +Ejb €ΗωεrΘ-–ς„~±ΓA-ΚK.y{Υΐ"ΰ!@ΌΈUHˆŠ°όͺkϊ”^HΜή)·:՝§9­Zuv¬ΗηMΐγιΟϋXbΝOGώσ¦φqτ¦–Kώgkεr‚“D7ž\ϊ`φ;jϊÜpIr·8š:€$2Dq₯z»‹R˜pA“θ("Š—σ`rƁΛBO\Σ#@@‘B>οRtA7Δωœ†Ρ ε,”Η©¨‘&&Ί/iY@jΗΚ©QŸ7τ'Ρ½0%¦§€ϋ9“ϊxΊ?CΛO ϋ3΄rg§‹@`ό}Ό³ΠPφ~§ώΌŠ Οnt`χ½·ϋξN +‡Aq.γΎύΦ£¦';Ÿμ|)ήΊΔvόίέ―—έτ1h Σk…—©s“ν―­Ουώ ~ύμΉ΅ΣˆΙΌϋTWšt9€pψ%!=ΑCωςΣZ£*‚ S ΔRP„¬<‰X!DfΤΒΩ>yf\z >GD )αqʐW„ς«°}•τ9ͺB€€6 €οс.C€ε ΘkX©ΕS4;‘Ζω²xε^Ι‹ˆ_$π ǦƏ,Βwόζ₯·x™Χ•¬•ΤψΥΐήf'Ρ2ωHΰέͺy•G@Aœρ/\‹!’ŠΎ™υRHDgΟ1 œSιœ6&7x;$5}JkτZK–φΌ(Ž€ΊRhoƒrAo(€‡Αb«f=ώDnΪΔzD€ϊζ§oFΉ¦Υ±¨mŒ*uu^+Bω€Žδμ%iPήμŒΒΗ‚”»χ.λ m@<‹ˆFB’;αET‰JϊT%Ι.D9%±…θŠΣ7„ς₯ύVXŒ ψA±μτΆρfάnΙ5@EΨ9k‰T½q7Θ({΄ΔSS”₯ώ(g}•r.I'Δ+’k εν"Yƒέ‹‹ͺ*ΔK²d&%™φ9δ(:{.( κRΓWάΘσ²ž]tν΄Δ.!:Λ1lΓΡKN`ΑΫPεͺ`ZDIη\.A[P-Ώ(”τ‚D(4΅mT„εΤ€Q +…l!όͺdπδ˜HW€‰€,HŽ^"λLιΕβΪΉ‘˜Ί“φnCψe©Nˆ…Ϋd˜MV<«r2δR[IηG*“ΫT9gΘ!$)]„";―©x+$μ!»Νs k +Yο-ŽoJ‘Jp›\Ihαz­Yo‘L΄δڲ­ \šφφΆ¨(4Ήδ’;D–/M' ZW‹NcKg ±TšΌΉ‚ΊX*3I«ˆΞ—MΔ“ΰ₯»έ ΞςȝH±€PŽ38&Q’Σ―Fρμ‰0jUšQTλ +pΎιHΙABœB_’φD.ωΓ]3a—„ς"\€Z‚0ƒΟ&œ[ˆ²ε4%²—²_δ5Ζ )acvΚ€Ύ¨Ο"*9³&²ΩEaψβJ€Ί¬Ze\r₯oŠΤuΜυ¦©βQ7Y²cIμΤtG“tŒ Z$ Vή\A™HFμŠξπ¬Ωˆ2X.;| ΪWߚ©Ό…Τ1‰S7~žεδΊφ\Χ©ξ‹ŒΚ€l¬ΈΥΆξΎ,’‘Μ=Y$’?RS”{²jUΒk\΅ΕΎ@c‹4Ξ₯N.Ρ₯lŸΓ₯fd@Ζ“9…X€L0ΙvŽήΥ*ΟΥfΠΊΦΔ[ˆ‘–’ ¦3€NΛrmθT”ύ(iͺΣΛ“π²CJ.:Γ·Γ₯(­˜ΛHˆ„Z„¨ψ‘μr1΄ <‘ε'ΚθŒtE.ΏdtfΡΦs΄Ρ53­Σbμc‹ω‰fΠ±δ‘`ΕT’ΒžΥ‚jNrg&γVN»$Sˆ@j y‚nβ†25žsC%Rο Ή·JΌκυ"t~•7 γn)±μ²Σ‰ΰΝReκ―ΌiΫ›mWΡdk‹Ο ˜Ξ3b‘’“ΔΌDΟΈxMΐœϋk:7C?fnLŽ›Α3‡ΖΫ”g +δΖ¨N΄Θaνc&8I™ήσUά¨bSΔήyΉΛLΗΔsΗL«‘£οTš%ι'›+ βdakY―䦂tŽςΠN ?C.j¦«Šb³ΈI2Ό’U!ς9?!{=n§Ψ`τα‰,Ρx™ΰν©`\Δ+':5•R@Α$-ƒσœΨh6€)ςΌŠΝˆ^yY4hŠΞŽςοl‰°λuAN―oςθML'αΖ¨ΧJ Hx(«†1ž[725Pΐ­}΅ι ΚΈ1°5έ’δ_ή«hF@NϊͺAANΖξΜ Π€ωIωΌίQfp,ΔδŒr“*–k5Ϋ'Tεˆ|#˜₯ΆZ0ͺΠ„A“fgœL^ν +•’€v…D΅eM +ab;}Ÿ³$»–§£&Y°ύ{­;O7,P³σYPεΥΨ]žc₯§_ΝL7’Š0mbcJ?ζωκJ‘0oC©q¦r΅±΅{Ήyκ˜Β΄Ρζ.@nWΔ• i‘ƒŠ$ƒΖUΝΊ:Τ+/υt 9S―δήζ dΌ0€½C €σλVptήώ°ζξ"o΄ ‚α>Α¨Zœ™A8½εΝ2β₯}ž΅Έ=ΒD“’ςG–aΡΗ€ΜͺH„8Ψ@N•XhM ΝΝΟ1Fk‹ήK³ωκ"Ulζށ+Ϊf ^k¬€―φΙ-§žsΚxωy‰‰Ÿr\†P–­šTΞT±:œYovGΙ5)³έ• +uΈfωBά“%ε*΄{ΔH@Υ‡(Β5ΩWΛΨ“Δ/ΆP΄Ο ξΊeπ²z(‚GΚ‰š…ςfΥm!Κ‘I!Ρϟ5-ŒCM}Z£ zϊy—q”ΙΜΉ©IPτΝnΕ+’w₯’ %θ›Μή‡yΑ³-$j³u’—₯d{£είͺSnjpM ΑŒVZU`ζͺ¨­4j”§»‚ͺ―Š•ŠΓΧΙϊFχ69z :,J‘ΐx‚ΉtόxΣT$/ή BΥI₯`Β7δίb]ZWu‘ΞvΞRˆfΆΆΜ?Χ •†΄90¨ζMU^5–Φmqƒ \,ΤαΰΣΫR9»CΊ¦ š-˜7‰oήξNοΎ ©ΫˆyΠή 1/<Η¬ «H57€K2Ξ$,θb:ŠnΘλΧά8IΗ!Ε <PIνε, 3|½ΔΈΈBΖΎ€·₯r8ΣΑyτ‘+d8/ΕvΒ +I²œdxΚ«L’€§―–K$ε:‡=‘E”™£ή†ZKηs`9R‹YΟ!N-σλsNΣτeΧζκ«thn9l‘ˆbί£“{H΄%£†[MqΚ˜PPτ}d?κ<₯3λ’τM `H’bnC·ν|‚τΑαΞ &юNN<]Θvτ$>BΑv$½Μ€`ΆΝLόύ·Θm|VΌ[Ζ„Ύω¬οφ=ύ\XΚpZEIz^=[άBwΆ o΄;‘φ’³½‹ndά³”yΧ?G°: +€n.κJ[SeΕ7qD‰+>:έLΔ…Σ‘> ζxTFHί.Κ¨G!xTP €Ϋp½ϋ ·iοtsβE δψO k¨΅α‹c;a1€¬ΊΕm'ΫW“XΥbŽΨ}ΞΊςxYA‹δUϋ Ν·œOέbςZ·c•‘Ξ–#%%(Ι₯  ιk”ΣΒwU&h‰¦D-Ρ6>§ΪA–$hN†~ ‹φΚ)σΓα©a”4+¦“ˆƏ€όΰDœl))βX€iΊΈαXμ­Ν4<Ω —‘Γ$G}ΥόYN‘ro-Ig€ΚNν†ωΈNΆ«2&Σqu:ˁړ)(°EΩΔi‘Tn’*Υ“FΈΖ t΅ΒlΫBzsκ Σ¦ω‘hNT‰°w¦GȞsvmΟβœK LΉϋ3(:ώ(rζ·½tt^K³Ξ_Mφϟ 6[΄τΘ™ίσgΞ΄΄~ΖUΘ;ž\(Ω/˜Α$¬w΄Γ3KgGΩ—OμwŸn8ξŽ!0¬Rτδ?ρ~Ή=σ―μ“η‹šXŽGΒΘσEK RkΚ Ό―½?υ˜†˜»oAKΙ.λx­Νρ&φ¦_`¨ΈKŠΧ› +&¨Ρ38Γ7+3Πqϋ‡“;—šB9K7Xf’ˆXμ„πBΖpL•ΑK@S†D¨V'H^eΪύφΉ ~hφ#Jk} •ΊΨWΧΐiGΔ ψ€f θΐ ™HΟ ΜγΑlW +¬/Ÿ…ͺ“δMc₯ΣΏηWΞ0ιΜΑΩ\9—ŒδH.Άg—,.7ΗΛ_„‚Y +όβωD CM!`Υɜλ™a‡;Β%0Ypν»/„4£ $+Ν °Š+Σ"”aξΊΆFkPΥ~$«κpkθΚό/*+un­9‹ M_mΓ?4z‡ƒš-Εy 8B \³Ž•χήn§9ό²%Œ‰CΏΡ –W©-δqV@6s(X)0Auνπ r]Ξ­5Ρ“ζ―κUeςͺυΙ;‘.Rκdk]Μ?ΝI…‹;¦έiζͺ£ε7Mpu2!B%X·Mδͺπαy?“Υ pΔ ϊά`’ΡΪΚLΣWW¦³Ξ­œ9F0xθΚηcB¦Υ`Σ6­šuzkΆxΦ ―RΚ±6Πΰύ4βO­‹œ]«¦ΏbΌ.H α)kN‚OJo–Z$’& HcΎu\NPψΊHΎ§ή_Pγ4oΉ.œͺΙιN€TU% a¦#η~%ΈBΒ+š$1žk#™`΄† Ο|΅ ηκθ]cΞUšΗМωΌ§±ΆαΥsBήnež9^“άκ4ΓςͺΤJՎ+ETΐN_ήΓ·…&Αc ήΤ;·V$moώj1Υnξ]‘ ρ<†,Ni¬%‹B¦© ΕsmΣΜAŒΑ°fg{₯ψδD l#£Mτ‚XΔ!ž­|&$,‘τŸŸσγ«ΪΚMΣWW½[ysŒaεαi¬―ۜL+ΒfnZ9λ σςδTgJπvΙ<“kE¦…πΞ{HS¬r «1ΆΦ*<…΄Πf»/r)©ΉŒ]υΧυ5;š#Ή΅OPο0›^fCRόjiΖ€|wo4ڍΉȚ1z6όφNžF(3{WΕ”>I ƒ<<,Ψί†JΌΟΎ{8KΦy¨~Γ―α0±„!B,ˆ"x{ρLVBΔD’(9ήξΆ"£+AH”™o c‹o:όΩ$… +Xœ8΅cβ*EFΔbskJZΗΌ²'AΘ”΄γ o;DG‘‘™ΝSΤƒωϋ·MΈω_QŠ9XΈ9}Ÿηy;Β£ pώ™»Π>Μϋ…}΅ώXXi%ί Ό™ΌΆπ2‰%E8OF­H±'AQIη)ϋ¨#x`ˆθ+ήO’QWœ7—Bί±§"|iœ&ƒ>HΛ΅$κη(ωΒ…ePW=ž·DLή…ˆaΘ8qΔ―½ŸbƒUŒ±N _wαš›/Fz›€γ¨ΚjzϊΒVN½+#ˁΌ9ςΘpΒl΄©))°qέη8_Š*Δ$δm4#ŒG‹νύ•Ά!Ί˜ϊ"U»P#PtΥ-j‰θH5½ŽΡ~!DsZρ˜!>¦θ1`£…œŠZ‘‘5 βHd'Β„υΦ­…PBxΆiŸ› r±Sόν¬83’ΪZw_ΔGΘΞ ω7ά<±ΒίμΦΗcΘX³(»7U`p» ,Yj‰όͺΫ>C^&P]ˆ†`ΘΦθ‡μΔΩμyεΉk“už‚^)ιTΗ‘:$½yΊFQΈB΄XD«Dτ†ž"΅λ†w#Z‰Ξςϋ¬"ϋTϋ θ“Mm^77χV +ψΓ‘T [ λ™E’> dέNZhvόΦΓX6;š$ΕSΞέDη0–eˆ²‰·:?؞0ΈΣ’ον’™οϋb$ψcφ^PΧΐ‡G½ ΐΛ]ή³ΓΣΒ€σ" ωm`W˜€©…p“:“ž1Σΰ”—szw\ŠΛ_Μ`zž5κ$Nyκεζ o)»›3|xΫ―«mψV‘½‹@χΝx Εσ#ΰP„v ΪδσMˆδaΜΣ,ΕPΝΛΞ•μXrœLρχ=ε=J½t«BSΆ,ν²‘δl­e/ς*Œs}YφΊΛŠιˆ— χ•p«?―bSΗ4UλΜΥ‚z2Ιƒε ΨςθŽg€ηΌ€ŽK Δ—ΰEΉ9§ΉXβhαύgnOΠif˜Ζ12hΑω―q~•a]ΧuCΑβΧ耑 Ή4MU…‚ρuΧ͚9‘pžA½EίΜ&8Ψ~₯iΛ;·ιm2ιͺo‰Ό’7@xλ b.6#­€δ4 ‰Γο!k,[Μ™  J„· λΒہο*=Άύ»³Ηwv_#–b¨{F›e9»šΒ1! rAžŠΓ-¨Ϋαs‚H°ΰ™q“1 ―ޝ‘IΣύΊι:@όZ§ι₯ΓS5ΈΑfGC΅HΣhƒψΑ}—o†S͚Υθ–΅†YsΌ²zνvβ=FWp*†¬ΣNˆμΤN―’¬U۝_˜aό˜Οΐ0΄Ÿι‡M: Ϊ$ψΫvιλΪb`6—›Ϋΰ§ϊΌπZbΏ²οΙΗuϋ ΅=m±θΑvz>S(o¨ςμΒυτ)Žβ­ήcΏπόκ'‹‘c2ωϊΥ§ο˜•ΣΣ?£qΫd“hWaϋξϊ‡BήύϊΕ/ξO‹b{OEΨ…[$2@aγόcα +OΖε#Γ“₯¨Π +O–(²DΡΙθ"3ΑΙβŽΐ+8MHͺήΑI4+Ή)cl2ΪΚ γȊM–€YΩb“ΡIEoλΨ$ϊΘ‰›DKŽλŠMf—¨=6Ή„›|ζ}ξmΌό!»œ…ˆΪ-–||δ μψ­ζƒDΒU4ΡwΧ)¦ΦrJΒν,XσIt +Ε`Χηˆ] +wU”ImxP½”MwΖ1γ|\!Άαίͺΰ•½Βl9$ ͺht™π,€ιBOŒ‘oMpˆΘ +†ΐΘΥύ*‰F‰‰ –ZE: »„θέρΤ ₯θW°Ω²μ!Χ8ΗΤͺ6ΗΉ‡½‰šϋ₯>…D°ΗυΫG XΝx(#εένRCφv>.Ύš΄έόšzj₯:f=<€eƒΤ΄$ςυΰςZ<Γl™πy9NublwjCΒ\0χˁ“GΞ“σ~—fLu!κγpZœƒΠ˜cΨ\‚ΰ ždΚΖ1G›ΰ:&Τ~άY^YΈ>΅qαhžC"F@—₯ρwΒ¦ƒŠ˜·Nt‰Αe'ψΤ¦Έ5±.–‡ +¦ίͺŽ”Ό>$ΫΪXαΉvCx_φ@ƒp‘·ΝΠKΘΖέΪΠUžΟβΎΉψ‚VΈ²λΘO‡½FξΓ0R†πΞΑ‰Ί™x`BT Gu˜ˆ#ΤοjΟl6‘„St5Pέ5ζΎ5‘]Κ§Δ¦~.λX;›νΒνκ‰uݝιdΨν‚ υΘ–œŠωfνHοΩοίŽά•ΧwΆΓΠι`$&wŽZ;33΄F·ln³ΝB;ΝγšsΥPYϊaNΫι’βœϋέχ -«Ο₯FΌ±fT3o¬Ε0nΰ›h°ΎΒ·Zˆ s΅Θ/υρΠ™Xϊνέ¦BTΫΜu«ΏtmFۈDξn΄@ΕκZƒ‹:}‹5 σ'˚ͺ)ΊεmJηαN’ΫΤOWγCAœ_$M τΘ(Dυ/…Ί•Œž!FJٜbδ·/εέΒxKΙΧuΉΦ―ε‚ΩŸš k½έΖ“;”ΛtϋΦ΅œsLΦ’Ο‘[Ζaα͈x&6SƒΙΪμњΡΝnyζ7γfύΨlΰ£NγvςV•g¦V>DΦήMh-ί~­/ϊ΄Ό™²Q{+vmΐDΒϋ°°Oœnή#ψ‘•s& +0Έœ,$‹9›Ž–DEK^1Ζt·Υ’™ώ₯OQηλΪΙ–Pαι‘9_*Ά‚Gυ6ΝΔΊmΗΪγΧξΞι§ή‰…ρΫ5u!Μ/h‡™#·οŒ.MΚl{LΟŸ¦£§?€:tΒr†šQ˜…bœ–ShaˆF’η΅άYθpΔDSmΒΧκ,«wΣB(q(ΞΪ·ι·­­vywsΫ}•>맆k£φGFδ.ρ]|5tg)Κμ:R•r@†3kΨΦj[Γ[ΰ,ϋ4ΔBmN·q²BΔ²λmR·…οɯɎž*ΡYžͺT³UGͺD TŠω₯ΓΎ eΧS½>₯αΟُ±Η/<„+KΒΫ9g)[4ŠpžYΚθ$¦#˜³”ѝbz-δβ­μ§ς²²”­₯ +:ϋؚ«ΗΆ,eλN|­λΊKδ3KΩ{D½μYΚ6ςάξ,%Ϊ” 9ςΜRΆ±%cœ₯lΣ₯‚™₯ j%Έœ₯ŒΊ.ίV–²E±!kΓ,e°-]!-΄IV–ς!dή ?f³Κ,e<”$έ[–2^NΆ@YΚψ‚~*4ΐ,e X;ƒ³”1"Σ{>CB1n7žYΚίbΖiʘ–ƒeš2f«sχ[Zːεί΄8F•Χ½₯EHSΆζΫ–¦lqRΞΨX‘^$ΦΝ4e«¦ Ψ”‘›Υ9I¦)›šΑoiΚ–δv[š²UΧ“fš2ΦΓQ4œš\7[šr­°-OΉ WN²]ιE~%ά Ÿ—rf*Ϋ0―ϋ–ͺŒ)mΦ@Ο(xŸ_2Us<ν9UΩΒ +:Θ0QλμAό²R•-˜1}«S•‘ ω¦*[ΛΉS‘ ™~qͺ_ΗuΑρ—Ώ†Te[Y–•ͺŒ9>}R•1Ε§_ŽŽs‹Φ8^σNUΖηΫŸΆ.‘ +Ϊ·T%¦£e,(‘_Φb–Σ±‹”ͺ|ȘͺάζΦΉJT›+WRμΚ~V'K2W£;³XFΙΚX|eεάη)Cž)\ΫvΈθKŽ|„λ&ΠΘdeλ6x[²2ΪP~*“•‘—·Γ―HVΆ‘1𕬠-—"9Y‰]aHΔde,™ζQr²ς]ΨNGŸ™¬ Q΅f²ς!r²r*YΩ–Wγdεηuϊq»'­=wλ •¨ήpm ΐZvK₯d%Έb²Κ+«MΦσφΡ3@―de”~χΩFpΤΜϋƒp=γύΊ@Yά”°½Γ.9'{_‘>šσΓeμiόψ-3˜lΟtC²νέάEvϋ‚B‚β%Š[ [F>―Λ1f»£ Κ)0Ι_W’-Π/‚ο­'‡~μςΎ8€B(ZKpHα ;£ΏC*ϊ_g2܎Ό―“‘;’Iπ©§ Lΐ!]"(;o]B”ΒβΧ.3Aαxj5aFc)!ގ ΑΊΆ«±9I€’ σ₯žθ‡TΘΐ_Nz…8Α†θ}ΚoŠ^·¨ΡνΖ!BtN’πΐ%Υ28€ +η΄ϋηE!s`9…šTƒγώ’ΌqPΊ !κ·o½Ρ‰R£¦Φ‰€’HΞΆ)€BΤNhw΄? @³])eθ8 >8€NߊΊέ—δΒϊ Ιο²§ˆRO‚ιC/†±*9*%"Ÿ^„ޏ)€πΊ) PHήΩΘΔ{ΰVh1H…Θͺp²ό ΛT+!€bpηόθ$P”8ηPT4!jγ,›HSΚf"λΊC]Χ©€‘ώ*·ωΉ + Ψψ©]+\­Ί‹φ~ΉΙ1ΤώΈξMψF‘fϊ"u3DKύΛ£šUK R0³ο R0ΓΓ ²¬’˜•_rΌ2Πή^YάE$ +Έ‘_6©Š6Β7ep{`ηΘF0!•UύKδ΅p>― >^STρ"$΅ψΠSVu©ω£hρ-‰Έ+vΣ7²H(dŠΫ‹?*$ΰ‡αψΔ8†θ}Eˆaή g”γσ’Es¦a“Δriœγ”5Ά‘{ΚF $γJξ(tθ?‹¦:©£ cœF{(οn~Θλ[<. 9BΪΙΦ¨ΰS$Φ¨]ρ“J ‘tkΠψ-έξ3ŸΦΠσUƒΝKJ{π·<„ΩL_)ΌkΎAΘ.τl»ςΎΥΰN­’pFΑΘΘO?ˆ‹ΎΑ+­ψΰ6΄Όžz•#uγΛπύΫ.”Sπ‘π†HυΏ!‚ƒ€d<ω&6ω‹³B$wB΅kψ*Ά~υΙzo€lWΦ³†̱ݎΩC·’ „ˆ AΔτj/œϋ]TY-ύΫ.Δ‰λš|ϊΏ¦τυ«yήN`₯§}›Ψ,@VδήΪφJσϊRΟάw/=)겍nνclΧ™ω&³Y-L…Pr"¬²zΣXFι@¬‘R³»΅ΜpείτzβΦΛ !ί?ύšƒεQS61 +‘χΈΙSoC „ΐI…H[¦ŠT!_ο iΒwΌ― ¦do”ΙYdƒθ.z7ψxœŒάe&!Κϊ|yΞΡ!š‘H·κ}±₯„€ίCο† …wšΧxςX#~ω™<ΰ•j₯ž,΄Σ\ΙΨNΖ]Bd͜δK Ρ`g3‹βVτέ)λ=―«^Z|³Ψγx«ύΛ ”βΦΞ₯ΗoSjˆΤω/†­°{Z¨e‘a2KwοΖ>θθC$=ŒνσNΠΙΣα2ο›ί‚ήΐOˆ_ΎΫ…gΣW +υύΎ=VMgXŸqy£κэ/ΎŸ έq$ŸάEgΆ©LŒ0#‚*ܜΓ^V DΊΎ‹G@Χ•΄‘ςΘκƒήL2Tβ]γέΚΝ%σZ€a!ιμ­oαͺ)ΉΙΝΪ΄j"ΚLΏ+(ZOozt‰‚ε[V Ά – +]§m]’bƁ§°ρKAΌ!γ:O~UιR +v_Ύ›IaΩwSΪ£eYˆΆΣ[Ύuθ”p*.£všR–-jcAΛΙ³DIˆ΄»:`ͺβΝΝΆΈΦΙ'ΐιήuΩ»zΜM{.—QΥξθHTιzΠ:ιΣ@ΣΠ]οΪiΜϊΦΒΧ‡pν%%κ¦λ #‹p,‡%Α²/=垠·ωΌϋδ ŒGΛO‘ΑX<· >γ—B.szep­°θ}Z#γ¨Z³ͺy’NˆώΓtT³ΊΒ ‘ι8}rΠΎΤyV£cEM\"­>ݚΒΖ‹N3{^E¦―f εf«/Ό™6ΡK§Ιxι( +=Ν’l Λ±!q˜£κy`k€θφΔˆ‘½M°=δS‡ύvCv.EyFyDGB_§γ +ŽŽ(WϋuΆJ'#p± ΩΫΦWᑝ/°μz—I–ΩΙλKξΧUšχΛ‹M›ϋE8ΆΪ3Ϋ4…c±Φ)gV-@ΰCL{ΟςRγLdχ«qΨEi2—°―O€κψVΌηΫ_¬l`kk₯MΓ O3ΜJ)UbρTή’œ:^H[Ύ―„uPm‘Τ¬ΰΑHž€eυ,ΓΖ"Γ”mΜΈ΅λq]η―}Z₯ΞUE/ΪK8„ψξPpΨ©˜=3:·"恍–ΕΜλrΞk ύ Μ}5―π”ΗŽŠƒ/1αέc‡v7Ή«·+γlyή4·{NΗg|ωQγfΧc’βGσ©y™c +:‰Μ|jξx3£J…eυΌu +νyπ uΫ ξνQšθ‹B³eQVGεˆ>Υυ“$τψT ˆ"’ΌΗ†γp8wu\ ‘ϋ@•ΪέΆρd~Δ.ΩͺύΔ[U*Ϋ–‡r…ηž°{Άβ_‹†tP\ާΥΠπ}£ΣHˆΠίuJt_ΛΠ0(TΕ6BΓE±!Rν‘ΆVo…GJήX»cλHiAtWε‡ˆέΑMBŸ$ ο&{£L“Z}BΊ·¨(ΔC„ήm4 ƒΪUŒ7=ϊe-P³’+χΝ~ωΞwΥю8ΟΒΛCp˜1ζ42Ž3F‘QΗ£ΜH/ηˆL,ίήχX'ϊLS£λ ΝuΆ †π%έkN4’8ήZ2–ά”j‰z‘‹`„ΏcΊTξ`α„VΝΖθ:”€šπŠ#†C˜β +{€BκwΧ5D:Φ [Ct3½ΈήλQνφώŒλl‡šΐw£’Ϋ g•²Φ£yF…ΙΘίβ)ΰθ6‡ŝοΦεx^6μŒa=Ÿ9XΐΊΏΪΜΊμό€ιΓΪώ‘σσ€LοekΨnŸ=ΌqkΤ,»άœ!(Ψ]bχ˜Il’Ή^xbξΏvσπΉ?5ΞŒ‹oow+ϋ·Ύaͺ,eϋVp½Σ’―1A)6‘#ήψˆA¬hZOΝ™h:`9]ΐB‡—±fΥ"κƒf]gYΏeEΪΉΐωj©•λR{χ-Ÿd­…Ά΅fΆα-aΌ¦‘l%ώš¬]”“Ί„9ωλΧRE>­Τt\κΦ²ΰΙ‹8xŒ₯§Χw8£jώφ(· žwεί‡yΥ^8©Ν±™©BγιΔvωαIS:Γ,τ!’  ,fΝ·D\ΕB'μ׍|ͺ~­»Β{κ`‚x»α$εϊ†adΜώ­Γς5&Γ¨’5pAi\­(ΜcU( Θ"γΑγΦPε§(g| E’ΎΪ`f}κΘΔσφvbfίΏ‘ t·Ύ<οŒ¬1…peΦΘ ΝΙ6Β¨ω§ƒΏfΒ,τΫ| ‘ƞΦ"ͺĝEΊ.΅dύZjΣώΤΤΊυv©›λR‡χoMUΟ!Yλ!n­›m€NNDυa{MΧmΣΊ 5ύλΧRI>­Φ§σdTzy ?Βd΅‡p$‡YνC(„Sx˜Α<™ξHx95+³Ϊ@,ͺΕ—wΜpΦ`7fLy(p"υ"τVϋξπlΒΞψέ„‚«Ypuc η•εu=3{A³yΊΉδ) +f{ΌΚ™εΑlΕ|f+/SΫc0cΣA"—²'·}Λ¦…ΨΩ J*AγΘζ]‚ΌΝΫ5_[²λCiΑ\y™Mƒv!DŒΜώ€‰ή··97αλ.άfζσ8ο“PS!+“7? tωΏΨ£X:\ ͺy˜Ζ+ Οφ(‘ ½Œ‹α£Λχ-<Υύ*(ΌnΰεΐQVψς φ\ρWFr#裑.lλΕ‹$Yˆlϊ‹+bρG’][Ne’»u7ΆΘ·a±ΰΒԁμX'Cπο…H%Α•†Ix"θΜ‘ΊŠU¨vQςG=…B―ίiϊ;ίⲁ^ξΆ™‰³Y½–Β'nΤ<ηΑpΙ5 3ƒ©δ>lωό97„'y#αU&ŠIσA @&‹@ +3ΪάίͺzβοE UˆvU,*\Π+‘­@ͺRΌΣή†ςχl$p3fEεR†[ΡΠΐtί|η~0΅jފ„M―κF2Hόkfyd7lΌ(€0wGM ϋΤ²—H.ΰ τ αL†‹Ψ{€=‹Bͺ"Š .k«<‘5+E!ΐiΙoG~’Δ‡”ˆβ Ε]ωμMEb„¦gΰʏ›\ ˜)ΡδΩu3.Θƒ@ΝχbZ¨!Nσ.;NxswΜιƒAͺi λΉ™Gί,C_Θύ™§μN]‡ŠB*$‚χoŽ]΄9ξ‹B*vΐάFϊ)εƒD5­O‘d&½Z΅:O₯ ΐ ΕCΒ5Y“/> /©ΑSld§Ωψϊiζ:αtG2ΖζκNš}EQ/α•^’A +σ2ƒΤΉc¦%α„ +΅΅]₯<ΑΘΊ—nι$Ά5ΓPΚχδβz!W‚ §mt₯‘ ‰ΜΨ‹ +KW3k`sΌ3υΉ’xW(δ}vQ/Ή.Όl§λ&δc‡Ε—»ΛΠΙb”}ξώ6πζo! ―” (Dί¬²{ιγ™Ν8υjΝͺυ ά?΄ Ά€©ZbZ8>VΧάΕ š“ΠNϊ4ΝT7†qŸΠξZ†5ρΞ€n,ΗΚl8"ΊdzΓ&Κ.r^’Α" ίh6Iœ€ΆŸŸμώΔ™ˆϊυ^SA°νεηΊΣΉφ‘5·J­`,:η>ͺ‹Ωh ~„R©Y3™S"Νδ’SΪf΄Kg\‰ιL>Τ§?Iœ f*o~?L/*”ρ4‚Ύά:»E —j―Λr¬Λu²?4ΧΣzΉ\uλruξŸznυγ/υ5niφα]–#§!Ν 'j™ m2ΣR圧1KΕ86ΆβԟΘ&Ή=ΚΊΣ„”q“€Κ¦,{ύT_ζςieΦοLώQ~PΨM‘Ωέ™QJ9ξ,SN¬Ιͺv΅„ο2˜¬PIoŽRϋ Κΐ,18ž*ή(K³V< χϋ\ν΅Χ%d~hF₯ύjΝΘ"Ώ}ΛΈΫφb}ήΗ"‹#׈΅ ₯ζ―όl΅– ΘώW@‹|6KpJ„ΓΔ|^ΐ\].Oύ SβΥΕ‚&‰"άΖaφNHHIξΫ±πAΕ φwm_ƒΩυM2ΧΛξB=σ§lJ bGŠˆφΞΰAζΔ 5‹ΐa x{/GΖΓϋ6c>1hmQD ·uάnPp 4sP³ν<И)"ΣAͺό”vd‚›ϋXQ_₯Χ˜9τ£Vӊ(n†κnώdXV•IV„CŒζͺςq:τςxPD…θ}—Χ­ ˆ‚BχE₯MξφιΣQDΛ^9NΧZ3ΰΌ!zo­. _ΒdƒŠς{‹_ ·0ϊηeό–ΈΎΛυC ž,›[ Q'Q‹*βEW°‘ήα[pŽοiRy†bΪη’M<‰žt'A ΅jσ 'τΜ Έ³cυH₯_Y4Lό5?\‡•―_»…““YŠ(Ή€7›ρνnρ΄kt;Θ WΠ¦-oάfΨά;`ˆΒΐgBˆΝ_5UC>N”?͟GF²hΣ7Ι₯ύr΄Ολ΄IŸφι=Τ†™=Τœ[!„ψHΞΕ…± ˜‡ΜfΉ ;”ˆΥ=šPQ"ϋ}Χa5@ψ0ͺ/ΖXΨy€θKŽ|„;ΝMcv(> endobj xref 0 24 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000050684 00000 n +0000000000 00000 f +0000076383 00000 n +0000314406 00000 n +0000050735 00000 n +0000051106 00000 n +0000076682 00000 n +0000076569 00000 n +0000075159 00000 n +0000075822 00000 n +0000075870 00000 n +0000076453 00000 n +0000076484 00000 n +0000076755 00000 n +0000076995 00000 n +0000078044 00000 n +0000099517 00000 n +0000165105 00000 n +0000230693 00000 n +0000296281 00000 n +0000314429 00000 n +trailer <<4A522AF4A964405ABB7B71D6B2C53942>]>> startxref 314618 %%EOF \ No newline at end of file diff --git a/code/images/GitHub-Mark/Vector/GitHub-Mark.eps b/code/images/GitHub-Mark/Vector/GitHub-Mark.eps new file mode 100644 index 00000000..fdd83fdc --- /dev/null +++ b/code/images/GitHub-Mark/Vector/GitHub-Mark.eps @@ -0,0 +1,7696 @@ +%!PS-Adobe-3.1 EPSF-3.0 +%ADO_DSC_Encoding: MacOS Roman +%%Title: GitHub-Mark.eps +%%Creator: Adobe Illustrator(R) 17.1 +%%For: Cameron McEfee +%%CreationDate: 2/5/14 +%%BoundingBox: 0 0 531 500 +%%HiResBoundingBox: 0 0 530.9731 499.9882 +%%CropBox: 0 0 530.9731 499.9882 +%%LanguageLevel: 2 +%%DocumentData: Clean7Bit +%ADOBeginClientInjection: DocumentHeader "AI11EPS" +%%AI8_CreatorVersion: 17.1.0 %AI9_PrintingDataBegin %ADO_BuildNumber: Adobe Illustrator(R) 17.1.0 x273 R agm 4.7709 ct 5.3840 %ADO_ContainsXMP: MainFirst +%ADOEndClientInjection: DocumentHeader "AI11EPS" +%%Pages: 1 +%%DocumentNeededResources: +%%DocumentSuppliedResources: procset Adobe_AGM_Image 1.0 0 +%%+ procset Adobe_CoolType_Utility_T42 1.0 0 +%%+ procset Adobe_CoolType_Utility_MAKEOCF 1.23 0 +%%+ procset Adobe_CoolType_Core 2.31 0 +%%+ procset Adobe_AGM_Core 2.0 0 +%%+ procset Adobe_AGM_Utils 1.0 0 +%%DocumentFonts: +%%DocumentNeededFonts: +%%DocumentNeededFeatures: +%%DocumentSuppliedFeatures: +%%DocumentProcessColors: Cyan Magenta Yellow Black +%%DocumentCustomColors: +%%CMYKCustomColor: +%%RGBCustomColor: +%%EndComments + + + + + + +%%BeginDefaults +%%ViewingOrientation: 1 0 0 1 +%%EndDefaults +%%BeginProlog +%%BeginResource: procset Adobe_AGM_Utils 1.0 0 +%%Version: 1.0 0 +%%Copyright: Copyright(C)2000-2006 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{currentpacking true setpacking}if +userdict/Adobe_AGM_Utils 75 dict dup begin put +/bdf +{bind def}bind def +/nd{null def}bdf +/xdf +{exch def}bdf +/ldf +{load def}bdf +/ddf +{put}bdf +/xddf +{3 -1 roll put}bdf +/xpt +{exch put}bdf +/ndf +{ + exch dup where{ + pop pop pop + }{ + xdf + }ifelse +}def +/cdndf +{ + exch dup currentdict exch known{ + pop pop + }{ + exch def + }ifelse +}def +/gx +{get exec}bdf +/ps_level + /languagelevel where{ + pop systemdict/languagelevel gx + }{ + 1 + }ifelse +def +/level2 + ps_level 2 ge +def +/level3 + ps_level 3 ge +def +/ps_version + {version cvr}stopped{-1}if +def +/set_gvm +{currentglobal exch setglobal}bdf +/reset_gvm +{setglobal}bdf +/makereadonlyarray +{ + /packedarray where{pop packedarray + }{ + array astore readonly}ifelse +}bdf +/map_reserved_ink_name +{ + dup type/stringtype eq{ + dup/Red eq{ + pop(_Red_) + }{ + dup/Green eq{ + pop(_Green_) + }{ + dup/Blue eq{ + pop(_Blue_) + }{ + dup()cvn eq{ + pop(Process) + }if + }ifelse + }ifelse + }ifelse + }if +}bdf +/AGMUTIL_GSTATE 22 dict def +/get_gstate +{ + AGMUTIL_GSTATE begin + /AGMUTIL_GSTATE_clr_spc currentcolorspace def + /AGMUTIL_GSTATE_clr_indx 0 def + /AGMUTIL_GSTATE_clr_comps 12 array def + mark currentcolor counttomark + {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 3 -1 roll put + /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 add def}repeat pop + /AGMUTIL_GSTATE_fnt rootfont def + /AGMUTIL_GSTATE_lw currentlinewidth def + /AGMUTIL_GSTATE_lc currentlinecap def + /AGMUTIL_GSTATE_lj currentlinejoin def + /AGMUTIL_GSTATE_ml currentmiterlimit def + currentdash/AGMUTIL_GSTATE_do xdf/AGMUTIL_GSTATE_da xdf + /AGMUTIL_GSTATE_sa currentstrokeadjust def + /AGMUTIL_GSTATE_clr_rnd currentcolorrendering def + /AGMUTIL_GSTATE_op currentoverprint def + /AGMUTIL_GSTATE_bg currentblackgeneration cvlit def + /AGMUTIL_GSTATE_ucr currentundercolorremoval cvlit def + currentcolortransfer cvlit/AGMUTIL_GSTATE_gy_xfer xdf cvlit/AGMUTIL_GSTATE_b_xfer xdf + cvlit/AGMUTIL_GSTATE_g_xfer xdf cvlit/AGMUTIL_GSTATE_r_xfer xdf + /AGMUTIL_GSTATE_ht currenthalftone def + /AGMUTIL_GSTATE_flt currentflat def + end +}def +/set_gstate +{ + AGMUTIL_GSTATE begin + AGMUTIL_GSTATE_clr_spc setcolorspace + AGMUTIL_GSTATE_clr_indx{AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 1 sub get + /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 sub def}repeat setcolor + AGMUTIL_GSTATE_fnt setfont + AGMUTIL_GSTATE_lw setlinewidth + AGMUTIL_GSTATE_lc setlinecap + AGMUTIL_GSTATE_lj setlinejoin + AGMUTIL_GSTATE_ml setmiterlimit + AGMUTIL_GSTATE_da AGMUTIL_GSTATE_do setdash + AGMUTIL_GSTATE_sa setstrokeadjust + AGMUTIL_GSTATE_clr_rnd setcolorrendering + AGMUTIL_GSTATE_op setoverprint + AGMUTIL_GSTATE_bg cvx setblackgeneration + AGMUTIL_GSTATE_ucr cvx setundercolorremoval + AGMUTIL_GSTATE_r_xfer cvx AGMUTIL_GSTATE_g_xfer cvx AGMUTIL_GSTATE_b_xfer cvx + AGMUTIL_GSTATE_gy_xfer cvx setcolortransfer + AGMUTIL_GSTATE_ht/HalftoneType get dup 9 eq exch 100 eq or + { + currenthalftone/HalftoneType get AGMUTIL_GSTATE_ht/HalftoneType get ne + { + mark AGMUTIL_GSTATE_ht{sethalftone}stopped cleartomark + }if + }{ + AGMUTIL_GSTATE_ht sethalftone + }ifelse + AGMUTIL_GSTATE_flt setflat + end +}def +/get_gstate_and_matrix +{ + AGMUTIL_GSTATE begin + /AGMUTIL_GSTATE_ctm matrix currentmatrix def + end + get_gstate +}def +/set_gstate_and_matrix +{ + set_gstate + AGMUTIL_GSTATE begin + AGMUTIL_GSTATE_ctm setmatrix + end +}def +/AGMUTIL_str256 256 string def +/AGMUTIL_src256 256 string def +/AGMUTIL_dst64 64 string def +/AGMUTIL_srcLen nd +/AGMUTIL_ndx nd +/AGMUTIL_cpd nd +/capture_cpd{ + //Adobe_AGM_Utils/AGMUTIL_cpd currentpagedevice ddf +}def +/thold_halftone +{ + level3 + {sethalftone currenthalftone} + { + dup/HalftoneType get 3 eq + { + sethalftone currenthalftone + }{ + begin + Width Height mul{ + Thresholds read{pop}if + }repeat + end + currenthalftone + }ifelse + }ifelse +}def +/rdcmntline +{ + currentfile AGMUTIL_str256 readline pop + (%)anchorsearch{pop}if +}bdf +/filter_cmyk +{ + dup type/filetype ne{ + exch()/SubFileDecode filter + }{ + exch pop + } + ifelse + [ + exch + { + AGMUTIL_src256 readstring pop + dup length/AGMUTIL_srcLen exch def + /AGMUTIL_ndx 0 def + AGMCORE_plate_ndx 4 AGMUTIL_srcLen 1 sub{ + 1 index exch get + AGMUTIL_dst64 AGMUTIL_ndx 3 -1 roll put + /AGMUTIL_ndx AGMUTIL_ndx 1 add def + }for + pop + AGMUTIL_dst64 0 AGMUTIL_ndx getinterval + } + bind + /exec cvx + ]cvx +}bdf +/filter_indexed_devn +{ + cvi Names length mul names_index add Lookup exch get +}bdf +/filter_devn +{ + 4 dict begin + /srcStr xdf + /dstStr xdf + dup type/filetype ne{ + 0()/SubFileDecode filter + }if + [ + exch + [ + /devicen_colorspace_dict/AGMCORE_gget cvx/begin cvx + currentdict/srcStr get/readstring cvx/pop cvx + /dup cvx/length cvx 0/gt cvx[ + Adobe_AGM_Utils/AGMUTIL_ndx 0/ddf cvx + names_index Names length currentdict/srcStr get length 1 sub{ + 1/index cvx/exch cvx/get cvx + currentdict/dstStr get/AGMUTIL_ndx/load cvx 3 -1/roll cvx/put cvx + Adobe_AGM_Utils/AGMUTIL_ndx/AGMUTIL_ndx/load cvx 1/add cvx/ddf cvx + }for + currentdict/dstStr get 0/AGMUTIL_ndx/load cvx/getinterval cvx + ]cvx/if cvx + /end cvx + ]cvx + bind + /exec cvx + ]cvx + end +}bdf +/AGMUTIL_imagefile nd +/read_image_file +{ + AGMUTIL_imagefile 0 setfileposition + 10 dict begin + /imageDict xdf + /imbufLen Width BitsPerComponent mul 7 add 8 idiv def + /imbufIdx 0 def + /origDataSource imageDict/DataSource get def + /origMultipleDataSources imageDict/MultipleDataSources get def + /origDecode imageDict/Decode get def + /dstDataStr imageDict/Width get colorSpaceElemCnt mul string def + imageDict/MultipleDataSources known{MultipleDataSources}{false}ifelse + { + /imbufCnt imageDict/DataSource get length def + /imbufs imbufCnt array def + 0 1 imbufCnt 1 sub{ + /imbufIdx xdf + imbufs imbufIdx imbufLen string put + imageDict/DataSource get imbufIdx[AGMUTIL_imagefile imbufs imbufIdx get/readstring cvx/pop cvx]cvx put + }for + DeviceN_PS2{ + imageDict begin + /DataSource[DataSource/devn_sep_datasource cvx]cvx def + /MultipleDataSources false def + /Decode[0 1]def + end + }if + }{ + /imbuf imbufLen string def + Indexed_DeviceN level3 not and DeviceN_NoneName or{ + /srcDataStrs[imageDict begin + currentdict/MultipleDataSources known{MultipleDataSources{DataSource length}{1}ifelse}{1}ifelse + { + Width Decode length 2 div mul cvi string + }repeat + end]def + imageDict begin + /DataSource[AGMUTIL_imagefile Decode BitsPerComponent false 1/filter_indexed_devn load dstDataStr srcDataStrs devn_alt_datasource/exec cvx]cvx def + /Decode[0 1]def + end + }{ + imageDict/DataSource[1 string dup 0 AGMUTIL_imagefile Decode length 2 idiv string/readstring cvx/pop cvx names_index/get cvx/put cvx]cvx put + imageDict/Decode[0 1]put + }ifelse + }ifelse + imageDict exch + load exec + imageDict/DataSource origDataSource put + imageDict/MultipleDataSources origMultipleDataSources put + imageDict/Decode origDecode put + end +}bdf +/write_image_file +{ + begin + {(AGMUTIL_imagefile)(w+)file}stopped{ + false + }{ + Adobe_AGM_Utils/AGMUTIL_imagefile xddf + 2 dict begin + /imbufLen Width BitsPerComponent mul 7 add 8 idiv def + MultipleDataSources{DataSource 0 get}{DataSource}ifelse type/filetype eq{ + /imbuf imbufLen string def + }if + 1 1 Height MultipleDataSources not{Decode length 2 idiv mul}if{ + pop + MultipleDataSources{ + 0 1 DataSource length 1 sub{ + DataSource type dup + /arraytype eq{ + pop DataSource exch gx + }{ + /filetype eq{ + DataSource exch get imbuf readstring pop + }{ + DataSource exch get + }ifelse + }ifelse + AGMUTIL_imagefile exch writestring + }for + }{ + DataSource type dup + /arraytype eq{ + pop DataSource exec + }{ + /filetype eq{ + DataSource imbuf readstring pop + }{ + DataSource + }ifelse + }ifelse + AGMUTIL_imagefile exch writestring + }ifelse + }for + end + true + }ifelse + end +}bdf +/close_image_file +{ + AGMUTIL_imagefile closefile(AGMUTIL_imagefile)deletefile +}def +statusdict/product known userdict/AGMP_current_show known not and{ + /pstr statusdict/product get def + pstr(HP LaserJet 2200)eq + pstr(HP LaserJet 4000 Series)eq or + pstr(HP LaserJet 4050 Series )eq or + pstr(HP LaserJet 8000 Series)eq or + pstr(HP LaserJet 8100 Series)eq or + pstr(HP LaserJet 8150 Series)eq or + pstr(HP LaserJet 5000 Series)eq or + pstr(HP LaserJet 5100 Series)eq or + pstr(HP Color LaserJet 4500)eq or + pstr(HP Color LaserJet 4600)eq or + pstr(HP LaserJet 5Si)eq or + pstr(HP LaserJet 1200 Series)eq or + pstr(HP LaserJet 1300 Series)eq or + pstr(HP LaserJet 4100 Series)eq or + { + userdict/AGMP_current_show/show load put + userdict/show{ + currentcolorspace 0 get + /Pattern eq + {false charpath f} + {AGMP_current_show}ifelse + }put + }if + currentdict/pstr undef +}if +/consumeimagedata +{ + begin + AGMIMG_init_common + currentdict/MultipleDataSources known not + {/MultipleDataSources false def}if + MultipleDataSources + { + DataSource 0 get type + dup/filetype eq + { + 1 dict begin + /flushbuffer Width cvi string def + 1 1 Height cvi + { + pop + 0 1 DataSource length 1 sub + { + DataSource exch get + flushbuffer readstring pop pop + }for + }for + end + }if + dup/arraytype eq exch/packedarraytype eq or DataSource 0 get xcheck and + { + Width Height mul cvi + { + 0 1 DataSource length 1 sub + {dup DataSource exch gx length exch 0 ne{pop}if}for + dup 0 eq + {pop exit}if + sub dup 0 le + {exit}if + }loop + pop + }if + } + { + /DataSource load type + dup/filetype eq + { + 1 dict begin + /flushbuffer Width Decode length 2 idiv mul cvi string def + 1 1 Height{pop DataSource flushbuffer readstring pop pop}for + end + }if + dup/arraytype eq exch/packedarraytype eq or/DataSource load xcheck and + { + Height Width BitsPerComponent mul 8 BitsPerComponent sub add 8 idiv Decode length 2 idiv mul mul + { + DataSource length dup 0 eq + {pop exit}if + sub dup 0 le + {exit}if + }loop + pop + }if + }ifelse + end +}bdf +/addprocs +{ + 2{/exec load}repeat + 3 1 roll + [5 1 roll]bind cvx +}def +/modify_halftone_xfer +{ + currenthalftone dup length dict copy begin + currentdict 2 index known{ + 1 index load dup length dict copy begin + currentdict/TransferFunction known{ + /TransferFunction load + }{ + currenttransfer + }ifelse + addprocs/TransferFunction xdf + currentdict end def + currentdict end sethalftone + }{ + currentdict/TransferFunction known{ + /TransferFunction load + }{ + currenttransfer + }ifelse + addprocs/TransferFunction xdf + currentdict end sethalftone + pop + }ifelse +}def +/clonearray +{ + dup xcheck exch + dup length array exch + Adobe_AGM_Core/AGMCORE_tmp -1 ddf + { + Adobe_AGM_Core/AGMCORE_tmp 2 copy get 1 add ddf + dup type/dicttype eq + { + Adobe_AGM_Core/AGMCORE_tmp get + exch + clonedict + Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf + }if + dup type/arraytype eq + { + Adobe_AGM_Core/AGMCORE_tmp get exch + clonearray + Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf + }if + exch dup + Adobe_AGM_Core/AGMCORE_tmp get 4 -1 roll put + }forall + exch{cvx}if +}bdf +/clonedict +{ + dup length dict + begin + { + dup type/dicttype eq + {clonedict}if + dup type/arraytype eq + {clonearray}if + def + }forall + currentdict + end +}bdf +/DeviceN_PS2 +{ + /currentcolorspace AGMCORE_gget 0 get/DeviceN eq level3 not and +}bdf +/Indexed_DeviceN +{ + /indexed_colorspace_dict AGMCORE_gget dup null ne{ + dup/CSDBase known{ + /CSDBase get/CSD get_res/Names known + }{ + pop false + }ifelse + }{ + pop false + }ifelse +}bdf +/DeviceN_NoneName +{ + /Names where{ + pop + false Names + { + (None)eq or + }forall + }{ + false + }ifelse +}bdf +/DeviceN_PS2_inRip_seps +{ + /AGMCORE_in_rip_sep where + { + pop dup type dup/arraytype eq exch/packedarraytype eq or + { + dup 0 get/DeviceN eq level3 not and AGMCORE_in_rip_sep and + { + /currentcolorspace exch AGMCORE_gput + false + }{ + true + }ifelse + }{ + true + }ifelse + }{ + true + }ifelse +}bdf +/base_colorspace_type +{ + dup type/arraytype eq{0 get}if +}bdf +/currentdistillerparams where{pop currentdistillerparams/CoreDistVersion get 5000 lt}{true}ifelse +{ + /pdfmark_5{cleartomark}bind def +}{ + /pdfmark_5{pdfmark}bind def +}ifelse +/ReadBypdfmark_5 +{ + currentfile exch 0 exch/SubFileDecode filter + /currentdistillerparams where + {pop currentdistillerparams/CoreDistVersion get 5000 lt}{true}ifelse + {flushfile cleartomark} + {/PUT pdfmark}ifelse +}bdf +/ReadBypdfmark_5_string +{ + 2 dict begin + /makerString exch def string/tmpString exch def + { + currentfile tmpString readline not{pop exit}if + makerString anchorsearch + { + pop pop cleartomark exit + }{ + 3 copy/PUT pdfmark_5 pop 2 copy(\n)/PUT pdfmark_5 + }ifelse + }loop + end +}bdf +/xpdfm +{ + { + dup 0 get/Label eq + { + aload length[exch 1 add 1 roll/PAGELABEL + }{ + aload pop + [{ThisPage}<<5 -2 roll>>/PUT + }ifelse + pdfmark_5 + }forall +}bdf +/lmt{ + dup 2 index le{exch}if pop dup 2 index ge{exch}if pop +}bdf +/int{ + dup 2 index sub 3 index 5 index sub div 6 -2 roll sub mul exch pop add exch pop +}bdf +/ds{ + Adobe_AGM_Utils begin +}bdf +/dt{ + currentdict Adobe_AGM_Utils eq{ + end + }if +}bdf +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_AGM_Core 2.0 0 +%%Version: 2.0 0 +%%Copyright: Copyright(C)1997-2007 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Core 209 dict dup begin put +/Adobe_AGM_Core_Id/Adobe_AGM_Core_2.0_0 def +/AGMCORE_str256 256 string def +/AGMCORE_save nd +/AGMCORE_graphicsave nd +/AGMCORE_c 0 def +/AGMCORE_m 0 def +/AGMCORE_y 0 def +/AGMCORE_k 0 def +/AGMCORE_cmykbuf 4 array def +/AGMCORE_screen[currentscreen]cvx def +/AGMCORE_tmp 0 def +/AGMCORE_&setgray nd +/AGMCORE_&setcolor nd +/AGMCORE_&setcolorspace nd +/AGMCORE_&setcmykcolor nd +/AGMCORE_cyan_plate nd +/AGMCORE_magenta_plate nd +/AGMCORE_yellow_plate nd +/AGMCORE_black_plate nd +/AGMCORE_plate_ndx nd +/AGMCORE_get_ink_data nd +/AGMCORE_is_cmyk_sep nd +/AGMCORE_host_sep nd +/AGMCORE_avoid_L2_sep_space nd +/AGMCORE_distilling nd +/AGMCORE_composite_job nd +/AGMCORE_producing_seps nd +/AGMCORE_ps_level -1 def +/AGMCORE_ps_version -1 def +/AGMCORE_environ_ok nd +/AGMCORE_CSD_cache 0 dict def +/AGMCORE_currentoverprint false def +/AGMCORE_deltaX nd +/AGMCORE_deltaY nd +/AGMCORE_name nd +/AGMCORE_sep_special nd +/AGMCORE_err_strings 4 dict def +/AGMCORE_cur_err nd +/AGMCORE_current_spot_alias false def +/AGMCORE_inverting false def +/AGMCORE_feature_dictCount nd +/AGMCORE_feature_opCount nd +/AGMCORE_feature_ctm nd +/AGMCORE_ConvertToProcess false def +/AGMCORE_Default_CTM matrix def +/AGMCORE_Default_PageSize nd +/AGMCORE_Default_flatness nd +/AGMCORE_currentbg nd +/AGMCORE_currentucr nd +/AGMCORE_pattern_paint_type 0 def +/knockout_unitsq nd +currentglobal true setglobal +[/CSA/Gradient/Procedure] +{ + /Generic/Category findresource dup length dict copy/Category defineresource pop +}forall +setglobal +/AGMCORE_key_known +{ + where{ + /Adobe_AGM_Core_Id known + }{ + false + }ifelse +}ndf +/flushinput +{ + save + 2 dict begin + /CompareBuffer 3 -1 roll def + /readbuffer 256 string def + mark + { + currentfile readbuffer{readline}stopped + {cleartomark mark} + { + not + {pop exit} + if + CompareBuffer eq + {exit} + if + }ifelse + }loop + cleartomark + end + restore +}bdf +/getspotfunction +{ + AGMCORE_screen exch pop exch pop + dup type/dicttype eq{ + dup/HalftoneType get 1 eq{ + /SpotFunction get + }{ + dup/HalftoneType get 2 eq{ + /GraySpotFunction get + }{ + pop + { + abs exch abs 2 copy add 1 gt{ + 1 sub dup mul exch 1 sub dup mul add 1 sub + }{ + dup mul exch dup mul add 1 exch sub + }ifelse + }bind + }ifelse + }ifelse + }if +}def +/np +{newpath}bdf +/clp_npth +{clip np}def +/eoclp_npth +{eoclip np}def +/npth_clp +{np clip}def +/graphic_setup +{ + /AGMCORE_graphicsave save store + concat + 0 setgray + 0 setlinecap + 0 setlinejoin + 1 setlinewidth + []0 setdash + 10 setmiterlimit + np + false setoverprint + false setstrokeadjust + //Adobe_AGM_Core/spot_alias gx + /Adobe_AGM_Image where{ + pop + Adobe_AGM_Image/spot_alias 2 copy known{ + gx + }{ + pop pop + }ifelse + }if + /sep_colorspace_dict null AGMCORE_gput + 100 dict begin + /dictstackcount countdictstack def + /showpage{}def + mark +}def +/graphic_cleanup +{ + cleartomark + dictstackcount 1 countdictstack 1 sub{end}for + end + AGMCORE_graphicsave restore +}def +/compose_error_msg +{ + grestoreall initgraphics + /Helvetica findfont 10 scalefont setfont + /AGMCORE_deltaY 100 def + /AGMCORE_deltaX 310 def + clippath pathbbox np pop pop 36 add exch 36 add exch moveto + 0 AGMCORE_deltaY rlineto AGMCORE_deltaX 0 rlineto + 0 AGMCORE_deltaY neg rlineto AGMCORE_deltaX neg 0 rlineto closepath + 0 AGMCORE_&setgray + gsave 1 AGMCORE_&setgray fill grestore + 1 setlinewidth gsave stroke grestore + currentpoint AGMCORE_deltaY 15 sub add exch 8 add exch moveto + /AGMCORE_deltaY 12 def + /AGMCORE_tmp 0 def + AGMCORE_err_strings exch get + { + dup 32 eq + { + pop + AGMCORE_str256 0 AGMCORE_tmp getinterval + stringwidth pop currentpoint pop add AGMCORE_deltaX 28 add gt + { + currentpoint AGMCORE_deltaY sub exch pop + clippath pathbbox pop pop pop 44 add exch moveto + }if + AGMCORE_str256 0 AGMCORE_tmp getinterval show( )show + 0 1 AGMCORE_str256 length 1 sub + { + AGMCORE_str256 exch 0 put + }for + /AGMCORE_tmp 0 def + }{ + AGMCORE_str256 exch AGMCORE_tmp xpt + /AGMCORE_tmp AGMCORE_tmp 1 add def + }ifelse + }forall +}bdf +/AGMCORE_CMYKDeviceNColorspaces[ + [/Separation/None/DeviceCMYK{0 0 0}] + [/Separation(Black)/DeviceCMYK{0 0 0 4 -1 roll}bind] + [/Separation(Yellow)/DeviceCMYK{0 0 3 -1 roll 0}bind] + [/DeviceN[(Yellow)(Black)]/DeviceCMYK{0 0 4 2 roll}bind] + [/Separation(Magenta)/DeviceCMYK{0 exch 0 0}bind] + [/DeviceN[(Magenta)(Black)]/DeviceCMYK{0 3 1 roll 0 exch}bind] + [/DeviceN[(Magenta)(Yellow)]/DeviceCMYK{0 3 1 roll 0}bind] + [/DeviceN[(Magenta)(Yellow)(Black)]/DeviceCMYK{0 4 1 roll}bind] + [/Separation(Cyan)/DeviceCMYK{0 0 0}] + [/DeviceN[(Cyan)(Black)]/DeviceCMYK{0 0 3 -1 roll}bind] + [/DeviceN[(Cyan)(Yellow)]/DeviceCMYK{0 exch 0}bind] + [/DeviceN[(Cyan)(Yellow)(Black)]/DeviceCMYK{0 3 1 roll}bind] + [/DeviceN[(Cyan)(Magenta)]/DeviceCMYK{0 0}] + [/DeviceN[(Cyan)(Magenta)(Black)]/DeviceCMYK{0 exch}bind] + [/DeviceN[(Cyan)(Magenta)(Yellow)]/DeviceCMYK{0}] + [/DeviceCMYK] +]def +/ds{ + Adobe_AGM_Core begin + /currentdistillerparams where + { + pop currentdistillerparams/CoreDistVersion get 5000 lt + {<>setdistillerparams}if + }if + /AGMCORE_ps_version xdf + /AGMCORE_ps_level xdf + errordict/AGM_handleerror known not{ + errordict/AGM_handleerror errordict/handleerror get put + errordict/handleerror{ + Adobe_AGM_Core begin + $error/newerror get AGMCORE_cur_err null ne and{ + $error/newerror false put + AGMCORE_cur_err compose_error_msg + }if + $error/newerror true put + end + errordict/AGM_handleerror get exec + }bind put + }if + /AGMCORE_environ_ok + ps_level AGMCORE_ps_level ge + ps_version AGMCORE_ps_version ge and + AGMCORE_ps_level -1 eq or + def + AGMCORE_environ_ok not + {/AGMCORE_cur_err/AGMCORE_bad_environ def}if + /AGMCORE_&setgray systemdict/setgray get def + level2{ + /AGMCORE_&setcolor systemdict/setcolor get def + /AGMCORE_&setcolorspace systemdict/setcolorspace get def + }if + /AGMCORE_currentbg currentblackgeneration def + /AGMCORE_currentucr currentundercolorremoval def + /AGMCORE_Default_flatness currentflat def + /AGMCORE_distilling + /product where{ + pop systemdict/setdistillerparams known product(Adobe PostScript Parser)ne and + }{ + false + }ifelse + def + /AGMCORE_GSTATE AGMCORE_key_known not{ + /AGMCORE_GSTATE 21 dict def + /AGMCORE_tmpmatrix matrix def + /AGMCORE_gstack 64 array def + /AGMCORE_gstackptr 0 def + /AGMCORE_gstacksaveptr 0 def + /AGMCORE_gstackframekeys 14 def + /AGMCORE_&gsave/gsave ldf + /AGMCORE_&grestore/grestore ldf + /AGMCORE_&grestoreall/grestoreall ldf + /AGMCORE_&save/save ldf + /AGMCORE_&setoverprint/setoverprint ldf + /AGMCORE_gdictcopy{ + begin + {def}forall + end + }def + /AGMCORE_gput{ + AGMCORE_gstack AGMCORE_gstackptr get + 3 1 roll + put + }def + /AGMCORE_gget{ + AGMCORE_gstack AGMCORE_gstackptr get + exch + get + }def + /gsave{ + AGMCORE_&gsave + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 64 ge{limitcheck}if + /AGMCORE_gstackptr exch store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /grestore{ + AGMCORE_&grestore + AGMCORE_gstackptr 1 sub + dup AGMCORE_gstacksaveptr lt{1 add}if + dup AGMCORE_gstack exch get dup/AGMCORE_currentoverprint known + {/AGMCORE_currentoverprint get setoverprint}{pop}ifelse + /AGMCORE_gstackptr exch store + }def + /grestoreall{ + AGMCORE_&grestoreall + /AGMCORE_gstackptr AGMCORE_gstacksaveptr store + }def + /save{ + AGMCORE_&save + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 64 ge{limitcheck}if + /AGMCORE_gstackptr exch store + /AGMCORE_gstacksaveptr AGMCORE_gstackptr store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /setoverprint{ + dup/AGMCORE_currentoverprint exch AGMCORE_gput AGMCORE_&setoverprint + }def + 0 1 AGMCORE_gstack length 1 sub{ + AGMCORE_gstack exch AGMCORE_gstackframekeys dict put + }for + }if + level3/AGMCORE_&sysshfill AGMCORE_key_known not and + { + /AGMCORE_&sysshfill systemdict/shfill get def + /AGMCORE_&sysmakepattern systemdict/makepattern get def + /AGMCORE_&usrmakepattern/makepattern load def + }if + /currentcmykcolor[0 0 0 0]AGMCORE_gput + /currentstrokeadjust false AGMCORE_gput + /currentcolorspace[/DeviceGray]AGMCORE_gput + /sep_tint 0 AGMCORE_gput + /devicen_tints[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]AGMCORE_gput + /sep_colorspace_dict null AGMCORE_gput + /devicen_colorspace_dict null AGMCORE_gput + /indexed_colorspace_dict null AGMCORE_gput + /currentcolor_intent()AGMCORE_gput + /customcolor_tint 1 AGMCORE_gput + /absolute_colorimetric_crd null AGMCORE_gput + /relative_colorimetric_crd null AGMCORE_gput + /saturation_crd null AGMCORE_gput + /perceptual_crd null AGMCORE_gput + currentcolortransfer cvlit/AGMCore_gray_xfer xdf cvlit/AGMCore_b_xfer xdf + cvlit/AGMCore_g_xfer xdf cvlit/AGMCore_r_xfer xdf + << + /MaxPatternItem currentsystemparams/MaxPatternCache get + >> + setuserparams + end +}def +/ps +{ + /setcmykcolor where{ + pop + Adobe_AGM_Core/AGMCORE_&setcmykcolor/setcmykcolor load put + }if + Adobe_AGM_Core begin + /setcmykcolor + { + 4 copy AGMCORE_cmykbuf astore/currentcmykcolor exch AGMCORE_gput + 1 sub 4 1 roll + 3{ + 3 index add neg dup 0 lt{ + pop 0 + }if + 3 1 roll + }repeat + setrgbcolor pop + }ndf + /currentcmykcolor + { + /currentcmykcolor AGMCORE_gget aload pop + }ndf + /setoverprint + {pop}ndf + /currentoverprint + {false}ndf + /AGMCORE_cyan_plate 1 0 0 0 test_cmyk_color_plate def + /AGMCORE_magenta_plate 0 1 0 0 test_cmyk_color_plate def + /AGMCORE_yellow_plate 0 0 1 0 test_cmyk_color_plate def + /AGMCORE_black_plate 0 0 0 1 test_cmyk_color_plate def + /AGMCORE_plate_ndx + AGMCORE_cyan_plate{ + 0 + }{ + AGMCORE_magenta_plate{ + 1 + }{ + AGMCORE_yellow_plate{ + 2 + }{ + AGMCORE_black_plate{ + 3 + }{ + 4 + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_have_reported_unsupported_color_space false def + /AGMCORE_report_unsupported_color_space + { + AGMCORE_have_reported_unsupported_color_space false eq + { + (Warning: Job contains content that cannot be separated with on-host methods. This content appears on the black plate, and knocks out all other plates.)== + Adobe_AGM_Core/AGMCORE_have_reported_unsupported_color_space true ddf + }if + }def + /AGMCORE_composite_job + AGMCORE_cyan_plate AGMCORE_magenta_plate and AGMCORE_yellow_plate and AGMCORE_black_plate and def + /AGMCORE_in_rip_sep + /AGMCORE_in_rip_sep where{ + pop AGMCORE_in_rip_sep + }{ + AGMCORE_distilling + { + false + }{ + userdict/Adobe_AGM_OnHost_Seps known{ + false + }{ + level2{ + currentpagedevice/Separations 2 copy known{ + get + }{ + pop pop false + }ifelse + }{ + false + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_producing_seps AGMCORE_composite_job not AGMCORE_in_rip_sep or def + /AGMCORE_host_sep AGMCORE_producing_seps AGMCORE_in_rip_sep not and def + /AGM_preserve_spots + /AGM_preserve_spots where{ + pop AGM_preserve_spots + }{ + AGMCORE_distilling AGMCORE_producing_seps or + }ifelse + def + /AGM_is_distiller_preserving_spotimages + { + currentdistillerparams/PreserveOverprintSettings known + { + currentdistillerparams/PreserveOverprintSettings get + { + currentdistillerparams/ColorConversionStrategy known + { + currentdistillerparams/ColorConversionStrategy get + /sRGB ne + }{ + true + }ifelse + }{ + false + }ifelse + }{ + false + }ifelse + }def + /convert_spot_to_process where{pop}{ + /convert_spot_to_process + { + //Adobe_AGM_Core begin + dup map_alias{ + /Name get exch pop + }if + dup dup(None)eq exch(All)eq or + { + pop false + }{ + AGMCORE_host_sep + { + gsave + 1 0 0 0 setcmykcolor currentgray 1 exch sub + 0 1 0 0 setcmykcolor currentgray 1 exch sub + 0 0 1 0 setcmykcolor currentgray 1 exch sub + 0 0 0 1 setcmykcolor currentgray 1 exch sub + add add add 0 eq + { + pop false + }{ + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + }ifelse + grestore + }{ + AGMCORE_distilling + { + pop AGM_is_distiller_preserving_spotimages not + }{ + //Adobe_AGM_Core/AGMCORE_name xddf + false + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 0 eq + AGMUTIL_cpd/OverrideSeparations known and + { + AGMUTIL_cpd/OverrideSeparations get + { + /HqnSpots/ProcSet resourcestatus + { + pop pop pop true + }if + }if + }if + { + AGMCORE_name/HqnSpots/ProcSet findresource/TestSpot gx not + }{ + gsave + [/Separation AGMCORE_name/DeviceGray{}]AGMCORE_&setcolorspace + false + AGMUTIL_cpd/SeparationColorNames 2 copy known + { + get + {AGMCORE_name eq or}forall + not + }{ + pop pop pop true + }ifelse + grestore + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + }ifelse + /convert_to_process where{pop}{ + /convert_to_process + { + dup length 0 eq + { + pop false + }{ + AGMCORE_host_sep + { + dup true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process and}ifelse + } + forall + { + true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + (Black)eq or and + }forall + not + }{pop false}ifelse + }{ + false exch + { + /PhotoshopDuotoneList where{pop false}{true}ifelse + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process or}ifelse + } + { + convert_spot_to_process or + } + ifelse + } + forall + }ifelse + }ifelse + }def + }ifelse + /AGMCORE_avoid_L2_sep_space + version cvr 2012 lt + level2 and + AGMCORE_producing_seps not and + def + /AGMCORE_is_cmyk_sep + AGMCORE_cyan_plate AGMCORE_magenta_plate or AGMCORE_yellow_plate or AGMCORE_black_plate or + def + /AGM_avoid_0_cmyk where{ + pop AGM_avoid_0_cmyk + }{ + AGM_preserve_spots + userdict/Adobe_AGM_OnHost_Seps known + userdict/Adobe_AGM_InRip_Seps known or + not and + }ifelse + { + /setcmykcolor[ + { + 4 copy add add add 0 eq currentoverprint and{ + pop 0.0005 + }if + }/exec cvx + /AGMCORE_&setcmykcolor load dup type/operatortype ne{ + /exec cvx + }if + ]cvx def + }if + /AGMCORE_IsSeparationAProcessColor + { + dup(Cyan)eq exch dup(Magenta)eq exch dup(Yellow)eq exch(Black)eq or or or + }def + AGMCORE_host_sep{ + /setcolortransfer + { + AGMCORE_cyan_plate{ + pop pop pop + }{ + AGMCORE_magenta_plate{ + 4 3 roll pop pop pop + }{ + AGMCORE_yellow_plate{ + 4 2 roll pop pop pop + }{ + 4 1 roll pop pop pop + }ifelse + }ifelse + }ifelse + settransfer + } + def + /AGMCORE_get_ink_data + AGMCORE_cyan_plate{ + {pop pop pop} + }{ + AGMCORE_magenta_plate{ + {4 3 roll pop pop pop} + }{ + AGMCORE_yellow_plate{ + {4 2 roll pop pop pop} + }{ + {4 1 roll pop pop pop} + }ifelse + }ifelse + }ifelse + def + /AGMCORE_RemoveProcessColorNames + { + 1 dict begin + /filtername + { + dup/Cyan eq 1 index(Cyan)eq or + {pop(_cyan_)}if + dup/Magenta eq 1 index(Magenta)eq or + {pop(_magenta_)}if + dup/Yellow eq 1 index(Yellow)eq or + {pop(_yellow_)}if + dup/Black eq 1 index(Black)eq or + {pop(_black_)}if + }def + dup type/arraytype eq + {[exch{filtername}forall]} + {filtername}ifelse + end + }def + level3{ + /AGMCORE_IsCurrentColor + { + dup AGMCORE_IsSeparationAProcessColor + { + AGMCORE_plate_ndx 0 eq + {dup(Cyan)eq exch/Cyan eq or}if + AGMCORE_plate_ndx 1 eq + {dup(Magenta)eq exch/Magenta eq or}if + AGMCORE_plate_ndx 2 eq + {dup(Yellow)eq exch/Yellow eq or}if + AGMCORE_plate_ndx 3 eq + {dup(Black)eq exch/Black eq or}if + AGMCORE_plate_ndx 4 eq + {pop false}if + }{ + gsave + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + grestore + }ifelse + }def + /AGMCORE_filter_functiondatasource + { + 5 dict begin + /data_in xdf + data_in type/stringtype eq + { + /ncomp xdf + /comp xdf + /string_out data_in length ncomp idiv string def + 0 ncomp data_in length 1 sub + { + string_out exch dup ncomp idiv exch data_in exch ncomp getinterval comp get 255 exch sub put + }for + string_out + }{ + string/string_in xdf + /string_out 1 string def + /component xdf + [ + data_in string_in/readstring cvx + [component/get cvx 255/exch cvx/sub cvx string_out/exch cvx 0/exch cvx/put cvx string_out]cvx + [/pop cvx()]cvx/ifelse cvx + ]cvx/ReusableStreamDecode filter + }ifelse + end + }def + /AGMCORE_separateShadingFunction + { + 2 dict begin + /paint? xdf + /channel xdf + dup type/dicttype eq + { + begin + FunctionType 0 eq + { + /DataSource channel Range length 2 idiv DataSource AGMCORE_filter_functiondatasource def + currentdict/Decode known + {/Decode Decode channel 2 mul 2 getinterval def}if + paint? not + {/Decode[1 1]def}if + }if + FunctionType 2 eq + { + paint? + { + /C0[C0 channel get 1 exch sub]def + /C1[C1 channel get 1 exch sub]def + }{ + /C0[1]def + /C1[1]def + }ifelse + }if + FunctionType 3 eq + { + /Functions[Functions{channel paint? AGMCORE_separateShadingFunction}forall]def + }if + currentdict/Range known + {/Range[0 1]def}if + currentdict + end}{ + channel get 0 paint? AGMCORE_separateShadingFunction + }ifelse + end + }def + /AGMCORE_separateShading + { + 3 -1 roll begin + currentdict/Function known + { + currentdict/Background known + {[1 index{Background 3 index get 1 exch sub}{1}ifelse]/Background xdf}if + Function 3 1 roll AGMCORE_separateShadingFunction/Function xdf + /ColorSpace[/DeviceGray]def + }{ + ColorSpace dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }{ + ColorSpace dup 1 get AGMCORE_RemoveProcessColorNames 1 exch put + }ifelse + ColorSpace 0 get/Separation eq + { + { + [1/exch cvx/sub cvx]cvx + }{ + [/pop cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll put + pop + }{ + { + [exch ColorSpace 1 get length 1 sub exch sub/index cvx 1/exch cvx/sub cvx ColorSpace 1 get length 1 add 1/roll cvx ColorSpace 1 get length{/pop cvx}repeat]cvx + }{ + pop[ColorSpace 1 get length{/pop cvx}repeat cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll bind put + }ifelse + ColorSpace 2/DeviceGray put + }ifelse + end + }def + /AGMCORE_separateShadingDict + { + dup/ColorSpace get + dup type/arraytype ne + {[exch]}if + dup 0 get/DeviceCMYK eq + { + exch begin + currentdict + AGMCORE_cyan_plate + {0 true}if + AGMCORE_magenta_plate + {1 true}if + AGMCORE_yellow_plate + {2 true}if + AGMCORE_black_plate + {3 true}if + AGMCORE_plate_ndx 4 eq + {0 false}if + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + currentdict + end exch + }if + dup 0 get/Separation eq + { + exch begin + ColorSpace 1 get dup/None ne exch/All ne and + { + ColorSpace 1 get AGMCORE_IsCurrentColor AGMCORE_plate_ndx 4 lt and ColorSpace 1 get AGMCORE_IsSeparationAProcessColor not and + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /Separation + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + }if + }ifelse + }{ + currentdict ColorSpace 1 get AGMCORE_IsCurrentColor + 0 exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + }if + currentdict + end exch + }if + dup 0 get/DeviceN eq + { + exch begin + ColorSpace 1 get convert_to_process + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /DeviceN + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + /ColorSpace[/DeviceGray]def + }if + }ifelse + }{ + currentdict + false -1 ColorSpace 1 get + { + AGMCORE_IsCurrentColor + { + 1 add + exch pop true exch exit + }if + 1 add + }forall + exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + currentdict + end exch + }if + dup 0 get dup/DeviceCMYK eq exch dup/Separation eq exch/DeviceN eq or or not + { + exch begin + ColorSpace dup type/arraytype eq + {0 get}if + /DeviceGray ne + { + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + ColorSpace 0 get/CIEBasedA eq + { + /ColorSpace[/Separation/_ciebaseda_/DeviceGray{}]def + }if + ColorSpace 0 get dup/CIEBasedABC eq exch dup/CIEBasedDEF eq exch/DeviceRGB eq or or + { + /ColorSpace[/DeviceN[/_red_/_green_/_blue_]/DeviceRGB{}]def + }if + ColorSpace 0 get/CIEBasedDEFG eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }if + currentdict 0 false AGMCORE_separateShading + }if + }if + currentdict + end exch + }if + pop + dup/AGMCORE_ignoreshade known + { + begin + /ColorSpace[/Separation(None)/DeviceGray{}]def + currentdict end + }if + }def + /shfill + { + AGMCORE_separateShadingDict + dup/AGMCORE_ignoreshade known + {pop} + {AGMCORE_&sysshfill}ifelse + }def + /makepattern + { + exch + dup/PatternType get 2 eq + { + clonedict + begin + /Shading Shading AGMCORE_separateShadingDict def + Shading/AGMCORE_ignoreshade known + currentdict end exch + {pop<>}if + exch AGMCORE_&sysmakepattern + }{ + exch AGMCORE_&usrmakepattern + }ifelse + }def + }if + }if + AGMCORE_in_rip_sep{ + /setcustomcolor + { + exch aload pop + dup 7 1 roll inRip_spot_has_ink not { + 4{4 index mul 4 1 roll} + repeat + /DeviceCMYK setcolorspace + 6 -2 roll pop pop + }{ + //Adobe_AGM_Core begin + /AGMCORE_k xdf/AGMCORE_y xdf/AGMCORE_m xdf/AGMCORE_c xdf + end + [/Separation 4 -1 roll/DeviceCMYK + {dup AGMCORE_c mul exch dup AGMCORE_m mul exch dup AGMCORE_y mul exch AGMCORE_k mul} + ] + setcolorspace + }ifelse + setcolor + }ndf + /setseparationgray + { + [/Separation(All)/DeviceGray{}]setcolorspace_opt + 1 exch sub setcolor + }ndf + }{ + /setseparationgray + { + AGMCORE_&setgray + }ndf + }ifelse + /findcmykcustomcolor + { + 5 makereadonlyarray + }ndf + /setcustomcolor + { + exch aload pop pop + 4{4 index mul 4 1 roll}repeat + setcmykcolor pop + }ndf + /has_color + /colorimage where{ + AGMCORE_producing_seps{ + pop true + }{ + systemdict eq + }ifelse + }{ + false + }ifelse + def + /map_index + { + 1 index mul exch getinterval{255 div}forall + }bdf + /map_indexed_devn + { + Lookup Names length 3 -1 roll cvi map_index + }bdf + /n_color_components + { + base_colorspace_type + dup/DeviceGray eq{ + pop 1 + }{ + /DeviceCMYK eq{ + 4 + }{ + 3 + }ifelse + }ifelse + }bdf + level2{ + /mo/moveto ldf + /li/lineto ldf + /cv/curveto ldf + /knockout_unitsq + { + 1 setgray + 0 0 1 1 rectfill + }def + level2/setcolorspace AGMCORE_key_known not and{ + /AGMCORE_&&&setcolorspace/setcolorspace ldf + /AGMCORE_ReplaceMappedColor + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + /AGMCORE_SpotAliasAry2 where{ + begin + dup 0 get dup/Separation eq + { + pop + dup length array copy + dup dup 1 get + current_spot_alias + { + dup map_alias + { + false set_spot_alias + dup 1 exch setsepcolorspace + true set_spot_alias + begin + /sep_colorspace_dict currentdict AGMCORE_gput + pop pop pop + [ + /Separation Name + CSA map_csa + MappedCSA + /sep_colorspace_proc load + ] + dup Name + end + }if + }if + map_reserved_ink_name 1 xpt + }{ + /DeviceN eq + { + dup length array copy + dup dup 1 get[ + exch{ + current_spot_alias{ + dup map_alias{ + /Name get exch pop + }if + }if + map_reserved_ink_name + }forall + ]1 xpt + }if + }ifelse + end + }if + }if + }def + /setcolorspace + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + dup 0 get/Indexed eq + { + AGMCORE_distilling + { + /PhotoshopDuotoneList where + { + pop false + }{ + true + }ifelse + }{ + true + }ifelse + { + aload pop 3 -1 roll + AGMCORE_ReplaceMappedColor + 3 1 roll 4 array astore + }if + }{ + AGMCORE_ReplaceMappedColor + }ifelse + }if + DeviceN_PS2_inRip_seps{AGMCORE_&&&setcolorspace}if + }def + }if + }{ + /adj + { + currentstrokeadjust{ + transform + 0.25 sub round 0.25 add exch + 0.25 sub round 0.25 add exch + itransform + }if + }def + /mo{ + adj moveto + }def + /li{ + adj lineto + }def + /cv{ + 6 2 roll adj + 6 2 roll adj + 6 2 roll adj curveto + }def + /knockout_unitsq + { + 1 setgray + 8 8 1[8 0 0 8 0 0]{}image + }def + /currentstrokeadjust{ + /currentstrokeadjust AGMCORE_gget + }def + /setstrokeadjust{ + /currentstrokeadjust exch AGMCORE_gput + }def + /setcolorspace + { + /currentcolorspace exch AGMCORE_gput + }def + /currentcolorspace + { + /currentcolorspace AGMCORE_gget + }def + /setcolor_devicecolor + { + base_colorspace_type + dup/DeviceGray eq{ + pop setgray + }{ + /DeviceCMYK eq{ + setcmykcolor + }{ + setrgbcolor + }ifelse + }ifelse + }def + /setcolor + { + currentcolorspace 0 get + dup/DeviceGray ne{ + dup/DeviceCMYK ne{ + dup/DeviceRGB ne{ + dup/Separation eq{ + pop + currentcolorspace 3 gx + currentcolorspace 2 get + }{ + dup/Indexed eq{ + pop + currentcolorspace 3 get dup type/stringtype eq{ + currentcolorspace 1 get n_color_components + 3 -1 roll map_index + }{ + exec + }ifelse + currentcolorspace 1 get + }{ + /AGMCORE_cur_err/AGMCORE_invalid_color_space def + AGMCORE_invalid_color_space + }ifelse + }ifelse + }if + }if + }if + setcolor_devicecolor + }def + }ifelse + /sop/setoverprint ldf + /lw/setlinewidth ldf + /lc/setlinecap ldf + /lj/setlinejoin ldf + /ml/setmiterlimit ldf + /dsh/setdash ldf + /sadj/setstrokeadjust ldf + /gry/setgray ldf + /rgb/setrgbcolor ldf + /cmyk[ + /currentcolorspace[/DeviceCMYK]/AGMCORE_gput cvx + /setcmykcolor load dup type/operatortype ne{/exec cvx}if + ]cvx bdf + level3 AGMCORE_host_sep not and{ + /nzopmsc{ + 6 dict begin + /kk exch def + /yy exch def + /mm exch def + /cc exch def + /sum 0 def + cc 0 ne{/sum sum 2#1000 or def cc}if + mm 0 ne{/sum sum 2#0100 or def mm}if + yy 0 ne{/sum sum 2#0010 or def yy}if + kk 0 ne{/sum sum 2#0001 or def kk}if + AGMCORE_CMYKDeviceNColorspaces sum get setcolorspace + sum 0 eq{0}if + end + setcolor + }bdf + }{ + /nzopmsc/cmyk ldf + }ifelse + /sep/setsepcolor ldf + /devn/setdevicencolor ldf + /idx/setindexedcolor ldf + /colr/setcolor ldf + /csacrd/set_csa_crd ldf + /sepcs/setsepcolorspace ldf + /devncs/setdevicencolorspace ldf + /idxcs/setindexedcolorspace ldf + /cp/closepath ldf + /clp/clp_npth ldf + /eclp/eoclp_npth ldf + /f/fill ldf + /ef/eofill ldf + /@/stroke ldf + /nclp/npth_clp ldf + /gset/graphic_setup ldf + /gcln/graphic_cleanup ldf + /ct/concat ldf + /cf/currentfile ldf + /fl/filter ldf + /rs/readstring ldf + /AGMCORE_def_ht currenthalftone def + /clonedict Adobe_AGM_Utils begin/clonedict load end def + /clonearray Adobe_AGM_Utils begin/clonearray load end def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall + /getrampcolor + { + /indx exch def + 0 1 NumComp 1 sub + { + dup + Samples exch get + dup type/stringtype eq{indx get}if + exch + Scaling exch get aload pop + 3 1 roll + mul add + }for + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /sssetbackground{ + aload pop + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /RadialShade + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /r2 xdf + /c2y xdf + /c2x xdf + /r1 xdf + /c1y xdf + /c1x xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + c1x c2x eq + { + c1y c2y lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope c2y c1y sub c2x c1x sub div def + /theta slope 1 atan def + c2x c1x lt c2y c1y ge and{/theta theta 180 sub def}if + c2x c1x lt c2y c1y lt and{/theta theta 180 add def}if + }ifelse + gsave + clippath + c1x c1y translate + theta rotate + -90 rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax xdf + /xMax xdf + /yMin xdf + /xMin xdf + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + /max{2 copy gt{pop}{exch pop}ifelse}bdf + /min{2 copy lt{pop}{exch pop}ifelse}bdf + rampdict begin + 40 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + c1x c1y translate + theta rotate + -90 rotate + /c2y c1x c2x sub dup mul c1y c2y sub dup mul add sqrt def + /c1y 0 def + /c1x 0 def + /c2x 0 def + ext0 + { + 0 getrampcolor + c2y r2 add r1 sub 0.0001 lt + { + c1x c1y r1 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2y r1 add r2 le + { + c1x c1y r1 0 360 arc + fill + } + { + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r1 neg def + /p1y c1y def + /p2x r1 def + /p2y c1y def + p1x p1y moveto p2x p2y lineto p2x yMin lineto p1x yMin lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r1 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y p1x SS1 div neg def + /SS2 90 theta sub dup sin exch cos div def + /p2x r1 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y p2x SS2 div neg def + r1 r2 gt + { + /L1maxX p1x yMin p1y sub SS1 div add def + /L2maxX p2x yMin p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + c1x c2x sub dup mul + c1y c2y sub dup mul + add 0.5 exp + 0 dtransform + dup mul exch dup mul add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + /hires xdf + hires mul + /numpix xdf + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + /xInc c2x c1x sub numsteps div def + /yInc c2y c1y sub numsteps div def + /rInc r2 r1 sub numsteps div def + /cx c1x def + /cy c1y def + /radius r1 def + np + xInc 0 eq yInc 0 eq rInc 0 eq and and + { + 0 getrampcolor + cx cy radius 0 360 arc + stroke + NumSamples 1 sub getrampcolor + cx cy radius 72 hires div add 0 360 arc + 0 setlinewidth + stroke + }{ + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + cx cy radius 0 360 arc + /cx cx xInc add def + /cy cy yInc add def + /radius radius rInc add def + cx cy radius 360 0 arcn + eofill + rampIndxInc add + }repeat + pop + }ifelse + ext1 + { + c2y r2 add r1 lt + { + c2x c2y r2 0 360 arc + fill + }{ + c2y r1 add r2 sub 0.0001 le + { + c2x c2y r2 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r2 neg def + /p1y c2y def + /p2x r2 def + /p2y c2y def + p1x p1y moveto p2x p2y lineto p2x yMax lineto p1x yMax lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r2 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y c2y p1x SS1 div sub def + /SS2 90 theta sub dup sin exch cos div def + /p2x r2 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y c2y p2x SS2 div sub def + r1 r2 lt + { + /L1maxX p1x yMax p1y sub SS1 div add def + /L2maxX p2x yMax p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + grestore + grestore + end + end + end + }ifelse + }bdf + /GenStrips + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /y2 xdf + /x2 xdf + /y1 xdf + /x1 xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + x1 x2 eq + { + y1 y2 lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope y2 y1 sub x2 x1 sub div def + /theta slope 1 atan def + x2 x1 lt y2 y1 ge and{/theta theta 180 sub def}if + x2 x1 lt y2 y1 lt and{/theta theta 180 add def}if + } + ifelse + gsave + clippath + x1 y1 translate + theta rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax exch def + /xMax exch def + /yMin exch def + /xMin exch def + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + rampdict begin + 20 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + x1 y1 translate + theta rotate + /xStart 0 def + /xEnd x2 x1 sub dup mul y2 y1 sub dup mul add 0.5 exp def + /ySpan yMax yMin sub def + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + xStart 0 transform + xEnd 0 transform + 3 -1 roll + sub dup mul + 3 1 roll + sub dup mul + add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + mul + /numpix xdf + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + ext0 + { + 0 getrampcolor + xMin xStart lt + { + xMin yMin xMin neg ySpan rectfill + }if + }if + /xInc xEnd xStart sub numsteps div def + /x xStart def + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + x yMin xInc ySpan rectfill + /x x xInc add def + rampIndxInc add + }repeat + pop + ext1{ + xMax xEnd gt + { + xEnd yMin xMax xEnd sub ySpan rectfill + }if + }if + grestore + grestore + end + end + end + }ifelse + }bdf +}def +/pt +{ + end +}def +/dt{ +}def +/pgsv{ + //Adobe_AGM_Core/AGMCORE_save save put +}def +/pgrs{ + //Adobe_AGM_Core/AGMCORE_save get restore +}def +systemdict/findcolorrendering known{ + /findcolorrendering systemdict/findcolorrendering get def +}if +systemdict/setcolorrendering known{ + /setcolorrendering systemdict/setcolorrendering get def +}if +/test_cmyk_color_plate +{ + gsave + setcmykcolor currentgray 1 ne + grestore +}def +/inRip_spot_has_ink +{ + dup//Adobe_AGM_Core/AGMCORE_name xddf + convert_spot_to_process not +}def +/map255_to_range +{ + 1 index sub + 3 -1 roll 255 div mul add +}def +/set_csa_crd +{ + /sep_colorspace_dict null AGMCORE_gput + begin + CSA get_csa_by_name setcolorspace_opt + set_crd + end +} +def +/map_csa +{ + currentdict/MappedCSA known{MappedCSA null ne}{false}ifelse + {pop}{get_csa_by_name/MappedCSA xdf}ifelse +}def +/setsepcolor +{ + /sep_colorspace_dict AGMCORE_gget begin + dup/sep_tint exch AGMCORE_gput + TintProc + end +}def +/setdevicencolor +{ + /devicen_colorspace_dict AGMCORE_gget begin + Names length copy + Names length 1 sub -1 0 + { + /devicen_tints AGMCORE_gget 3 1 roll xpt + }for + TintProc + end +}def +/sep_colorspace_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + currentdict/Components known{ + Components aload pop + TintMethod/Lab eq{ + 2{AGMCORE_tmp mul NComponents 1 roll}repeat + LMax sub AGMCORE_tmp mul LMax add NComponents 1 roll + }{ + TintMethod/Subtractive eq{ + NComponents{ + AGMCORE_tmp mul NComponents 1 roll + }repeat + }{ + NComponents{ + 1 sub AGMCORE_tmp mul 1 add NComponents 1 roll + }repeat + }ifelse + }ifelse + }{ + ColorLookup AGMCORE_tmp ColorLookup length 1 sub mul round cvi get + aload pop + }ifelse + end +}def +/sep_colorspace_gray_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + GrayLookup AGMCORE_tmp GrayLookup length 1 sub mul round cvi get + end +}def +/sep_proc_name +{ + dup 0 get + dup/DeviceRGB eq exch/DeviceCMYK eq or level2 not and has_color not and{ + pop[/DeviceGray] + /sep_colorspace_gray_proc + }{ + /sep_colorspace_proc + }ifelse +}def +/setsepcolorspace +{ + current_spot_alias{ + dup begin + Name map_alias{ + exch pop + }if + end + }if + dup/sep_colorspace_dict exch AGMCORE_gput + begin + CSA map_csa + /AGMCORE_sep_special Name dup()eq exch(All)eq or store + AGMCORE_avoid_L2_sep_space{ + [/Indexed MappedCSA sep_proc_name 255 exch + {255 div}/exec cvx 3 -1 roll[4 1 roll load/exec cvx]cvx + ]setcolorspace_opt + /TintProc{ + 255 mul round cvi setcolor + }bdf + }{ + MappedCSA 0 get/DeviceCMYK eq + currentdict/Components known and + AGMCORE_sep_special not and{ + /TintProc[ + Components aload pop Name findcmykcustomcolor + /exch cvx/setcustomcolor cvx + ]cvx bdf + }{ + AGMCORE_host_sep Name(All)eq and{ + /TintProc{ + 1 exch sub setseparationgray + }bdf + }{ + AGMCORE_in_rip_sep MappedCSA 0 get/DeviceCMYK eq and + AGMCORE_host_sep or + Name()eq and{ + /TintProc[ + MappedCSA sep_proc_name exch 0 get/DeviceCMYK eq{ + cvx/setcmykcolor cvx + }{ + cvx/setgray cvx + }ifelse + ]cvx bdf + }{ + AGMCORE_producing_seps MappedCSA 0 get dup/DeviceCMYK eq exch/DeviceGray eq or and AGMCORE_sep_special not and{ + /TintProc[ + /dup cvx + MappedCSA sep_proc_name cvx exch + 0 get/DeviceGray eq{ + 1/exch cvx/sub cvx 0 0 0 4 -1/roll cvx + }if + /Name cvx/findcmykcustomcolor cvx/exch cvx + AGMCORE_host_sep{ + AGMCORE_is_cmyk_sep + /Name cvx + /AGMCORE_IsSeparationAProcessColor load/exec cvx + /not cvx/and cvx + }{ + Name inRip_spot_has_ink not + }ifelse + [ + /pop cvx 1 + ]cvx/if cvx + /setcustomcolor cvx + ]cvx bdf + }{ + /TintProc{setcolor}bdf + [/Separation Name MappedCSA sep_proc_name load]setcolorspace_opt + }ifelse + }ifelse + }ifelse + }ifelse + }ifelse + set_crd + setsepcolor + end +}def +/additive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 + 0 1 numarrays 1 sub + { + 1 exch add/index cvx + c1/get cvx/mul cvx + }for + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/subtractive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 1 + 0 1 numarrays 1 sub + { + 1 3 3 -1 roll add/index cvx + c1/get cvx/sub cvx/mul cvx + }for + /sub cvx + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/exec_tint_transform +{ + /TintProc[ + /TintTransform cvx/setcolor cvx + ]cvx bdf + MappedCSA setcolorspace_opt +}bdf +/devn_makecustomcolor +{ + 2 dict begin + /names_index xdf + /Names xdf + 1 1 1 1 Names names_index get findcmykcustomcolor + /devicen_tints AGMCORE_gget names_index get setcustomcolor + Names length{pop}repeat + end +}bdf +/setdevicencolorspace +{ + dup/AliasedColorants known{false}{true}ifelse + current_spot_alias and{ + 7 dict begin + /names_index 0 def + dup/names_len exch/Names get length def + /new_names names_len array def + /new_LookupTables names_len array def + /alias_cnt 0 def + dup/Names get + { + dup map_alias{ + exch pop + dup/ColorLookup known{ + dup begin + new_LookupTables names_index ColorLookup put + end + }{ + dup/Components known{ + dup begin + new_LookupTables names_index Components put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + new_names names_index 3 -1 roll/Name get put + /alias_cnt alias_cnt 1 add def + }{ + /name xdf + new_names names_index name put + dup/LookupTables known{ + dup begin + new_LookupTables names_index LookupTables names_index get put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + /names_index names_index 1 add def + }forall + alias_cnt 0 gt{ + /AliasedColorants true def + /lut_entry_len new_LookupTables 0 get dup length 256 ge{0 get length}{length}ifelse def + 0 1 names_len 1 sub{ + /names_index xdf + new_LookupTables names_index get dup length 256 ge{0 get length}{length}ifelse lut_entry_len ne{ + /AliasedColorants false def + exit + }{ + new_LookupTables names_index get 0 get null eq{ + dup/Names get names_index get/name xdf + name(Cyan)eq name(Magenta)eq name(Yellow)eq name(Black)eq + or or or not{ + /AliasedColorants false def + exit + }if + }if + }ifelse + }for + lut_entry_len 1 eq{ + /AliasedColorants false def + }if + AliasedColorants{ + dup begin + /Names new_names def + /LookupTables new_LookupTables def + /AliasedColorants true def + /NComponents lut_entry_len def + /TintMethod NComponents 4 eq{/Subtractive}{/Additive}ifelse def + /MappedCSA TintMethod/Additive eq{/DeviceRGB}{/DeviceCMYK}ifelse def + currentdict/TTTablesIdx known not{ + /TTTablesIdx -1 def + }if + end + }if + }if + end + }if + dup/devicen_colorspace_dict exch AGMCORE_gput + begin + currentdict/AliasedColorants known{ + AliasedColorants + }{ + false + }ifelse + dup not{ + CSA map_csa + }if + /TintTransform load type/nulltype eq or{ + /TintTransform[ + 0 1 Names length 1 sub + { + /TTTablesIdx TTTablesIdx 1 add def + dup LookupTables exch get dup 0 get null eq + { + 1 index + Names exch get + dup(Cyan)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0 0 0 + } + { + dup(Magenta)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0/exch cvx 0 0 + }{ + (Yellow)eq + { + exch + LookupTables length exch sub + /index cvx + 0 0 3 -1/roll cvx 0 + }{ + exch + LookupTables length exch sub + /index cvx + 0 0 0 4 -1/roll cvx + }ifelse + }ifelse + }ifelse + 5 -1/roll cvx/astore cvx + }{ + dup length 1 sub + LookupTables length 4 -1 roll sub 1 add + /index cvx/mul cvx/round cvx/cvi cvx/get cvx + }ifelse + Names length TTTablesIdx add 1 add 1/roll cvx + }for + Names length[/pop cvx]cvx/repeat cvx + NComponents Names length + TintMethod/Subtractive eq + { + subtractive_blend + }{ + additive_blend + }ifelse + ]cvx bdf + }if + AGMCORE_host_sep{ + Names convert_to_process{ + exec_tint_transform + } + { + currentdict/AliasedColorants known{ + AliasedColorants not + }{ + false + }ifelse + 5 dict begin + /AvoidAliasedColorants xdf + /painted? false def + /names_index 0 def + /names_len Names length def + AvoidAliasedColorants{ + /currentspotalias current_spot_alias def + false set_spot_alias + }if + Names{ + AGMCORE_is_cmyk_sep{ + dup(Cyan)eq AGMCORE_cyan_plate and exch + dup(Magenta)eq AGMCORE_magenta_plate and exch + dup(Yellow)eq AGMCORE_yellow_plate and exch + (Black)eq AGMCORE_black_plate and or or or{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + }if + painted?{exit}if + }{ + 0 0 0 0 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + exit + }if + }ifelse + /names_index names_index 1 add def + }forall + AvoidAliasedColorants{ + currentspotalias set_spot_alias + }if + painted?{ + /devicen_colorspace_dict AGMCORE_gget/names_index names_index put + }{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + names_len[/pop cvx]cvx/repeat cvx 1/setseparationgray cvx + 0 0 0 0/setcmykcolor cvx + ]cvx ddf + }ifelse + end + }ifelse + } + { + AGMCORE_in_rip_sep{ + Names convert_to_process not + }{ + level3 + }ifelse + { + [/DeviceN Names MappedCSA/TintTransform load]setcolorspace_opt + /TintProc level3 not AGMCORE_in_rip_sep and{ + [ + Names/length cvx[/pop cvx]cvx/repeat cvx + ]cvx bdf + }{ + {setcolor}bdf + }ifelse + }{ + exec_tint_transform + }ifelse + }ifelse + set_crd + /AliasedColorants false def + end +}def +/setindexedcolorspace +{ + dup/indexed_colorspace_dict exch AGMCORE_gput + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + currentdict devncs + }{ + 1 currentdict sepcs + }ifelse + AGMCORE_host_sep{ + 4 dict begin + /compCnt/Names where{pop Names length}{1}ifelse def + /NewLookup HiVal 1 add string def + 0 1 HiVal{ + /tableIndex xdf + Lookup dup type/stringtype eq{ + compCnt tableIndex map_index + }{ + exec + }ifelse + /Names where{ + pop setdevicencolor + }{ + setsepcolor + }ifelse + currentgray + tableIndex exch + 255 mul cvi + NewLookup 3 1 roll put + }for + [/Indexed currentcolorspace HiVal NewLookup]setcolorspace_opt + end + }{ + level3 + { + currentdict/Names known{ + [/Indexed[/DeviceN Names MappedCSA/TintTransform load]HiVal Lookup]setcolorspace_opt + }{ + [/Indexed[/Separation Name MappedCSA sep_proc_name load]HiVal Lookup]setcolorspace_opt + }ifelse + }{ + [/Indexed MappedCSA HiVal + [ + currentdict/Names known{ + Lookup dup type/stringtype eq + {/exch cvx CSDBase/CSD get_res/Names get length dup/mul cvx exch/getinterval cvx{255 div}/forall cvx} + {/exec cvx}ifelse + /TintTransform load/exec cvx + }{ + Lookup dup type/stringtype eq + {/exch cvx/get cvx 255/div cvx} + {/exec cvx}ifelse + CSDBase/CSD get_res/MappedCSA get sep_proc_name exch pop/load cvx/exec cvx + }ifelse + ]cvx + ]setcolorspace_opt + }ifelse + }ifelse + end + set_crd + } + { + CSA map_csa + AGMCORE_host_sep level2 not and{ + 0 0 0 0 setcmykcolor + }{ + [/Indexed MappedCSA + level2 not has_color not and{ + dup 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or{ + pop[/DeviceGray] + }if + HiVal GrayLookup + }{ + HiVal + currentdict/RangeArray known{ + { + /indexed_colorspace_dict AGMCORE_gget begin + Lookup exch + dup HiVal gt{ + pop HiVal + }if + NComponents mul NComponents getinterval{}forall + NComponents 1 sub -1 0{ + RangeArray exch 2 mul 2 getinterval aload pop map255_to_range + NComponents 1 roll + }for + end + }bind + }{ + Lookup + }ifelse + }ifelse + ]setcolorspace_opt + set_crd + }ifelse + }ifelse + end +}def +/setindexedcolor +{ + AGMCORE_host_sep{ + /indexed_colorspace_dict AGMCORE_gget + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + map_indexed_devn + devn + } + { + Lookup 1 3 -1 roll map_index + sep + }ifelse + end + }{ + Lookup MappedCSA/DeviceCMYK eq{4}{1}ifelse 3 -1 roll + map_index + MappedCSA/DeviceCMYK eq{setcmykcolor}{setgray}ifelse + }ifelse + end + }{ + level3 not AGMCORE_in_rip_sep and/indexed_colorspace_dict AGMCORE_gget/CSDBase known and{ + /indexed_colorspace_dict AGMCORE_gget/CSDBase get/CSD get_res begin + map_indexed_devn + devn + end + } + { + setcolor + }ifelse + }ifelse +}def +/ignoreimagedata +{ + currentoverprint not{ + gsave + dup clonedict begin + 1 setgray + /Decode[0 1]def + /DataSourcedef + /MultipleDataSources false def + /BitsPerComponent 8 def + currentdict end + systemdict/image gx + grestore + }if + consumeimagedata +}def +/add_res +{ + dup/CSD eq{ + pop + //Adobe_AGM_Core begin + /AGMCORE_CSD_cache load 3 1 roll put + end + }{ + defineresource pop + }ifelse +}def +/del_res +{ + { + aload pop exch + dup/CSD eq{ + pop + {//Adobe_AGM_Core/AGMCORE_CSD_cache get exch undef}forall + }{ + exch + {1 index undefineresource}forall + pop + }ifelse + }forall +}def +/get_res +{ + dup/CSD eq{ + pop + dup type dup/nametype eq exch/stringtype eq or{ + AGMCORE_CSD_cache exch get + }if + }{ + findresource + }ifelse +}def +/get_csa_by_name +{ + dup type dup/nametype eq exch/stringtype eq or{ + /CSA get_res + }if +}def +/paintproc_buf_init +{ + /count get 0 0 put +}def +/paintproc_buf_next +{ + dup/count get dup 0 get + dup 3 1 roll + 1 add 0 xpt + get +}def +/cachepaintproc_compress +{ + 5 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + /string_size 16000 def + /readbuffer string_size string def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + /LZWFilter + { + exch + dup length 0 eq{ + pop + }{ + ppdict dup length 1 sub 3 -1 roll put + }ifelse + {string_size}{0}ifelse string + }/LZWEncode filter def + { + ReadFilter readbuffer readstring + exch LZWFilter exch writestring + not{exit}if + }loop + LZWFilter closefile + ppdict + end +}def +/cachepaintproc +{ + 2 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + { + ReadFilter 16000 string readstring exch + ppdict dup length 1 sub 3 -1 roll put + not{exit}if + }loop + ppdict dup dup length 1 sub()put + end +}def +/make_pattern +{ + exch clonedict exch + dup matrix currentmatrix matrix concatmatrix 0 0 3 2 roll itransform + exch 3 index/XStep get 1 index exch 2 copy div cvi mul sub sub + exch 3 index/YStep get 1 index exch 2 copy div cvi mul sub sub + matrix translate exch matrix concatmatrix + 1 index begin + BBox 0 get XStep div cvi XStep mul/xshift exch neg def + BBox 1 get YStep div cvi YStep mul/yshift exch neg def + BBox 0 get xshift add + BBox 1 get yshift add + BBox 2 get xshift add + BBox 3 get yshift add + 4 array astore + /BBox exch def + [xshift yshift/translate load null/exec load]dup + 3/PaintProc load put cvx/PaintProc exch def + end + gsave 0 setgray + makepattern + grestore +}def +/set_pattern +{ + dup/PatternType get 1 eq{ + dup/PaintType get 1 eq{ + currentoverprint sop[/DeviceGray]setcolorspace 0 setgray + }if + }if + setpattern +}def +/setcolorspace_opt +{ + dup currentcolorspace eq{pop}{setcolorspace}ifelse +}def +/updatecolorrendering +{ + currentcolorrendering/RenderingIntent known{ + currentcolorrendering/RenderingIntent get + } + { + Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/Saturation eq + { + /saturation_crd AGMCORE_gget dup null eq + } + { + /perceptual_crd AGMCORE_gget dup null eq + }ifelse + }ifelse + }ifelse + { + pop null + } + { + /RenderingIntent known{null}{Intent}ifelse + }ifelse + }ifelse + Intent ne{ + Intent/ColorRendering{findresource}stopped + { + pop pop systemdict/findcolorrendering known + { + Intent findcolorrendering + { + /ColorRendering findresource true exch + } + { + /ColorRendering findresource + product(Xerox Phaser 5400)ne + exch + }ifelse + dup Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd exch AGMCORE_gput + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd exch AGMCORE_gput + } + { + Intent/Saturation eq + { + /saturation_crd exch AGMCORE_gput + } + { + Intent/Perceptual eq + { + /perceptual_crd exch AGMCORE_gput + } + { + pop + }ifelse + }ifelse + }ifelse + }ifelse + 1 index{exch}{pop}ifelse + } + {false}ifelse + } + {true}ifelse + { + dup begin + currentdict/TransformPQR known{ + currentdict/TransformPQR get aload pop + 3{{}eq 3 1 roll}repeat or or + } + {true}ifelse + currentdict/MatrixPQR known{ + currentdict/MatrixPQR get aload pop + 1.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 1.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 0.0 eq 9 1 roll 1.0 eq + and and and and and and and and + } + {true}ifelse + end + or + { + clonedict begin + /TransformPQR[ + {4 -1 roll 3 get dup 3 1 roll sub 5 -1 roll 3 get 3 -1 roll sub div + 3 -1 roll 3 get 3 -1 roll 3 get dup 4 1 roll sub mul add}bind + {4 -1 roll 4 get dup 3 1 roll sub 5 -1 roll 4 get 3 -1 roll sub div + 3 -1 roll 4 get 3 -1 roll 4 get dup 4 1 roll sub mul add}bind + {4 -1 roll 5 get dup 3 1 roll sub 5 -1 roll 5 get 3 -1 roll sub div + 3 -1 roll 5 get 3 -1 roll 5 get dup 4 1 roll sub mul add}bind + ]def + /MatrixPQR[0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296]def + /RangePQR[-0.3227950745 2.3229645538 -1.5003771057 3.5003465881 -0.1369979095 2.136967392]def + currentdict end + }if + setcolorrendering_opt + }if + }if +}def +/set_crd +{ + AGMCORE_host_sep not level2 and{ + currentdict/ColorRendering known{ + ColorRendering/ColorRendering{findresource}stopped not{setcolorrendering_opt}if + }{ + currentdict/Intent known{ + updatecolorrendering + }if + }ifelse + currentcolorspace dup type/arraytype eq + {0 get}if + /DeviceRGB eq + { + currentdict/UCR known + {/UCR}{/AGMCORE_currentucr}ifelse + load setundercolorremoval + currentdict/BG known + {/BG}{/AGMCORE_currentbg}ifelse + load setblackgeneration + }if + }if +}def +/set_ucrbg +{ + dup null eq {pop /AGMCORE_currentbg load}{/Procedure get_res}ifelse + dup currentblackgeneration eq {pop}{setblackgeneration}ifelse + dup null eq {pop /AGMCORE_currentucr load}{/Procedure get_res}ifelse + dup currentundercolorremoval eq {pop}{setundercolorremoval}ifelse +}def +/setcolorrendering_opt +{ + dup currentcolorrendering eq{ + pop + }{ + product(HP Color LaserJet 2605)anchorsearch{ + pop pop pop + }{ + pop + clonedict + begin + /Intent Intent def + currentdict + end + setcolorrendering + }ifelse + }ifelse +}def +/cpaint_gcomp +{ + convert_to_process//Adobe_AGM_Core/AGMCORE_ConvertToProcess xddf + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get not + { + (%end_cpaint_gcomp)flushinput + }if +}def +/cpaint_gsep +{ + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get + { + (%end_cpaint_gsep)flushinput + }if +}def +/cpaint_gend +{np}def +/T1_path +{ + currentfile token pop currentfile token pop mo + { + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 exch rlineto + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 rlineto + }loop +}def +/T1_gsave + level3 + {/clipsave} + {/gsave}ifelse + load def +/T1_grestore + level3 + {/cliprestore} + {/grestore}ifelse + load def +/set_spot_alias_ary +{ + dup inherit_aliases + //Adobe_AGM_Core/AGMCORE_SpotAliasAry xddf +}def +/set_spot_normalization_ary +{ + dup inherit_aliases + dup length + /AGMCORE_SpotAliasAry where{pop AGMCORE_SpotAliasAry length add}if + array + //Adobe_AGM_Core/AGMCORE_SpotAliasAry2 xddf + /AGMCORE_SpotAliasAry where{ + pop + AGMCORE_SpotAliasAry2 0 AGMCORE_SpotAliasAry putinterval + AGMCORE_SpotAliasAry length + }{0}ifelse + AGMCORE_SpotAliasAry2 3 1 roll exch putinterval + true set_spot_alias +}def +/inherit_aliases +{ + {dup/Name get map_alias{/CSD put}{pop}ifelse}forall +}def +/set_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias 3 -1 roll put + }{ + pop + }ifelse +}def +/current_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias get + }{ + false + }ifelse +}def +/map_alias +{ + /AGMCORE_SpotAliasAry2 where{ + begin + /AGMCORE_name xdf + false + AGMCORE_SpotAliasAry2{ + dup/Name get AGMCORE_name eq{ + /CSD get/CSD get_res + exch pop true + exit + }{ + pop + }ifelse + }forall + end + }{ + pop false + }ifelse +}bdf +/spot_alias +{ + true set_spot_alias + /AGMCORE_&setcustomcolor AGMCORE_key_known not{ + //Adobe_AGM_Core/AGMCORE_&setcustomcolor/setcustomcolor load put + }if + /customcolor_tint 1 AGMCORE_gput + //Adobe_AGM_Core begin + /setcustomcolor + { + //Adobe_AGM_Core begin + dup/customcolor_tint exch AGMCORE_gput + 1 index aload pop pop 1 eq exch 1 eq and exch 1 eq and exch 1 eq and not + current_spot_alias and{1 index 4 get map_alias}{false}ifelse + { + false set_spot_alias + /sep_colorspace_dict AGMCORE_gget null ne + {/sep_colorspace_dict AGMCORE_gget/ForeignContent known not}{false}ifelse + 3 1 roll 2 index{ + exch pop/sep_tint AGMCORE_gget exch + }if + mark 3 1 roll + setsepcolorspace + counttomark 0 ne{ + setsepcolor + }if + pop + not{/sep_tint 1.0 AGMCORE_gput/sep_colorspace_dict AGMCORE_gget/ForeignContent true put}if + pop + true set_spot_alias + }{ + AGMCORE_&setcustomcolor + }ifelse + end + }bdf + end +}def +/begin_feature +{ + Adobe_AGM_Core/AGMCORE_feature_dictCount countdictstack put + count Adobe_AGM_Core/AGMCORE_feature_opCount 3 -1 roll put + {Adobe_AGM_Core/AGMCORE_feature_ctm matrix currentmatrix put}if +}def +/end_feature +{ + 2 dict begin + /spd/setpagedevice load def + /setpagedevice{get_gstate spd set_gstate}def + stopped{$error/newerror false put}if + end + count Adobe_AGM_Core/AGMCORE_feature_opCount get sub dup 0 gt{{pop}repeat}{pop}ifelse + countdictstack Adobe_AGM_Core/AGMCORE_feature_dictCount get sub dup 0 gt{{end}repeat}{pop}ifelse + {Adobe_AGM_Core/AGMCORE_feature_ctm get setmatrix}if +}def +/set_negative +{ + //Adobe_AGM_Core begin + /AGMCORE_inverting exch def + level2{ + currentpagedevice/NegativePrint known AGMCORE_distilling not and{ + currentpagedevice/NegativePrint get//Adobe_AGM_Core/AGMCORE_inverting get ne{ + true begin_feature true{ + <>setpagedevice + }end_feature + }if + /AGMCORE_inverting false def + }if + }if + AGMCORE_inverting{ + [{1 exch sub}/exec load dup currenttransfer exch]cvx bind settransfer + AGMCORE_distilling{ + erasepage + }{ + gsave np clippath 1/setseparationgray where{pop setseparationgray}{setgray}ifelse + /AGMIRS_&fill where{pop AGMIRS_&fill}{fill}ifelse grestore + }ifelse + }if + end +}def +/lw_save_restore_override{ + /md where{ + pop + md begin + initializepage + /initializepage{}def + /pmSVsetup{}def + /endp{}def + /pse{}def + /psb{}def + /orig_showpage where + {pop} + {/orig_showpage/showpage load def} + ifelse + /showpage{orig_showpage gR}def + end + }if +}def +/pscript_showpage_override{ + /NTPSOct95 where + { + begin + showpage + save + /showpage/restore load def + /restore{exch pop}def + end + }if +}def +/driver_media_override +{ + /md where{ + pop + md/initializepage known{ + md/initializepage{}put + }if + md/rC known{ + md/rC{4{pop}repeat}put + }if + }if + /mysetup where{ + /mysetup[1 0 0 1 0 0]put + }if + Adobe_AGM_Core/AGMCORE_Default_CTM matrix currentmatrix put + level2 + {Adobe_AGM_Core/AGMCORE_Default_PageSize currentpagedevice/PageSize get put}if +}def +/capture_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup Pscript_Win_Data/mysetup get put + }if + }if +}def +/restore_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup known{ + Pscript_Win_Data/mysetup Adobe_AGM_Core/save_mysetup get put + Adobe_AGM_Core/save_mysetup undef + }if + }if + }if +}def +/driver_check_media_override +{ + /PrepsDict where + {pop} + { + Adobe_AGM_Core/AGMCORE_Default_CTM get matrix currentmatrix ne + Adobe_AGM_Core/AGMCORE_Default_PageSize get type/arraytype eq + { + Adobe_AGM_Core/AGMCORE_Default_PageSize get 0 get currentpagedevice/PageSize get 0 get eq and + Adobe_AGM_Core/AGMCORE_Default_PageSize get 1 get currentpagedevice/PageSize get 1 get eq and + }if + { + Adobe_AGM_Core/AGMCORE_Default_CTM get setmatrix + }if + }ifelse +}def +AGMCORE_err_strings begin + /AGMCORE_bad_environ(Environment not satisfactory for this job. Ensure that the PPD is correct or that the PostScript level requested is supported by this printer. )def + /AGMCORE_color_space_onhost_seps(This job contains colors that will not separate with on-host methods. )def + /AGMCORE_invalid_color_space(This job contains an invalid color space. )def +end +/set_def_ht +{AGMCORE_def_ht sethalftone}def +/set_def_flat +{AGMCORE_Default_flatness setflat}def +end +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_CoolType_Core 2.31 0 %%Copyright: Copyright 1997-2006 Adobe Systems Incorporated. All Rights Reserved. %%Version: 2.31 0 10 dict begin /Adobe_CoolType_Passthru currentdict def /Adobe_CoolType_Core_Defined userdict/Adobe_CoolType_Core known def Adobe_CoolType_Core_Defined {/Adobe_CoolType_Core userdict/Adobe_CoolType_Core get def} if userdict/Adobe_CoolType_Core 70 dict dup begin put /Adobe_CoolType_Version 2.31 def /Level2? systemdict/languagelevel known dup {pop systemdict/languagelevel get 2 ge} if def Level2? not { /currentglobal false def /setglobal/pop load def /gcheck{pop false}bind def /currentpacking false def /setpacking/pop load def /SharedFontDirectory 0 dict def } if currentpacking true setpacking currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def end setglobal currentglobal true setglobal userdict/Adobe_CoolType_GVMFonts known not {userdict/Adobe_CoolType_GVMFonts 10 dict put} if setglobal currentglobal false setglobal userdict/Adobe_CoolType_LVMFonts known not {userdict/Adobe_CoolType_LVMFonts 10 dict put} if setglobal /ct_VMDictPut { dup gcheck{Adobe_CoolType_GVMFonts}{Adobe_CoolType_LVMFonts}ifelse 3 1 roll put }bind def /ct_VMDictUndef { dup Adobe_CoolType_GVMFonts exch known {Adobe_CoolType_GVMFonts exch undef} { dup Adobe_CoolType_LVMFonts exch known {Adobe_CoolType_LVMFonts exch undef} {pop} ifelse }ifelse }bind def /ct_str1 1 string def /ct_xshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_yshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 exch rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_xyshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { {_ct_na _ct_i 1 add get}stopped {pop pop pop} { _ct_x _ct_y moveto rmoveto } ifelse } ifelse /_ct_i _ct_i 2 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /xsh{{@xshow}stopped{Adobe_CoolType_Data begin ct_xshow end}if}bind def /ysh{{@yshow}stopped{Adobe_CoolType_Data begin ct_yshow end}if}bind def /xysh{{@xyshow}stopped{Adobe_CoolType_Data begin ct_xyshow end}if}bind def currentglobal true setglobal /ct_T3Defs { /BuildChar { 1 index/Encoding get exch get 1 index/BuildGlyph get exec }bind def /BuildGlyph { exch begin GlyphProcs exch get exec end }bind def }bind def setglobal /@_SaveStackLevels { Adobe_CoolType_Data begin /@vmState currentglobal def false setglobal @opStackCountByLevel @opStackLevel 2 copy known not { 2 copy 3 dict dup/args 7 index 5 add array put put get } { get dup/args get dup length 3 index lt { dup length 5 add array exch 1 index exch 0 exch putinterval 1 index exch/args exch put } {pop} ifelse } ifelse begin count 1 sub 1 index lt {pop count} if dup/argCount exch def dup 0 gt { args exch 0 exch getinterval astore pop } {pop} ifelse count /restCount exch def end /@opStackLevel @opStackLevel 1 add def countdictstack 1 sub @dictStackCountByLevel exch @dictStackLevel exch put /@dictStackLevel @dictStackLevel 1 add def @vmState setglobal end }bind def /@_RestoreStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def @opStackCountByLevel @opStackLevel get begin count restCount sub dup 0 gt {{pop}repeat} {pop} ifelse args 0 argCount getinterval{}forall end /@dictStackLevel @dictStackLevel 1 sub def @dictStackCountByLevel @dictStackLevel get end countdictstack exch sub dup 0 gt {{end}repeat} {pop} ifelse }bind def /@_PopStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def /@dictStackLevel @dictStackLevel 1 sub def end }bind def /@Raise { exch cvx exch errordict exch get exec stop }bind def /@ReRaise { cvx $error/errorname get errordict exch get exec stop }bind def /@Stopped { 0 @#Stopped }bind def /@#Stopped { @_SaveStackLevels stopped {@_RestoreStackLevels true} {@_PopStackLevels false} ifelse }bind def /@Arg { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 1 sub get begin args exch argCount 1 sub exch sub get end end }bind def currentglobal true setglobal /CTHasResourceForAllBug Level2? { 1 dict dup /@shouldNotDisappearDictValue true def Adobe_CoolType_Data exch/@shouldNotDisappearDict exch put begin count @_SaveStackLevels {(*){pop stop}128 string/Category resourceforall} stopped pop @_RestoreStackLevels currentdict Adobe_CoolType_Data/@shouldNotDisappearDict get dup 3 1 roll ne dup 3 1 roll { /@shouldNotDisappearDictValue known { { end currentdict 1 index eq {pop exit} if } loop } if } { pop end } ifelse } {false} ifelse def true setglobal /CTHasResourceStatusBug Level2? { mark {/steveamerige/Category resourcestatus} stopped {cleartomark true} {cleartomark currentglobal not} ifelse } {false} ifelse def setglobal /CTResourceStatus { mark 3 1 roll /Category findresource begin ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse end }bind def /CTWorkAroundBugs { Level2? { /cid_PreLoad/ProcSet resourcestatus { pop pop currentglobal mark { (*) { dup/CMap CTHasResourceStatusBug {CTResourceStatus} {resourcestatus} ifelse { pop dup 0 eq exch 1 eq or { dup/CMap findresource gcheck setglobal /CMap undefineresource } { pop CTHasResourceForAllBug {exit} {stop} ifelse } ifelse } {pop} ifelse } 128 string/CMap resourceforall } stopped {cleartomark} stopped pop setglobal } if } if }bind def /ds { Adobe_CoolType_Core begin CTWorkAroundBugs /mo/moveto load def /nf/newencodedfont load def /msf{makefont setfont}bind def /uf{dup undefinefont ct_VMDictUndef}bind def /ur/undefineresource load def /chp/charpath load def /awsh/awidthshow load def /wsh/widthshow load def /ash/ashow load def /@xshow/xshow load def /@yshow/yshow load def /@xyshow/xyshow load def /@cshow/cshow load def /sh/show load def /rp/repeat load def /.n/.notdef def end currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /AddWidths? false def /CC 0 def /charcode 2 string def /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def /InVMFontsByCMap 10 dict def /InVMDeepCopiedFonts 10 dict def end setglobal }bind def /dt { currentdict Adobe_CoolType_Core eq {end} if }bind def /ps { Adobe_CoolType_Core begin Adobe_CoolType_GVMFonts begin Adobe_CoolType_LVMFonts begin SharedFontDirectory begin }bind def /pt { end end end end }bind def /unload { systemdict/languagelevel known { systemdict/languagelevel get 2 ge { userdict/Adobe_CoolType_Core 2 copy known {undef} {pop pop} ifelse } if } if }bind def /ndf { 1 index where {pop pop pop} {dup xcheck{bind}if def} ifelse }def /findfont systemdict begin userdict begin /globaldict where{/globaldict get begin}if dup where pop exch get /globaldict where{pop end}if end end Adobe_CoolType_Core_Defined {/systemfindfont exch def} { /findfont 1 index def /systemfindfont exch def } ifelse /undefinefont {pop}ndf /copyfont { currentglobal 3 1 roll 1 index gcheck setglobal dup null eq{0}{dup length}ifelse 2 index length add 1 add dict begin exch { 1 index/FID eq {pop pop} {def} ifelse } forall dup null eq {pop} {{def}forall} ifelse currentdict end exch setglobal }bind def /copyarray { currentglobal exch dup gcheck setglobal dup length array copy exch setglobal }bind def /newencodedfont { currentglobal { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } { FontDirectory 3 index known {FontDirectory 3 index get/FontReferenced known} { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } ifelse } ifelse dup { 3 index findfont/FontReferenced get 2 index dup type/nametype eq {findfont} if ne {pop false} if } if dup { 1 index dup type/nametype eq {findfont} if dup/CharStrings known { /CharStrings get length 4 index findfont/CharStrings get length ne { pop false } if } {pop} ifelse } if { pop 1 index findfont /Encoding get exch 0 1 255 {2 copy get 3 index 3 1 roll put} for pop pop pop } { currentglobal 4 1 roll dup type/nametype eq {findfont} if dup gcheck setglobal dup dup maxlength 2 add dict begin exch { 1 index/FID ne 2 index/Encoding ne and {def} {pop pop} ifelse } forall /FontReferenced exch def /Encoding exch dup length array copy def /FontName 1 index dup type/stringtype eq{cvn}if def dup currentdict end definefont ct_VMDictPut setglobal } ifelse }bind def /SetSubstituteStrategy { $SubstituteFont begin dup type/dicttype ne {0 dict} if currentdict/$Strategies known { exch $Strategies exch 2 copy known { get 2 copy maxlength exch maxlength add dict begin {def}forall {def}forall currentdict dup/$Init known {dup/$Init get exec} if end /$Strategy exch def } {pop pop pop} ifelse } {pop pop} ifelse end }bind def /scff { $SubstituteFont begin dup type/stringtype eq {dup length exch} {null} ifelse /$sname exch def /$slen exch def /$inVMIndex $sname null eq { 1 index $str cvs dup length $slen sub $slen getinterval cvn } {$sname} ifelse def end {findfont} @Stopped { dup length 8 add string exch 1 index 0(BadFont:)putinterval 1 index exch 8 exch dup length string cvs putinterval cvn {findfont} @Stopped {pop/Courier findfont} if } if $SubstituteFont begin /$sname null def /$slen 0 def /$inVMIndex null def end }bind def /isWidthsOnlyFont { dup/WidthsOnly known {pop pop true} { dup/FDepVector known {/FDepVector get{isWidthsOnlyFont dup{exit}if}forall} { dup/FDArray known {/FDArray get{isWidthsOnlyFont dup{exit}if}forall} {pop} ifelse } ifelse } ifelse }bind def /ct_StyleDicts 4 dict dup begin /Adobe-Japan1 4 dict dup begin Level2? { /Serif /HeiseiMin-W3-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMin-W3} { /CIDFont/Category resourcestatus { pop pop /HeiseiMin-W3/CIDFont resourcestatus {pop pop/HeiseiMin-W3} {/Ryumin-Light} ifelse } {/Ryumin-Light} ifelse } ifelse def /SansSerif /HeiseiKakuGo-W5-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiKakuGo-W5} { /CIDFont/Category resourcestatus { pop pop /HeiseiKakuGo-W5/CIDFont resourcestatus {pop pop/HeiseiKakuGo-W5} {/GothicBBB-Medium} ifelse } {/GothicBBB-Medium} ifelse } ifelse def /HeiseiMaruGo-W4-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMaruGo-W4} { /CIDFont/Category resourcestatus { pop pop /HeiseiMaruGo-W4/CIDFont resourcestatus {pop pop/HeiseiMaruGo-W4} { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } ifelse /RoundSansSerif exch def /Default Serif def } { /Serif/Ryumin-Light def /SansSerif/GothicBBB-Medium def { (fonts/Jun101-Light-83pv-RKSJ-H)status }stopped {pop}{ {pop pop pop pop/Jun101-Light} {SansSerif} ifelse /RoundSansSerif exch def }ifelse /Default Serif def } ifelse end def /Adobe-Korea1 4 dict dup begin /Serif/HYSMyeongJo-Medium def /SansSerif/HYGoThic-Medium def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-GB1 4 dict dup begin /Serif/STSong-Light def /SansSerif/STHeiti-Regular def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-CNS1 4 dict dup begin /Serif/MKai-Medium def /SansSerif/MHei-Medium def /RoundSansSerif SansSerif def /Default Serif def end def end def Level2?{currentglobal true setglobal}if /ct_BoldRomanWidthProc { stringwidth 1 index 0 ne{exch .03 add exch}if setcharwidth 0 0 }bind def /ct_Type0WidthProc { dup stringwidth 0 0 moveto 2 index true charpath pathbbox 0 -1 7 index 2 div .88 setcachedevice2 pop 0 0 }bind def /ct_Type0WMode1WidthProc { dup stringwidth pop 2 div neg -0.88 2 copy moveto 0 -1 5 -1 roll true charpath pathbbox setcachedevice }bind def /cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_BoldBaseFont 11 dict begin /FontType 3 def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /Encoding cHexEncoding def /_setwidthProc/ct_BoldRomanWidthProc load def /_bcstr1 1 string def /BuildChar { exch begin _basefont setfont _bcstr1 dup 0 4 -1 roll put dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def systemdict/composefont known { /ct_DefineIdentity-H { /Identity-H/CMap resourcestatus { pop pop } { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse } def /ct_BoldBaseCIDFont 11 dict begin /CIDFontType 1 def /CIDFontName/ct_BoldBaseCIDFont def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /_setwidthProc/ct_Type0WidthProc load def /_bcstr2 2 string def /BuildGlyph { exch begin _basefont setfont _bcstr2 1 2 index 256 mod put _bcstr2 0 3 -1 roll 256 idiv put _bcstr2 dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def }if Level2?{setglobal}if /ct_CopyFont{ { 1 index/FID ne 2 index/UniqueID ne and {def}{pop pop}ifelse }forall }bind def /ct_Type0CopyFont { exch dup length dict begin ct_CopyFont [ exch FDepVector { dup/FontType get 0 eq { 1 index ct_Type0CopyFont /_ctType0 exch definefont } { /_ctBaseFont exch 2 index exec } ifelse exch } forall pop ] /FDepVector exch def currentdict end }bind def /ct_MakeBoldFont { dup/ct_SyntheticBold known { dup length 3 add dict begin ct_CopyFont /ct_StrokeWidth .03 0 FontMatrix idtransform pop def /ct_SyntheticBold true def currentdict end definefont } { dup dup length 3 add dict begin ct_CopyFont /PaintType 2 def /StrokeWidth .03 0 FontMatrix idtransform pop def /dummybold currentdict end definefont dup/FontType get dup 9 ge exch 11 le and { ct_BoldBaseCIDFont dup length 3 add dict copy begin dup/CIDSystemInfo get/CIDSystemInfo exch def ct_DefineIdentity-H /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefont exch def /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefonto exch def currentdict end /CIDFont defineresource } { ct_BoldBaseFont dup length 3 add dict copy begin /_basefont exch def /_basefonto exch def currentdict end definefont } ifelse } ifelse }bind def /ct_MakeBold{ 1 index 1 index findfont currentglobal 5 1 roll dup gcheck setglobal dup /FontType get 0 eq { dup/WMode known{dup/WMode get 1 eq}{false}ifelse version length 4 ge and {version 0 4 getinterval cvi 2015 ge} {true} ifelse {/ct_Type0WidthProc} {/ct_Type0WMode1WidthProc} ifelse ct_BoldBaseFont/_setwidthProc 3 -1 roll load put {ct_MakeBoldFont}ct_Type0CopyFont definefont } { dup/_fauxfont known not 1 index/SubstMaster known not and { ct_BoldBaseFont/_setwidthProc /ct_BoldRomanWidthProc load put ct_MakeBoldFont } { 2 index 2 index eq {exch pop } { dup length dict begin ct_CopyFont currentdict end definefont } ifelse } ifelse } ifelse pop pop pop setglobal }bind def /?str1 256 string def /?set { $SubstituteFont begin /$substituteFound false def /$fontname 1 index def /$doSmartSub false def end dup findfont $SubstituteFont begin $substituteFound {false} { dup/FontName known { dup/FontName get $fontname eq 1 index/DistillerFauxFont known not and /currentdistillerparams where {pop false 2 index isWidthsOnlyFont not and} if } {false} ifelse } ifelse exch pop /$doSmartSub true def end { 5 1 roll pop pop pop pop findfont } { 1 index findfont dup/FontType get 3 eq { 6 1 roll pop pop pop pop pop false } {pop true} ifelse { $SubstituteFont begin pop pop /$styleArray 1 index def /$regOrdering 2 index def pop pop 0 1 $styleArray length 1 sub { $styleArray exch get ct_StyleDicts $regOrdering 2 copy known { get exch 2 copy known not {pop/Default} if get dup type/nametype eq { ?str1 cvs length dup 1 add exch ?str1 exch(-)putinterval exch dup length exch ?str1 exch 3 index exch putinterval add ?str1 exch 0 exch getinterval cvn } { pop pop/Unknown } ifelse } { pop pop pop pop/Unknown } ifelse } for end findfont }if } ifelse currentglobal false setglobal 3 1 roll null copyfont definefont pop setglobal }bind def setpacking userdict/$SubstituteFont 25 dict put 1 dict begin /SubstituteFont dup $error exch 2 copy known {get} {pop pop{pop/Courier}bind} ifelse def /currentdistillerparams where dup { pop pop currentdistillerparams/CannotEmbedFontPolicy 2 copy known {get/Error eq} {pop pop false} ifelse } if not { countdictstack array dictstack 0 get begin userdict begin $SubstituteFont begin /$str 128 string def /$fontpat 128 string def /$slen 0 def /$sname null def /$match false def /$fontname null def /$substituteFound false def /$inVMIndex null def /$doSmartSub true def /$depth 0 def /$fontname null def /$italicangle 26.5 def /$dstack null def /$Strategies 10 dict dup begin /$Type3Underprint { currentglobal exch false setglobal 11 dict begin /UseFont exch $WMode 0 ne { dup length dict copy dup/WMode $WMode put /UseFont exch definefont } if def /FontName $fontname dup type/stringtype eq{cvn}if def /FontType 3 def /FontMatrix[.001 0 0 .001 0 0]def /Encoding 256 array dup 0 1 255{/.notdef put dup}for pop def /FontBBox[0 0 0 0]def /CCInfo 7 dict dup begin /cc null def /x 0 def /y 0 def end def /BuildChar { exch begin CCInfo begin 1 string dup 0 3 index put exch pop /cc exch def UseFont 1000 scalefont setfont cc stringwidth/y exch def/x exch def x y setcharwidth $SubstituteFont/$Strategy get/$Underprint get exec 0 0 moveto cc show x y moveto end end }bind def currentdict end exch setglobal }bind def /$GetaTint 2 dict dup begin /$BuildFont { dup/WMode known {dup/WMode get} {0} ifelse /$WMode exch def $fontname exch dup/FontName known { dup/FontName get dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse exch Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index/FontName get known { pop Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index get null copyfont } {$deepcopyfont} ifelse exch 1 index exch/FontBasedOn exch put dup/FontName $fontname dup type/stringtype eq{cvn}if put definefont Adobe_CoolType_Data/InVMDeepCopiedFonts get begin dup/FontBasedOn get 1 index def end }bind def /$Underprint { gsave x abs y abs gt {/y 1000 def} {/x -1000 def 500 120 translate} ifelse Level2? { [/Separation(All)/DeviceCMYK{0 0 0 1 pop}] setcolorspace } {0 setgray} ifelse 10 setlinewidth x .8 mul [7 3] { y mul 8 div 120 sub x 10 div exch moveto 0 y 4 div neg rlineto dup 0 rlineto 0 y 4 div rlineto closepath gsave Level2? {.2 setcolor} {.8 setgray} ifelse fill grestore stroke } forall pop grestore }bind def end def /$Oblique 1 dict dup begin /$BuildFont { currentglobal exch dup gcheck setglobal null copyfont begin /FontBasedOn currentdict/FontName known { FontName dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse def /FontName $fontname dup type/stringtype eq{cvn}if def /currentdistillerparams where {pop} { /FontInfo currentdict/FontInfo known {FontInfo null copyfont} {2 dict} ifelse dup begin /ItalicAngle $italicangle def /FontMatrix FontMatrix [1 0 ItalicAngle dup sin exch cos div 1 0 0] matrix concatmatrix readonly end 4 2 roll def def } ifelse FontName currentdict end definefont exch setglobal }bind def end def /$None 1 dict dup begin /$BuildFont{}bind def end def end def /$Oblique SetSubstituteStrategy /$findfontByEnum { dup type/stringtype eq{cvn}if dup/$fontname exch def $sname null eq {$str cvs dup length $slen sub $slen getinterval} {pop $sname} ifelse $fontpat dup 0(fonts/*)putinterval exch 7 exch putinterval /$match false def $SubstituteFont/$dstack countdictstack array dictstack put mark { $fontpat 0 $slen 7 add getinterval {/$match exch def exit} $str filenameforall } stopped { cleardictstack currentdict true $SubstituteFont/$dstack get { exch { 1 index eq {pop false} {true} ifelse } {begin false} ifelse } forall pop } if cleartomark /$slen 0 def $match false ne {$match(fonts/)anchorsearch pop pop cvn} {/Courier} ifelse }bind def /$ROS 1 dict dup begin /Adobe 4 dict dup begin /Japan1 [/Ryumin-Light/HeiseiMin-W3 /GothicBBB-Medium/HeiseiKakuGo-W5 /HeiseiMaruGo-W4/Jun101-Light]def /Korea1 [/HYSMyeongJo-Medium/HYGoThic-Medium]def /GB1 [/STSong-Light/STHeiti-Regular]def /CNS1 [/MKai-Medium/MHei-Medium]def end def end def /$cmapname null def /$deepcopyfont { dup/FontType get 0 eq { 1 dict dup/FontName/copied put copyfont begin /FDepVector FDepVector copyarray 0 1 2 index length 1 sub { 2 copy get $deepcopyfont dup/FontName/copied put /copied exch definefont 3 copy put pop pop } for def currentdict end } {$Strategies/$Type3Underprint get exec} ifelse }bind def /$buildfontname { dup/CIDFont findresource/CIDSystemInfo get begin Registry length Ordering length Supplement 8 string cvs 3 copy length 2 add add add string dup 5 1 roll dup 0 Registry putinterval dup 4 index(-)putinterval dup 4 index 1 add Ordering putinterval 4 2 roll add 1 add 2 copy(-)putinterval end 1 add 2 copy 0 exch getinterval $cmapname $fontpat cvs exch anchorsearch {pop pop 3 2 roll putinterval cvn/$cmapname exch def} {pop pop pop pop pop} ifelse length $str 1 index(-)putinterval 1 add $str 1 index $cmapname $fontpat cvs putinterval $cmapname length add $str exch 0 exch getinterval cvn }bind def /$findfontByROS { /$fontname exch def $ROS Registry 2 copy known { get Ordering 2 copy known {get} {pop pop[]} ifelse } {pop pop[]} ifelse false exch { dup/CIDFont resourcestatus { pop pop save 1 index/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get} {false} ifelse exch pop exch restore {pop} {exch pop true exit} ifelse } {pop} ifelse } forall {$str cvs $buildfontname} { false(*) { save exch dup/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get not} {true} ifelse exch/CIDSystemInfo get dup/Registry get Registry eq exch/Ordering get Ordering eq and and {exch restore exch pop true exit} {pop restore} ifelse } $str/CIDFont resourceforall {$buildfontname} {$fontname $findfontByEnum} ifelse } ifelse }bind def end end currentdict/$error known currentdict/languagelevel known and dup {pop $error/SubstituteFont known} if dup {$error} {Adobe_CoolType_Core} ifelse begin { /SubstituteFont /CMap/Category resourcestatus { pop pop { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $sname null eq {dup $str cvs dup length $slen sub $slen getinterval cvn} {$sname} ifelse Adobe_CoolType_Data/InVMFontsByCMap get 1 index 2 copy known { get false exch { pop currentglobal { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } { FontDirectory 1 index known {exch pop true exit} { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } ifelse } ifelse } forall } {pop pop false} ifelse { exch pop exch pop } { dup/CMap resourcestatus { pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS } { 128 string cvs dup(-)search { 3 1 roll search { 3 1 roll pop {dup cvi} stopped {pop pop pop pop pop $findfontByEnum} { 4 2 roll pop pop exch length exch 2 index length 2 index sub exch 1 sub -1 0 { $str cvs dup length 4 index 0 4 index 4 3 roll add getinterval exch 1 index exch 3 index exch putinterval dup/CMap resourcestatus { pop pop 4 1 roll pop pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS true exit } {pop} ifelse } for dup type/booleantype eq {pop} {pop pop pop $findfontByEnum} ifelse } ifelse } {pop pop pop $findfontByEnum} ifelse } {pop pop $findfontByEnum} ifelse } ifelse } ifelse } {//SubstituteFont exec} ifelse /$slen 0 def end } } { { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and {$findfontByEnum} {//SubstituteFont exec} ifelse end } } ifelse bind readonly def Adobe_CoolType_Core/scfindfont/systemfindfont load put } { /scfindfont { $SubstituteFont begin dup systemfindfont dup/FontName known {dup/FontName get dup 3 index ne} {/noname true} ifelse dup { /$origfontnamefound 2 index def /$origfontname 4 index def/$substituteFound true def } if exch pop { $slen 0 gt $sname null ne 3 index length $slen gt or and { pop dup $findfontByEnum findfont dup maxlength 1 add dict begin {1 index/FID eq{pop pop}{def}ifelse} forall currentdict end definefont dup/FontName known{dup/FontName get}{null}ifelse $origfontnamefound ne { $origfontname $str cvs print ( substitution revised, using )print dup/FontName known {dup/FontName get}{(unspecified font)} ifelse $str cvs print(.\n)print } if } {exch pop} ifelse } {exch pop} ifelse end }bind def } ifelse end end Adobe_CoolType_Core_Defined not { Adobe_CoolType_Core/findfont { $SubstituteFont begin $depth 0 eq { /$fontname 1 index dup type/stringtype ne{$str cvs}if def /$substituteFound false def } if /$depth $depth 1 add def end scfindfont $SubstituteFont begin /$depth $depth 1 sub def $substituteFound $depth 0 eq and { $inVMIndex null ne {dup $inVMIndex $AddInVMFont} if $doSmartSub { currentdict/$Strategy known {$Strategy/$BuildFont get exec} if } if } if end }bind put } if } if end /$AddInVMFont { exch/FontName 2 copy known { get 1 dict dup begin exch 1 index gcheck def end exch Adobe_CoolType_Data/InVMFontsByCMap get exch $DictAdd } {pop pop pop} ifelse }bind def /$DictAdd { 2 copy known not {2 copy 4 index length dict put} if Level2? not { 2 copy get dup maxlength exch length 4 index length add lt 2 copy get dup length 4 index length add exch maxlength 1 index lt { 2 mul dict begin 2 copy get{forall}def 2 copy currentdict put end } {pop} ifelse } if get begin {def} forall end }bind def end end %%EndResource currentglobal true setglobal %%BeginResource: procset Adobe_CoolType_Utility_MAKEOCF 1.23 0 %%Copyright: Copyright 1987-2006 Adobe Systems Incorporated. %%Version: 1.23 0 systemdict/languagelevel known dup {currentglobal false setglobal} {false} ifelse exch userdict/Adobe_CoolType_Utility 2 copy known {2 copy get dup maxlength 27 add dict copy} {27 dict} ifelse put Adobe_CoolType_Utility begin /@eexecStartData def /@recognizeCIDFont null def /ct_Level2? exch def /ct_Clone? 1183615869 internaldict dup /CCRun known not exch/eCCRun known not ct_Level2? and or def ct_Level2? {globaldict begin currentglobal true setglobal} if /ct_AddStdCIDMap ct_Level2? {{ mark Adobe_CoolType_Utility/@recognizeCIDFont currentdict put { ((Hex)57 StartData 0615 1e27 2c39 1c60 d8a8 cc31 fe2b f6e0 7aa3 e541 e21c 60d8 a8c9 c3d0 6d9e 1c60 d8a8 c9c2 02d7 9a1c 60d8 a849 1c60 d8a8 cc36 74f4 1144 b13b 77)0()/SubFileDecode filter cvx exec } stopped { cleartomark Adobe_CoolType_Utility/@recognizeCIDFont get countdictstack dup array dictstack exch 1 sub -1 0 { 2 copy get 3 index eq {1 index length exch sub 1 sub{end}repeat exit} {pop} ifelse } for pop pop Adobe_CoolType_Utility/@eexecStartData get eexec } {cleartomark} ifelse }} {{ Adobe_CoolType_Utility/@eexecStartData get eexec }} ifelse bind def userdict/cid_extensions known dup{cid_extensions/cid_UpdateDB known and}if { cid_extensions begin /cid_GetCIDSystemInfo { 1 index type/stringtype eq {exch cvn exch} if cid_extensions begin dup load 2 index known { 2 copy cid_GetStatusInfo dup null ne { 1 index load 3 index get dup null eq {pop pop cid_UpdateDB} { exch 1 index/Created get eq {exch pop exch pop} {pop cid_UpdateDB} ifelse } ifelse } {pop cid_UpdateDB} ifelse } {cid_UpdateDB} ifelse end }bind def end } if ct_Level2? {end setglobal} if /ct_UseNativeCapability? systemdict/composefont known def /ct_MakeOCF 35 dict def /ct_Vars 25 dict def /ct_GlyphDirProcs 6 dict def /ct_BuildCharDict 15 dict dup begin /charcode 2 string def /dst_string 1500 string def /nullstring()def /usewidths? true def end def ct_Level2?{setglobal}{pop}ifelse ct_GlyphDirProcs begin /GetGlyphDirectory { systemdict/languagelevel known {pop/CIDFont findresource/GlyphDirectory get} { 1 index/CIDFont findresource/GlyphDirectory get dup type/dicttype eq { dup dup maxlength exch length sub 2 index lt { dup length 2 index add dict copy 2 index /CIDFont findresource/GlyphDirectory 2 index put } if } if exch pop exch pop } ifelse + }def /+ { systemdict/languagelevel known { currentglobal false setglobal 3 dict begin /vm exch def } {1 dict begin} ifelse /$ exch def systemdict/languagelevel known { vm setglobal /gvm currentglobal def $ gcheck setglobal } if ?{$ begin}if }def /?{$ type/dicttype eq}def /|{ userdict/Adobe_CoolType_Data known { Adobe_CoolType_Data/AddWidths? known { currentdict Adobe_CoolType_Data begin begin AddWidths? { Adobe_CoolType_Data/CC 3 index put ?{def}{$ 3 1 roll put}ifelse CC charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore currentfont/Widths get exch CC exch put } {?{def}{$ 3 1 roll put}ifelse} ifelse end end } {?{def}{$ 3 1 roll put}ifelse} ifelse } {?{def}{$ 3 1 roll put}ifelse} ifelse }def /! { ?{end}if systemdict/languagelevel known {gvm setglobal} if end }def /:{string currentfile exch readstring pop}executeonly def end ct_MakeOCF begin /ct_cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_CID_STR_SIZE 8000 def /ct_mkocfStr100 100 string def /ct_defaultFontMtx[.001 0 0 .001 0 0]def /ct_1000Mtx[1000 0 0 1000 0 0]def /ct_raise{exch cvx exch errordict exch get exec stop}bind def /ct_reraise {cvx $error/errorname get(Error: )print dup( )cvs print errordict exch get exec stop }bind def /ct_cvnsi { 1 index add 1 sub 1 exch 0 4 1 roll { 2 index exch get exch 8 bitshift add } for exch pop }bind def /ct_GetInterval { Adobe_CoolType_Utility/ct_BuildCharDict get begin /dst_index 0 def dup dst_string length gt {dup string/dst_string exch def} if 1 index ct_CID_STR_SIZE idiv /arrayIndex exch def 2 index arrayIndex get 2 index arrayIndex ct_CID_STR_SIZE mul sub { dup 3 index add 2 index length le { 2 index getinterval dst_string dst_index 2 index putinterval length dst_index add/dst_index exch def exit } { 1 index length 1 index sub dup 4 1 roll getinterval dst_string dst_index 2 index putinterval pop dup dst_index add/dst_index exch def sub /arrayIndex arrayIndex 1 add def 2 index dup length arrayIndex gt {arrayIndex get} { pop exit } ifelse 0 } ifelse } loop pop pop pop dst_string 0 dst_index getinterval end }bind def ct_Level2? { /ct_resourcestatus currentglobal mark true setglobal {/unknowninstancename/Category resourcestatus} stopped {cleartomark setglobal true} {cleartomark currentglobal not exch setglobal} ifelse { { mark 3 1 roll/Category findresource begin ct_Vars/vm currentglobal put ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse ct_Vars/vm get setglobal end } } {{resourcestatus}} ifelse bind def /CIDFont/Category ct_resourcestatus {pop pop} { currentglobal true setglobal /Generic/Category findresource dup length dict copy dup/InstanceType/dicttype put /CIDFont exch/Category defineresource pop setglobal } ifelse ct_UseNativeCapability? { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } if } { /ct_Category 2 dict begin /CIDFont 10 dict def /ProcSet 2 dict def currentdict end def /defineresource { ct_Category 1 index 2 copy known { get dup dup maxlength exch length eq { dup length 10 add dict copy ct_Category 2 index 2 index put } if 3 index 3 index put pop exch pop } {pop pop/defineresource/undefined ct_raise} ifelse }bind def /findresource { ct_Category 1 index 2 copy known { get 2 index 2 copy known {get 3 1 roll pop pop} {pop pop/findresource/undefinedresource ct_raise} ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /resourcestatus { ct_Category 1 index 2 copy known { get 2 index known exch pop exch pop { 0 -1 true } { false } ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /ct_resourcestatus/resourcestatus load def } ifelse /ct_CIDInit 2 dict begin /ct_cidfont_stream_init { { dup(Binary)eq { pop null currentfile ct_Level2? { {cid_BYTE_COUNT()/SubFileDecode filter} stopped {pop pop pop} if } if /readstring load exit } if dup(Hex)eq { pop currentfile ct_Level2? { {null exch/ASCIIHexDecode filter/readstring} stopped {pop exch pop(>)exch/readhexstring} if } {(>)exch/readhexstring} ifelse load exit } if /StartData/typecheck ct_raise } loop cid_BYTE_COUNT ct_CID_STR_SIZE le { 2 copy cid_BYTE_COUNT string exch exec pop 1 array dup 3 -1 roll 0 exch put } { cid_BYTE_COUNT ct_CID_STR_SIZE div ceiling cvi dup array exch 2 sub 0 exch 1 exch { 2 copy 5 index ct_CID_STR_SIZE string 6 index exec pop put pop } for 2 index cid_BYTE_COUNT ct_CID_STR_SIZE mod string 3 index exec pop 1 index exch 1 index length 1 sub exch put } ifelse cid_CIDFONT exch/GlyphData exch put 2 index null eq { pop pop pop } { pop/readstring load 1 string exch { 3 copy exec pop dup length 0 eq { pop pop pop pop pop true exit } if 4 index eq { pop pop pop pop false exit } if } loop pop } ifelse }bind def /StartData { mark { currentdict dup/FDArray get 0 get/FontMatrix get 0 get 0.001 eq { dup/CDevProc known not { /CDevProc 1183615869 internaldict/stdCDevProc 2 copy known {get} { pop pop {pop pop pop pop pop 0 -1000 7 index 2 div 880} } ifelse def } if } { /CDevProc { pop pop pop pop pop 0 1 cid_temp/cid_CIDFONT get /FDArray get 0 get /FontMatrix get 0 get div 7 index 2 div 1 index 0.88 mul }def } ifelse /cid_temp 15 dict def cid_temp begin /cid_CIDFONT exch def 3 copy pop dup/cid_BYTE_COUNT exch def 0 gt { ct_cidfont_stream_init FDArray { /Private get dup/SubrMapOffset known { begin /Subrs SubrCount array def Subrs SubrMapOffset SubrCount SDBytes ct_Level2? { currentdict dup/SubrMapOffset undef dup/SubrCount undef /SDBytes undef } if end /cid_SD_BYTES exch def /cid_SUBR_COUNT exch def /cid_SUBR_MAP_OFFSET exch def /cid_SUBRS exch def cid_SUBR_COUNT 0 gt { GlyphData cid_SUBR_MAP_OFFSET cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi 0 1 cid_SUBR_COUNT 1 sub { exch 1 index 1 add cid_SD_BYTES mul cid_SUBR_MAP_OFFSET add GlyphData exch cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi cid_SUBRS 4 2 roll GlyphData exch 4 index 1 index sub ct_GetInterval dup length string copy put } for pop } if } {pop} ifelse } forall } if cleartomark pop pop end CIDFontName currentdict/CIDFont defineresource pop end end } stopped {cleartomark/StartData ct_reraise} if }bind def currentdict end def /ct_saveCIDInit { /CIDInit/ProcSet ct_resourcestatus {true} {/CIDInitC/ProcSet ct_resourcestatus} ifelse { pop pop /CIDInit/ProcSet findresource ct_UseNativeCapability? {pop null} {/CIDInit ct_CIDInit/ProcSet defineresource pop} ifelse } {/CIDInit ct_CIDInit/ProcSet defineresource pop null} ifelse ct_Vars exch/ct_oldCIDInit exch put }bind def /ct_restoreCIDInit { ct_Vars/ct_oldCIDInit get dup null ne {/CIDInit exch/ProcSet defineresource pop} {pop} ifelse }bind def /ct_BuildCharSetUp { 1 index begin CIDFont begin Adobe_CoolType_Utility/ct_BuildCharDict get begin /ct_dfCharCode exch def /ct_dfDict exch def CIDFirstByte ct_dfCharCode add dup CIDCount ge {pop 0} if /cid exch def { GlyphDirectory cid 2 copy known {get} {pop pop nullstring} ifelse dup length FDBytes sub 0 gt { dup FDBytes 0 ne {0 FDBytes ct_cvnsi} {pop 0} ifelse /fdIndex exch def dup length FDBytes sub FDBytes exch getinterval /charstring exch def exit } { pop cid 0 eq {/charstring nullstring def exit} if /cid 0 def } ifelse } loop }def /ct_SetCacheDevice { 0 0 moveto dup stringwidth 3 -1 roll true charpath pathbbox 0 -1000 7 index 2 div 880 setcachedevice2 0 0 moveto }def /ct_CloneSetCacheProc { 1 eq { stringwidth pop -2 div -880 0 -1000 setcharwidth moveto } { usewidths? { currentfont/Widths get cid 2 copy known {get exch pop aload pop} {pop pop stringwidth} ifelse } {stringwidth} ifelse setcharwidth 0 0 moveto } ifelse }def /ct_Type3ShowCharString { ct_FDDict fdIndex 2 copy known {get} { currentglobal 3 1 roll 1 index gcheck setglobal ct_Type1FontTemplate dup maxlength dict copy begin FDArray fdIndex get dup/FontMatrix 2 copy known {get} {pop pop ct_defaultFontMtx} ifelse /FontMatrix exch dup length array copy def /Private get /Private exch def /Widths rootfont/Widths get def /CharStrings 1 dict dup/.notdef dup length string copy put def currentdict end /ct_Type1Font exch definefont dup 5 1 roll put setglobal } ifelse dup/CharStrings get 1 index/Encoding get ct_dfCharCode get charstring put rootfont/WMode 2 copy known {get} {pop pop 0} ifelse exch 1000 scalefont setfont ct_str1 0 ct_dfCharCode put ct_str1 exch ct_dfSetCacheProc ct_SyntheticBold { currentpoint ct_str1 show newpath moveto ct_str1 true charpath ct_StrokeWidth setlinewidth stroke } {ct_str1 show} ifelse }def /ct_Type4ShowCharString { ct_dfDict ct_dfCharCode charstring FDArray fdIndex get dup/FontMatrix get dup ct_defaultFontMtx ct_matrixeq not {ct_1000Mtx matrix concatmatrix concat} {pop} ifelse /Private get Adobe_CoolType_Utility/ct_Level2? get not { ct_dfDict/Private 3 -1 roll {put} 1183615869 internaldict/superexec get exec } if 1183615869 internaldict Adobe_CoolType_Utility/ct_Level2? get {1 index} {3 index/Private get mark 6 1 roll} ifelse dup/RunInt known {/RunInt get} {pop/CCRun} ifelse get exec Adobe_CoolType_Utility/ct_Level2? get not {cleartomark} if }bind def /ct_BuildCharIncremental { { Adobe_CoolType_Utility/ct_MakeOCF get begin ct_BuildCharSetUp ct_ShowCharString } stopped {stop} if end end end end }bind def /BaseFontNameStr(BF00)def /ct_Type1FontTemplate 14 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /PaintType 0 def currentdict end def /BaseFontTemplate 11 dict begin /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /BuildChar/ct_BuildCharIncremental load def ct_Clone? { /FontType 3 def /ct_ShowCharString/ct_Type3ShowCharString load def /ct_dfSetCacheProc/ct_CloneSetCacheProc load def /ct_SyntheticBold false def /ct_StrokeWidth 1 def } { /FontType 4 def /Private 1 dict dup/lenIV 4 put def /CharStrings 1 dict dup/.notdefput def /PaintType 0 def /ct_ShowCharString/ct_Type4ShowCharString load def } ifelse /ct_str1 1 string def currentdict end def /BaseFontDictSize BaseFontTemplate length 5 add def /ct_matrixeq { true 0 1 5 { dup 4 index exch get exch 3 index exch get eq and dup not {exit} if } for exch pop exch pop }bind def /ct_makeocf { 15 dict begin exch/WMode exch def exch/FontName exch def /FontType 0 def /FMapType 2 def dup/FontMatrix known {dup/FontMatrix get/FontMatrix exch def} {/FontMatrix matrix def} ifelse /bfCount 1 index/CIDCount get 256 idiv 1 add dup 256 gt{pop 256}if def /Encoding 256 array 0 1 bfCount 1 sub{2 copy dup put pop}for bfCount 1 255{2 copy bfCount put pop}for def /FDepVector bfCount dup 256 lt{1 add}if array def BaseFontTemplate BaseFontDictSize dict copy begin /CIDFont exch def CIDFont/FontBBox known {CIDFont/FontBBox get/FontBBox exch def} if CIDFont/CDevProc known {CIDFont/CDevProc get/CDevProc exch def} if currentdict end BaseFontNameStr 3(0)putinterval 0 1 bfCount dup 256 eq{1 sub}if { FDepVector exch 2 index BaseFontDictSize dict copy begin dup/CIDFirstByte exch 256 mul def FontType 3 eq {/ct_FDDict 2 dict def} if currentdict end 1 index 16 BaseFontNameStr 2 2 getinterval cvrs pop BaseFontNameStr exch definefont put } for ct_Clone? {/Widths 1 index/CIDFont get/GlyphDirectory get length dict def} if FontName currentdict end definefont ct_Clone? { gsave dup 1000 scalefont setfont ct_BuildCharDict begin /usewidths? false def currentfont/Widths get begin exch/CIDFont get/GlyphDirectory get { pop dup charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore def } forall end /usewidths? true def end grestore } {exch pop} ifelse }bind def currentglobal true setglobal /ct_ComposeFont { ct_UseNativeCapability? { 2 index/CMap ct_resourcestatus {pop pop exch pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 3 index def /CMapVersion 1.000 def /CMapType 1 def exch/WMode exch def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search { dup length string copy exch pop exch pop } {pop(Identity)} ifelse } {pop (Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { 3 2 roll pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def setglobal /ct_MakeIdentity { ct_UseNativeCapability? { 1 index/CMap ct_resourcestatus {pop pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 2 index def /CMapVersion 1.000 def /CMapType 1 def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search {dup length string copy exch pop exch pop} {pop(Identity)} ifelse } {pop(Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { exch pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def currentdict readonly pop end end %%EndResource setglobal %%BeginResource: procset Adobe_CoolType_Utility_T42 1.0 0 %%Copyright: Copyright 1987-2004 Adobe Systems Incorporated. %%Version: 1.0 0 userdict/ct_T42Dict 15 dict put ct_T42Dict begin /Is2015? { version cvi 2015 ge }bind def /AllocGlyphStorage { Is2015? { pop } { {string}forall }ifelse }bind def /Type42DictBegin { 25 dict begin /FontName exch def /CharStrings 256 dict begin /.notdef 0 def currentdict end def /Encoding exch def /PaintType 0 def /FontType 42 def /FontMatrix[1 0 0 1 0 0]def 4 array astore cvx/FontBBox exch def /sfnts }bind def /Type42DictEnd { currentdict dup/FontName get exch definefont end ct_T42Dict exch dup/FontName get exch put }bind def /RD{string currentfile exch readstring pop}executeonly def /PrepFor2015 { Is2015? { /GlyphDirectory 16 dict def sfnts 0 get dup 2 index (glyx) putinterval 2 index (locx) putinterval pop pop } { pop pop }ifelse }bind def /AddT42Char { Is2015? { /GlyphDirectory get begin def end pop pop } { /sfnts get 4 index get 3 index 2 index putinterval pop pop pop pop }ifelse }bind def /T0AddT42Mtx2 { /CIDFont findresource/Metrics2 get begin def end }bind def end %%EndResource currentglobal true setglobal %%BeginFile: MMFauxFont.prc %%Copyright: Copyright 1987-2001 Adobe Systems Incorporated. %%All Rights Reserved. userdict /ct_EuroDict 10 dict put ct_EuroDict begin /ct_CopyFont { { 1 index /FID ne {def} {pop pop} ifelse} forall } def /ct_GetGlyphOutline { gsave initmatrix newpath exch findfont dup length 1 add dict begin ct_CopyFont /Encoding Encoding dup length array copy dup 4 -1 roll 0 exch put def currentdict end /ct_EuroFont exch definefont 1000 scalefont setfont 0 0 moveto [ <00> stringwidth <00> false charpath pathbbox [ {/m cvx} {/l cvx} {/c cvx} {/cp cvx} pathforall grestore counttomark 8 add } def /ct_MakeGlyphProc { ] cvx /ct_PSBuildGlyph cvx ] cvx } def /ct_PSBuildGlyph { gsave 8 -1 roll pop 7 1 roll 6 -2 roll ct_FontMatrix transform 6 2 roll 4 -2 roll ct_FontMatrix transform 4 2 roll ct_FontMatrix transform currentdict /PaintType 2 copy known {get 2 eq}{pop pop false} ifelse dup 9 1 roll { currentdict /StrokeWidth 2 copy known { get 2 div 0 ct_FontMatrix dtransform pop 5 1 roll 4 -1 roll 4 index sub 4 1 roll 3 -1 roll 4 index sub 3 1 roll exch 4 index add exch 4 index add 5 -1 roll pop } { pop pop } ifelse } if setcachedevice ct_FontMatrix concat ct_PSPathOps begin exec end { currentdict /StrokeWidth 2 copy known { get } { pop pop 0 } ifelse setlinewidth stroke } { fill } ifelse grestore } def /ct_PSPathOps 4 dict dup begin /m {moveto} def /l {lineto} def /c {curveto} def /cp {closepath} def end def /ct_matrix1000 [1000 0 0 1000 0 0] def /ct_AddGlyphProc { 2 index findfont dup length 4 add dict begin ct_CopyFont /CharStrings CharStrings dup length 1 add dict copy begin 3 1 roll def currentdict end def /ct_FontMatrix ct_matrix1000 FontMatrix matrix concatmatrix def /ct_PSBuildGlyph /ct_PSBuildGlyph load def /ct_PSPathOps /ct_PSPathOps load def currentdict end definefont pop } def systemdict /languagelevel known { /ct_AddGlyphToPrinterFont { 2 copy ct_GetGlyphOutline 3 add -1 roll restore ct_MakeGlyphProc ct_AddGlyphProc } def } { /ct_AddGlyphToPrinterFont { pop pop restore Adobe_CTFauxDict /$$$FONTNAME get /Euro Adobe_CTFauxDict /$$$SUBSTITUTEBASE get ct_EuroDict exch get ct_AddGlyphProc } def } ifelse /AdobeSansMM { 556 0 24 -19 541 703 { 541 628 m 510 669 442 703 354 703 c 201 703 117 607 101 444 c 50 444 l 25 372 l 97 372 l 97 301 l 49 301 l 24 229 l 103 229 l 124 67 209 -19 350 -19 c 435 -19 501 25 509 32 c 509 131 l 492 105 417 60 343 60 c 267 60 204 127 197 229 c 406 229 l 430 301 l 191 301 l 191 372 l 455 372 l 479 444 l 194 444 l 201 531 245 624 348 624 c 433 624 484 583 509 534 c cp 556 0 m } ct_PSBuildGlyph } def /AdobeSerifMM { 500 0 10 -12 484 692 { 347 298 m 171 298 l 170 310 170 322 170 335 c 170 362 l 362 362 l 374 403 l 172 403 l 184 580 244 642 308 642 c 380 642 434 574 457 457 c 481 462 l 474 691 l 449 691 l 433 670 429 657 410 657 c 394 657 360 692 299 692 c 204 692 94 604 73 403 c 22 403 l 10 362 l 70 362 l 69 352 69 341 69 330 c 69 319 69 308 70 298 c 22 298 l 10 257 l 73 257 l 97 57 216 -12 295 -12 c 364 -12 427 25 484 123 c 458 142 l 425 101 384 37 316 37 c 256 37 189 84 173 257 c 335 257 l cp 500 0 m } ct_PSBuildGlyph } def end %%EndFile setglobal Adobe_CoolType_Core begin /$Oblique SetSubstituteStrategy end %%BeginResource: procset Adobe_AGM_Image 1.0 0 +%%Version: 1.0 0 +%%Copyright: Copyright(C)2000-2006 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Image 71 dict dup begin put +/Adobe_AGM_Image_Id/Adobe_AGM_Image_1.0_0 def +/nd{ + null def +}bind def +/AGMIMG_&image nd +/AGMIMG_&colorimage nd +/AGMIMG_&imagemask nd +/AGMIMG_mbuf()def +/AGMIMG_ybuf()def +/AGMIMG_kbuf()def +/AGMIMG_c 0 def +/AGMIMG_m 0 def +/AGMIMG_y 0 def +/AGMIMG_k 0 def +/AGMIMG_tmp nd +/AGMIMG_imagestring0 nd +/AGMIMG_imagestring1 nd +/AGMIMG_imagestring2 nd +/AGMIMG_imagestring3 nd +/AGMIMG_imagestring4 nd +/AGMIMG_imagestring5 nd +/AGMIMG_cnt nd +/AGMIMG_fsave nd +/AGMIMG_colorAry nd +/AGMIMG_override nd +/AGMIMG_name nd +/AGMIMG_maskSource nd +/AGMIMG_flushfilters nd +/invert_image_samples nd +/knockout_image_samples nd +/img nd +/sepimg nd +/devnimg nd +/idximg nd +/ds +{ + Adobe_AGM_Core begin + Adobe_AGM_Image begin + /AGMIMG_&image systemdict/image get def + /AGMIMG_&imagemask systemdict/imagemask get def + /colorimage where{ + pop + /AGMIMG_&colorimage/colorimage ldf + }if + end + end +}def +/ps +{ + Adobe_AGM_Image begin + /AGMIMG_ccimage_exists{/customcolorimage where + { + pop + /Adobe_AGM_OnHost_Seps where + { + pop false + }{ + /Adobe_AGM_InRip_Seps where + { + pop false + }{ + true + }ifelse + }ifelse + }{ + false + }ifelse + }bdf + level2{ + /invert_image_samples + { + Adobe_AGM_Image/AGMIMG_tmp Decode length ddf + /Decode[Decode 1 get Decode 0 get]def + }def + /knockout_image_samples + { + Operator/imagemask ne{ + /Decode[1 1]def + }if + }def + }{ + /invert_image_samples + { + {1 exch sub}currenttransfer addprocs settransfer + }def + /knockout_image_samples + { + {pop 1}currenttransfer addprocs settransfer + }def + }ifelse + /img/imageormask ldf + /sepimg/sep_imageormask ldf + /devnimg/devn_imageormask ldf + /idximg/indexed_imageormask ldf + /_ctype 7 def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall +}def +/pt +{ + end +}def +/dt +{ +}def +/AGMIMG_flushfilters +{ + dup type/arraytype ne + {1 array astore}if + dup 0 get currentfile ne + {dup 0 get flushfile}if + { + dup type/filetype eq + { + dup status 1 index currentfile ne and + {closefile} + {pop} + ifelse + }{pop}ifelse + }forall +}def +/AGMIMG_init_common +{ + currentdict/T known{/ImageType/T ldf currentdict/T undef}if + currentdict/W known{/Width/W ldf currentdict/W undef}if + currentdict/H known{/Height/H ldf currentdict/H undef}if + currentdict/M known{/ImageMatrix/M ldf currentdict/M undef}if + currentdict/BC known{/BitsPerComponent/BC ldf currentdict/BC undef}if + currentdict/D known{/Decode/D ldf currentdict/D undef}if + currentdict/DS known{/DataSource/DS ldf currentdict/DS undef}if + currentdict/O known{ + /Operator/O load 1 eq{ + /imagemask + }{ + /O load 2 eq{ + /image + }{ + /colorimage + }ifelse + }ifelse + def + currentdict/O undef + }if + currentdict/HSCI known{/HostSepColorImage/HSCI ldf currentdict/HSCI undef}if + currentdict/MD known{/MultipleDataSources/MD ldf currentdict/MD undef}if + currentdict/I known{/Interpolate/I ldf currentdict/I undef}if + currentdict/SI known{/SkipImageProc/SI ldf currentdict/SI undef}if + /DataSource load xcheck not{ + DataSource type/arraytype eq{ + DataSource 0 get type/filetype eq{ + /_Filters DataSource def + currentdict/MultipleDataSources known not{ + /DataSource DataSource dup length 1 sub get def + }if + }if + }if + currentdict/MultipleDataSources known not{ + /MultipleDataSources DataSource type/arraytype eq{ + DataSource length 1 gt + } + {false}ifelse def + }if + }if + /NComponents Decode length 2 div def + currentdict/SkipImageProc known not{/SkipImageProc{false}def}if +}bdf +/imageormask_sys +{ + begin + AGMIMG_init_common + save mark + level2{ + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + AGMIMG_&imagemask + }{ + BitsPerComponent ImageMatrix/DataSource load + AGMIMG_&image + }ifelse + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + cleartomark restore + end +}def +/overprint_plate +{ + currentoverprint{ + 0 get dup type/nametype eq{ + dup/DeviceGray eq{ + pop AGMCORE_black_plate not + }{ + /DeviceCMYK eq{ + AGMCORE_is_cmyk_sep not + }if + }ifelse + }{ + false exch + { + AGMOHS_sepink eq or + }forall + not + }ifelse + }{ + pop false + }ifelse +}def +/process_mask +{ + level3{ + dup begin + /ImageType 1 def + end + 4 dict begin + /DataDict exch def + /ImageType 3 def + /InterleaveType 3 def + /MaskDict 9 dict begin + /ImageType 1 def + /Width DataDict dup/MaskWidth known{/MaskWidth}{/Width}ifelse get def + /Height DataDict dup/MaskHeight known{/MaskHeight}{/Height}ifelse get def + /ImageMatrix[Width 0 0 Height neg 0 Height]def + /NComponents 1 def + /BitsPerComponent 1 def + /Decode DataDict dup/MaskD known{/MaskD}{[1 0]}ifelse get def + /DataSource Adobe_AGM_Core/AGMIMG_maskSource get def + currentdict end def + currentdict end + }if +}def +/use_mask +{ + dup/Mask known {dup/Mask get}{false}ifelse +}def +/imageormask +{ + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + } + { + save mark + level2 AGMCORE_host_sep not and{ + currentdict + Operator/imagemask eq DeviceN_PS2 not and{ + imagemask + }{ + AGMCORE_in_rip_sep currentoverprint and currentcolorspace 0 get/DeviceGray eq and{ + [/Separation/Black/DeviceGray{}]setcolorspace + /Decode[Decode 1 get Decode 0 get]def + }if + use_mask{ + process_mask image + }{ + DeviceN_NoneName DeviceN_PS2 Indexed_DeviceN level3 not and or or AGMCORE_in_rip_sep and + { + Names convert_to_process not{ + 2 dict begin + /imageDict xdf + /names_index 0 def + gsave + imageDict write_image_file{ + Names{ + dup(None)ne{ + [/Separation 3 -1 roll/DeviceGray{1 exch sub}]setcolorspace + Operator imageDict read_image_file + names_index 0 eq{true setoverprint}if + /names_index names_index 1 add def + }{ + pop + }ifelse + }forall + close_image_file + }if + grestore + end + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + /Adobe_AGM_OnHost_Seps where{ + pop imagemask + }{ + currentgray 1 ne{ + currentdict imageormask_sys + }{ + currentoverprint not{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }ifelse + }{ + BitsPerComponent ImageMatrix + MultipleDataSources{ + 0 1 NComponents 1 sub{ + DataSource exch get + }for + }{ + /DataSource load + }ifelse + Operator/colorimage eq{ + AGMCORE_host_sep{ + MultipleDataSources level2 or NComponents 4 eq and{ + AGMCORE_is_cmyk_sep{ + MultipleDataSources{ + /DataSource DataSource 0 get xcheck + { + [ + DataSource 0 get/exec cvx + DataSource 1 get/exec cvx + DataSource 2 get/exec cvx + DataSource 3 get/exec cvx + /AGMCORE_get_ink_data cvx + ]cvx + }{ + DataSource aload pop AGMCORE_get_ink_data + }ifelse def + }{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + /DataSource load + filter_cmyk 0()/SubFileDecode filter def + }ifelse + /Decode[Decode 0 get Decode 1 get]def + /MultipleDataSources false def + /NComponents 1 def + /Operator/image def + invert_image_samples + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }{ + MultipleDataSources NComponents AGMIMG_&colorimage + }ifelse + }{ + true NComponents colorimage + }ifelse + }{ + Operator/image eq{ + AGMCORE_host_sep{ + /DoImage true def + currentdict/HostSepColorImage known{HostSepColorImage not}{false}ifelse + { + AGMCORE_black_plate not Operator/imagemask ne and{ + /DoImage false def + currentdict ignoreimagedata + }if + }if + 1 AGMCORE_&setgray + DoImage + {currentdict imageormask_sys}if + }{ + use_mask{ + process_mask image + }{ + image + }ifelse + }ifelse + }{ + Operator/knockout eq{ + pop pop pop pop pop + currentcolorspace overprint_plate not{ + knockout_unitsq + }if + }if + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/sep_imageormask +{ + /sep_colorspace_dict AGMCORE_gget begin + CSA map_csa + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_avoid_L2_sep_space{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + }if + AGMIMG_ccimage_exists + MappedCSA 0 get/DeviceCMYK eq and + currentdict/Components known and + Name()ne and + Name(All)ne and + Operator/image eq and + AGMCORE_producing_seps not and + level2 not and + { + Width Height BitsPerComponent ImageMatrix + [ + /DataSource load/exec cvx + { + 0 1 2 index length 1 sub{ + 1 index exch + 2 copy get 255 xor put + }for + }/exec cvx + ]cvx bind + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Name findcmykcustomcolor + customcolorimage + }{ + AGMCORE_producing_seps not{ + level2{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne AGMCORE_avoid_L2_sep_space not and currentcolorspace 0 get/Separation ne and{ + [/Separation Name MappedCSA sep_proc_name exch dup 0 get 15 string cvs(/Device)anchorsearch{pop pop 0 get}{pop}ifelse exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + currentdict imageormask + }{ + currentdict + Operator/imagemask eq{ + imageormask + }{ + sep_imageormask_lev1 + }ifelse + }ifelse + }{ + AGMCORE_host_sep{ + Operator/knockout eq{ + currentdict/ImageMatrix get concat + knockout_unitsq + }{ + currentgray 1 ne{ + AGMCORE_is_cmyk_sep Name(All)ne and{ + level2{ + Name AGMCORE_IsSeparationAProcessColor + { + Operator/imagemask eq{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + /sep_tint AGMCORE_gget 1 exch sub AGMCORE_&setcolor + }if + }{ + invert_image_samples + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + [/Separation Name[/DeviceGray] + { + sep_colorspace_proc AGMCORE_get_ink_data + 1 exch sub + }bind + ]AGMCORE_&setcolorspace + /sep_tint AGMCORE_gget AGMCORE_&setcolor + }if + }ifelse + currentdict imageormask_sys + }{ + currentdict + Operator/imagemask eq{ + imageormask_sys + }{ + sep_image_lev1_sep + }ifelse + }ifelse + }{ + Operator/imagemask ne{ + invert_image_samples + }if + currentdict imageormask_sys + }ifelse + }{ + currentoverprint not Name(All)eq or Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + currentcolorspace 0 get/Separation ne{ + [/Separation Name MappedCSA sep_proc_name exch 0 get exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + }if + currentoverprint + MappedCSA 0 get/DeviceCMYK eq and + Name AGMCORE_IsSeparationAProcessColor not and + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{Name inRip_spot_has_ink not and}{false}ifelse + Name(All)ne and{ + imageormask_l2_overprint + }{ + currentdict imageormask + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end +}def +/colorSpaceElemCnt +{ + mark currentcolor counttomark dup 2 add 1 roll cleartomark +}bdf +/devn_sep_datasource +{ + 1 dict begin + /dataSource xdf + [ + 0 1 dataSource length 1 sub{ + dup currentdict/dataSource get/exch cvx/get cvx/exec cvx + /exch cvx names_index/ne cvx[/pop cvx]cvx/if cvx + }for + ]cvx bind + end +}bdf +/devn_alt_datasource +{ + 11 dict begin + /convProc xdf + /origcolorSpaceElemCnt xdf + /origMultipleDataSources xdf + /origBitsPerComponent xdf + /origDecode xdf + /origDataSource xdf + /dsCnt origMultipleDataSources{origDataSource length}{1}ifelse def + /DataSource origMultipleDataSources + { + [ + BitsPerComponent 8 idiv origDecode length 2 idiv mul string + 0 1 origDecode length 2 idiv 1 sub + { + dup 7 mul 1 add index exch dup BitsPerComponent 8 idiv mul exch + origDataSource exch get 0()/SubFileDecode filter + BitsPerComponent 8 idiv string/readstring cvx/pop cvx/putinterval cvx + }for + ]bind cvx + }{origDataSource}ifelse 0()/SubFileDecode filter def + [ + origcolorSpaceElemCnt string + 0 2 origDecode length 2 sub + { + dup origDecode exch get dup 3 -1 roll 1 add origDecode exch get exch sub 2 BitsPerComponent exp 1 sub div + 1 BitsPerComponent 8 idiv{DataSource/read cvx/not cvx{0}/if cvx/mul cvx}repeat/mul cvx/add cvx + }for + /convProc load/exec cvx + origcolorSpaceElemCnt 1 sub -1 0 + { + /dup cvx 2/add cvx/index cvx + 3 1/roll cvx/exch cvx 255/mul cvx/cvi cvx/put cvx + }for + ]bind cvx 0()/SubFileDecode filter + end +}bdf +/devn_imageormask +{ + /devicen_colorspace_dict AGMCORE_gget begin + CSA map_csa + 2 dict begin + dup + /srcDataStrs[3 -1 roll begin + AGMIMG_init_common + currentdict/MultipleDataSources known{MultipleDataSources{DataSource length}{1}ifelse}{1}ifelse + { + Width Decode length 2 div mul cvi + { + dup 65535 gt{1 add 2 div cvi}{exit}ifelse + }loop + string + }repeat + end]def + /dstDataStr srcDataStrs 0 get length string def + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_producing_seps not{ + level3 not{ + Operator/imagemask ne{ + /DataSource[[ + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + colorSpaceElemCnt/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource 1/string cvx/readstring cvx/pop cvx]cvx colorSpaceElemCnt 1 sub{dup}repeat]def + /MultipleDataSources true def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + }if + }if + currentdict imageormask + }{ + AGMCORE_host_sep{ + Names convert_to_process{ + CSA get_csa_by_name 0 get/DeviceCMYK eq{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + 4/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + filter_cmyk 0()/SubFileDecode filter def + /MultipleDataSources false def + /Decode[1 0]def + /DeviceGray setcolorspace + currentdict imageormask_sys + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate{ + /DataSource + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + CSA get_csa_by_name 0 get/DeviceRGB eq{3}{1}ifelse/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + /MultipleDataSources false def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + currentdict imageormask_sys + }{ + gsave + knockout_unitsq + grestore + currentdict consumeimagedata + }ifelse + }ifelse + } + { + /devicen_colorspace_dict AGMCORE_gget/names_index known{ + Operator/imagemask ne{ + MultipleDataSources{ + /DataSource[DataSource devn_sep_datasource/exec cvx]cvx def + /MultipleDataSources false def + }{ + /DataSource/DataSource load dstDataStr srcDataStrs 0 get filter_devn def + }ifelse + invert_image_samples + }if + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + currentdict imageormask + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end + end +}def +/imageormask_l2_overprint +{ + currentdict + currentcmykcolor add add add 0 eq{ + currentdict consumeimagedata + }{ + level3{ + currentcmykcolor + /AGMIMG_k xdf + /AGMIMG_y xdf + /AGMIMG_m xdf + /AGMIMG_c xdf + Operator/imagemask eq{ + [/DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ]/DeviceCMYK{}]setcolorspace + AGMIMG_c 0 ne{AGMIMG_c}if + AGMIMG_m 0 ne{AGMIMG_m}if + AGMIMG_y 0 ne{AGMIMG_y}if + AGMIMG_k 0 ne{AGMIMG_k}if + setcolor + }{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + [/Indexed + [ + /DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ] + /DeviceCMYK{ + AGMIMG_k 0 eq{0}if + AGMIMG_y 0 eq{0 exch}if + AGMIMG_m 0 eq{0 3 1 roll}if + AGMIMG_c 0 eq{0 4 1 roll}if + } + ] + 255 + { + 255 div + mark exch + dup dup dup + AGMIMG_k 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 1 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_y 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 2 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_m 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 3 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_c 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + counttomark 1 add -1 roll pop + } + ]setcolorspace + }ifelse + imageormask_sys + }{ + write_image_file{ + currentcmykcolor + 0 ne{ + [/Separation/Black/DeviceGray{}]setcolorspace + gsave + /Black + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 1 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Yellow/DeviceGray{}]setcolorspace + gsave + /Yellow + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 2 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Magenta/DeviceGray{}]setcolorspace + gsave + /Magenta + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 3 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Cyan/DeviceGray{}]setcolorspace + gsave + /Cyan + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + close_image_file + }{ + imageormask + }ifelse + }ifelse + }ifelse +}def +/indexed_imageormask +{ + begin + AGMIMG_init_common + save mark + currentdict + AGMCORE_host_sep{ + Operator/knockout eq{ + /indexed_colorspace_dict AGMCORE_gget dup/CSA known{ + /CSA get get_csa_by_name + }{ + /Names get + }ifelse + overprint_plate not{ + knockout_unitsq + }if + }{ + Indexed_DeviceN{ + /devicen_colorspace_dict AGMCORE_gget dup/names_index known exch/Names get convert_to_process or{ + indexed_image_lev2_sep + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }{ + AGMCORE_is_cmyk_sep{ + Operator/imagemask eq{ + imageormask_sys + }{ + level2{ + indexed_image_lev2_sep + }{ + indexed_image_lev1_sep + }ifelse + }ifelse + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + level2{ + Indexed_DeviceN{ + /indexed_colorspace_dict AGMCORE_gget begin + }{ + /indexed_colorspace_dict AGMCORE_gget dup null ne + { + begin + currentdict/CSDBase known{CSDBase/CSD get_res/MappedCSA get}{CSA}ifelse + get_csa_by_name 0 get/DeviceCMYK eq ps_level 3 ge and ps_version 3015.007 lt and + AGMCORE_in_rip_sep and{ + [/Indexed[/DeviceN[/Cyan/Magenta/Yellow/Black]/DeviceCMYK{}]HiVal Lookup] + setcolorspace + }if + end + } + {pop}ifelse + }ifelse + imageormask + Indexed_DeviceN{ + end + }if + }{ + Operator/imagemask eq{ + imageormask + }{ + indexed_imageormask_lev1 + }ifelse + }ifelse + }ifelse + cleartomark restore + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/indexed_image_lev2_sep +{ + /indexed_colorspace_dict AGMCORE_gget begin + begin + Indexed_DeviceN not{ + currentcolorspace + dup 1/DeviceGray put + dup 3 + currentcolorspace 2 get 1 add string + 0 1 2 3 AGMCORE_get_ink_data 4 currentcolorspace 3 get length 1 sub + { + dup 4 idiv exch currentcolorspace 3 get exch get 255 exch sub 2 index 3 1 roll put + }for + put setcolorspace + }if + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + end end +}def + /OPIimage + { + dup type/dicttype ne{ + 10 dict begin + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /ImageType 1 def + /Decode[0 1 def] + currentdict + end + }if + dup begin + /NComponents 1 cdndf + /MultipleDataSources false cdndf + /SkipImageProc{false}cdndf + /Decode[ + 0 + currentcolorspace 0 get/Indexed eq{ + 2 BitsPerComponent exp 1 sub + }{ + 1 + }ifelse + ]cdndf + /Operator/image cdndf + end + /sep_colorspace_dict AGMCORE_gget null eq{ + imageormask + }{ + gsave + dup begin invert_image_samples end + sep_imageormask + grestore + }ifelse + }def +/cachemask_level2 +{ + 3 dict begin + /LZWEncode filter/WriteFilter xdf + /readBuffer 256 string def + /ReadFilter + currentfile + 0(%EndMask)/SubFileDecode filter + /ASCII85Decode filter + /RunLengthDecode filter + def + { + ReadFilter readBuffer readstring exch + WriteFilter exch writestring + not{exit}if + }loop + WriteFilter closefile + end +}def +/spot_alias +{ + /mapto_sep_imageormask + { + dup type/dicttype ne{ + 12 dict begin + /ImageType 1 def + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /MultipleDataSources false def + }{ + begin + }ifelse + /Decode[/customcolor_tint AGMCORE_gget 0]def + /Operator/image def + /SkipImageProc{false}def + currentdict + end + sep_imageormask + }bdf + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_colorAry xddf + /customcolor_tint AGMCORE_gget + << + /Name AGMIMG_colorAry 4 get + /CSA[/DeviceCMYK] + /TintMethod/Subtractive + /TintProc null + /MappedCSA null + /NComponents 4 + /Components[AGMIMG_colorAry aload pop pop] + >> + setsepcolorspace + mapto_sep_imageormask + }ndf + Adobe_AGM_Image/AGMIMG_&customcolorimage/customcolorimage load put + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_override false put + current_spot_alias{dup 4 get map_alias}{false}ifelse + { + false set_spot_alias + /customcolor_tint AGMCORE_gget exch setsepcolorspace + pop + mapto_sep_imageormask + true set_spot_alias + }{ + //Adobe_AGM_Image/AGMIMG_&customcolorimage get exec + }ifelse + }bdf +}def +/snap_to_device +{ + 6 dict begin + matrix currentmatrix + dup 0 get 0 eq 1 index 3 get 0 eq and + 1 index 1 get 0 eq 2 index 2 get 0 eq and or exch pop + { + 1 1 dtransform 0 gt exch 0 gt/AGMIMG_xSign? exch def/AGMIMG_ySign? exch def + 0 0 transform + AGMIMG_ySign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + AGMIMG_xSign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + itransform/AGMIMG_llY exch def/AGMIMG_llX exch def + 1 1 transform + AGMIMG_ySign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + AGMIMG_xSign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + itransform/AGMIMG_urY exch def/AGMIMG_urX exch def + [AGMIMG_urX AGMIMG_llX sub 0 0 AGMIMG_urY AGMIMG_llY sub AGMIMG_llX AGMIMG_llY]concat + }{ + }ifelse + end +}def +level2 not{ + /colorbuf + { + 0 1 2 index length 1 sub{ + dup 2 index exch get + 255 exch sub + 2 index + 3 1 roll + put + }for + }def + /tint_image_to_color + { + begin + Width Height BitsPerComponent ImageMatrix + /DataSource load + end + Adobe_AGM_Image begin + /AGMIMG_mbuf 0 string def + /AGMIMG_ybuf 0 string def + /AGMIMG_kbuf 0 string def + { + colorbuf dup length AGMIMG_mbuf length ne + { + dup length dup dup + /AGMIMG_mbuf exch string def + /AGMIMG_ybuf exch string def + /AGMIMG_kbuf exch string def + }if + dup AGMIMG_mbuf copy AGMIMG_ybuf copy AGMIMG_kbuf copy pop + } + addprocs + {AGMIMG_mbuf}{AGMIMG_ybuf}{AGMIMG_kbuf}true 4 colorimage + end + }def + /sep_imageormask_lev1 + { + begin + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + { + 255 mul round cvi GrayLookup exch get + }currenttransfer addprocs settransfer + currentdict imageormask + }{ + /sep_colorspace_dict AGMCORE_gget/Components known{ + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + AGMIMG_y 0.0 eq AGMIMG_m 0.0 eq and AGMIMG_c 0.0 eq and{ + {AGMIMG_k mul 1 exch sub}currenttransfer addprocs settransfer + currentdict imageormask + }{ + currentcolortransfer + {AGMIMG_k mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_y mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_m mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_c mul 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }{ + MappedCSA 0 get/DeviceGray eq{ + {255 mul round cvi ColorLookup exch get 0 get}currenttransfer addprocs settransfer + currentdict imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + /sep_image_lev1_sep + { + begin + /sep_colorspace_dict AGMCORE_gget/Components known{ + Components aload pop + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + {AGMIMG_c mul 1 exch sub} + {AGMIMG_m mul 1 exch sub} + {AGMIMG_y mul 1 exch sub} + {AGMIMG_k mul 1 exch sub} + }{ + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} + }ifelse + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end + }def + /indexed_imageormask_lev1 + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + currentdict + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + {HiVal mul round cvi GrayLookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceGray eq{ + {HiVal mul round cvi Lookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 2 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 1 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi Lookup exch get HiVal div}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }ifelse + }ifelse + }ifelse + end end + }def + /indexed_image_lev1_sep + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end end + }def +}if +end +systemdict/setpacking known +{setpacking}if +%%EndResource +currentdict Adobe_AGM_Utils eq {end} if +%%EndProlog +%%BeginSetup +Adobe_AGM_Utils begin +2 2010 Adobe_AGM_Core/ds gx +Adobe_CoolType_Core/ds get exec Adobe_AGM_Image/ds gx +currentdict Adobe_AGM_Utils eq {end} if +%%EndSetup +%%Page: 1 1 +%%EndPageComments +%%BeginPageSetup +%ADOBeginClientInjection: PageSetup Start "AI11EPS" +%AI12_RMC_Transparency: Balance=75 RasterRes=300 GradRes=150 Text=0 Stroke=1 Clip=1 OP=0 +%ADOEndClientInjection: PageSetup Start "AI11EPS" +Adobe_AGM_Utils begin +Adobe_AGM_Core/ps gx +Adobe_AGM_Utils/capture_cpd gx +Adobe_CoolType_Core/ps get exec Adobe_AGM_Image/ps gx +%ADOBeginClientInjection: PageSetup End "AI11EPS" +/currentdistillerparams where {pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse { userdict /AI11_PDFMark5 /cleartomark load put userdict /AI11_ReadMetadata_PDFMark5 {flushfile cleartomark } bind put} { userdict /AI11_PDFMark5 /pdfmark load put userdict /AI11_ReadMetadata_PDFMark5 {/PUT pdfmark} bind put } ifelse [/NamespacePush AI11_PDFMark5 [/_objdef {ai_metadata_stream_123} /type /stream /OBJ AI11_PDFMark5 [{ai_metadata_stream_123} currentfile 0 (% &&end XMP packet marker&&) /SubFileDecode filter AI11_ReadMetadata_PDFMark5 + + + + application/postscript + + + Print + + + 2014-02-05T13:25:58-08:00 + 2014-02-05T13:25:58-08:00 + 2014-02-05T13:25:58-08:00 + Adobe Illustrator CC (Macintosh) + + + + 256 + 244 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA9AEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYqhpKfpKAbV9Gam+/wBuLoPDJD6T+O9ieaJyLJ2KuxV2KuxV5l+YX/OQv5feTJpb GS4fVdYiJV9PsaOY2HaWUkRp7ipYeGKvGtW/5zJ82STMdI0CwtYf2Fu3muW+kxtbD8MUoW1/5zG/ MBZAbvR9JlirusSXMTU/1mmlH4Yq9M8k/wDOWPkbWpY7TX7eXy/dPsJpG9e0r7yqFda/5SUHjitP bLa5t7q3jubaVJ7eZQ8M0bB0dGFQystQQR0IxQqYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYqh3J/SMA7ejL22+1H3yQ+k/jvY9URkWTsVdirsVfMf/ORX/OQF3Fd3XkvylcNB 6BMOs6rEaOXGzW0LD7PHo7jevwilDVS+bJrDUI7aO8mtpUtriphuHRgklCQeLkUbcdsVQ+KuxVXs 7G9vpxb2VvLdTtuIoUaRyP8AVUE4q9N/Jb879Y/L7VFsb8y3nled6XdgTV4GJ3mtw32WH7SdG+dC FX23p+oWWo2Fvf2My3FndxrNbzoaq8bjkrD5g4oRGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxVDSD/clAdv7mbvv9qLtkh9J/HexPNE5Fk7FXYqwL88PPUvkv8utR1S1fhqVxxst Nan2Z5wRzHvGis49xir4GZmdizEszGrMdySe5xS+/fyt07RdT/J/yzZT2Mc+nzaXbLcWlzGHR3CD 1SyPyBDScmGKEFaf848fk5bTSSr5cikeRy9JZbiRVqa8VRpCoH0Yratf/kD+T98hWXy1bR1FOVu0 sBHuPSdPHFbZJ5S8k+VvKOmrp/l/TorGAAeo6CsshH7UsrVdzv8AtH5Yq+A/zANsfPnmQ2qGO1Oq Xpt4ypXjGbhyg4npRe2KX0b/AM4hefJ73S9R8mXjl300fXdNJNaW8jhZo9zsEkZWH+ucVfReKHYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXkn5q/nLreia5/hHyPpH6d81rbm7u4yrOkEXHkAIkKvL IVPLiDsKda0Clguj/nt+dfl521Dz95Vl/wAOJIi3d19VezliEr8V9IuQklD+zSv+UOuKvo7T7+z1 GwttQspRNZ3kST20y1o8Uqh0YVod1IOKFfFXYqhpK/pGDrT0Zu232ou+SH0n8d7HqiciydirsVfN H/OZ+pkQeVtLVzR3u7qaPelUESRt4ftvil8//l9oMGv+edB0W5qba/voIbkA0JiaQepQ+PCuKv0V hhihiSGFFjhjUJHGgCqqqKBVA2AAxQuxV2KuxV8bf85a+XbHTPzGt9QtEEbaxZJPdKNgZ43aIvQD 9pFWvvU4pY//AM42am1h+cehDf07v6xbShe4kt3K9abc1UnFX3Tih2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV80HU/wDAf/OTOvapr1hc3tpq1tzsbq3iM8scc/pBZEjUc3VDG0LcRUfrUsl/5yi/ MHy9Y+T7jydPby3Os61DDPZr6ZEcaLcA+oXNPjHpEBRv47Yq9D/KLRtR0b8s/Lmm6ipjvYLJDNE1 eSF6yCNq9CgbiR7YoZfirsVQ0n/HSg/4wzd/8qLtkh9J/HexPNE5Fk7FXYq+Zf8AnM/Tjx8q6kqm gN5bSt2qfSeMfg+KXz15P1waD5s0bW2Xmmm3tvdOg6ssMquy/SBir9GbO8tb2zgvLSRZrW5jSa3m TdXjkUMjD2INcUK2KuxV2Kvir/nKjzTa63+Z72do4eHRLZLGRlNQZ+TSy/SpkCH3XFKVf8436c99 +ceg0rwtjcXMjDsI7eTj97lRir7qxQ7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqkXmvyN5V82Q QQ69YJd/VX9S1mq0c0Td+EsZR1DftAGh74q1q/kTylrHmCx8wappsd5qumoY7KaYsyxgtyr6RPpl g24YrUYqn2KuxV2KoeSn6Rg8fRm7f5UXfJD6T+O9j1RGRZOxV2KvPPz68jS+cfy3v7G0jMmpWRW/ 09AKlpYAeSD3eNnUe5GKvizyf5b03zBey6VPqJ0/VpgF0mOSLlBPPX+4kk5AxM/SM8SC2xp1xSz7 8vfz387/AJZSSeXL6CPVtItJWX6jLJRojX4vq9wvMBGO9CrL3FKnFX1J+VX5lxfmFoEuswaVcaZb xzGBTO0brI6qC/plTyIWtCSo9u9FDJPMGqvpGh32qJaS3xsoXnNpBxEsgjHIhOZVa0Hj8t8VfK/n r/nLjzJq1lLYeWNOXQ0mUpJfySevcgHb91RUSM07/EfChxS8Cd3kdndi7uSzMxqSTuSScVfUP/OH /kSaC21PzpeRFBdL9Q0ssKco1YNcSCo6F1VAR/K2KvpTFDsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVQ0n/HSg/wCMM3f/ACou2SH0n8d7E80TkWTsVdirsVfKn/ORH5DX2n6hcedf KVuz2ErG41Wxg+3by15NPEq7+merAfZO/wBn7Klj0X5o/lN5rt4bn8w9EvB5hiVFudR00Qul0VMQ MjiRkeNjHDx4qSnxOwAYiir6Y/Jy48r3P5c6TP5Xhng0N/rH1VLtIY5/guZEcyLB+7qXU0I7Urvi hmmKvzOvEVLudFFFWRgo8AGOKXoH5O/k1rn5haurcXtPLts4/SGpldjShMMNdmkIP+x6nsCq+5dH 0jTdG0u10rTIFtrCyjWG2gToqKKD5nxJ3J3xQjMVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdiqGk/46UH/ABhm7f5UXfJD6T+O9ieaJyLJ2KuxV2KuxV5F+YX/ADjN5B81zSX1iG8v 6rIavPZopgc9y9seK190K+9cVtnH5b+S08k+StN8sJdm+GniWt2Y/SLmaZ5ieHJ+NDJT7RxVkuKv BvLn/OIvk+z1WS+17U7jWojKZIrJYxaRUJrxlKvI7/7FlxTb3HT9OsNNsobHT7eO0srdeEFvCoSN F8FVaAYoRGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KrDEDMk1TVFZAvYh ipqff4cN7Uil+BLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVaV0Y sFYEqaMAa0NK0P340qU+arG9v9EntLGX0rp2hYESGFiqyqzLzAanNVK0p8XTatRfp5iMwTy3+5o1 EDKFR57da6/j38mLxaJ+aUFiqQ6siyRwpHFAfSljUiIqTzlheZiGow5OanrtmWcunJ3j9/6DX2OI MOoEdpb15EcvMX57lNvJuneZLO4vZtfuknnukt0UJJyHrRiRpaJRVXkGBooynUzxyAEBQF/ob9ND JGzM2SB897ZQrKyhlIZTuCNwcw3LbxV2KuxV2KuxV2KuxV2KtBlJIBBK7MB2774qwjWLf8xUiNvo 89vbcLi6lNxLKjmSO4uS8I4yRvw4I3H50HTpsMZwc5AnYfYN+rgZY56qBA3P2nbp3IJIfzYnvLuG 11ALb2s4jWe4W1BlVZZTyXhBsDD6fIdeXQruMsvTAAkbkdL8vPvtqEdSSQJbA+W+5/o91X59zPrC K5hsoIrqdrm4RAJp3CAs9NzSNUXr4KM1syCTQoOygCAATZV8iydirsVdirsVdirsVdirsVdirsVd irsVdirsVYVceQNSfVJbiDWZrazubr6zc20LzxsytKzSxh45UA9SN1BbjUcFptmfHWR4aMbIFdP1 fi3Alo5GViRAJvr5316/oV/NPkIa3dTXEVyls0zWzvyjLgvbx3MXNgHStFuVIB2qlCCDkdPq/DFE Xz+3h/V9qdRo/ENg1y+wSH6fsQ2j+TPNcMlncXnmGcNEKzwRvNICzxKjGs0kiMysC4qnGv7IyeTV YzYEB9n6B+3zRi0uQUTM/b3eZ/RXk1rn5cNqMsoiuYo4bi5kuZ3aOs3OSG3j5I6leLepbeoeNK7D 7NQXFreEcuQry5n9dIy6HiJ32Jvz5R/Vf7LsOn5e+ZF9SKDWhpsLHkq2IniRC8ryOsUImEaD4x2J LKK/DVckdZj6x4vfX31+PtY/kp8hLh91jqTyuv289tmd2sckdrDHKwaREVXYFiCwABILlm/4Ik5r pGy7GIoKuBLsVdirsVdirsVdirDL7yJqkuqXl5Z6xLaR3sryypG9wjAtGY6KUlRd6rWqmnFeNMz4 auIiAY3Xu/V+LcGekkZEiVX7+6uh/FbKnmfyEurPI1s8MQnihgnE6GUskXMfaJ+0UfiG6jqPioRH Bq+Dne1stRpBkvzoFLF/LrzBBeyGx1ZLS3kDFmhE8RZw6MryLFKgeR1VkeQ70b4aHLvzsCN42fh+ rl3Bp/JTB9MqHlflz359CflTI7Py9rEFtpEUmtXDtp0zvduKH62hEgUS+qJWr8a1o3H+UD4eOLLN EmR4R6uXly5fj9LkxwSAiOI+k7+fPn+PdW1H+YzkuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvmL/AKHG 1L/qV4f+ktv+qWKad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0 lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFa d/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1 K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW 3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3 /Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Ur w/8ASW3/AFSxWnf9Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf 9UsVp3/Q42pf9SvD/wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFad/0ONqX/Urw/8ASW3/AFSxWnf9 Djal/wBSvD/0lt/1SxWnf9Djal/1K8P/AElt/wBUsVp3/Q42pf8AUrw/9Jbf9UsVp3/Q42pf9SvD /wBJbf8AVLFad/0ONqX/AFK8P/SW3/VLFafOeKXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F VQQsYHmqOKMqEd6uGI/4hjSqeKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KoqOv6MuOtPXh7bfYl74eiOqFwJdirsVdiqaeW/LOueZdYg0jRLR 7y/nPwRp0Cjq7sfhVV7sdsVfUHkD/nFXyvpcUd35tlOs6hSrWcbNHZofDbjJJTxJA/ycUW9i0nyt 5a0eJItK0q0sY0+yLeCOPfxqoG/vihFXumabfIUvbSG6QihWaNZBTwowOKvNvOX/ADjj+WvmKJ3t LIaFfkH07nTwEjB7crf+6I/1Qp98Vt8t/mT+VPmnyDqCw6rGJrCckWepwgmGWm/Hf7D06qfoqN8W VsMxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVFRgfo2c9/Wh7/AORL2w9E dULgS7FXYqq2trcXd1Da20ZluLh1ihiXdmdyFVR7knFX3N+Tv5Wad5B8tRwcFl1y8VZNWvKAkyUr 6SN/vuPoPE798WLH7/8A5yY8k6X5z1Dy3qtvc28VhcNatqcYWaLnGeL80X94oVqr8IbpitMzu/zY /LO0himn8z6cEmUPGFuI3Yq3QlELMPpGKqVn+cH5X3kwhg8z6f6jGiiSZYgSewMnEYqxTzv/AM5L /l/5buGsrFpNevUNJBZFfQQjsZ2+En/UDYrTPLzTvL/nrybFFqFuLnSNatYrhUanJVmQSRujfsuv IFWHfFXw7+ZHkW/8kebbzQbsmRI6S2dzSgmt3r6clPoKt/lA4sgxfFXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FWwCTQbk9BiqpPa3VuQLiF4S26iRStflUDFVLFXYq7FUVH/xzJ/+M0Pb/Il74eiO qFwJdirsVex/84t+VYtY/MY6lcIHt9Dt2ulB6eu59OL7qsw9xigvsOeeGCGSeZxHDEpeWRjRVVRV mJ8AMUPz38+6tpusedtd1bTA4sNQvri5g9TZiJZC/IjtyJrTtiySHFXYq7FX3x+UGvaRrX5b6DPp TN9WtbOGxaN/tpJaxrCyN/wNa9xvixeb/wDOW3lWO88p6d5kiQfWdLuBbzuOpt7nbc/5MqrT/WOK Q+T8UuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvoLyOmj/AJW/lRpv5izadBqfmHWrxY7eO5JV o7asnwwNRuDMkRcvTuBihPfLn55aR+anmCy8leYfLVrBpupidHllmadw6xM8XpH04vTeq/ar8qYr T5787eW28tebdW0EyesunXMkMcvd4waoxp3KEV98UpJirsVRUf8AxzZ/+M0Pf/Il7YeiOqFwJdir sVfTX/OHFvCLTzTcdZmksoz02VVmIp33LfhigvYvzca5X8sPNJtjST9GXNTv9j0z6nT/ACK4ofAe LJ2KuxV2Kvq7/nEBrn/ButqxP1YaiDGO3MwJz/ALigs5/wCcgYY5vyf8xrIKhYoXH+slzEyn7xih 8MYsnYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXu3kPzl5N80/lhF5C82eilxo8jz2L3FyLL1I6 OyNDclXjWWMyMnB1oynap2xQUN+QV9+V3l3T9R86eZp/T1rSp2j0y3aUO7JLF8Po24AZpK8l5n4R X9mlcVLyjzZ5huPMfmbU9duEEcuo3ElwYhuEDtVUB78VoMUpTirsVRUf/HMn/wCM0Pb/ACJe+Hoj qhcCXYq7FXvv/OIWuxWvmrWtFkYK2pWkc8Vf2ntHI4j34zsfoxQX1LqFjbahYXNhdLztruJ4J08Y 5FKMPpBxQ+CPzH/LvXfI3mKfS9RiY2pZm0++ofTnhr8LK3TlT7S9jiyYpirsVRel6VqWrahBp2mW 0l5fXLBILeFSzsT4Afjir7p/J7yE3kjyJZaNOVbUHLXWosu6/WJaclB7hFVUr3pXFixb/nKTXotO /K6bT+dJ9YuYLdEHUrE4uHPy/dAH54pD40xS7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FUVH/xzJ/+M0Pf/Il7YeiOqFwJdirsVTryb5ovvKvmjTvMFj8U9hMJPTJoHQ/DJGfZ0JXF X2zqHp+ePKth5l8p6pPb3yRNcaVJFM6RM7LRre6hB9NtxxbkCUO491il3lj8wfJPnTy39U8xi2N3 CDFqun6jHGFWaP1OXJGMiI59B24cuQAr0oSq+YPz0XyZB56m0/ynp0VjYWUSJM8XqgTTOPUZuMho qqGCjio8d9sUhhehXenWes2VzqVot/p8UyNd2bl1EkQPxrVGRgadN+vtil9/+WvJ3lHy9BTy/pVr YJKorLBGod16jlJ9tvpOLFOyQBU9MVfFX/OQ35kxecvOX1fTpvV0PRg1vZupqkspP76ZfEMVCqe4 UHvikPK8UuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVFR0/Rs/j60Pb/Il74ei OqFwJdirsVdir0j8n/zo1j8vr9oJFa+8vXLA3en8qFG6GWAnYPTqOjd+xCgh9FweT/yM/NWvmG0t 4bq9kFbt7aWS1uQWFCLmKNkPL/KZd/EjFD5j/Ony1o3ln8y9Y0TRYDbabaC2EEJd5CPUtIpHPKQs xq7k9cWQYRir9Fv0rpmlaBDfaldRWVnDBGZbid1jRRwHVmIGLF80/nb/AM5GjW7a48t+TneLTJKx 3+qkFHnTvHCDRkjP7TGhbpQDqpAfP+KXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FUVH/wAc2fr/AH0Pfb7EvbD0R1QuBLsVdirsVdiqJ0/UtR066S70+6ms7qP+7uLeRopF+ToQ wxVq+v77ULuW9v7mW7vJzymuZ3aWV2pSrO5LE/PFUPiqYap5h1/VkiTVNTu79IAFgW6nkmCKBQBB IzcRTwxVL8VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqvZ2k13cx20IBkkNFqaDYVJJPtko QMjQYTmIizyVX0jU0cqbWU0NKqjMD8iBQ5M4J9xYDU4/5wv5Hv5c1l1p17aJE9zEY1mBMdSKmlK1 Fajr3yM8co8xTOGWMuRtDZBm7FXYq7FXYq7FXYq7FXYq7FUQmn3zsVjt5JGCo5Eal6CReS1416jJ jFI7ANZyxAskD9i79FapUD6nPU9P3b/0yRwZB/CfkxGoxnlKPzChJFLE5jlRo3HVGBBFd+hysxIN Hm2xkCLG4WYEuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kpo3l3UfRhljCSLND6/wBtE4jqftlT sCKn3zIGlmRYrlfMOMdXAEg3zrkVXRLC+9e3urSaBXcScRIWoOBVSrUHU+oKYcGGR3jXX9A/TsjU Z4R9Mr6fpP8AvTaZG884oDMYUZYyQQvpt+1SlFap3FNssl4wPEf0NcDhIER+nu+77EPc2msay0Kz SwKyIHRQHFPVJUqaK1Cpioa98TjyZasjv/Hy+5Rkx4roHbb5C+/z+woBvLeq1T0kSZJFDxyI6gMp puA5Vu47ZUNLM8t/x8/2tp1cB9Vx+H6RY8+fLcpa6lHZDQlSQaEMNvAioP0ZjlyQtxV2KuxV2Kux V2KuxVNB5d1J4YJIVWX109QKGUEDbsSK/aFadMvGmkQCK38w451UASDe3ke6/wAd/RNtLl1o2yvb NaLSkDNRmdjFRFDGMNWg79Kb9MvwTybcJA6fL4fjm0aiGOjxCRrfn3npuN/111REz+YbWK3jtooK 8eEr81PORFHxH1PTPIKnv+GW8ebhHDXn8vPuAaODDxEzB3O1++9qurMutHpTGrjT9Taa6kkhZniJ e5ZaMoJox3Wo/arQZgnDOzt9PPydgM8Kjv8AVy80FlTc7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYqjBq2pCAwC4b0SvAp248eNPlTJjLICrNNZxQJuhanb395bACCZo6cqcf8ALADffxGMcko8jSZY 4y5i1e51zVbn1BLcMUkqGjFAtD2pkpZpyuzzYxwQjVAbKdvqmoW6FIJ2jUrw+GleNWagPUbuTkRk kBQLI4ok2Rv+P1Kz+YdZZOP1phuSWWgJr7jJePPvLHwIdwQMkjyyPJIeTuSzse5JqTlRLaAsxV2K uxV2KuxV2KuxVGxazqkUaxR3LrGoAVQdgF6UyYySAoFgccSbIW2mqahZqVtp2jUkkqKUqaV6/IYI zlHkUygJcwrr5h1hYRELlqClG25UXtXwyYzzAqy1nT4yboIOS7uZHkeSRneVQkjNuWVaUqf9gMgZ E9WwQA6KORZOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kvs3/rF/8A79r/AKd8WLv+sX/+/a/6d8Vd/wBY v/8Aftf9O+Ku/wCsX/8Av2v+nfFXf9Yv/wDftf8ATvirv+sX/wDv2v8Ap3xV3/WL/wD37X/Tvirv +sX/APv2v+nfFXf9Yv8A/ftf9O+Ku/6xf/79r/p3xV3/AFi//wB+1/074q7/AKxf/wC/a/6d8Vd/ 1i//AN+1/wBO+Ku/6xf/AO/a/wCnfFXf9Yv/APftf9O+Ku/6xf8A+/a/6d8Vd/1i/wD9+1/074q7 /rF//v2v+nfFXf8AWL//AH7X/Tvirv8ArF//AL9r/p3xV3/WL/8A37X/AE74q7/rF/8A79r/AKd8 Vd/1i/8A9+1/074q7/rF/wD79r/p3xV3/WL/AP37X/Tvirv+sX/+/a/6d8Vd/wBYv/8Aftf9O+Ku /wCsX/8Av2v+nfFXf9Yv/wDftf8ATvirv+sX/wDv2v8Ap3xV3/WL/wD37X/Tvirv+sX/APv2v+nf FX//2Q== + + + + xmp.iid:ee0a8c46-5e4f-4c70-b018-b95f44861aee + xmp.did:ee0a8c46-5e4f-4c70-b018-b95f44861aee + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:515d112b-95c6-47fc-ad4a-2b4617c0cb0e + xmp.did:515d112b-95c6-47fc-ad4a-2b4617c0cb0e + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:0280117407206811822ADB221B803221 + 2013-04-15T13:46:51-07:00 + Adobe Illustrator CS6 (Macintosh) + / + + + saved + xmp.iid:0380117407206811822ADB221B803221 + 2013-04-15T14:17:29-07:00 + Adobe Illustrator CS6 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:9ae2759d-7219-4f2d-acab-53711d513d22 + 2014-02-05T13:24:36-08:00 + Adobe Illustrator CC (Macintosh) + / + + + saved + xmp.iid:ee0a8c46-5e4f-4c70-b018-b95f44861aee + 2014-02-05T13:25:58-08:00 + Adobe Illustrator CC (Macintosh) + / + + + + Print + False + False + 1 + + 530.973085 + 551.985800 + Points + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + CMYK Red + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + CMYK Yellow + CMYK + PROCESS + 0.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Green + CMYK + PROCESS + 100.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Cyan + CMYK + PROCESS + 100.000000 + 0.000000 + 0.000000 + 0.000000 + + + CMYK Blue + CMYK + PROCESS + 100.000000 + 100.000000 + 0.000000 + 0.000000 + + + CMYK Magenta + CMYK + PROCESS + 0.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=15 M=100 Y=90 K=10 + CMYK + PROCESS + 15.000000 + 100.000000 + 90.000000 + 10.000000 + + + C=0 M=90 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 90.000000 + 85.000000 + 0.000000 + + + C=0 M=80 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 80.000000 + 95.000000 + 0.000000 + + + C=0 M=50 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 50.000000 + 100.000000 + 0.000000 + + + C=0 M=35 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 35.000000 + 85.000000 + 0.000000 + + + C=5 M=0 Y=90 K=0 + CMYK + PROCESS + 5.000000 + 0.000000 + 90.000000 + 0.000000 + + + C=20 M=0 Y=100 K=0 + CMYK + PROCESS + 20.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=50 M=0 Y=100 K=0 + CMYK + PROCESS + 50.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=75 M=0 Y=100 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=85 M=10 Y=100 K=10 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 10.000000 + + + C=90 M=30 Y=95 K=30 + CMYK + PROCESS + 90.000000 + 30.000000 + 95.000000 + 30.000000 + + + C=75 M=0 Y=75 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 75.000000 + 0.000000 + + + C=80 M=10 Y=45 K=0 + CMYK + PROCESS + 80.000000 + 10.000000 + 45.000000 + 0.000000 + + + C=70 M=15 Y=0 K=0 + CMYK + PROCESS + 70.000000 + 15.000000 + 0.000000 + 0.000000 + + + C=85 M=50 Y=0 K=0 + CMYK + PROCESS + 85.000000 + 50.000000 + 0.000000 + 0.000000 + + + C=100 M=95 Y=5 K=0 + CMYK + PROCESS + 100.000000 + 95.000000 + 5.000000 + 0.000000 + + + C=100 M=100 Y=25 K=25 + CMYK + PROCESS + 100.000000 + 100.000000 + 25.000000 + 25.000000 + + + C=75 M=100 Y=0 K=0 + CMYK + PROCESS + 75.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=50 M=100 Y=0 K=0 + CMYK + PROCESS + 50.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=35 M=100 Y=35 K=10 + CMYK + PROCESS + 35.000000 + 100.000000 + 35.000000 + 10.000000 + + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000000 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 95.000000 + 20.000000 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 40.000000 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 40.000000 + 45.000000 + 50.000000 + 5.000000 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000000 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000000 + 60.000000 + 65.000000 + 40.000000 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 40.000000 + 65.000000 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000000 + 50.000000 + 75.000000 + 10.000000 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000000 + 60.000000 + 80.000000 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 40.000000 + 65.000000 + 90.000000 + 35.000000 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 40.000000 + 70.000000 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 70.000000 + 80.000000 + 70.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999400 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998800 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999700 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999100 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999400 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998800 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999700 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999100 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998800 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000000 + 95.000000 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000000 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000000 + 90.000000 + 0.003100 + 0.003100 + + + + + + + Adobe PDF library 10.01 + + + + + + + + + + + + + + + + + + + + + + + + + % &&end XMP packet marker&& [{ai_metadata_stream_123} <> /PUT AI11_PDFMark5 [/Document 1 dict begin /Metadata {ai_metadata_stream_123} def currentdict end /BDC AI11_PDFMark5 +%ADOEndClientInjection: PageSetup End "AI11EPS" +%%EndPageSetup +1 -1 scale 0 -499.988 translate +pgsv +[1 0 0 1 0 0 ]ct +gsave +np +gsave +0 0 mo +0 499.988 li +530.973 499.988 li +530.973 0 li +cp +clp +530.973 499.988 mo +0 499.988 li +0 224.002 li +530.973 224.002 li +530.973 499.988 li +cp +false sop +/0 +[/DeviceCMYK] /CSA add_res +0 0 0 1 cmyk +f +152.608 55.4428 mo +143.614 55.4428 136.32 62.7358 136.32 71.7333 cv +136.32 78.9296 140.987 85.0351 147.46 87.1894 cv +148.275 87.3388 148.572 86.8359 148.572 86.4042 cv +148.572 86.0175 148.558 84.9931 148.55 83.6337 cv +144.019 84.6181 143.063 81.4501 143.063 81.4501 cv +142.322 79.5683 141.254 79.0673 141.254 79.0673 cv +139.775 78.0566 141.366 78.0771 141.366 78.0771 cv +143.001 78.1923 143.861 79.7558 143.861 79.7558 cv +145.314 82.2451 147.674 81.5263 148.602 81.1093 cv +148.75 80.0566 149.171 79.3388 149.636 78.9316 cv +146.019 78.5205 142.216 77.123 142.216 70.8808 cv +142.216 69.1025 142.851 67.6484 143.893 66.5097 cv +143.725 66.0976 143.166 64.4414 144.053 62.1987 cv +144.053 62.1987 145.42 61.7607 148.532 63.8686 cv +149.831 63.5073 151.225 63.3266 152.61 63.3203 cv +153.994 63.3266 155.387 63.5073 156.688 63.8686 cv +159.798 61.7607 161.163 62.1987 161.163 62.1987 cv +162.052 64.4414 161.493 66.0976 161.326 66.5097 cv +162.37 67.6484 163 69.1025 163 70.8808 cv +163 77.1386 159.191 78.5156 155.563 78.9189 cv +156.147 79.4218 156.668 80.416 156.668 81.9355 cv +156.668 84.1132 156.648 85.8701 156.648 86.4042 cv +156.648 86.8398 156.942 87.3466 157.768 87.1875 cv +164.236 85.0292 168.899 78.9277 168.899 71.7333 cv +168.899 62.7358 161.605 55.4428 152.608 55.4428 cv +cp +.714844 .671875 .652344 .796875 cmyk +ef +350.609 6.4335 mo +317.262 6.4335 290.221 33.4687 290.221 66.8212 cv +290.221 93.5019 307.524 116.138 331.518 124.123 cv +334.536 124.682 335.644 122.813 335.644 121.218 cv +335.644 119.778 335.588 115.021 335.562 109.975 cv +318.762 113.628 315.217 102.85 315.217 102.85 cv +312.47 95.8701 308.512 94.0136 308.512 94.0136 cv +303.033 90.2656 308.925 90.3427 308.925 90.3427 cv +314.989 90.7685 318.182 96.5664 318.182 96.5664 cv +323.568 105.798 332.309 103.129 335.755 101.586 cv +336.297 97.6835 337.862 95.0185 339.589 93.5107 cv +326.176 91.9843 312.076 86.8056 312.076 63.6669 cv +312.076 57.0742 314.435 51.687 318.298 47.458 cv +317.671 45.9365 315.604 39.7949 318.883 31.4765 cv +318.883 31.4765 323.954 29.8544 335.494 37.6674 cv +340.311 36.3291 345.477 35.6582 350.609 35.6347 cv +355.741 35.6582 360.911 36.3291 365.737 37.6674 cv +377.263 29.8544 382.327 31.4765 382.327 31.4765 cv +385.614 39.7949 383.546 45.9365 382.919 47.458 cv +386.791 51.687 389.134 57.0742 389.134 63.6669 cv +389.134 86.8613 375.007 91.9677 361.56 93.4628 cv +363.726 95.3369 365.656 99.0117 365.656 104.646 cv +365.656 112.726 365.586 119.229 365.586 121.218 cv +365.586 122.825 366.673 124.708 369.734 124.115 cv +393.715 116.121 410.996 93.4931 410.996 66.8212 cv +410.996 33.4687 383.959 6.4335 350.609 6.4335 cv +cp +ef +313.093 93.1367 mo +312.96 93.4375 312.488 93.5273 312.058 93.3212 cv +311.62 93.124 311.374 92.7148 311.516 92.414 cv +311.646 92.1054 312.119 92.0195 312.556 92.2255 cv +312.995 92.4228 313.245 92.8359 313.093 93.1367 cv +313.093 93.1367 li +cp +f +315.539 95.8652 mo +315.251 96.1318 314.688 96.0078 314.306 95.5859 cv +313.911 95.165 313.837 94.6015 314.129 94.331 cv +314.426 94.0644 314.972 94.1894 315.368 94.6103 cv +315.763 95.0361 315.84 95.5947 315.539 95.8652 cv +315.539 95.8652 li +cp +f +317.92 99.3427 mo +317.55 99.6005 316.945 99.3593 316.571 98.8222 cv +316.201 98.2851 316.201 97.6406 316.579 97.3828 cv +316.954 97.125 317.55 97.3574 317.929 97.8896 cv +318.298 98.4355 318.298 99.08 317.92 99.3427 cv +317.92 99.3427 li +cp +f +321.182 102.703 mo +320.851 103.068 320.146 102.97 319.63 102.472 cv +319.102 101.985 318.955 101.294 319.287 100.929 cv +319.622 100.563 320.331 100.666 320.851 101.16 cv +321.375 101.646 321.535 102.342 321.182 102.703 cv +321.182 102.703 li +cp +f +325.682 104.654 mo +325.536 105.127 324.857 105.342 324.173 105.141 cv +323.49 104.934 323.043 104.38 323.181 103.902 cv +323.323 103.426 324.005 103.202 324.694 103.417 cv +325.376 103.623 325.824 104.173 325.682 104.654 cv +325.682 104.654 li +cp +f +330.624 105.016 mo +330.641 105.514 330.061 105.927 329.343 105.936 cv +328.621 105.952 328.037 105.549 328.029 105.059 cv +328.029 104.556 328.596 104.147 329.318 104.135 cv +330.036 104.121 330.624 104.521 330.624 105.016 cv +330.624 105.016 li +cp +f +335.223 104.233 mo +335.309 104.719 334.81 105.218 334.097 105.351 cv +333.396 105.479 332.747 105.179 332.658 104.697 cv +332.571 104.199 333.079 103.7 333.779 103.571 cv +334.493 103.447 335.132 103.739 335.223 104.233 cv +335.223 104.233 li +cp +f +1 lw +1 lc +0 lj +10 ml +[] 0 dsh +true sadj +224.898 .5 mo +224.898 1 li +.828122 .409705 .05182 0 cmyk +@ +[.99995 1.9999 ] 0 dsh +224.898 3 mo +224.898 136.993 li +@ +[] 0 dsh +224.898 137.993 mo +224.898 138.493 li +@ +133.276 152.509 mo +132.895 152.232 132.41 152.095 131.818 152.095 cv +131.578 152.095 131.342 152.119 131.11 152.166 cv +130.877 152.215 130.672 152.295 130.492 152.406 cv +130.312 152.52 130.168 152.669 130.059 152.857 cv +129.952 153.045 129.898 153.279 129.898 153.559 cv +129.898 153.822 129.975 154.037 130.132 154.201 cv +130.287 154.365 130.496 154.499 130.756 154.602 cv +131.016 154.707 131.309 154.793 131.638 154.861 cv +131.966 154.929 132.3 155.003 132.64 155.082 cv +132.98 155.162 133.313 155.257 133.642 155.365 cv +133.97 155.473 134.264 155.619 134.524 155.803 cv +134.784 155.986 134.992 156.219 135.148 156.498 cv +135.304 156.779 135.382 157.131 135.382 157.555 cv +135.382 158.011 135.28 158.4 135.076 158.725 cv +134.871 159.049 134.61 159.313 134.29 159.517 cv +133.97 159.721 133.612 159.869 133.216 159.961 cv +132.82 160.053 132.426 160.099 132.034 160.099 cv +131.554 160.099 131.1 160.039 130.672 159.919 cv +130.244 159.799 129.868 159.617 129.544 159.373 cv +129.22 159.129 128.964 158.816 128.776 158.436 cv +128.588 158.057 128.494 157.607 128.494 157.087 cv +129.574 157.087 li +129.574 157.447 129.643 157.757 129.784 158.017 cv +129.924 158.277 130.108 158.49 130.336 158.658 cv +130.564 158.826 130.829 158.951 131.134 159.031 cv +131.438 159.111 131.749 159.15 132.07 159.15 cv +132.326 159.15 132.584 159.127 132.844 159.078 cv +133.104 159.031 133.338 158.949 133.546 158.832 cv +133.754 158.717 133.922 158.559 134.05 158.359 cv +134.178 158.158 134.242 157.902 134.242 157.591 cv +134.242 157.295 134.163 157.055 134.008 156.871 cv +133.852 156.688 133.643 156.537 133.384 156.421 cv +133.123 156.305 132.829 156.211 132.502 156.139 cv +132.174 156.066 131.84 155.992 131.5 155.916 cv +131.16 155.841 130.826 155.753 130.498 155.652 cv +130.17 155.553 129.875 155.421 129.616 155.257 cv +129.356 155.093 129.148 154.881 128.992 154.621 cv +128.836 154.361 128.758 154.035 128.758 153.643 cv +128.758 153.211 128.846 152.837 129.022 152.52 cv +129.198 152.205 129.432 151.945 129.724 151.74 cv +130.016 151.537 130.348 151.385 130.72 151.285 cv +131.092 151.184 131.474 151.135 131.866 151.135 cv +132.306 151.135 132.714 151.188 133.09 151.291 cv +133.466 151.395 133.796 151.559 134.079 151.783 cv +134.364 152.007 134.588 152.289 134.752 152.629 cv +134.915 152.969 135.006 153.375 135.022 153.847 cv +133.942 153.847 li +133.877 153.23 133.656 152.785 133.276 152.509 cv +cp +1 .5 0 0 cmyk +f +137.554 153.703 mo +137.554 154.615 li +137.578 154.615 li +138.041 153.91 138.709 153.559 139.581 153.559 cv +139.966 153.559 140.313 153.639 140.625 153.799 cv +140.938 153.959 141.158 154.23 141.286 154.615 cv +141.494 154.279 141.768 154.02 142.108 153.835 cv +142.448 153.65 142.822 153.559 143.229 153.559 cv +143.541 153.559 143.824 153.593 144.076 153.66 cv +144.328 153.729 144.543 153.835 144.724 153.979 cv +144.904 154.123 145.043 154.309 145.143 154.537 cv +145.244 154.765 145.293 155.039 145.293 155.359 cv +145.293 159.906 li +144.274 159.906 li +144.274 155.839 li +144.274 155.646 144.257 155.467 144.225 155.299 cv +144.194 155.131 144.134 154.984 144.046 154.861 cv +143.957 154.736 143.835 154.639 143.68 154.566 cv +143.524 154.494 143.322 154.459 143.074 154.459 cv +142.57 154.459 142.174 154.602 141.886 154.891 cv +141.598 155.179 141.454 155.563 141.454 156.043 cv +141.454 159.906 li +140.433 159.906 li +140.433 155.839 li +140.433 155.639 140.415 155.455 140.38 155.287 cv +140.344 155.119 140.282 154.973 140.194 154.849 cv +140.105 154.725 139.988 154.629 139.84 154.561 cv +139.691 154.492 139.501 154.459 139.27 154.459 cv +138.974 154.459 138.72 154.518 138.508 154.639 cv +138.295 154.759 138.123 154.902 137.992 155.07 cv +137.86 155.238 137.764 155.412 137.704 155.593 cv +137.643 155.773 137.614 155.923 137.614 156.043 cv +137.614 159.906 li +136.594 159.906 li +136.594 153.703 li +137.554 153.703 li +cp +f +150.165 156.912 mo +149.957 156.957 149.74 156.992 149.512 157.02 cv +149.284 157.049 149.053 157.08 148.821 157.117 cv +148.589 157.152 148.381 157.211 148.198 157.291 cv +148.013 157.371 147.863 157.484 147.747 157.633 cv +147.631 157.781 147.574 157.982 147.574 158.238 cv +147.574 158.406 147.607 158.549 147.675 158.664 cv +147.743 158.781 147.831 158.875 147.939 158.947 cv +148.047 159.018 148.175 159.07 148.324 159.102 cv +148.472 159.135 148.621 159.15 148.773 159.15 cv +149.109 159.15 149.397 159.105 149.638 159.013 cv +149.877 158.921 150.073 158.805 150.225 158.664 cv +150.377 158.525 150.49 158.373 150.561 158.209 cv +150.633 158.045 150.669 157.891 150.669 157.746 cv +150.669 156.703 li +150.541 156.799 150.373 156.869 150.165 156.912 cv +cp +151.594 160.039 mo +151.329 160.039 151.12 159.965 150.963 159.816 cv +150.808 159.669 150.729 159.427 150.729 159.091 cv +150.449 159.427 150.123 159.669 149.751 159.816 cv +149.379 159.965 148.977 160.039 148.545 160.039 cv +148.266 160.039 148.001 160.009 147.753 159.949 cv +147.505 159.889 147.287 159.789 147.1 159.648 cv +146.912 159.509 146.764 159.329 146.656 159.109 cv +146.547 158.889 146.494 158.623 146.494 158.311 cv +146.494 157.959 146.554 157.671 146.673 157.447 cv +146.793 157.223 146.951 157.041 147.147 156.9 cv +147.343 156.761 147.567 156.654 147.819 156.582 cv +148.071 156.511 148.329 156.451 148.594 156.402 cv +148.873 156.347 149.14 156.305 149.392 156.277 cv +149.643 156.249 149.866 156.209 150.058 156.156 cv +150.249 156.105 150.401 156.029 150.514 155.929 cv +150.625 155.828 150.682 155.683 150.682 155.49 cv +150.682 155.268 150.64 155.087 150.556 154.951 cv +150.472 154.814 150.363 154.711 150.231 154.639 cv +150.1 154.566 149.951 154.518 149.787 154.494 cv +149.623 154.471 149.461 154.459 149.302 154.459 cv +148.87 154.459 148.51 154.541 148.222 154.705 cv +147.933 154.869 147.777 155.179 147.753 155.635 cv +146.733 155.635 li +146.749 155.251 146.829 154.927 146.974 154.662 cv +147.118 154.398 147.309 154.184 147.549 154.02 cv +147.789 153.857 148.065 153.738 148.377 153.666 cv +148.689 153.595 149.017 153.559 149.361 153.559 cv +149.642 153.559 149.919 153.578 150.195 153.619 cv +150.472 153.658 150.722 153.74 150.945 153.865 cv +151.169 153.988 151.35 154.163 151.485 154.387 cv +151.621 154.611 151.689 154.902 151.689 155.263 cv +151.689 158.455 li +151.689 158.695 151.704 158.871 151.731 158.982 cv +151.759 159.095 151.854 159.15 152.014 159.15 cv +152.102 159.15 152.205 159.131 152.326 159.091 cv +152.326 159.883 li +152.149 159.986 151.906 160.039 151.594 160.039 cv +cp +f +154.354 151.339 mo +154.354 159.906 li +153.333 159.906 li +153.333 151.339 li +154.354 151.339 li +cp +f +157.017 151.339 mo +157.017 159.906 li +155.997 159.906 li +155.997 151.339 li +157.017 151.339 li +cp +f +101.854 169.002 mo +101.854 168.102 li +102.898 168.102 li +102.898 167.179 li +102.898 166.675 103.044 166.293 103.336 166.033 cv +103.628 165.773 104.054 165.643 104.614 165.643 cv +104.71 165.643 104.82 165.65 104.944 165.666 cv +105.068 165.683 105.178 165.707 105.274 165.738 cv +105.274 166.627 li +105.186 166.595 105.09 166.572 104.986 166.561 cv +104.882 166.549 104.786 166.543 104.698 166.543 cv +104.45 166.543 104.258 166.591 104.122 166.686 cv +103.986 166.783 103.918 166.967 103.918 167.238 cv +103.918 168.102 li +105.118 168.102 li +105.118 169.002 li +103.918 169.002 li +103.918 174.307 li +102.898 174.307 li +102.898 169.002 li +101.854 169.002 li +cp +f +106.924 172.213 mo +107.023 172.505 107.162 172.748 107.338 172.945 cv +107.514 173.141 107.72 173.291 107.955 173.395 cv +108.191 173.498 108.442 173.551 108.705 173.551 cv +108.97 173.551 109.22 173.498 109.455 173.395 cv +109.691 173.291 109.897 173.141 110.074 172.945 cv +110.249 172.748 110.388 172.505 110.488 172.213 cv +110.588 171.921 110.638 171.587 110.638 171.211 cv +110.638 170.834 110.588 170.501 110.488 170.209 cv +110.388 169.916 110.249 169.671 110.074 169.471 cv +109.897 169.271 109.691 169.119 109.455 169.015 cv +109.22 168.91 108.97 168.858 108.705 168.858 cv +108.442 168.858 108.191 168.91 107.955 169.015 cv +107.72 169.119 107.514 169.271 107.338 169.471 cv +107.162 169.671 107.023 169.916 106.924 170.209 cv +106.824 170.501 106.774 170.834 106.774 171.211 cv +106.774 171.587 106.824 171.921 106.924 172.213 cv +cp +105.886 169.933 mo +106.014 169.537 106.205 169.193 106.462 168.9 cv +106.718 168.609 107.034 168.379 107.41 168.211 cv +107.786 168.043 108.218 167.959 108.705 167.959 cv +109.202 167.959 109.636 168.043 110.008 168.211 cv +110.38 168.379 110.693 168.609 110.95 168.9 cv +111.205 169.193 111.397 169.537 111.526 169.933 cv +111.654 170.328 111.718 170.755 111.718 171.211 cv +111.718 171.666 111.654 172.091 111.526 172.482 cv +111.397 172.875 111.205 173.217 110.95 173.509 cv +110.693 173.801 110.38 174.029 110.008 174.193 cv +109.636 174.356 109.202 174.438 108.705 174.438 cv +108.218 174.438 107.786 174.356 107.41 174.193 cv +107.034 174.029 106.718 173.801 106.462 173.509 cv +106.205 173.217 106.014 172.875 105.886 172.482 cv +105.758 172.091 105.694 171.666 105.694 171.211 cv +105.694 170.755 105.758 170.328 105.886 169.933 cv +cp +f +113.842 168.102 mo +113.842 169.41 li +113.866 169.41 li +114.114 168.906 114.418 168.535 114.778 168.295 cv +115.138 168.055 115.594 167.943 116.146 167.959 cv +116.146 169.039 li +115.738 169.039 115.39 169.095 115.102 169.207 cv +114.814 169.318 114.581 169.482 114.406 169.699 cv +114.23 169.914 114.101 170.177 114.022 170.484 cv +113.942 170.793 113.902 171.146 113.902 171.547 cv +113.902 174.307 li +112.882 174.307 li +112.882 168.102 li +113.842 168.102 li +cp +f +122.733 174.307 mo +122.733 168.211 li +120.525 168.211 li +120.525 167.395 li +120.813 167.395 121.093 167.373 121.365 167.328 cv +121.637 167.285 121.883 167.203 122.103 167.082 cv +122.323 166.963 122.509 166.799 122.662 166.591 cv +122.813 166.383 122.917 166.119 122.974 165.799 cv +123.753 165.799 li +123.753 174.307 li +122.733 174.307 li +cp +f +128.829 169.885 mo +128.614 169.984 128.43 170.121 128.278 170.293 cv +128.126 170.465 128.012 170.669 127.936 170.904 cv +127.86 171.141 127.822 171.391 127.822 171.654 cv +127.822 171.918 127.862 172.166 127.942 172.398 cv +128.021 172.631 128.136 172.83 128.284 172.998 cv +128.432 173.166 128.616 173.301 128.836 173.4 cv +129.056 173.501 129.306 173.551 129.586 173.551 cv +129.866 173.551 130.112 173.501 130.324 173.4 cv +130.536 173.301 130.714 173.162 130.858 172.986 cv +131.002 172.811 131.112 172.608 131.188 172.381 cv +131.264 172.152 131.302 171.914 131.302 171.666 cv +131.302 171.402 131.268 171.152 131.2 170.916 cv +131.132 170.681 131.026 170.477 130.882 170.305 cv +130.738 170.133 130.558 169.994 130.342 169.891 cv +130.126 169.787 129.874 169.734 129.586 169.734 cv +129.298 169.734 129.046 169.785 128.829 169.885 cv +cp +130.678 167.047 mo +130.43 166.814 130.102 166.699 129.694 166.699 cv +129.262 166.699 128.913 166.805 128.65 167.017 cv +128.386 167.229 128.18 167.496 128.032 167.82 cv +127.884 168.145 127.782 168.494 127.725 168.871 cv +127.67 169.246 127.638 169.599 127.63 169.927 cv +127.654 169.951 li +127.894 169.559 128.192 169.275 128.548 169.099 cv +128.904 168.923 129.314 168.834 129.778 168.834 cv +130.186 168.834 130.552 168.904 130.876 169.045 cv +131.2 169.184 131.472 169.379 131.692 169.627 cv +131.912 169.875 132.082 170.166 132.202 170.502 cv +132.322 170.839 132.382 171.203 132.382 171.595 cv +132.382 171.906 132.334 172.23 132.238 172.566 cv +132.142 172.902 131.984 173.209 131.764 173.484 cv +131.543 173.761 131.252 173.988 130.888 174.168 cv +130.524 174.349 130.074 174.438 129.537 174.438 cv +128.906 174.438 128.398 174.311 128.014 174.055 cv +127.63 173.799 127.334 173.471 127.126 173.07 cv +126.917 172.671 126.78 172.23 126.712 171.75 cv +126.643 171.27 126.61 170.807 126.61 170.358 cv +126.61 169.775 126.66 169.209 126.76 168.66 cv +126.86 168.113 127.03 167.627 127.27 167.203 cv +127.51 166.779 127.829 166.439 128.23 166.183 cv +128.63 165.927 129.134 165.799 129.742 165.799 cv +130.446 165.799 131.006 165.984 131.422 166.356 cv +131.838 166.729 132.078 167.267 132.142 167.971 cv +131.121 167.971 li +131.074 167.586 130.926 167.279 130.678 167.047 cv +cp +f +138.316 170.305 mo +138.24 170.029 138.123 169.783 137.968 169.566 cv +137.811 169.35 137.612 169.179 137.368 169.051 cv +137.123 168.923 136.837 168.858 136.51 168.858 cv +136.165 168.858 135.873 168.927 135.634 169.063 cv +135.393 169.199 135.198 169.377 135.046 169.597 cv +134.893 169.816 134.784 170.066 134.716 170.347 cv +134.647 170.627 134.614 170.91 134.614 171.199 cv +134.614 171.503 134.65 171.797 134.722 172.08 cv +134.793 172.365 134.908 172.615 135.063 172.83 cv +135.22 173.047 135.421 173.221 135.67 173.352 cv +135.917 173.484 136.218 173.551 136.57 173.551 cv +136.921 173.551 137.216 173.482 137.452 173.347 cv +137.688 173.211 137.877 173.031 138.021 172.807 cv +138.165 172.583 138.27 172.326 138.333 172.039 cv +138.397 171.75 138.43 171.455 138.43 171.15 cv +138.43 170.863 138.392 170.58 138.316 170.305 cv +cp +134.65 168.102 mo +134.65 168.943 li +134.674 168.943 li +134.842 168.599 135.105 168.349 135.466 168.193 cv +135.826 168.037 136.222 167.959 136.654 167.959 cv +137.134 167.959 137.552 168.047 137.908 168.223 cv +138.264 168.398 138.559 168.637 138.796 168.936 cv +139.032 169.236 139.209 169.583 139.329 169.975 cv +139.45 170.367 139.51 170.783 139.51 171.223 cv +139.51 171.662 139.452 172.078 139.335 172.471 cv +139.22 172.863 139.043 173.205 138.808 173.496 cv +138.572 173.789 138.275 174.018 137.92 174.186 cv +137.563 174.354 137.149 174.438 136.678 174.438 cv +136.525 174.438 136.355 174.422 136.167 174.391 cv +135.979 174.358 135.793 174.307 135.61 174.234 cv +135.426 174.162 135.251 174.064 135.088 173.94 cv +134.924 173.816 134.786 173.662 134.674 173.479 cv +134.65 173.479 li +134.65 176.67 li +133.63 176.67 li +133.63 168.102 li +134.65 168.102 li +cp +f +140.217 168.102 mo +141.525 168.102 li +143.013 170.274 li +144.561 168.102 li +145.786 168.102 li +143.649 170.959 li +146.049 174.307 li +144.741 174.307 li +143.013 171.738 li +141.286 174.307 li +140.049 174.307 li +142.377 171.043 li +140.217 168.102 li +cp +f +150.225 170.49 mo +150.225 171.451 li +146.757 171.451 li +146.757 170.49 li +150.225 170.49 li +cp +f +154.077 174.307 mo +154.077 168.211 li +151.869 168.211 li +151.869 167.395 li +152.157 167.395 152.437 167.373 152.709 167.328 cv +152.981 167.285 153.227 167.203 153.447 167.082 cv +153.667 166.963 153.853 166.799 154.005 166.591 cv +154.157 166.383 154.261 166.119 154.317 165.799 cv +155.097 165.799 li +155.097 174.307 li +154.077 174.307 li +cp +f +158.157 167.611 mo +158.269 167.242 158.443 166.925 158.679 166.656 cv +158.915 166.389 159.209 166.179 159.561 166.027 cv +159.913 165.875 160.313 165.799 160.761 165.799 cv +161.129 165.799 161.475 165.852 161.799 165.961 cv +162.123 166.068 162.405 166.225 162.645 166.429 cv +162.885 166.633 163.075 166.887 163.215 167.19 cv +163.355 167.494 163.425 167.847 163.425 168.246 cv +163.425 168.623 163.367 168.955 163.251 169.242 cv +163.135 169.531 162.981 169.789 162.789 170.017 cv +162.597 170.244 162.377 170.451 162.129 170.635 cv +161.881 170.818 161.625 170.994 161.361 171.162 cv +161.097 171.322 160.833 171.48 160.569 171.637 cv +160.305 171.793 160.063 171.959 159.843 172.135 cv +159.623 172.311 159.435 172.5 159.279 172.705 cv +159.123 172.908 159.021 173.143 158.973 173.406 cv +163.341 173.406 li +163.341 174.307 li +157.785 174.307 li +157.825 173.803 157.915 173.373 158.055 173.017 cv +158.195 172.66 158.373 172.35 158.589 172.086 cv +158.805 171.822 159.049 171.591 159.321 171.391 cv +159.593 171.191 159.877 171.003 160.173 170.826 cv +160.533 170.602 160.849 170.396 161.121 170.209 cv +161.393 170.021 161.619 169.83 161.799 169.639 cv +161.979 169.447 162.115 169.238 162.207 169.015 cv +162.299 168.791 162.345 168.531 162.345 168.234 cv +162.345 168.003 162.301 167.793 162.213 167.604 cv +162.125 167.417 162.007 167.255 161.859 167.119 cv +161.711 166.982 161.537 166.879 161.337 166.807 cv +161.137 166.734 160.925 166.699 160.701 166.699 cv +160.405 166.699 160.151 166.761 159.939 166.885 cv +159.727 167.009 159.553 167.171 159.417 167.371 cv +159.281 167.57 159.183 167.797 159.123 168.049 cv +159.063 168.301 159.037 168.555 159.045 168.811 cv +158.025 168.811 li +158.001 168.379 158.045 167.979 158.157 167.611 cv +cp +f +165.783 171.193 mo +165.803 171.589 165.868 171.961 165.975 172.309 cv +166.083 172.656 166.257 172.951 166.497 173.19 cv +166.737 173.431 167.073 173.551 167.505 173.551 cv +167.938 173.551 168.273 173.431 168.514 173.19 cv +168.753 172.951 168.927 172.656 169.036 172.309 cv +169.143 171.961 169.207 171.589 169.227 171.193 cv +169.247 170.797 169.257 170.438 169.257 170.119 cv +169.257 169.91 169.255 169.681 169.251 169.429 cv +169.247 169.177 169.227 168.925 169.191 168.673 cv +169.155 168.42 169.104 168.175 169.036 167.934 cv +168.967 167.695 168.868 167.484 168.735 167.305 cv +168.604 167.125 168.438 166.979 168.237 166.867 cv +168.037 166.755 167.793 166.699 167.505 166.699 cv +167.217 166.699 166.973 166.755 166.773 166.867 cv +166.573 166.979 166.407 167.125 166.275 167.305 cv +166.143 167.484 166.043 167.695 165.975 167.934 cv +165.907 168.175 165.855 168.42 165.819 168.673 cv +165.783 168.925 165.763 169.177 165.759 169.429 cv +165.755 169.681 165.753 169.91 165.753 170.119 cv +165.753 170.438 165.763 170.797 165.783 171.193 cv +cp +164.697 169.158 mo +164.713 168.822 164.753 168.494 164.817 168.175 cv +164.881 167.855 164.974 167.551 165.093 167.263 cv +165.213 166.975 165.377 166.723 165.585 166.507 cv +165.793 166.291 166.055 166.119 166.371 165.99 cv +166.688 165.863 167.065 165.799 167.505 165.799 cv +167.945 165.799 168.323 165.863 168.64 165.99 cv +168.955 166.119 169.217 166.291 169.425 166.507 cv +169.633 166.723 169.797 166.975 169.917 167.263 cv +170.037 167.551 170.129 167.855 170.193 168.175 cv +170.257 168.494 170.297 168.822 170.313 169.158 cv +170.329 169.494 170.337 169.818 170.337 170.131 cv +170.337 170.443 170.329 170.767 170.313 171.102 cv +170.297 171.438 170.257 171.767 170.193 172.086 cv +170.129 172.406 170.037 172.709 169.917 172.992 cv +169.797 173.277 169.633 173.527 169.425 173.742 cv +169.217 173.959 168.957 174.129 168.645 174.252 cv +168.333 174.377 167.954 174.438 167.505 174.438 cv +167.065 174.438 166.688 174.377 166.371 174.252 cv +166.055 174.129 165.793 173.959 165.585 173.742 cv +165.377 173.527 165.213 173.277 165.093 172.992 cv +164.974 172.709 164.881 172.406 164.817 172.086 cv +164.753 171.767 164.713 171.438 164.697 171.102 cv +164.681 170.767 164.673 170.443 164.673 170.131 cv +164.673 169.818 164.681 169.494 164.697 169.158 cv +cp +f +176.331 170.305 mo +176.255 170.029 176.139 169.783 175.983 169.566 cv +175.827 169.35 175.627 169.179 175.383 169.051 cv +175.139 168.923 174.853 168.858 174.525 168.858 cv +174.181 168.858 173.889 168.927 173.649 169.063 cv +173.409 169.199 173.213 169.377 173.061 169.597 cv +172.909 169.816 172.799 170.066 172.731 170.347 cv +172.663 170.627 172.629 170.91 172.629 171.199 cv +172.629 171.503 172.665 171.797 172.737 172.08 cv +172.809 172.365 172.923 172.615 173.079 172.83 cv +173.235 173.047 173.437 173.221 173.686 173.352 cv +173.933 173.484 174.233 173.551 174.585 173.551 cv +174.937 173.551 175.231 173.482 175.467 173.347 cv +175.703 173.211 175.893 173.031 176.037 172.807 cv +176.181 172.583 176.285 172.326 176.349 172.039 cv +176.413 171.75 176.445 171.455 176.445 171.15 cv +176.445 170.863 176.407 170.58 176.331 170.305 cv +cp +172.665 168.102 mo +172.665 168.943 li +172.689 168.943 li +172.857 168.599 173.121 168.349 173.481 168.193 cv +173.841 168.037 174.237 167.959 174.669 167.959 cv +175.149 167.959 175.567 168.047 175.923 168.223 cv +176.279 168.398 176.575 168.637 176.811 168.936 cv +177.047 169.236 177.225 169.583 177.345 169.975 cv +177.465 170.367 177.525 170.783 177.525 171.223 cv +177.525 171.662 177.467 172.078 177.351 172.471 cv +177.235 172.863 177.059 173.205 176.823 173.496 cv +176.587 173.789 176.291 174.018 175.936 174.186 cv +175.579 174.354 175.165 174.438 174.693 174.438 cv +174.541 174.438 174.371 174.422 174.183 174.391 cv +173.995 174.358 173.809 174.307 173.625 174.234 cv +173.441 174.162 173.267 174.064 173.104 173.94 cv +172.939 173.816 172.801 173.662 172.689 173.479 cv +172.665 173.479 li +172.665 176.67 li +171.645 176.67 li +171.645 168.102 li +172.665 168.102 li +cp +f +178.233 168.102 mo +179.541 168.102 li +181.029 170.274 li +182.577 168.102 li +183.801 168.102 li +181.665 170.959 li +184.065 174.307 li +182.757 174.307 li +181.029 171.738 li +179.301 174.307 li +178.065 174.307 li +180.393 171.043 li +178.233 168.102 li +cp +f +335.633 151.338 mo +335.633 158.945 li +340.169 158.945 li +340.169 159.906 li +334.494 159.906 li +334.494 151.338 li +335.633 151.338 li +cp +f +344.333 156.912 mo +344.124 156.956 343.908 156.992 343.679 157.02 cv +343.451 157.048 343.22 157.08 342.989 157.115 cv +342.757 157.152 342.548 157.21 342.365 157.289 cv +342.181 157.369 342.031 157.484 341.915 157.632 cv +341.798 157.779 341.742 157.982 341.742 158.238 cv +341.742 158.406 341.775 158.548 341.843 158.664 cv +341.911 158.779 341.999 158.873 342.107 158.945 cv +342.214 159.018 342.343 159.07 342.492 159.102 cv +342.639 159.134 342.788 159.15 342.941 159.15 cv +343.277 159.15 343.565 159.104 343.805 159.012 cv +344.044 158.92 344.241 158.804 344.393 158.664 cv +344.544 158.523 344.658 158.371 344.729 158.207 cv +344.8 158.044 344.837 157.89 344.837 157.746 cv +344.837 156.701 li +344.708 156.798 344.54 156.867 344.333 156.912 cv +cp +345.761 160.037 mo +345.497 160.037 345.287 159.964 345.13 159.816 cv +344.975 159.668 344.897 159.426 344.897 159.09 cv +344.617 159.426 344.29 159.668 343.919 159.816 cv +343.546 159.964 343.145 160.037 342.712 160.037 cv +342.433 160.037 342.169 160.008 341.921 159.947 cv +341.673 159.888 341.454 159.787 341.267 159.648 cv +341.079 159.508 340.931 159.328 340.824 159.107 cv +340.714 158.888 340.662 158.621 340.662 158.309 cv +340.662 157.958 340.721 157.67 340.841 157.445 cv +340.96 157.222 341.119 157.04 341.315 156.9 cv +341.511 156.76 341.735 156.654 341.987 156.582 cv +342.239 156.51 342.497 156.449 342.761 156.402 cv +343.04 156.346 343.307 156.304 343.559 156.275 cv +343.811 156.248 344.033 156.208 344.225 156.156 cv +344.417 156.104 344.569 156.027 344.681 155.928 cv +344.792 155.828 344.849 155.682 344.849 155.49 cv +344.849 155.266 344.807 155.086 344.723 154.949 cv +344.639 154.814 344.531 154.71 344.399 154.638 cv +344.267 154.566 344.119 154.518 343.954 154.494 cv +343.79 154.47 343.628 154.457 343.469 154.457 cv +343.037 154.457 342.677 154.54 342.389 154.703 cv +342.101 154.867 341.945 155.178 341.921 155.634 cv +340.901 155.634 li +340.917 155.25 340.997 154.926 341.141 154.662 cv +341.285 154.398 341.477 154.184 341.716 154.02 cv +341.956 153.855 342.233 153.738 342.544 153.666 cv +342.857 153.594 343.185 153.558 343.529 153.558 cv +343.809 153.558 344.087 153.578 344.363 153.617 cv +344.639 153.658 344.889 153.74 345.113 153.863 cv +345.337 153.988 345.517 154.162 345.653 154.386 cv +345.788 154.609 345.857 154.902 345.857 155.262 cv +345.857 158.453 li +345.857 158.693 345.871 158.869 345.899 158.982 cv +345.927 159.094 346.021 159.15 346.181 159.15 cv +346.269 159.15 346.372 159.13 346.494 159.09 cv +346.494 159.882 li +346.317 159.986 346.074 160.037 345.761 160.037 cv +cp +f +348.365 153.701 mo +348.365 155.01 li +348.388 155.01 li +348.636 154.506 348.941 154.134 349.3 153.893 cv +349.661 153.654 350.117 153.542 350.669 153.558 cv +350.669 154.638 li +350.261 154.638 349.913 154.693 349.624 154.806 cv +349.337 154.918 349.105 155.082 348.929 155.298 cv +348.753 155.514 348.624 155.775 348.544 156.084 cv +348.464 156.392 348.425 156.746 348.425 157.146 cv +348.425 159.906 li +347.405 159.906 li +347.405 153.701 li +348.365 153.701 li +cp +f +354.454 158.867 mo +354.691 158.729 354.88 158.544 355.025 158.316 cv +355.169 158.088 355.275 157.83 355.343 157.542 cv +355.411 157.254 355.445 156.966 355.445 156.678 cv +355.445 156.406 355.413 156.138 355.349 155.873 cv +355.285 155.609 355.183 155.371 355.042 155.16 cv +354.903 154.947 354.72 154.777 354.497 154.65 cv +354.273 154.521 354.001 154.457 353.681 154.457 cv +353.353 154.457 353.073 154.52 352.841 154.643 cv +352.609 154.768 352.419 154.934 352.271 155.142 cv +352.122 155.35 352.015 155.59 351.947 155.861 cv +351.878 156.134 351.845 156.418 351.845 156.714 cv +351.845 156.994 351.872 157.273 351.929 157.554 cv +351.985 157.834 352.081 158.088 352.216 158.316 cv +352.353 158.544 352.533 158.729 352.757 158.867 cv +352.981 159.008 353.261 159.078 353.597 159.078 cv +353.933 159.078 354.218 159.008 354.454 158.867 cv +cp +355.757 161.658 mo +355.292 162.162 354.565 162.414 353.574 162.414 cv +353.285 162.414 352.992 162.382 352.691 162.318 cv +352.391 162.254 352.119 162.15 351.874 162.006 cv +351.63 161.861 351.429 161.674 351.269 161.441 cv +351.109 161.209 351.021 160.926 351.005 160.59 cv +352.025 160.59 li +352.033 160.773 352.091 160.93 352.199 161.058 cv +352.307 161.186 352.439 161.289 352.595 161.369 cv +352.751 161.449 352.921 161.508 353.105 161.544 cv +353.288 161.58 353.464 161.598 353.632 161.598 cv +353.969 161.598 354.253 161.539 354.485 161.424 cv +354.716 161.308 354.91 161.148 355.061 160.943 cv +355.212 160.74 355.323 160.494 355.391 160.205 cv +355.458 159.918 355.494 159.602 355.494 159.258 cv +355.494 158.85 li +355.469 158.85 li +355.292 159.234 355.027 159.516 354.671 159.695 cv +354.315 159.876 353.937 159.966 353.537 159.966 cv +353.073 159.966 352.669 159.882 352.326 159.714 cv +351.981 159.546 351.693 159.32 351.46 159.035 cv +351.229 158.752 351.054 158.42 350.939 158.039 cv +350.823 157.66 350.765 157.258 350.765 156.834 cv +350.765 156.466 350.813 156.088 350.91 155.699 cv +351.005 155.313 351.165 154.96 351.389 154.643 cv +351.613 154.328 351.91 154.068 352.277 153.863 cv +352.645 153.66 353.097 153.558 353.632 153.558 cv +354.025 153.558 354.384 153.645 354.712 153.816 cv +355.04 153.988 355.296 154.246 355.481 154.59 cv +355.494 154.59 li +355.494 153.701 li +356.453 153.701 li +356.453 159.378 li +356.453 160.393 356.22 161.154 355.757 161.658 cv +cp +f +362.134 155.525 mo +362.042 155.309 361.919 155.123 361.763 154.968 cv +361.607 154.811 361.422 154.688 361.21 154.596 cv +360.998 154.504 360.765 154.457 360.509 154.457 cv +360.245 154.457 360.006 154.504 359.794 154.596 cv +359.582 154.688 359.4 154.814 359.248 154.974 cv +359.097 155.134 358.976 155.32 358.888 155.531 cv +358.8 155.744 358.748 155.97 358.733 156.21 cv +362.296 156.21 li +362.281 155.97 362.226 155.742 362.134 155.525 cv +cp +362.38 159.51 mo +361.917 159.861 361.332 160.037 360.628 160.037 cv +360.132 160.037 359.703 159.957 359.339 159.798 cv +358.974 159.638 358.668 159.414 358.421 159.126 cv +358.173 158.838 357.987 158.494 357.863 158.094 cv +357.739 157.693 357.668 157.258 357.653 156.785 cv +357.653 156.314 357.724 155.882 357.869 155.49 cv +358.013 155.098 358.214 154.758 358.474 154.47 cv +358.734 154.182 359.042 153.958 359.399 153.798 cv +359.754 153.638 360.144 153.558 360.569 153.558 cv +361.121 153.558 361.579 153.672 361.943 153.9 cv +362.306 154.128 362.599 154.418 362.819 154.77 cv +363.038 155.122 363.191 155.506 363.275 155.922 cv +363.359 156.338 363.392 156.734 363.376 157.109 cv +358.733 157.109 li +358.724 157.382 358.757 157.64 358.829 157.884 cv +358.901 158.128 359.017 158.344 359.177 158.531 cv +359.336 158.72 359.54 158.869 359.788 158.982 cv +360.037 159.094 360.329 159.15 360.664 159.15 cv +361.097 159.15 361.451 159.05 361.726 158.85 cv +362.003 158.65 362.185 158.346 362.273 157.938 cv +363.281 157.938 li +363.144 158.634 362.845 159.158 362.38 159.51 cv +cp +f +365.357 153.701 mo +365.357 155.01 li +365.38 155.01 li +365.628 154.506 365.933 154.134 366.292 153.893 cv +366.652 153.654 367.109 153.542 367.661 153.558 cv +367.661 154.638 li +367.252 154.638 366.905 154.693 366.617 154.806 cv +366.329 154.918 366.096 155.082 365.92 155.298 cv +365.745 155.514 365.617 155.775 365.537 156.084 cv +365.456 156.392 365.417 156.746 365.417 157.146 cv +365.417 159.906 li +364.396 159.906 li +364.396 153.701 li +365.357 153.701 li +cp +f +318.257 169.002 mo +318.257 168.102 li +319.301 168.102 li +319.301 167.178 li +319.301 166.674 319.447 166.291 319.74 166.031 cv +320.031 165.771 320.456 165.642 321.017 165.642 cv +321.113 165.642 321.223 165.65 321.347 165.666 cv +321.471 165.682 321.581 165.705 321.677 165.738 cv +321.677 166.625 li +321.589 166.594 321.494 166.572 321.389 166.559 cv +321.285 166.548 321.189 166.541 321.101 166.541 cv +320.853 166.541 320.662 166.59 320.525 166.686 cv +320.389 166.781 320.322 166.966 320.322 167.238 cv +320.322 168.102 li +321.521 168.102 li +321.521 169.002 li +320.322 169.002 li +320.322 174.306 li +319.301 174.306 li +319.301 169.002 li +318.257 169.002 li +cp +f +323.328 172.211 mo +323.427 172.504 323.565 172.748 323.742 172.943 cv +323.917 173.14 324.122 173.289 324.359 173.393 cv +324.595 173.498 324.845 173.55 325.109 173.55 cv +325.372 173.55 325.622 173.498 325.859 173.393 cv +326.095 173.289 326.3 173.14 326.477 172.943 cv +326.653 172.748 326.79 172.504 326.891 172.211 cv +326.992 171.92 327.04 171.586 327.04 171.209 cv +327.04 170.834 326.992 170.5 326.891 170.207 cv +326.79 169.916 326.653 169.67 326.477 169.47 cv +326.3 169.27 326.095 169.117 325.859 169.014 cv +325.622 168.91 325.372 168.857 325.109 168.857 cv +324.845 168.857 324.595 168.91 324.359 169.014 cv +324.122 169.117 323.917 169.27 323.742 169.47 cv +323.565 169.67 323.427 169.916 323.328 170.207 cv +323.227 170.5 323.177 170.834 323.177 171.209 cv +323.177 171.586 323.227 171.92 323.328 172.211 cv +cp +322.288 169.932 mo +322.417 169.535 322.609 169.191 322.865 168.9 cv +323.121 168.607 323.437 168.377 323.813 168.209 cv +324.189 168.041 324.621 167.957 325.109 167.957 cv +325.605 167.957 326.038 168.041 326.412 168.209 cv +326.783 168.377 327.097 168.607 327.353 168.9 cv +327.609 169.191 327.8 169.535 327.929 169.932 cv +328.057 170.328 328.121 170.754 328.121 171.209 cv +328.121 171.666 328.057 172.09 327.929 172.481 cv +327.8 172.873 327.609 173.216 327.353 173.508 cv +327.097 173.8 326.783 174.027 326.412 174.191 cv +326.038 174.355 325.605 174.438 325.109 174.438 cv +324.621 174.438 324.189 174.355 323.813 174.191 cv +323.437 174.027 323.121 173.8 322.865 173.508 cv +322.609 173.216 322.417 172.873 322.288 172.481 cv +322.162 172.09 322.097 171.666 322.097 171.209 cv +322.097 170.754 322.162 170.328 322.288 169.932 cv +cp +f +330.246 168.102 mo +330.246 169.41 li +330.269 169.41 li +330.517 168.906 330.822 168.533 331.181 168.293 cv +331.54 168.054 331.997 167.941 332.549 167.957 cv +332.549 169.037 li +332.141 169.037 331.793 169.094 331.505 169.205 cv +331.217 169.318 330.985 169.481 330.809 169.697 cv +330.633 169.914 330.505 170.176 330.425 170.484 cv +330.345 170.791 330.305 171.145 330.305 171.546 cv +330.305 174.306 li +329.285 174.306 li +329.285 168.102 li +330.246 168.102 li +cp +f +339.136 174.306 mo +339.136 168.209 li +336.929 168.209 li +336.929 167.393 li +337.216 167.393 337.496 167.371 337.769 167.328 cv +338.04 167.283 338.287 167.201 338.507 167.082 cv +338.726 166.961 338.912 166.798 339.065 166.59 cv +339.216 166.382 339.321 166.117 339.376 165.798 cv +340.157 165.798 li +340.157 174.306 li +339.136 174.306 li +cp +f +343.217 167.609 mo +343.329 167.242 343.503 166.924 343.74 166.656 cv +343.975 166.388 344.269 166.178 344.621 166.025 cv +344.973 165.874 345.372 165.798 345.822 165.798 cv +346.189 165.798 346.535 165.852 346.859 165.959 cv +347.183 166.068 347.465 166.224 347.704 166.428 cv +347.945 166.632 348.135 166.886 348.275 167.189 cv +348.415 167.494 348.486 167.846 348.486 168.246 cv +348.486 168.621 348.427 168.953 348.311 169.242 cv +348.195 169.529 348.04 169.787 347.849 170.016 cv +347.658 170.244 347.437 170.449 347.189 170.634 cv +346.941 170.818 346.685 170.994 346.421 171.162 cv +346.158 171.322 345.893 171.479 345.628 171.636 cv +345.365 171.791 345.122 171.958 344.904 172.134 cv +344.683 172.309 344.496 172.5 344.339 172.703 cv +344.183 172.908 344.081 173.142 344.033 173.406 cv +348.402 173.406 li +348.402 174.306 li +342.845 174.306 li +342.885 173.802 342.975 173.371 343.115 173.016 cv +343.255 172.66 343.433 172.35 343.649 172.086 cv +343.865 171.822 344.109 171.59 344.381 171.39 cv +344.653 171.189 344.937 171.002 345.233 170.826 cv +345.593 170.602 345.91 170.395 346.181 170.207 cv +346.453 170.02 346.679 169.83 346.859 169.638 cv +347.038 169.445 347.175 169.238 347.267 169.014 cv +347.359 168.789 347.406 168.529 347.406 168.234 cv +347.406 168.002 347.361 167.791 347.273 167.604 cv +347.185 167.416 347.067 167.254 346.919 167.117 cv +346.771 166.982 346.597 166.877 346.397 166.806 cv +346.197 166.734 345.985 166.697 345.761 166.697 cv +345.464 166.697 345.21 166.76 344.999 166.884 cv +344.787 167.008 344.613 167.17 344.477 167.369 cv +344.341 167.57 344.244 167.796 344.183 168.048 cv +344.122 168.3 344.097 168.554 344.105 168.809 cv +343.085 168.809 li +343.061 168.377 343.105 167.977 343.217 167.609 cv +cp +f +350.843 171.191 mo +350.863 171.588 350.927 171.959 351.035 172.308 cv +351.143 172.656 351.317 172.949 351.557 173.189 cv +351.796 173.43 352.132 173.55 352.565 173.55 cv +352.997 173.55 353.333 173.43 353.574 173.189 cv +353.813 172.949 353.987 172.656 354.095 172.308 cv +354.203 171.959 354.267 171.588 354.287 171.191 cv +354.306 170.796 354.317 170.438 354.317 170.117 cv +354.317 169.91 354.315 169.68 354.311 169.428 cv +354.306 169.176 354.287 168.924 354.251 168.672 cv +354.214 168.42 354.163 168.174 354.095 167.934 cv +354.027 167.693 353.927 167.484 353.794 167.304 cv +353.663 167.123 353.497 166.979 353.296 166.865 cv +353.097 166.754 352.853 166.697 352.565 166.697 cv +352.277 166.697 352.033 166.754 351.833 166.865 cv +351.632 166.979 351.466 167.123 351.335 167.304 cv +351.203 167.484 351.103 167.693 351.035 167.934 cv +350.966 168.174 350.915 168.42 350.878 168.672 cv +350.843 168.924 350.823 169.176 350.819 169.428 cv +350.815 169.68 350.813 169.91 350.813 170.117 cv +350.813 170.438 350.823 170.796 350.843 171.191 cv +cp +349.757 169.158 mo +349.773 168.822 349.813 168.494 349.876 168.174 cv +349.941 167.854 350.033 167.55 350.153 167.262 cv +350.273 166.974 350.437 166.722 350.645 166.506 cv +350.853 166.289 351.115 166.117 351.431 165.99 cv +351.747 165.861 352.124 165.798 352.565 165.798 cv +353.005 165.798 353.382 165.861 353.699 165.99 cv +354.015 166.117 354.277 166.289 354.485 166.506 cv +354.693 166.722 354.857 166.974 354.977 167.262 cv +355.097 167.55 355.189 167.854 355.253 168.174 cv +355.317 168.494 355.357 168.822 355.372 169.158 cv +355.389 169.494 355.397 169.818 355.397 170.13 cv +355.397 170.441 355.389 170.766 355.372 171.102 cv +355.357 171.438 355.317 171.766 355.253 172.086 cv +355.189 172.406 355.097 172.708 354.977 172.992 cv +354.857 173.275 354.693 173.525 354.485 173.742 cv +354.277 173.957 354.017 174.128 353.704 174.252 cv +353.393 174.375 353.013 174.438 352.565 174.438 cv +352.124 174.438 351.747 174.375 351.431 174.252 cv +351.115 174.128 350.853 173.957 350.645 173.742 cv +350.437 173.525 350.273 173.275 350.153 172.992 cv +350.033 172.708 349.941 172.406 349.876 172.086 cv +349.813 171.766 349.773 171.438 349.757 171.102 cv +349.741 170.766 349.733 170.441 349.733 170.13 cv +349.733 169.818 349.741 169.494 349.757 169.158 cv +cp +f +361.391 170.304 mo +361.315 170.027 361.199 169.781 361.042 169.565 cv +360.886 169.35 360.687 169.178 360.443 169.05 cv +360.199 168.922 359.912 168.857 359.585 168.857 cv +359.241 168.857 358.949 168.926 358.708 169.061 cv +358.468 169.197 358.273 169.375 358.121 169.596 cv +357.968 169.816 357.859 170.066 357.79 170.346 cv +357.722 170.626 357.689 170.91 357.689 171.197 cv +357.689 171.502 357.725 171.796 357.796 172.08 cv +357.869 172.363 357.983 172.613 358.138 172.83 cv +358.294 173.046 358.496 173.22 358.746 173.352 cv +358.993 173.484 359.292 173.55 359.645 173.55 cv +359.996 173.55 360.29 173.482 360.527 173.346 cv +360.763 173.21 360.953 173.029 361.097 172.806 cv +361.241 172.582 361.345 172.326 361.409 172.037 cv +361.472 171.75 361.505 171.453 361.505 171.15 cv +361.505 170.861 361.466 170.58 361.391 170.304 cv +cp +357.725 168.102 mo +357.725 168.941 li +357.749 168.941 li +357.917 168.598 358.181 168.348 358.54 168.191 cv +358.901 168.035 359.296 167.957 359.729 167.957 cv +360.208 167.957 360.626 168.046 360.983 168.222 cv +361.339 168.398 361.634 168.636 361.871 168.936 cv +362.107 169.236 362.285 169.582 362.405 169.974 cv +362.525 170.365 362.585 170.781 362.585 171.222 cv +362.585 171.662 362.527 172.078 362.411 172.47 cv +362.294 172.861 362.119 173.203 361.882 173.496 cv +361.647 173.787 361.351 174.018 360.996 174.186 cv +360.638 174.354 360.224 174.438 359.753 174.438 cv +359.601 174.438 359.431 174.422 359.243 174.39 cv +359.054 174.357 358.869 174.306 358.685 174.234 cv +358.501 174.162 358.327 174.064 358.163 173.939 cv +357.999 173.816 357.861 173.662 357.749 173.477 cv +357.725 173.477 li +357.725 176.67 li +356.704 176.67 li +356.704 168.102 li +357.725 168.102 li +cp +f +363.292 168.102 mo +364.601 168.102 li +366.088 170.273 li +367.636 168.102 li +368.861 168.102 li +366.724 170.957 li +369.124 174.306 li +367.816 174.306 li +366.088 171.738 li +364.361 174.306 li +363.124 174.306 li +365.453 171.041 li +363.292 168.102 li +cp +f +379.193 170.861 mo +379.193 171.678 li +376.577 171.678 li +376.577 174.306 li +375.761 174.306 li +375.761 171.678 li +373.145 171.678 li +373.145 170.861 li +375.761 170.861 li +375.761 168.234 li +376.577 168.234 li +376.577 170.861 li +379.193 170.861 li +cp +f +152.608 331.443 mo +143.614 331.443 136.32 338.736 136.32 347.733 cv +136.32 354.93 140.987 361.035 147.46 363.189 cv +148.275 363.339 148.572 362.836 148.572 362.404 cv +148.572 362.017 148.558 360.993 148.55 359.634 cv +144.019 360.618 143.063 357.45 143.063 357.45 cv +142.322 355.568 141.254 355.067 141.254 355.067 cv +139.775 354.057 141.366 354.077 141.366 354.077 cv +143.001 354.192 143.861 355.756 143.861 355.756 cv +145.314 358.245 147.674 357.526 148.602 357.109 cv +148.75 356.057 149.171 355.339 149.636 354.932 cv +146.019 354.521 142.216 353.123 142.216 346.881 cv +142.216 345.103 142.851 343.648 143.893 342.51 cv +143.725 342.098 143.166 340.441 144.053 338.199 cv +144.053 338.199 145.42 337.761 148.532 339.869 cv +149.831 339.507 151.225 339.327 152.61 339.32 cv +153.994 339.327 155.387 339.507 156.688 339.869 cv +159.798 337.761 161.163 338.199 161.163 338.199 cv +162.052 340.441 161.493 342.098 161.326 342.51 cv +162.37 343.648 163 345.103 163 346.881 cv +163 353.139 159.191 354.516 155.563 354.919 cv +156.147 355.422 156.668 356.416 156.668 357.935 cv +156.668 360.113 156.648 361.87 156.648 362.404 cv +156.648 362.84 156.942 363.347 157.768 363.188 cv +164.236 361.029 168.899 354.928 168.899 347.733 cv +168.899 338.736 161.605 331.443 152.608 331.443 cv +cp +0 0 0 0 cmyk +ef +350.609 282.434 mo +317.262 282.434 290.221 309.469 290.221 342.821 cv +290.221 369.502 307.524 392.138 331.518 400.123 cv +334.536 400.682 335.644 398.813 335.644 397.218 cv +335.644 395.778 335.588 391.021 335.562 385.975 cv +318.762 389.628 315.217 378.85 315.217 378.85 cv +312.47 371.87 308.512 370.014 308.512 370.014 cv +303.033 366.266 308.925 366.343 308.925 366.343 cv +314.989 366.768 318.182 372.566 318.182 372.566 cv +323.568 381.798 332.309 379.129 335.755 377.586 cv +336.297 373.684 337.862 371.018 339.589 369.511 cv +326.176 367.984 312.076 362.806 312.076 339.667 cv +312.076 333.074 314.435 327.687 318.298 323.458 cv +317.671 321.936 315.604 315.795 318.883 307.477 cv +318.883 307.477 323.954 305.854 335.494 313.667 cv +340.311 312.329 345.477 311.658 350.609 311.635 cv +355.741 311.658 360.911 312.329 365.737 313.667 cv +377.263 305.854 382.327 307.477 382.327 307.477 cv +385.614 315.795 383.546 321.936 382.919 323.458 cv +386.791 327.687 389.134 333.074 389.134 339.667 cv +389.134 362.861 375.007 367.968 361.56 369.463 cv +363.726 371.337 365.656 375.012 365.656 380.646 cv +365.656 388.725 365.586 395.228 365.586 397.218 cv +365.586 398.825 366.673 400.708 369.734 400.115 cv +393.715 392.121 410.996 369.493 410.996 342.821 cv +410.996 309.469 383.959 282.434 350.609 282.434 cv +cp +ef +313.093 369.137 mo +312.96 369.438 312.488 369.527 312.058 369.321 cv +311.62 369.124 311.374 368.715 311.516 368.414 cv +311.646 368.105 312.119 368.02 312.556 368.225 cv +312.995 368.423 313.245 368.836 313.093 369.137 cv +313.093 369.137 li +cp +f +315.539 371.865 mo +315.251 372.132 314.688 372.008 314.306 371.586 cv +313.911 371.165 313.837 370.602 314.129 370.331 cv +314.426 370.064 314.972 370.189 315.368 370.61 cv +315.763 371.036 315.84 371.595 315.539 371.865 cv +315.539 371.865 li +cp +f +317.92 375.343 mo +317.55 375.6 316.945 375.359 316.571 374.822 cv +316.201 374.285 316.201 373.641 316.579 373.383 cv +316.954 373.125 317.55 373.357 317.929 373.89 cv +318.298 374.435 318.298 375.08 317.92 375.343 cv +317.92 375.343 li +cp +f +321.182 378.703 mo +320.851 379.068 320.146 378.97 319.63 378.472 cv +319.102 377.985 318.955 377.294 319.287 376.929 cv +319.622 376.563 320.331 376.666 320.851 377.16 cv +321.375 377.646 321.535 378.342 321.182 378.703 cv +321.182 378.703 li +cp +f +325.682 380.654 mo +325.536 381.127 324.857 381.342 324.173 381.141 cv +323.49 380.934 323.043 380.38 323.181 379.902 cv +323.323 379.426 324.005 379.202 324.694 379.417 cv +325.376 379.623 325.824 380.173 325.682 380.654 cv +325.682 380.654 li +cp +f +330.624 381.016 mo +330.641 381.514 330.061 381.927 329.343 381.935 cv +328.621 381.952 328.037 381.549 328.029 381.059 cv +328.029 380.556 328.596 380.147 329.318 380.135 cv +330.036 380.121 330.624 380.521 330.624 381.016 cv +330.624 381.016 li +cp +f +335.223 380.233 mo +335.309 380.719 334.81 381.218 334.097 381.35 cv +333.396 381.479 332.747 381.179 332.658 380.697 cv +332.571 380.199 333.079 379.7 333.779 379.571 cv +334.493 379.447 335.132 379.739 335.223 380.233 cv +335.223 380.233 li +cp +f +224.898 276.5 mo +224.898 277 li +.828122 .409705 .05182 0 cmyk +@ +[.99995 1.9999 ] 0 dsh +224.898 279 mo +224.898 412.993 li +@ +[] 0 dsh +224.898 413.993 mo +224.898 414.493 li +@ +133.276 428.509 mo +132.895 428.232 132.41 428.095 131.818 428.095 cv +131.578 428.095 131.342 428.119 131.11 428.166 cv +130.877 428.215 130.672 428.295 130.492 428.406 cv +130.312 428.52 130.168 428.669 130.059 428.857 cv +129.952 429.045 129.898 429.279 129.898 429.559 cv +129.898 429.822 129.975 430.037 130.132 430.201 cv +130.287 430.365 130.496 430.499 130.756 430.603 cv +131.016 430.707 131.309 430.793 131.638 430.861 cv +131.966 430.929 132.3 431.003 132.64 431.082 cv +132.98 431.162 133.313 431.257 133.642 431.365 cv +133.97 431.473 134.264 431.619 134.524 431.803 cv +134.784 431.986 134.992 432.219 135.148 432.498 cv +135.304 432.779 135.382 433.131 135.382 433.555 cv +135.382 434.011 135.28 434.4 135.076 434.725 cv +134.871 435.049 134.61 435.313 134.29 435.517 cv +133.97 435.721 133.612 435.869 133.216 435.961 cv +132.82 436.053 132.426 436.099 132.034 436.099 cv +131.554 436.099 131.1 436.039 130.672 435.919 cv +130.244 435.799 129.868 435.617 129.544 435.373 cv +129.22 435.129 128.964 434.816 128.776 434.436 cv +128.588 434.057 128.494 433.607 128.494 433.087 cv +129.574 433.087 li +129.574 433.447 129.643 433.757 129.784 434.017 cv +129.924 434.277 130.108 434.49 130.336 434.658 cv +130.564 434.826 130.829 434.951 131.134 435.031 cv +131.438 435.111 131.749 435.15 132.07 435.15 cv +132.326 435.15 132.584 435.127 132.844 435.078 cv +133.104 435.031 133.338 434.949 133.546 434.832 cv +133.754 434.717 133.922 434.559 134.05 434.359 cv +134.178 434.158 134.242 433.902 134.242 433.591 cv +134.242 433.295 134.163 433.055 134.008 432.871 cv +133.852 432.688 133.643 432.537 133.384 432.421 cv +133.123 432.305 132.829 432.211 132.502 432.139 cv +132.174 432.066 131.84 431.992 131.5 431.916 cv +131.16 431.841 130.826 431.753 130.498 431.652 cv +130.17 431.553 129.875 431.421 129.616 431.257 cv +129.356 431.093 129.148 430.881 128.992 430.621 cv +128.836 430.361 128.758 430.035 128.758 429.642 cv +128.758 429.211 128.846 428.837 129.022 428.521 cv +129.198 428.205 129.432 427.945 129.724 427.74 cv +130.016 427.537 130.348 427.385 130.72 427.285 cv +131.092 427.185 131.474 427.135 131.866 427.135 cv +132.306 427.135 132.714 427.188 133.09 427.291 cv +133.466 427.395 133.796 427.559 134.079 427.783 cv +134.364 428.007 134.588 428.289 134.752 428.629 cv +134.915 428.969 135.006 429.375 135.022 429.847 cv +133.942 429.847 li +133.877 429.23 133.656 428.785 133.276 428.509 cv +cp +1 .5 0 0 cmyk +f +137.554 429.703 mo +137.554 430.615 li +137.578 430.615 li +138.041 429.91 138.709 429.559 139.581 429.559 cv +139.966 429.559 140.313 429.639 140.625 429.799 cv +140.938 429.959 141.158 430.23 141.286 430.615 cv +141.494 430.279 141.768 430.02 142.108 429.835 cv +142.448 429.65 142.822 429.559 143.229 429.559 cv +143.541 429.559 143.824 429.593 144.076 429.66 cv +144.328 429.728 144.543 429.835 144.724 429.978 cv +144.904 430.123 145.043 430.309 145.143 430.537 cv +145.244 430.765 145.293 431.039 145.293 431.359 cv +145.293 435.906 li +144.274 435.906 li +144.274 431.839 li +144.274 431.646 144.257 431.467 144.225 431.299 cv +144.194 431.131 144.134 430.984 144.046 430.861 cv +143.957 430.736 143.835 430.639 143.68 430.566 cv +143.524 430.494 143.322 430.459 143.074 430.459 cv +142.57 430.459 142.174 430.603 141.886 430.891 cv +141.598 431.179 141.454 431.563 141.454 432.043 cv +141.454 435.906 li +140.433 435.906 li +140.433 431.839 li +140.433 431.639 140.415 431.455 140.38 431.287 cv +140.344 431.119 140.282 430.973 140.194 430.849 cv +140.105 430.725 139.988 430.629 139.84 430.56 cv +139.691 430.492 139.501 430.459 139.27 430.459 cv +138.974 430.459 138.72 430.518 138.508 430.639 cv +138.295 430.759 138.123 430.902 137.992 431.07 cv +137.86 431.238 137.764 431.412 137.704 431.593 cv +137.643 431.773 137.614 431.923 137.614 432.043 cv +137.614 435.906 li +136.594 435.906 li +136.594 429.703 li +137.554 429.703 li +cp +f +150.165 432.912 mo +149.957 432.957 149.74 432.992 149.512 433.021 cv +149.284 433.049 149.053 433.08 148.821 433.117 cv +148.589 433.152 148.381 433.211 148.198 433.291 cv +148.013 433.371 147.863 433.484 147.747 433.633 cv +147.631 433.781 147.574 433.982 147.574 434.238 cv +147.574 434.406 147.607 434.549 147.675 434.664 cv +147.743 434.781 147.831 434.875 147.939 434.947 cv +148.047 435.018 148.175 435.07 148.324 435.103 cv +148.472 435.135 148.621 435.15 148.773 435.15 cv +149.109 435.15 149.397 435.105 149.638 435.013 cv +149.877 434.921 150.073 434.805 150.225 434.664 cv +150.377 434.525 150.49 434.373 150.561 434.209 cv +150.633 434.045 150.669 433.891 150.669 433.746 cv +150.669 432.703 li +150.541 432.799 150.373 432.869 150.165 432.912 cv +cp +151.594 436.039 mo +151.329 436.039 151.12 435.965 150.963 435.816 cv +150.808 435.669 150.729 435.427 150.729 435.091 cv +150.449 435.427 150.123 435.669 149.751 435.816 cv +149.379 435.965 148.977 436.039 148.545 436.039 cv +148.266 436.039 148.001 436.009 147.753 435.949 cv +147.505 435.889 147.287 435.789 147.1 435.648 cv +146.912 435.509 146.764 435.329 146.656 435.109 cv +146.547 434.889 146.494 434.623 146.494 434.31 cv +146.494 433.959 146.554 433.671 146.673 433.447 cv +146.793 433.223 146.951 433.041 147.147 432.9 cv +147.343 432.761 147.567 432.654 147.819 432.582 cv +148.071 432.511 148.329 432.451 148.594 432.402 cv +148.873 432.347 149.14 432.305 149.392 432.277 cv +149.643 432.249 149.866 432.209 150.058 432.156 cv +150.249 432.105 150.401 432.029 150.514 431.929 cv +150.625 431.828 150.682 431.683 150.682 431.49 cv +150.682 431.267 150.64 431.087 150.556 430.951 cv +150.472 430.814 150.363 430.711 150.231 430.639 cv +150.1 430.566 149.951 430.518 149.787 430.494 cv +149.623 430.471 149.461 430.459 149.302 430.459 cv +148.87 430.459 148.51 430.541 148.222 430.705 cv +147.933 430.869 147.777 431.179 147.753 431.635 cv +146.733 431.635 li +146.749 431.251 146.829 430.927 146.974 430.662 cv +147.118 430.398 147.309 430.185 147.549 430.021 cv +147.789 429.857 148.065 429.738 148.377 429.666 cv +148.689 429.595 149.017 429.559 149.361 429.559 cv +149.642 429.559 149.919 429.578 150.195 429.619 cv +150.472 429.658 150.722 429.74 150.945 429.865 cv +151.169 429.988 151.35 430.163 151.485 430.387 cv +151.621 430.611 151.689 430.902 151.689 431.263 cv +151.689 434.455 li +151.689 434.695 151.704 434.871 151.731 434.982 cv +151.759 435.095 151.854 435.15 152.014 435.15 cv +152.102 435.15 152.205 435.131 152.326 435.091 cv +152.326 435.883 li +152.149 435.986 151.906 436.039 151.594 436.039 cv +cp +f +154.354 427.339 mo +154.354 435.906 li +153.333 435.906 li +153.333 427.339 li +154.354 427.339 li +cp +f +157.017 427.339 mo +157.017 435.906 li +155.997 435.906 li +155.997 427.339 li +157.017 427.339 li +cp +f +101.854 445.002 mo +101.854 444.103 li +102.898 444.103 li +102.898 443.179 li +102.898 442.675 103.044 442.293 103.336 442.033 cv +103.628 441.773 104.054 441.642 104.614 441.642 cv +104.71 441.642 104.82 441.65 104.944 441.666 cv +105.068 441.683 105.178 441.707 105.274 441.738 cv +105.274 442.627 li +105.186 442.595 105.09 442.572 104.986 442.56 cv +104.882 442.549 104.786 442.543 104.698 442.543 cv +104.45 442.543 104.258 442.591 104.122 442.686 cv +103.986 442.783 103.918 442.967 103.918 443.238 cv +103.918 444.103 li +105.118 444.103 li +105.118 445.002 li +103.918 445.002 li +103.918 450.307 li +102.898 450.307 li +102.898 445.002 li +101.854 445.002 li +cp +f +106.924 448.213 mo +107.023 448.505 107.162 448.748 107.338 448.945 cv +107.514 449.141 107.72 449.291 107.955 449.395 cv +108.191 449.498 108.442 449.551 108.705 449.551 cv +108.97 449.551 109.22 449.498 109.455 449.395 cv +109.691 449.291 109.897 449.141 110.074 448.945 cv +110.249 448.748 110.388 448.505 110.488 448.213 cv +110.588 447.921 110.638 447.587 110.638 447.211 cv +110.638 446.834 110.588 446.501 110.488 446.209 cv +110.388 445.916 110.249 445.671 110.074 445.471 cv +109.897 445.271 109.691 445.119 109.455 445.015 cv +109.22 444.91 108.97 444.858 108.705 444.858 cv +108.442 444.858 108.191 444.91 107.955 445.015 cv +107.72 445.119 107.514 445.271 107.338 445.471 cv +107.162 445.671 107.023 445.916 106.924 446.209 cv +106.824 446.501 106.774 446.834 106.774 447.211 cv +106.774 447.587 106.824 447.921 106.924 448.213 cv +cp +105.886 445.933 mo +106.014 445.537 106.205 445.193 106.462 444.9 cv +106.718 444.609 107.034 444.379 107.41 444.211 cv +107.786 444.043 108.218 443.959 108.705 443.959 cv +109.202 443.959 109.636 444.043 110.008 444.211 cv +110.38 444.379 110.693 444.609 110.95 444.9 cv +111.205 445.193 111.397 445.537 111.526 445.933 cv +111.654 446.328 111.718 446.755 111.718 447.211 cv +111.718 447.666 111.654 448.091 111.526 448.482 cv +111.397 448.875 111.205 449.217 110.95 449.509 cv +110.693 449.801 110.38 450.029 110.008 450.193 cv +109.636 450.356 109.202 450.438 108.705 450.438 cv +108.218 450.438 107.786 450.356 107.41 450.193 cv +107.034 450.029 106.718 449.801 106.462 449.509 cv +106.205 449.217 106.014 448.875 105.886 448.482 cv +105.758 448.091 105.694 447.666 105.694 447.211 cv +105.694 446.755 105.758 446.328 105.886 445.933 cv +cp +f +113.842 444.103 mo +113.842 445.41 li +113.866 445.41 li +114.114 444.906 114.418 444.535 114.778 444.295 cv +115.138 444.055 115.594 443.943 116.146 443.959 cv +116.146 445.039 li +115.738 445.039 115.39 445.095 115.102 445.207 cv +114.814 445.318 114.581 445.482 114.406 445.699 cv +114.23 445.914 114.101 446.177 114.022 446.484 cv +113.942 446.793 113.902 447.146 113.902 447.547 cv +113.902 450.307 li +112.882 450.307 li +112.882 444.103 li +113.842 444.103 li +cp +f +122.733 450.307 mo +122.733 444.211 li +120.525 444.211 li +120.525 443.395 li +120.813 443.395 121.093 443.373 121.365 443.328 cv +121.637 443.285 121.883 443.203 122.103 443.082 cv +122.323 442.963 122.509 442.799 122.662 442.591 cv +122.813 442.383 122.917 442.119 122.974 441.799 cv +123.753 441.799 li +123.753 450.307 li +122.733 450.307 li +cp +f +128.829 445.885 mo +128.614 445.984 128.43 446.121 128.278 446.293 cv +128.126 446.465 128.012 446.669 127.936 446.904 cv +127.86 447.141 127.822 447.391 127.822 447.654 cv +127.822 447.918 127.862 448.166 127.942 448.398 cv +128.021 448.631 128.136 448.83 128.284 448.998 cv +128.432 449.166 128.616 449.301 128.836 449.4 cv +129.056 449.501 129.306 449.551 129.586 449.551 cv +129.866 449.551 130.112 449.501 130.324 449.4 cv +130.536 449.301 130.714 449.162 130.858 448.986 cv +131.002 448.81 131.112 448.608 131.188 448.381 cv +131.264 448.152 131.302 447.914 131.302 447.666 cv +131.302 447.402 131.268 447.152 131.2 446.916 cv +131.132 446.681 131.026 446.477 130.882 446.305 cv +130.738 446.133 130.558 445.994 130.342 445.891 cv +130.126 445.787 129.874 445.734 129.586 445.734 cv +129.298 445.734 129.046 445.785 128.829 445.885 cv +cp +130.678 443.047 mo +130.43 442.814 130.102 442.699 129.694 442.699 cv +129.262 442.699 128.913 442.805 128.65 443.017 cv +128.386 443.228 128.18 443.496 128.032 443.82 cv +127.884 444.145 127.782 444.494 127.725 444.871 cv +127.67 445.246 127.638 445.599 127.63 445.927 cv +127.654 445.951 li +127.894 445.559 128.192 445.275 128.548 445.099 cv +128.904 444.923 129.314 444.834 129.778 444.834 cv +130.186 444.834 130.552 444.904 130.876 445.045 cv +131.2 445.185 131.472 445.379 131.692 445.627 cv +131.912 445.875 132.082 446.166 132.202 446.502 cv +132.322 446.839 132.382 447.203 132.382 447.595 cv +132.382 447.906 132.334 448.23 132.238 448.566 cv +132.142 448.902 131.984 449.209 131.764 449.484 cv +131.543 449.761 131.252 449.988 130.888 450.168 cv +130.524 450.349 130.074 450.438 129.537 450.438 cv +128.906 450.438 128.398 450.31 128.014 450.055 cv +127.63 449.799 127.334 449.471 127.126 449.07 cv +126.917 448.671 126.78 448.23 126.712 447.75 cv +126.643 447.271 126.61 446.807 126.61 446.358 cv +126.61 445.775 126.66 445.209 126.76 444.66 cv +126.86 444.113 127.03 443.627 127.27 443.203 cv +127.51 442.779 127.829 442.439 128.23 442.183 cv +128.63 441.927 129.134 441.799 129.742 441.799 cv +130.446 441.799 131.006 441.984 131.422 442.356 cv +131.838 442.728 132.078 443.267 132.142 443.971 cv +131.121 443.971 li +131.074 443.586 130.926 443.279 130.678 443.047 cv +cp +f +138.316 446.305 mo +138.24 446.029 138.123 445.783 137.968 445.566 cv +137.811 445.35 137.612 445.179 137.368 445.051 cv +137.123 444.923 136.837 444.858 136.51 444.858 cv +136.165 444.858 135.873 444.927 135.634 445.063 cv +135.393 445.199 135.198 445.377 135.046 445.597 cv +134.893 445.816 134.784 446.066 134.716 446.347 cv +134.647 446.627 134.614 446.91 134.614 447.199 cv +134.614 447.503 134.65 447.797 134.722 448.08 cv +134.793 448.365 134.908 448.615 135.063 448.83 cv +135.22 449.047 135.421 449.221 135.67 449.353 cv +135.917 449.484 136.218 449.551 136.57 449.551 cv +136.921 449.551 137.216 449.482 137.452 449.347 cv +137.688 449.211 137.877 449.031 138.021 448.807 cv +138.165 448.583 138.27 448.326 138.333 448.039 cv +138.397 447.75 138.43 447.455 138.43 447.15 cv +138.43 446.863 138.392 446.58 138.316 446.305 cv +cp +134.65 444.103 mo +134.65 444.943 li +134.674 444.943 li +134.842 444.599 135.105 444.349 135.466 444.193 cv +135.826 444.037 136.222 443.959 136.654 443.959 cv +137.134 443.959 137.552 444.047 137.908 444.223 cv +138.264 444.398 138.559 444.637 138.796 444.936 cv +139.032 445.236 139.209 445.583 139.329 445.975 cv +139.45 446.367 139.51 446.783 139.51 447.223 cv +139.51 447.662 139.452 448.078 139.335 448.471 cv +139.22 448.863 139.043 449.205 138.808 449.496 cv +138.572 449.789 138.275 450.018 137.92 450.186 cv +137.563 450.354 137.149 450.438 136.678 450.438 cv +136.525 450.438 136.355 450.422 136.167 450.391 cv +135.979 450.358 135.793 450.307 135.61 450.234 cv +135.426 450.162 135.251 450.064 135.088 449.94 cv +134.924 449.816 134.786 449.662 134.674 449.478 cv +134.65 449.478 li +134.65 452.67 li +133.63 452.67 li +133.63 444.103 li +134.65 444.103 li +cp +f +140.217 444.103 mo +141.525 444.103 li +143.013 446.274 li +144.561 444.103 li +145.786 444.103 li +143.649 446.959 li +146.049 450.307 li +144.741 450.307 li +143.013 447.738 li +141.286 450.307 li +140.049 450.307 li +142.377 447.043 li +140.217 444.103 li +cp +f +150.225 446.49 mo +150.225 447.451 li +146.757 447.451 li +146.757 446.49 li +150.225 446.49 li +cp +f +154.077 450.307 mo +154.077 444.211 li +151.869 444.211 li +151.869 443.395 li +152.157 443.395 152.437 443.373 152.709 443.328 cv +152.981 443.285 153.227 443.203 153.447 443.082 cv +153.667 442.963 153.853 442.799 154.005 442.591 cv +154.157 442.383 154.261 442.119 154.317 441.799 cv +155.097 441.799 li +155.097 450.307 li +154.077 450.307 li +cp +f +158.157 443.611 mo +158.269 443.242 158.443 442.925 158.679 442.656 cv +158.915 442.389 159.209 442.179 159.561 442.027 cv +159.913 441.875 160.313 441.799 160.761 441.799 cv +161.129 441.799 161.475 441.853 161.799 441.961 cv +162.123 442.068 162.405 442.225 162.645 442.429 cv +162.885 442.633 163.075 442.887 163.215 443.19 cv +163.355 443.494 163.425 443.847 163.425 444.246 cv +163.425 444.623 163.367 444.955 163.251 445.242 cv +163.135 445.531 162.981 445.789 162.789 446.017 cv +162.597 446.244 162.377 446.451 162.129 446.635 cv +161.881 446.818 161.625 446.994 161.361 447.162 cv +161.097 447.322 160.833 447.48 160.569 447.637 cv +160.305 447.793 160.063 447.959 159.843 448.135 cv +159.623 448.31 159.435 448.5 159.279 448.705 cv +159.123 448.908 159.021 449.142 158.973 449.406 cv +163.341 449.406 li +163.341 450.307 li +157.785 450.307 li +157.825 449.803 157.915 449.373 158.055 449.017 cv +158.195 448.66 158.373 448.35 158.589 448.086 cv +158.805 447.822 159.049 447.591 159.321 447.391 cv +159.593 447.191 159.877 447.003 160.173 446.826 cv +160.533 446.603 160.849 446.396 161.121 446.209 cv +161.393 446.021 161.619 445.83 161.799 445.639 cv +161.979 445.447 162.115 445.238 162.207 445.015 cv +162.299 444.791 162.345 444.531 162.345 444.234 cv +162.345 444.003 162.301 443.793 162.213 443.604 cv +162.125 443.417 162.007 443.255 161.859 443.119 cv +161.711 442.982 161.537 442.879 161.337 442.807 cv +161.137 442.734 160.925 442.699 160.701 442.699 cv +160.405 442.699 160.151 442.761 159.939 442.885 cv +159.727 443.009 159.553 443.171 159.417 443.371 cv +159.281 443.57 159.183 443.797 159.123 444.049 cv +159.063 444.301 159.037 444.555 159.045 444.81 cv +158.025 444.81 li +158.001 444.379 158.045 443.978 158.157 443.611 cv +cp +f +165.783 447.193 mo +165.803 447.589 165.868 447.961 165.975 448.309 cv +166.083 448.656 166.257 448.951 166.497 449.19 cv +166.737 449.431 167.073 449.551 167.505 449.551 cv +167.938 449.551 168.273 449.431 168.514 449.19 cv +168.753 448.951 168.927 448.656 169.036 448.309 cv +169.143 447.961 169.207 447.589 169.227 447.193 cv +169.247 446.797 169.257 446.438 169.257 446.119 cv +169.257 445.91 169.255 445.681 169.251 445.429 cv +169.247 445.177 169.227 444.925 169.191 444.673 cv +169.155 444.42 169.104 444.175 169.036 443.935 cv +168.967 443.695 168.868 443.484 168.735 443.305 cv +168.604 443.125 168.438 442.978 168.237 442.867 cv +168.037 442.755 167.793 442.699 167.505 442.699 cv +167.217 442.699 166.973 442.755 166.773 442.867 cv +166.573 442.978 166.407 443.125 166.275 443.305 cv +166.143 443.484 166.043 443.695 165.975 443.935 cv +165.907 444.175 165.855 444.42 165.819 444.673 cv +165.783 444.925 165.763 445.177 165.759 445.429 cv +165.755 445.681 165.753 445.91 165.753 446.119 cv +165.753 446.438 165.763 446.797 165.783 447.193 cv +cp +164.697 445.158 mo +164.713 444.822 164.753 444.494 164.817 444.175 cv +164.881 443.855 164.974 443.551 165.093 443.263 cv +165.213 442.975 165.377 442.723 165.585 442.507 cv +165.793 442.291 166.055 442.119 166.371 441.99 cv +166.688 441.863 167.065 441.799 167.505 441.799 cv +167.945 441.799 168.323 441.863 168.64 441.99 cv +168.955 442.119 169.217 442.291 169.425 442.507 cv +169.633 442.723 169.797 442.975 169.917 443.263 cv +170.037 443.551 170.129 443.855 170.193 444.175 cv +170.257 444.494 170.297 444.822 170.313 445.158 cv +170.329 445.494 170.337 445.818 170.337 446.131 cv +170.337 446.443 170.329 446.767 170.313 447.103 cv +170.297 447.438 170.257 447.767 170.193 448.086 cv +170.129 448.406 170.037 448.709 169.917 448.992 cv +169.797 449.277 169.633 449.527 169.425 449.742 cv +169.217 449.959 168.957 450.129 168.645 450.252 cv +168.333 450.377 167.954 450.438 167.505 450.438 cv +167.065 450.438 166.688 450.377 166.371 450.252 cv +166.055 450.129 165.793 449.959 165.585 449.742 cv +165.377 449.527 165.213 449.277 165.093 448.992 cv +164.974 448.709 164.881 448.406 164.817 448.086 cv +164.753 447.767 164.713 447.438 164.697 447.103 cv +164.681 446.767 164.673 446.443 164.673 446.131 cv +164.673 445.818 164.681 445.494 164.697 445.158 cv +cp +f +176.331 446.305 mo +176.255 446.029 176.139 445.783 175.983 445.566 cv +175.827 445.35 175.627 445.179 175.383 445.051 cv +175.139 444.923 174.853 444.858 174.525 444.858 cv +174.181 444.858 173.889 444.927 173.649 445.063 cv +173.409 445.199 173.213 445.377 173.061 445.597 cv +172.909 445.816 172.799 446.066 172.731 446.347 cv +172.663 446.627 172.629 446.91 172.629 447.199 cv +172.629 447.503 172.665 447.797 172.737 448.08 cv +172.809 448.365 172.923 448.615 173.079 448.83 cv +173.235 449.047 173.437 449.221 173.686 449.353 cv +173.933 449.484 174.233 449.551 174.585 449.551 cv +174.937 449.551 175.231 449.482 175.467 449.347 cv +175.703 449.211 175.893 449.031 176.037 448.807 cv +176.181 448.583 176.285 448.326 176.349 448.039 cv +176.413 447.75 176.445 447.455 176.445 447.15 cv +176.445 446.863 176.407 446.58 176.331 446.305 cv +cp +172.665 444.103 mo +172.665 444.943 li +172.689 444.943 li +172.857 444.599 173.121 444.349 173.481 444.193 cv +173.841 444.037 174.237 443.959 174.669 443.959 cv +175.149 443.959 175.567 444.047 175.923 444.223 cv +176.279 444.398 176.575 444.637 176.811 444.936 cv +177.047 445.236 177.225 445.583 177.345 445.975 cv +177.465 446.367 177.525 446.783 177.525 447.223 cv +177.525 447.662 177.467 448.078 177.351 448.471 cv +177.235 448.863 177.059 449.205 176.823 449.496 cv +176.587 449.789 176.291 450.018 175.936 450.186 cv +175.579 450.354 175.165 450.438 174.693 450.438 cv +174.541 450.438 174.371 450.422 174.183 450.391 cv +173.995 450.358 173.809 450.307 173.625 450.234 cv +173.441 450.162 173.267 450.064 173.104 449.94 cv +172.939 449.816 172.801 449.662 172.689 449.478 cv +172.665 449.478 li +172.665 452.67 li +171.645 452.67 li +171.645 444.103 li +172.665 444.103 li +cp +f +178.233 444.103 mo +179.541 444.103 li +181.029 446.274 li +182.577 444.103 li +183.801 444.103 li +181.665 446.959 li +184.065 450.307 li +182.757 450.307 li +181.029 447.738 li +179.301 450.307 li +178.065 450.307 li +180.393 447.043 li +178.233 444.103 li +cp +f +335.633 427.338 mo +335.633 434.945 li +340.169 434.945 li +340.169 435.906 li +334.494 435.906 li +334.494 427.338 li +335.633 427.338 li +cp +f +344.333 432.912 mo +344.124 432.956 343.908 432.992 343.679 433.02 cv +343.451 433.048 343.22 433.08 342.989 433.115 cv +342.757 433.152 342.548 433.21 342.365 433.289 cv +342.181 433.369 342.031 433.484 341.915 433.632 cv +341.798 433.779 341.742 433.982 341.742 434.238 cv +341.742 434.406 341.775 434.548 341.843 434.664 cv +341.911 434.779 341.999 434.873 342.107 434.945 cv +342.214 435.017 342.343 435.07 342.492 435.102 cv +342.639 435.134 342.788 435.15 342.941 435.15 cv +343.277 435.15 343.565 435.103 343.805 435.012 cv +344.044 434.92 344.241 434.804 344.393 434.664 cv +344.544 434.523 344.658 434.371 344.729 434.207 cv +344.8 434.044 344.837 433.89 344.837 433.746 cv +344.837 432.701 li +344.708 432.798 344.54 432.867 344.333 432.912 cv +cp +345.761 436.037 mo +345.497 436.037 345.287 435.964 345.13 435.816 cv +344.975 435.668 344.897 435.426 344.897 435.09 cv +344.617 435.426 344.29 435.668 343.919 435.816 cv +343.546 435.964 343.145 436.037 342.712 436.037 cv +342.433 436.037 342.169 436.008 341.921 435.947 cv +341.673 435.888 341.454 435.787 341.267 435.648 cv +341.079 435.508 340.931 435.328 340.824 435.107 cv +340.714 434.888 340.662 434.621 340.662 434.31 cv +340.662 433.958 340.721 433.67 340.841 433.445 cv +340.96 433.222 341.119 433.04 341.315 432.9 cv +341.511 432.76 341.735 432.654 341.987 432.582 cv +342.239 432.51 342.497 432.449 342.761 432.402 cv +343.04 432.346 343.307 432.304 343.559 432.275 cv +343.811 432.248 344.033 432.208 344.225 432.156 cv +344.417 432.103 344.569 432.027 344.681 431.928 cv +344.792 431.828 344.849 431.682 344.849 431.49 cv +344.849 431.266 344.807 431.086 344.723 430.949 cv +344.639 430.814 344.531 430.71 344.399 430.638 cv +344.267 430.566 344.119 430.517 343.954 430.494 cv +343.79 430.47 343.628 430.457 343.469 430.457 cv +343.037 430.457 342.677 430.54 342.389 430.703 cv +342.101 430.867 341.945 431.178 341.921 431.634 cv +340.901 431.634 li +340.917 431.25 340.997 430.926 341.141 430.662 cv +341.285 430.398 341.477 430.184 341.716 430.02 cv +341.956 429.855 342.233 429.738 342.544 429.666 cv +342.857 429.594 343.185 429.558 343.529 429.558 cv +343.809 429.558 344.087 429.578 344.363 429.617 cv +344.639 429.658 344.889 429.74 345.113 429.863 cv +345.337 429.988 345.517 430.162 345.653 430.386 cv +345.788 430.609 345.857 430.902 345.857 431.262 cv +345.857 434.453 li +345.857 434.693 345.871 434.869 345.899 434.982 cv +345.927 435.094 346.021 435.15 346.181 435.15 cv +346.269 435.15 346.372 435.13 346.494 435.09 cv +346.494 435.882 li +346.317 435.986 346.074 436.037 345.761 436.037 cv +cp +f +348.365 429.701 mo +348.365 431.01 li +348.388 431.01 li +348.636 430.506 348.941 430.134 349.3 429.893 cv +349.661 429.654 350.117 429.542 350.669 429.558 cv +350.669 430.638 li +350.261 430.638 349.913 430.693 349.624 430.806 cv +349.337 430.918 349.105 431.082 348.929 431.298 cv +348.753 431.514 348.624 431.775 348.544 432.084 cv +348.464 432.392 348.425 432.746 348.425 433.146 cv +348.425 435.906 li +347.405 435.906 li +347.405 429.701 li +348.365 429.701 li +cp +f +354.454 434.867 mo +354.691 434.728 354.88 434.544 355.025 434.316 cv +355.169 434.088 355.275 433.83 355.343 433.542 cv +355.411 433.254 355.445 432.966 355.445 432.678 cv +355.445 432.406 355.413 432.138 355.349 431.873 cv +355.285 431.609 355.183 431.371 355.042 431.16 cv +354.903 430.947 354.72 430.777 354.497 430.65 cv +354.273 430.521 354.001 430.457 353.681 430.457 cv +353.353 430.457 353.073 430.52 352.841 430.643 cv +352.609 430.767 352.419 430.934 352.271 431.142 cv +352.122 431.35 352.015 431.59 351.947 431.861 cv +351.878 432.134 351.845 432.418 351.845 432.714 cv +351.845 432.994 351.872 433.273 351.929 433.554 cv +351.985 433.834 352.081 434.088 352.216 434.316 cv +352.353 434.544 352.533 434.728 352.757 434.867 cv +352.981 435.008 353.261 435.078 353.597 435.078 cv +353.933 435.078 354.218 435.008 354.454 434.867 cv +cp +355.757 437.658 mo +355.292 438.162 354.565 438.414 353.574 438.414 cv +353.285 438.414 352.992 438.382 352.691 438.318 cv +352.391 438.254 352.119 438.15 351.874 438.006 cv +351.63 437.861 351.429 437.674 351.269 437.441 cv +351.109 437.209 351.021 436.926 351.005 436.59 cv +352.025 436.59 li +352.033 436.773 352.091 436.93 352.199 437.058 cv +352.307 437.185 352.439 437.289 352.595 437.369 cv +352.751 437.449 352.921 437.508 353.105 437.544 cv +353.288 437.58 353.464 437.598 353.632 437.598 cv +353.969 437.598 354.253 437.539 354.485 437.424 cv +354.716 437.308 354.91 437.148 355.061 436.943 cv +355.212 436.74 355.323 436.494 355.391 436.205 cv +355.458 435.918 355.494 435.602 355.494 435.258 cv +355.494 434.85 li +355.469 434.85 li +355.292 435.234 355.027 435.516 354.671 435.695 cv +354.315 435.876 353.937 435.966 353.537 435.966 cv +353.073 435.966 352.669 435.882 352.326 435.714 cv +351.981 435.546 351.693 435.32 351.46 435.035 cv +351.229 434.752 351.054 434.42 350.939 434.039 cv +350.823 433.66 350.765 433.258 350.765 432.834 cv +350.765 432.466 350.813 432.088 350.91 431.699 cv +351.005 431.313 351.165 430.96 351.389 430.643 cv +351.613 430.328 351.91 430.068 352.277 429.863 cv +352.645 429.66 353.097 429.558 353.632 429.558 cv +354.025 429.558 354.384 429.645 354.712 429.816 cv +355.04 429.988 355.296 430.246 355.481 430.59 cv +355.494 430.59 li +355.494 429.701 li +356.453 429.701 li +356.453 435.378 li +356.453 436.393 356.22 437.154 355.757 437.658 cv +cp +f +362.134 431.525 mo +362.042 431.31 361.919 431.123 361.763 430.968 cv +361.607 430.811 361.422 430.688 361.21 430.596 cv +360.998 430.504 360.765 430.457 360.509 430.457 cv +360.245 430.457 360.006 430.504 359.794 430.596 cv +359.582 430.688 359.4 430.814 359.248 430.974 cv +359.097 431.134 358.976 431.32 358.888 431.531 cv +358.8 431.744 358.748 431.97 358.733 432.21 cv +362.296 432.21 li +362.281 431.97 362.226 431.742 362.134 431.525 cv +cp +362.38 435.51 mo +361.917 435.861 361.332 436.037 360.628 436.037 cv +360.132 436.037 359.703 435.957 359.339 435.798 cv +358.974 435.638 358.668 435.414 358.421 435.126 cv +358.173 434.838 357.987 434.494 357.863 434.094 cv +357.739 433.693 357.668 433.258 357.653 432.785 cv +357.653 432.314 357.724 431.882 357.869 431.49 cv +358.013 431.098 358.214 430.758 358.474 430.47 cv +358.734 430.182 359.042 429.958 359.399 429.798 cv +359.754 429.638 360.144 429.558 360.569 429.558 cv +361.121 429.558 361.579 429.672 361.943 429.9 cv +362.306 430.128 362.599 430.418 362.819 430.77 cv +363.038 431.122 363.191 431.506 363.275 431.922 cv +363.359 432.338 363.392 432.734 363.376 433.109 cv +358.733 433.109 li +358.724 433.382 358.757 433.64 358.829 433.884 cv +358.901 434.128 359.017 434.344 359.177 434.531 cv +359.336 434.72 359.54 434.869 359.788 434.982 cv +360.037 435.094 360.329 435.15 360.664 435.15 cv +361.097 435.15 361.451 435.05 361.726 434.85 cv +362.003 434.65 362.185 434.346 362.273 433.938 cv +363.281 433.938 li +363.144 434.634 362.845 435.158 362.38 435.51 cv +cp +f +365.357 429.701 mo +365.357 431.01 li +365.38 431.01 li +365.628 430.506 365.933 430.134 366.292 429.893 cv +366.652 429.654 367.109 429.542 367.661 429.558 cv +367.661 430.638 li +367.252 430.638 366.905 430.693 366.617 430.806 cv +366.329 430.918 366.096 431.082 365.92 431.298 cv +365.745 431.514 365.617 431.775 365.537 432.084 cv +365.456 432.392 365.417 432.746 365.417 433.146 cv +365.417 435.906 li +364.396 435.906 li +364.396 429.701 li +365.357 429.701 li +cp +f +318.257 445.002 mo +318.257 444.102 li +319.301 444.102 li +319.301 443.178 li +319.301 442.674 319.447 442.291 319.74 442.031 cv +320.031 441.771 320.456 441.642 321.017 441.642 cv +321.113 441.642 321.223 441.65 321.347 441.666 cv +321.471 441.682 321.581 441.705 321.677 441.738 cv +321.677 442.625 li +321.589 442.594 321.494 442.572 321.389 442.56 cv +321.285 442.548 321.189 442.541 321.101 442.541 cv +320.853 442.541 320.662 442.59 320.525 442.685 cv +320.389 442.781 320.322 442.966 320.322 443.238 cv +320.322 444.102 li +321.521 444.102 li +321.521 445.002 li +320.322 445.002 li +320.322 450.306 li +319.301 450.306 li +319.301 445.002 li +318.257 445.002 li +cp +f +323.328 448.211 mo +323.427 448.504 323.565 448.748 323.742 448.943 cv +323.917 449.14 324.122 449.289 324.359 449.393 cv +324.595 449.498 324.845 449.55 325.109 449.55 cv +325.372 449.55 325.622 449.498 325.859 449.393 cv +326.095 449.289 326.3 449.14 326.477 448.943 cv +326.653 448.748 326.79 448.504 326.891 448.211 cv +326.992 447.92 327.04 447.586 327.04 447.209 cv +327.04 446.834 326.992 446.5 326.891 446.207 cv +326.79 445.916 326.653 445.67 326.477 445.47 cv +326.3 445.27 326.095 445.117 325.859 445.014 cv +325.622 444.91 325.372 444.857 325.109 444.857 cv +324.845 444.857 324.595 444.91 324.359 445.014 cv +324.122 445.117 323.917 445.27 323.742 445.47 cv +323.565 445.67 323.427 445.916 323.328 446.207 cv +323.227 446.5 323.177 446.834 323.177 447.209 cv +323.177 447.586 323.227 447.92 323.328 448.211 cv +cp +322.288 445.932 mo +322.417 445.535 322.609 445.191 322.865 444.9 cv +323.121 444.607 323.437 444.377 323.813 444.209 cv +324.189 444.041 324.621 443.957 325.109 443.957 cv +325.605 443.957 326.038 444.041 326.412 444.209 cv +326.783 444.377 327.097 444.607 327.353 444.9 cv +327.609 445.191 327.8 445.535 327.929 445.932 cv +328.057 446.328 328.121 446.754 328.121 447.209 cv +328.121 447.666 328.057 448.09 327.929 448.481 cv +327.8 448.873 327.609 449.216 327.353 449.508 cv +327.097 449.8 326.783 450.027 326.412 450.191 cv +326.038 450.355 325.605 450.438 325.109 450.438 cv +324.621 450.438 324.189 450.355 323.813 450.191 cv +323.437 450.027 323.121 449.8 322.865 449.508 cv +322.609 449.216 322.417 448.873 322.288 448.481 cv +322.162 448.09 322.097 447.666 322.097 447.209 cv +322.097 446.754 322.162 446.328 322.288 445.932 cv +cp +f +330.246 444.102 mo +330.246 445.41 li +330.269 445.41 li +330.517 444.906 330.822 444.533 331.181 444.293 cv +331.54 444.054 331.997 443.941 332.549 443.957 cv +332.549 445.037 li +332.141 445.037 331.793 445.094 331.505 445.205 cv +331.217 445.318 330.985 445.481 330.809 445.697 cv +330.633 445.914 330.505 446.176 330.425 446.484 cv +330.345 446.791 330.305 447.146 330.305 447.546 cv +330.305 450.306 li +329.285 450.306 li +329.285 444.102 li +330.246 444.102 li +cp +f +339.136 450.306 mo +339.136 444.209 li +336.929 444.209 li +336.929 443.393 li +337.216 443.393 337.496 443.371 337.769 443.328 cv +338.04 443.283 338.287 443.201 338.507 443.082 cv +338.726 442.961 338.912 442.798 339.065 442.59 cv +339.216 442.382 339.321 442.117 339.376 441.798 cv +340.157 441.798 li +340.157 450.306 li +339.136 450.306 li +cp +f +343.217 443.609 mo +343.329 443.242 343.503 442.924 343.74 442.656 cv +343.975 442.388 344.269 442.178 344.621 442.025 cv +344.973 441.874 345.372 441.798 345.822 441.798 cv +346.189 441.798 346.535 441.852 346.859 441.959 cv +347.183 442.068 347.465 442.224 347.704 442.428 cv +347.945 442.632 348.135 442.886 348.275 443.189 cv +348.415 443.494 348.486 443.846 348.486 444.246 cv +348.486 444.621 348.427 444.953 348.311 445.242 cv +348.195 445.529 348.04 445.787 347.849 446.016 cv +347.658 446.244 347.437 446.449 347.189 446.634 cv +346.941 446.818 346.685 446.994 346.421 447.162 cv +346.158 447.322 345.893 447.479 345.628 447.636 cv +345.365 447.791 345.122 447.958 344.904 448.134 cv +344.683 448.31 344.496 448.5 344.339 448.703 cv +344.183 448.908 344.081 449.142 344.033 449.406 cv +348.402 449.406 li +348.402 450.306 li +342.845 450.306 li +342.885 449.802 342.975 449.371 343.115 449.016 cv +343.255 448.66 343.433 448.35 343.649 448.086 cv +343.865 447.822 344.109 447.59 344.381 447.39 cv +344.653 447.189 344.937 447.002 345.233 446.826 cv +345.593 446.602 345.91 446.396 346.181 446.207 cv +346.453 446.02 346.679 445.83 346.859 445.638 cv +347.038 445.445 347.175 445.238 347.267 445.014 cv +347.359 444.789 347.406 444.529 347.406 444.234 cv +347.406 444.002 347.361 443.791 347.273 443.603 cv +347.185 443.416 347.067 443.254 346.919 443.117 cv +346.771 442.982 346.597 442.877 346.397 442.806 cv +346.197 442.734 345.985 442.697 345.761 442.697 cv +345.464 442.697 345.21 442.76 344.999 442.884 cv +344.787 443.008 344.613 443.17 344.477 443.369 cv +344.341 443.57 344.244 443.796 344.183 444.048 cv +344.122 444.3 344.097 444.554 344.105 444.81 cv +343.085 444.81 li +343.061 444.377 343.105 443.978 343.217 443.609 cv +cp +f +350.843 447.191 mo +350.863 447.588 350.927 447.959 351.035 448.308 cv +351.143 448.656 351.317 448.949 351.557 449.189 cv +351.796 449.43 352.132 449.55 352.565 449.55 cv +352.997 449.55 353.333 449.43 353.574 449.189 cv +353.813 448.949 353.987 448.656 354.095 448.308 cv +354.203 447.959 354.267 447.588 354.287 447.191 cv +354.306 446.796 354.317 446.438 354.317 446.117 cv +354.317 445.91 354.315 445.68 354.311 445.428 cv +354.306 445.176 354.287 444.924 354.251 444.672 cv +354.214 444.42 354.163 444.174 354.095 443.934 cv +354.027 443.693 353.927 443.484 353.794 443.304 cv +353.663 443.123 353.497 442.978 353.296 442.865 cv +353.097 442.754 352.853 442.697 352.565 442.697 cv +352.277 442.697 352.033 442.754 351.833 442.865 cv +351.632 442.978 351.466 443.123 351.335 443.304 cv +351.203 443.484 351.103 443.693 351.035 443.934 cv +350.966 444.174 350.915 444.42 350.878 444.672 cv +350.843 444.924 350.823 445.176 350.819 445.428 cv +350.815 445.68 350.813 445.91 350.813 446.117 cv +350.813 446.438 350.823 446.796 350.843 447.191 cv +cp +349.757 445.158 mo +349.773 444.822 349.813 444.494 349.876 444.174 cv +349.941 443.853 350.033 443.55 350.153 443.262 cv +350.273 442.974 350.437 442.722 350.645 442.506 cv +350.853 442.289 351.115 442.117 351.431 441.99 cv +351.747 441.861 352.124 441.798 352.565 441.798 cv +353.005 441.798 353.382 441.861 353.699 441.99 cv +354.015 442.117 354.277 442.289 354.485 442.506 cv +354.693 442.722 354.857 442.974 354.977 443.262 cv +355.097 443.55 355.189 443.853 355.253 444.174 cv +355.317 444.494 355.357 444.822 355.372 445.158 cv +355.389 445.494 355.397 445.818 355.397 446.13 cv +355.397 446.441 355.389 446.766 355.372 447.102 cv +355.357 447.438 355.317 447.766 355.253 448.086 cv +355.189 448.406 355.097 448.708 354.977 448.992 cv +354.857 449.275 354.693 449.525 354.485 449.742 cv +354.277 449.957 354.017 450.128 353.704 450.252 cv +353.393 450.375 353.013 450.438 352.565 450.438 cv +352.124 450.438 351.747 450.375 351.431 450.252 cv +351.115 450.128 350.853 449.957 350.645 449.742 cv +350.437 449.525 350.273 449.275 350.153 448.992 cv +350.033 448.708 349.941 448.406 349.876 448.086 cv +349.813 447.766 349.773 447.438 349.757 447.102 cv +349.741 446.766 349.733 446.441 349.733 446.13 cv +349.733 445.818 349.741 445.494 349.757 445.158 cv +cp +f +361.391 446.304 mo +361.315 446.027 361.199 445.781 361.042 445.565 cv +360.886 445.35 360.687 445.178 360.443 445.05 cv +360.199 444.922 359.912 444.857 359.585 444.857 cv +359.241 444.857 358.949 444.926 358.708 445.061 cv +358.468 445.197 358.273 445.375 358.121 445.596 cv +357.968 445.816 357.859 446.066 357.79 446.346 cv +357.722 446.626 357.689 446.91 357.689 447.197 cv +357.689 447.502 357.725 447.796 357.796 448.08 cv +357.869 448.363 357.983 448.613 358.138 448.83 cv +358.294 449.046 358.496 449.22 358.746 449.352 cv +358.993 449.484 359.292 449.55 359.645 449.55 cv +359.996 449.55 360.29 449.482 360.527 449.346 cv +360.763 449.21 360.953 449.029 361.097 448.806 cv +361.241 448.582 361.345 448.326 361.409 448.037 cv +361.472 447.75 361.505 447.453 361.505 447.15 cv +361.505 446.861 361.466 446.58 361.391 446.304 cv +cp +357.725 444.102 mo +357.725 444.941 li +357.749 444.941 li +357.917 444.598 358.181 444.348 358.54 444.191 cv +358.901 444.035 359.296 443.957 359.729 443.957 cv +360.208 443.957 360.626 444.046 360.983 444.222 cv +361.339 444.398 361.634 444.636 361.871 444.935 cv +362.107 445.236 362.285 445.582 362.405 445.974 cv +362.525 446.365 362.585 446.781 362.585 447.222 cv +362.585 447.662 362.527 448.078 362.411 448.47 cv +362.294 448.861 362.119 449.203 361.882 449.496 cv +361.647 449.787 361.351 450.017 360.996 450.185 cv +360.638 450.353 360.224 450.438 359.753 450.438 cv +359.601 450.438 359.431 450.422 359.243 450.39 cv +359.054 450.357 358.869 450.306 358.685 450.234 cv +358.501 450.162 358.327 450.064 358.163 449.939 cv +357.999 449.816 357.861 449.662 357.749 449.478 cv +357.725 449.478 li +357.725 452.67 li +356.704 452.67 li +356.704 444.102 li +357.725 444.102 li +cp +f +363.292 444.102 mo +364.601 444.102 li +366.088 446.273 li +367.636 444.102 li +368.861 444.102 li +366.724 446.957 li +369.124 450.306 li +367.816 450.306 li +366.088 447.738 li +364.361 450.306 li +363.124 450.306 li +365.453 447.041 li +363.292 444.102 li +cp +f +379.193 446.861 mo +379.193 447.678 li +376.577 447.678 li +376.577 450.306 li +375.761 450.306 li +375.761 447.678 li +373.145 447.678 li +373.145 446.861 li +375.761 446.861 li +375.761 444.234 li +376.577 444.234 li +376.577 446.861 li +379.193 446.861 li +cp +f +%ADOBeginClientInjection: EndPageContent "AI11EPS" +userdict /annotatepage 2 copy known {get exec}{pop pop} ifelse +%ADOEndClientInjection: EndPageContent "AI11EPS" +grestore +grestore +pgrs +%%PageTrailer +%ADOBeginClientInjection: PageTrailer Start "AI11EPS" +[/EMC AI11_PDFMark5 [/NamespacePop AI11_PDFMark5 +%ADOEndClientInjection: PageTrailer Start "AI11EPS" +[ +[/CSA [/0 ]] +] del_res +Adobe_AGM_Image/pt gx +Adobe_CoolType_Core/pt get exec Adobe_AGM_Core/pt gx +currentdict Adobe_AGM_Utils eq {end} if +%%Trailer +Adobe_AGM_Image/dt get exec +Adobe_CoolType_Core/dt get exec Adobe_AGM_Core/dt get exec +%%EOF +%AI9_PrintingDataEnd userdict /AI9_read_buffer 256 string put userdict begin /ai9_skip_data { mark { currentfile AI9_read_buffer { readline } stopped { } { not { exit } if (%AI9_PrivateDataEnd) eq { exit } if } ifelse } loop cleartomark } def end userdict /ai9_skip_data get exec %AI9_PrivateDataBegin %!PS-Adobe-3.0 EPSF-3.0 %%Creator: Adobe Illustrator(R) 14.0 %%AI8_CreatorVersion: 17.1.0 %%For: (Cameron McEfee) () %%Title: (GitHub-Mark.eps) %%CreationDate: 2/5/14 1:26 PM %%Canvassize: 16383 %AI9_DataStream %Gb"-6CQDf4FXHqmp4'"o#+RtYfba(G:Cs2UWmZjPM%deog^jl4Z^4#\:r@d'AIJN1* %mr.*4oCh#75J+N*_i$HT^Nf:VrT2#K^V0L+S%&ECFnk+5JDX: %A&i`$O'P5)kLZoOrU--kmpC'mVLH(ID*)q=?i?&@f=mFH;L^iJgN)t'T/$1+>V5Q7Rtc3$PJ:#(o@<;:^\Z9K?2]gc0>;c*c?J[< %h>8j3s1buO6V;dqs7O/)lA':a^&+]dYM\*4E1sm^gFqE4p$/%%`:omRo7FTnB.3fQ%_mJ_md!sC%1qBFo)gnnp*F=TA,6!QV`@)QJ#%-a;Iq^;-O7-D)rVFdbqQ"8p55L-9pNNgU.L0jTD#PN* %_"Cb,Diaqo9'rD2^OPo'YM9-Fp(nJ%o[gkQ_BusGo@<6_DmB&ogV44&/oM/a^3TU`s%U9"0D>5Qht[NHhd?B#>O27a%E@c6JUc@e %r8fk%fUr0?]=1"Pp[^>YIG=_mk,Yu+H$/f+Y?nqmqp*LWX/gaJc2Y)!r70=n$-ZJcIeViu%:K3:TBd;s^\b&:LU3%gpZfp$BQ*I6 %nc'\[qsN!Qm2D;B^%MBLmpCM7p:G'A[CgbUe^_FIGk^$LL]6Bo0Aa?dGK"`br:dCEDh!%@4&s9QD3#O`JE/fH*599B7h\#3U&*4_ %-@54]GD==^O?!=L2Hsdd;q*JdJqO&NaM@22uiZm2s>@\gu3K)_``KmZWQ\>1YBn]a"r^OGq:]AL;NH#A3iJ(IBn\#05W+27]ugM^DJs)!=bWo]R#hS"F;ns`]fr8IPIYJ,GWiEk>ip"GM_KkpToT.g38`VZ": %qto![H2$=SlW4VR4rh@V?b\<6HM,5fYM[)E)t`jYn%e?rIIXochnA#^]`6f/pA@5Zc@M,^XeT?2rRE]"d^2*Sge)$0X*6er70f-?C^o5Edr %W;gW$*U^9PnP/12o,ll'Gk:U/^WmgkIHj[^%6+1Ig.0FQnla7&?1mO@g%^??iV%57\3E*jm;Id7nTMK<\+B!-]A@G7qsDYqmHr`s %rU'3grbf4bn#!^=2r?32leQ`nhqd'.mV_L]mdBP8htQl_rHLPLpZ[.@?gcPCNT473a$8h+:KRMkG6S9Ir,&4+#G1S[V`SU-p6Ql1 %V/>(TD;DX;heom?G.ZRIpY5;QhhQX8dm!6D^@'aiml1,P^YSAPqu-=bIl#l=2q(L4R;\C\ok(hhDf0G&2n.Vfh9GoCo0\!E%c^tY %Ur.R^%dRObm"_(J_)HIad^+>bl-;+dB6(B$j/7\KrUbPRmV)^,A9j??#9ff(SK:_u4gl?BA %a#VE9]Zf]Sc22lE+6Hf)m/-VSdW`m=N6AT(AR:[6?++5"?2 %Y3>g)IdAuIV*3J]2.3da]\T\[8,V#3iGhZffT)S5^aF`koB/4RI`t>>!PGu:>JKnk]j8PT[_K-hHuDm,"E%!Z%\F&)J?4`LG/FQX#8"h3p`WKFF5-5Ji43Wpqm4TRIVK,nVpLLR%)I.<,WsV1 %]\sPGmRBsF+#[U4Y1G+JVe*$CD;4_udXE)'0tm1g,J)+:[\0NAYe'#'>]95@f)n77]8t`#kW4aP0sK!66,-;.q/AQWjVihAIic(V %9fi0lVf547r9t`ZdC6l=mlI_SIt%@hRodW!)T-[mD`62]XQ$2Y%<;5W)qjs8r[3G>\aJ'h^REbi,9TqYC%6hGRqltOZkT7$ZqAe$(c`h*$J %!3^]&4p]K[B?SWDBAkZ<8bneL&D%grKr=YMkbb]d3*NrSF.48D_gchn>CKU:$_Nh_i\UDZh%6n3H\\N>'1d!g%c'^!N=j*m5Jh'c %rFb/sk%Eq;Ip@/02JiMSgiKPY^44$Z/NPE'4mCtB)CGW\?1&fAaL%/V>lA[XU)h3$H %#BODQg1JiL0l!#5_Mq%WN%,bq]JIVgFLIOJ;9[RhkA6B)17C7_]ht2E,Ib.*RQ!]d2^?;"&`mOKF#5Z.K3pC>I>_#^6>k[s7,?F* %>bVhnJR[XOTCWb7idui'.PI=5$m1SUf(SA!0AG/m5Ps6+I59#jnOn=KcTZPcTDN\*f7Q#1hXZ_NkshS'7`D%L>ml14^f^tV\`IChBID(58K;8%f]f?Ih,@bkahqmD^XQgoADCK182hEJ*uc$74_*;$ZoNUnSl7(,6IgH.aU+bJ6[-lCa[PTk#otlL1!(?Vg?dZB0(=X1Je#7L@TBi$TO4i4f>c_\h0J%4hY0W1XGj41e!LVnC&n``Olb&Vq%?OV=N0dPh^`OJ2mo<&T]]cG(c`aZH7NlB=HqA5gr!KS?@FKOg`q!3dDs$",V(CG=t-[VDCgL>3FBFoZem,BHF,ol(1hf %4*!OjEX[;lJ1IJ+RIVAI`f=H]P8lVL]Hb%1+G[47]!tYD"DpgH(.SFLT4oRLUsho1P[,W%>J=<]FXCCJ5*O:h%(ZJ.]-,?Aa['M) %1+`3_;dV7U;rLo;"4\&('bbXh8ISQfgf"[@.Ys'6.VSf.qa.1fU^9=W2KFm8Gt.:\4h3q!Ka4o7)]?DYX<(KVSikgL\[\,tSii0c %b$b)P%]UaiIR4OE,ER=?%]Ub\HpS=C,=2qHobbpBM%i&O"U=lM5EAn'4a"PLC\c_f+f"/oTBj%kSi]*EH4G8B+a3j7_sSk.-f=d6/1=jQ1ZkXu%;UWk18>[=X]ql,9Ce3s/>A<#YBXe\1.ekY'u6g;p6el:L;D'_'* %_t21(QM0AqFlPr.b*\cm^\0nS4MH*04Ejr-m'jZ%?_._51qf?`i2R_c2R %b;N&dc^E6C%('*)O>p*uPHr>M]S>79db=Ye[lH*\5BM#!la6'IP]Y`B7^1;CilY2+nul81,?J!>OX''hYP2V\pe0M*.1Kp$Qm]T? %E=tu,/(#X+'d_9"Qg=mBX9EJlE(bc>^$!%EUDjJ"=pS0_#/VtmS&"W3$Q,l@GEr2#,?L8CZCspgY&*IiAFFPs=4k0!ou_G2=M?J$ %,)a'D$^f\aDTE1BdJsRHpj!*c(pV:UMqCEu)HO+sm.Ej&fM8=@5RZ7^[O$MSInj3NTB/,_Me$NkWY5kW)Z%Q1MZ\I)m9e4mYQ*=?hC,bl/1q)@u':]/'Ng6dL&6@J+^amdd$fn`8pUgTfY^ %TAc^-=$Q!5033o(;\*!:V;^h2TMNcF(s21Y-V6d*Cug6*98D5NWI'R+;t44hbo>7%4$kDgF!8b]/-f%$U?>*(Baon!jsA"F1U+qHo@6(WoZ(1N/dfO?)FfSMJ'LcGs`*k0'1 %GJk^"=]0A0Crk`d(nbQ8F^qNmDAOLbPnNCPWHHN6?T8#A'(=TfpY^Z*Ra4%oW7tABl0>H5K3Ot,?+Ucj^6;>R0;V$VS>L)#h2hJ8cMX).XGmb7GIfl--/cs%fV5N*WT,7ST%=iUOia(^5lde,FMqpA&r9?C+=qD_W*3@g"@YV&\9 %/3Xt;/d@1l#);jS>bR=3hI^/>CD=H@?qU]:J?jenfQ0@q9VI!:"!GbE$.(L2OuhG/K-EB15S2iYd,W^YFP3WKBX1QIVoM)__[f_" %plm@V)H1b%(9O-,CgrCB*!L[G$Oc@?Ad9'S.fcfEC&N7]G8iQ=E%rlL@0[Xl_f>% %&KM54$H/4@N4[ZbT\X.e/2LgG`Q$,Se_F6b].0DQ4(5UMf1Nnt'q^cikT%nh19S58_XZC[]ZWjLc\QM\Y(pM16qmEEKa/V7qQo92 %o9rclQX'dVS9S7em]*0S1!e$ajBXW.1p%I9`2r>^SNN5_A0PpOCk0b8UHolNT6hUmGd9Kol(6K)dgW`NjlrAfrQf>rm.W.$3KmU( %)r3]]/)ngWNH^tkE&7ZHHH(m<0qFq;YStm4@S5I5^,52WK0Cj*WcFHoC#42WO^4'u5<-"+E/g %HoC#42WL;iInIZPA2DLET(<'@rqNDgR$U$\^r'ZRmW%'O=(HO_do.tc'baO`To(#Y7Zi(,Nk1JaG2Gk-q7Nt,oj[n-2jC'CZ^E9O %S6+gK$4W4WT:UM3ufH8'9lOr91M>) %/tq\kKXsdQS%:C"h4@25Li`+]Wr]6m@iK`/b*]->MiMDUa..(Y)8ink%@q_+86hB(sid"@)ks"m/TBDQ498m5%)N1#U %o:e?TqqRCpl,p2o#gPTVfk3J>f^7rlB"'Q!pQY=$c_5d4$)XU_hSW1j-TZhHK%tiI>VCGR-6h3>ZHpQthm`H[7L)r#:d_A_ED9Ea %W2!*%;@4*uYER[9FAbRu:Xr?58u]/nW)HET-UKjdK[?S]nDjhuHGH19&)A,6[%>&R&Z(7&TXT+P.%M*N2cdbj&P@AEE4lP0MibUb %[)]DaNcBDgjB`k==%D_e)%b4n!1uUQ3lUTZMrM>ca&hFjBES(AUI`*@Pmp$QHu47Z>/l[*mFM_(I4::.laS5!?RbTE9#*sL;qUAEI@leg# %%Su?O3=:,)*fFDJX)9QR-mgf:AZ"PHB,P77mGZ-j(uO+7td*2]fI5hIMsuu#*%5Cj%\HV#p#)bnIe#,!TXhZ %^/nGGPf'/UUQ-,(2LiQ3WD^iE0IV:aI79\:]PEY@+;:`7m\3XW<-@nd3e'G+0\EB6"q-,pAMG;J1J64IO267.bM^b.1YA^t"q-.V %Us'#V)$r_OG7$:3K8f-SiZ(g#jVqq*MB&H'ktX!f*2NcuPPV%.CM33bF;GU:4JY;l+E'bo0oGahRHn9CfoljTIluQME?<-R,[VMP %cY4P[*ob,c\5[EdkrVH>00^DH"odo3V32SoK?Ji_nTTuYLPjT %a$4(RcURj#Jec&Qmq',7bk=Et+rdLEnV8N)RlbZT1Xj)i<3!$!XS>R&hI%!l7HkphU1rFdZ1knAHWGka(0nH^8?,H$:V074l5@S2 %6]\aGmYPgJpE+^m%sL&64?q-je_9;KP=?X`l])Et1td.(YY3XPcK%F.A3;u<4RB_n@Zn_K3TMoc?$"OL/&TifD.!RnP4We+2MAE1 %G>VL+VKYcU2@V2/>)$&>Zq:lJa--f)%sRt#O_L91M+lK(AS/D=q`paBS1!fG8T(1@D%7(`1UkIs=6/2-lGO#G]6M'(AfY=ReW7?d4>(K^9EEu>?Ou6cUV'%kE %WD`'"C/%grM)EKQ`7$2"FJh$Sdjo`lo,:OqG@ZOi:'KtJ.j&c_IP`<7.$K*" %A/hk0:rL31'9-0-:f1?^/7:]Fqo?PGGS[I&.R,D'\+fL,gQjc13>"EqAGoM5LLTVqe`H9?A5k*3lWi:0/XGrN-e]q3:EIjr]ff(3 %pVGXEh;a\XHLAe]/r(g)o>GR=nBKFp6#<0f(.YOGEL1`O*`Rf&c'^3I:<%l/-bOi0g)C9n^"d-:8:M\fXf\G\5RDUY?O_K>oY]>! %mD3>V:O+Bj3J\L6D-0ii6l&bi\tn:EKQm0@stXQ7(?CignC=0WmN! %CSdGSapI!E]A`1pF8r3%,ZS%"8G]7Trja_8>1tWMIMV=_,C.!]1?6&L[ %O557]hmMU)+'1[6IU.FI`I\X[Bt%hV(hhha/(dumclHTtim>"8gE-Bb'S,LEoL>ap.`Zk2.W"3GS()j/FQF@6:<,$P<^pH;n)s1cdt[Y_7m-Y);s %?WgAXHLr^0`ugjpo<[!Qq4f>-6`5l>pE1Q"bQYDoNO'$iG=9>4aT"*fi#1>#I686[0j&Wf`O7R%m.nOu/5(V>DUe!j!S*pkOa#ef %@H`;&e=BMJ5Fk;*aQbt1""d$mmK3ko=-:-g*7..,3^mk)6/#`M&aRn>XT_m&9JWo3=c0ib6OR> %5ZT4kEW#E^j8Vsbd3FqN&(lLVakiO)H66a2/t5ikhPIj"]):bS#Mg[AV1SO7n:#rQmiKUD58k8[kEH9)^U2XfG<-OWHV0e-Z41nG %"R'4``I6`mO5lSb$(7C)0Bna_ig7sQkhX$+c'=(4-iNj[3fm-P55RJ#k5ddXpr=DZQuBj&1!DPpA92Ri\I^PslnmO\Hc31_VO2,d %O*qe)>SaYoX#n_fSmb$J]G;RtrTt14VCWuGEXlrXj2=6cM1;*jKMWjd"RCZW(Ob"\5GX;mL-amKS6\k8s';HHkt/#qZF.U?%GV6-F( %%PPk&;pH+MW=#DBVq"U=MP#9pEllua)`ME%_ZS6Pq56;gqT,;3Wi,M]T'd7R@/]0q=9hHt@`mpg%$IkGT3uc5VlaV(rO/0]1d+f1 %jU(C_'ijDT]!k=]VQbk5F<]J"kXLgN6J6S=3j5j!7B"f[s'J=G[pe %PD>Ila/.1a"oLC+Zc]27Y1J*#6AuuNjDHQ[_rZOV%s3*>*rjFP?GD!_f2m`G?G-1HgYCq`[IJjBEd'N;DU0JHZbkc!*#a$j_rA*E %&smVq>b<8"DBfLk@h@G>[!5,uf/"/u*>@Ae0_*u0>[DW@Z[$[8:?V:H!9%Yi@/"U?@F!dg/!FMIgg-M^X/(j$8MRf?X;L9PnmX"a %A54&r*G:AEPV_kYA`Ug`OkjM&7^cW-_g-[\\\ED2N[I9h?3FbRq!oN`^A6m&f5KN\Ie36=B,,O?J*?mj48`[\^\mZAqtI;N]eQa@ %rq;i50>;mH&0JYm%;E(/[2N?l2T*c)e\"]0_nJlIe%/g(1H0BC2uN-Zrho_P&,^Rk/-"3cn=T`irVF:1nNZE1YC:Kan,K`/qT<1@ %(!pA_&n>6rCTSs??2]3-)@QE=H@W>]c22GGIt)P2metu-Qg\:rIIlIS+0L&^N;PVi[r9$lqWZ8No6u(4s4-H0Dr5tgYY/n]p>rJb %J+MsK?bLd]ri`L(g0XQhm!nlcJ+T6eJ\T4*s1h5s\?ZuM)n,FnJC6YslE>CVC<"L:@[m*BPG4%OCt>m=qo^t'`MDedC-ZXiEOraC %H`Ono]f*J@=*&tWhE(F&#QV7_@jC[?hR:8>0#+l$YK5ERD"Df'[Y_m@s)-"`GPe4DYPssgVJFsc0@/\f`66I%c2$'')#`g" %'/BaE<4cQCN]$I]-S3:BZT4BRoX;,@^Rc#aO3a?oBJsB.a+mlkI2f@r %i_6egqN+X_c39r?%5,I(i51osr_ZHH# %A5_,uC#cuB0EA=e4upmBlC8;b'*\#BaiE2k8F'ka0dF0U#cs71rWZSlm7LiG6dB-P?jPX+dndE,);o3f`$ii0g23H?>\1_5Qo8`b %6SOn4(>G9@04sWB]@8&jh*,^Yd*KuC;:EFggLk?'[Hr'aJF`qqcuq$d1[UqCOLn;W$)02oW,/F.5TY[8`@2qc'Kj_rkF %B0/-nh9O#Jd4!?6Ls/@+bFfQMk^A)FgNUpsRHutd5-d$tK2#bJCc%l$/V>ER86@b32D3I-nJc?[o6NcC3-I2g>OZ+:UEoplHE=ru %)pF7EHqJ45S`PCF!<>^"kaf1#^q#IBC[nf-=J"*T+AnH,,>E-A2#uu_"bDZ]lG&iS!F@ndL+)Y@#-;HlR$&IFas%>RWJtJ %cC$@K1G4"r([u4-_aq>oD^5)OkJPn0p9SbEo=(iJAfj\t\(`?6f4Qn%b%Q9lCjQSLN:1(RJaMSE?p"S-c$hkp %_HQ?00-eh/%l?MkPm-Ub2I<2=T(tmn#O5!LUZ`3 %0"l]-Q(>j#9,+tI`IIK[="h;``JaKZ?N4s0I.btCS"Bp)na#)HIJ9lD.8r5OLgRjoc)WL9I_L;G$i/f\+,gPmko3e3iqKW`"aGtJ %!?Uc<_F!+7jm&anFnMs<@__lN+8CtBr#9r5UKs,+0^8XGm76=]Cp+;'!d"lEc6btb).RD,^_d*a\=3emf!++XkGpJ(:&t#t,^':t %[0o2:>[/jG*l,qlg:4#%[FhmX2nQiEM_*WHPX2tk/=0r*mBlsDm3]o>S'c7O:P&i_oIWuc]J^WU?S0`L5@ST,!J\'Q#VNcR7V1qP %)K@R=D?.9279Xm[+BLg3`Y;Zdeba"k$W&\N[B'R.!,\4]qBb-/>HFsSYiUgaod5-*q_`os.Ligd[L\+ippQlUC"o0U/DK6m`<_.e %f@J(-(:aAp_]!\gD!Ab5TWthC'Ll,OXor_4'D?T^-Y$rY2IP!-P->\Ujl?=WrOmrr_.QEI&&-@pWX[qJeQ-)qbmlHSB*E+D2?TcQ %Q=7(ukK0k7r\stK)CK4nIS+d5QP%@C!5n6SLTfBrS:P#?2-r(dPo"ckP]PTa^fbb/,CE1Ek#&^2A>OS_$RsupGA:f7U)V3c%]Y>5AcFhip(_:5^leaVPK^[Wuf6*Ri*VfCeo.Q#Q %JXsLU)7).pV-sD4h41^Md8#2HN-JjSI7iEg%F0qV^uU\NMh&e'&5h<&a`hndAo@pm:1.;BaH"jYQSX3Z)`:jdhfB_,5u6,-h&suk %&ipnTK4C:bC>m(-g!@[R%i*'k)en"lGn&Y@bNoEW,E'6H#^de6$S2@:T6f\E3Btm&dFr"1#T3b$+d15B_pjk\D`o,dd[*OTJQ %^4ueHCQ?1g2XY#kbW.udNdR*#2Ze=n^;)qVqgpbCr<^)m[IuCQ7m;md/DD('iE,H7`J155#+,V2:]ghBa?*X02#?RF@D!U?I)tIs %M7Lrr$r11%G9[I-h>.$EB0D"g@jNojlc$)Q?KqqB&_OVlT)9+I[=Pk3L9^(PK\)@G7-pEMF;[44k0DnNd?+)DK91!#a2>B4"2[#c %I-(^N2icQfMm'Vk#$^d$g_CrACe4Q.$raJQab%Va^mc"j]g:RJ6$,%J&c`?^Mg(m"EsS>Tmr9(S+;/@Fj0G$hAZ2K`Rk)H(?u+f^ %6-u6TbN!>Hi#_*X^;.(;(W]QqbDj2Tfcd,A)6tL*QjQj;7^+el6@hqJ]9:5<`keV>3%k_IRLRp$.4&CU-j+djjMGhs3t9N=%2)(4 %d:c`lar/\G,']bYHl(It)WAu7!/%Brd./0873HKhb6dekYe0A`l9m4fJD'^TI0D9gl,<$NG-VKh"=g>V:3rB1m-E(2-(O"- %ckhp^[QcAYXtsbo#kn^(9-JiW!h%l1(M%Oj'*J.IKN&C<\Q*,NAZ-2a&@We:\0,>&C>+[o9YfhZ!Pj.8BDu'(&CD8P#,'H5a!ask %heA8&fJ"kDB\hgNQeh0Qb+L%1NY/2&L<].A.u*f_&e4h2bASA=ak- %(h/iiqLJt8e^-`:)F2TG`[T(A\C8qRKRi#@DI"29"?O9Q:lg8E..aC_$ulIgAD*m1#X(ueEgK*L_J@&,G9DPdW8ksJe0:3)KcgR. %@d%BiW.n(M199LsHl8#D#^t27@Qu.Tc;``S2bJPkfk_l\ac2uP7d(`h]_N?FU]-k&gHFCkihRi,M6&-/($Gn-,mi39 %\kZ>&03L(Gh*trR1YSdi7Sj-FpR'?)2O/eGS!?^#.g!m1R#E`np;4S,m,ZKG\nX0Lii6euhF&9tZ=TEP:+L6cD!_??cj6IWhYeSu %q/SFb+e`HK"M>.Fg8IW]$p^:CDhH?[`3fq)Cpbr'#qd3H5gT9!)8`$kgXDMmL4^Y;'aQS?M820rTYP(W1-@qYQAfu%Y_O^3LH;Gd %H`1%ni/bB4!t`P,9-2[n\l>t0nY1sM[aOtD(Da$;WD@#Tll!B?heO>g&qTd/.%m6-ma)q;LB)+jFM-@eD)`R_9'^9f^*n#^t\nt;?A"cW+@FAM$=AX"DF'Q2U^5Oj0/^pA[g?95Z.mDn;].5[2bhm!I>MYV5UcaV$?;jb`UEiGof69GDO[5`RXN7do@%X %dP%p/d()qC-<_!A4YR@]a;`>JZ^2#6o.DKH*[9n+Hrj %%0REI**V.M&f`"])?ork/-:nfKGA@g6,J4tK^FA9?S!N4ElOEKg*!\8_bLS-@952FSs!=3`7C`Q8mJg4fu\%F1Cf%80/Hl&liup]@L91Y%5`Tlq+")m"s4d>Jr)h&;Wp%c7R0:qj[R,,3;0_^h$WO:+rQOW(s+>;_JRDek`QDO %%`'#S!4$$i)+$`C-&lB4,Uk9eksL[BJSXTqk!>":R;@C#*k"+dDR@P\>B"Oa_F))3a%[!dd.[q'5feg&CC[s`8E;Oci<_B>V!*4rOea!u`H&j.gSR,j>j*>4$.i!s#JV %Kh7?Pj1=8gWc`M9V-N8,F%$TOqCq>nid#Pt="X %Bq1W%P[^X4GNc14&lN]iJPOdL"b]HI-6SOBXT;HOh?;?VbmEmG!jB-UddlW@8J.o%-@K]g3-oqI& %80(m/SY@qMlm09E0UU@n%Ao>TC&Fa&oa.E+`4Ia?uZmT^GV[-JoN %d_Rl\:RZSA8La7"8>Yor#d-i',0[>6Lj58PR`LiH?j=JO+au^8NJ=Wuj[8s$Ca8+H.TWE]boDe'0k-#NZY>dSR0Qf--M=6WkWo4J"[LsZ2bEdBI)8I_^<)tb/Xtlf0\Wsk1iIPR+'<`t)SbVGYi2cZkf`B'ab>K/s]^1IaUG&r`a9+1k8n85! %AKt@!a=.E@bb,SHA1VSN)4=Gkk)n%k@ZbK5Q1-%$Y!ahoGU8*d'\nL[Z5?69P>O=c5FJ)^!O6_S5uL0g$(J5C2aXK;if[T*ff[4- %@U?7Wi!#n[HRs0)X!#q!OW(1L\"XYO(U+V>]G2%7.)r[N[_7Le/&Y)grhnq(@V=eH$X=GVQ"'nF&3X`hNoA`3NtN %-'\XRik@I1O_SAP[g^P8CHkjhM*+>2,:U;mPu:'YF\A,We1r\HQ%f(3HpO]VBV(/9F^7hsMGP(R/ZY./ASX[/V!S]kPYS4/@d,R6 %f2^*Xe7#7m(RWQT=",C>!"Df*;N>nZ0]B[>rI=P'TdLQK&=#=aT\lbj[,HFQ[aXe@Lr%Q-bU9sU0$BR--u<@3*3OTY+rn5NO4m< %Z`U%DBc5YhD&G^u@;%DnC+B0km:EBZDg^7+!R`W%!!"Hjg>H$IRqT+0_&#*#fP&@*1Gq#^J\W4DJeD@kn0:WRL[/pG#4%Rkqq=er:@8gKSgqe)GUG%Bq:U7s"I%=5N[,:)lZnm:?B8!.+G&Q6XXLa+?2/nu&^8'EEtr %nL5C>khG+H_'4n=bgs7PgbMZm)p,A$ME$+uJ_)0cVhs2[bt0J(gY9UK1jD7JK:lXqSb/EUYG$0df9TmuRotFaXou6]aE9PZ1(%]L %%-@DB;%0Vr2Tpoj'"Ijk\O+J/IKPN#i_Ag_gW)Yo:Y4S;6*M?Y %!nMbVF[`80.K'\6OkOTLlkSC&\1LjXdE98?P?lc)TgSHP)JH/8&oU %O?dsN1ZT6jquIU;6k)=Z379<(^^M:6Xq&[;37F>O(S^>t]&R*8BRhCIY!*c&ESe#O:!3TaV!1cMLCmpH,$pmD;sU_(5X[&*:OTk5 %\inF5.CKsPGo1>qc+FVJ,#Z2OZ2"FnciF5_`BipuX!.DSI,9rm!GM]_%$'.U&:igW1g(2_Z6i%pK8/7gMn[C?H4-uDJ<qY%=H!VI>]L410b#uPDg_eYWZ*CFW4a%!']-] %C4q]R6lVZEKXtU6Ta!>pIW!+Y*Q\g%aeLG#q'A($ka[nsclP+`<'D0N@2NE]6A-*sT.#W*V4[=%8`(8mYU\g''g>d#-TLB70a\go/ru"7,(m1rQtX7:,B&0>)&0aP^f`k(HS:=:L3kL6+%5"jCOUa5O"=_)hWXpJ2CZn=cu]1Pg!0GN+\"'iiBLs6/7WQ#'aN %7JEii0Shf4$3bG(>sdp[Eoj?Wi'FmE').*BG:\qU5A09e:GZ-0VP5`?P-k0t?rN=J@H/+eef`*S%T9H/E7F6o`c]PI#pFm,[,e6,cjTpL#M %V!+KT>)m[fk3LAeXM:YJ2*rtdAi=trd*!$(OBcQAHTB@hX;-*(!*fjk&USeLrf?%s/k=MVP366Bjd'C0D6KOVjPl[S(WYA2"9[!V %EdndOM/4fQlJ2I+R@PE.KKf"L&157?m"'_RSM/9.GM[kTQNg,)Hc^iabR\oe`H^2E^-ts0!2YYu3Oll_1F^cBQ3IhJ>X\3f."5;Mo]GYu)0HjTl-I2\qWKGdgnf41$5OofPp@/Yf %Scd&&AGh_U?j,SHU.'>;TI4B0KdP-^8B7G]QTPKtQ*%ioOll`@F=sc=F23_8&4i&KJ?B:,+=M^?S0bJi9U4dkkC@ENqJGZN'mU:n %,9W//7"`nX\*#RQYVqS67$[q"/o25^l7<0*ftKV3j^R'XB_j.8Yb0F&9USB7a;F %kO!7d5Ki26O\-qAk-+lMPAFe$+XiUdF*G+oCkQUg5iF`#V3T;>`o`a6S+H-B\!1]h2dJdIbNA4cPue%?*:*rZ(dg1d!6ot^.bPfN %HDB79Z8mm>oU;"\IX75C=uLl#JufU0?0!"SnugI,)VZLY]El]EiBR*K+jAs$Mmcp4VLmQM/=0_4W#!Pu5LHACb5XSgGCL$hr$:/" %F%*UpYf\miS35%r>ffP&"`3B_oRrSRHs@\aK%g_1(GRJ6'D"!)MK/asUQ]+,$_q#?0a"015&!$S"rF4.O#lh9YN7`X\+]lL&j\qh %%hU`GU,pR)L_)ruJqm>=*/OZOGnX$[.>Y]C&U4P+D-uMVl(NA>REh.A!$)o?uTf'^sY(LSJAIq3C+h>,2<5_;R/m''-5O-U%+HZu7'*5lk\$4XVKJ45F %GCqPW`)o:e%iB&?O]c!I@Zg1dbXtn@/7W=J.cCA5>%)`8\7Ydg&7lk%NC.7+7>+KIB[WIXZ5t7(=<3:d88ah0YYDlD3(68,2`VAH %Vs;'9l5p".3BA-b)a.jZI%4@DRRO8"F(btqi.t5%!JVXpP)*Lg\=Jd]X$bSI`E]pn^%3iH:,t!LpH&WS7.<;V:h\)t^g>f.K]!A^ %Ui315o`o5HjuK13h8e(V.`2/7:aZECUX)`TLc]!(;Xjm;[[96SP+9tamfoD%c1LbjT?SA'W0J2SfghMgQAWl')!'h+1;N.T!Nn+u %Bj]fei!Las*IOmoV6Re^/>F?u!:Gmj+O)@g>P*!g=lQW.q/k73@p![X'(1f5\3We3^FB=$+p443Vh.+BkJ>(W+A//,P%HtZlAa6A %E5#&\eSuJ"S7P5W>Sh-MG>C>!/er!=T#T#BU,GJpjJtl;1bNX^O?K'_,HJnAP/KsR!_g6`=9@\*KL*.A-DYr&U02geZSqi?DhaFN %b\j[e()7s0S#"05@R;G%Q])m8m*?`_P>o9@kd&Yp?T<995!i?imUHZ%XO7K,';W8^#TrI?:hnVH"np4$IY)Zpo2O'PcFgUX`suon %5]e>N-KNV<;H.HPh*nuMFmq6O9*1[cr!Kdk"NcUWL9="@LbC.cW0jOT3'60NcuAd=PtV83$"B`pJ(Mn21lA,[Q@G>QV?;kJ$N^HG %emt:UKq_mMG&NtDa]Y/#h;0nR@rePUr":"GE'!!WqUr?ciOa%f+G#D3_gXjA(&nIO&$\[CjpeZc?Z:YU=7EK2/V;N+HD+q"D+DWG %ZTe*a?s-d"YBeaX++hCae\A#aPoT:Z_l.<&g%\I*X.06LJ"fgJ,ek-Q6U(84l_oIK0U"Q+! %>P81IlCG8V34q\YB!$+Y/5$iG,%Ub]Fms?e1'S0G5*\:`a]JW/KTgc? %fYR4Ca:f-R.nr:Q;J-<_>/E(&/$'I):uF_GS.]%gTrSX= %a<7EPNIXk0F(@7J69`mJ#DU0&.%qm]_DDiOq,/XO,qb`T %'0*+N$jsW`nO%jD'k((gB,ugC3*$&Q)$_[f.I_Emq%UnT!E)8Y$DK"\To-5jnPDW>k_l1D7#%/o/l=,fJVg$gTU=1)!^F&d"9XUFiqC<0(:';d-`6fEE%7hkJp>3a2EdM`^N_>Yk(:eXb#N$r")6&Xa2'\JdUZ6oK(fJZ/i %#%+8f8o]>TjM,rX#g3o0fgPgtiJ\o*b`F:[2"ReCW+b\.MC3PL[fi45f!p]4c2;X>?Hl4c&`/t%n2:R'g%5pD+)JTaBeugI`8"s5 %5_6Hh/4Aj-,`4Y$=(4Z0"I<;e=CI%>9h_gf*5rtS*2N)b&=/b5jt'=XdQ%F_"[bp6CP&E0]IC?O`4H;iQ42D6BnrL_?uF)L$M]q. %f`[%&0NA*uO^03M>QSdVLb:\in`gaP,G\THFVFL%Z!6bg79kljqU/9^g6^AmL_KlTPq6\XReV=\'M:Th+Z,KgRQ8ou[=s@1X?RCB %8)G2e6EqQ);(4RBC6s*VV4H!?K`7j=;Q+lpdgU(i3V?2c(!$Zo;@>a`IM/0)I]>YBW3KN^%;hFS>7*(c^[u-_'p3f:2b=oI?+/,/ %[VaP\XBAYE`5%(dVsnq>$>Ok&YS\+H0oS_YYE\RVAjqkP!j>H;:m!Z_Bb9A@>5_d0GHBq9%F@d>juJ!=q>7AB&3(k4+ee1G8!FbmfHd5Z]a%+F"bRK#PotF\m?dRegao&YOUDQ";K0'U!P#1dV,;0urDm:=l98p$X6Is0Pj&``J.pQ7Cb*Zpn:ad)8??/7S@sfQE-;kg6p& %YKZt9d`YHW+8E/;I]3-8d4,tuFtsR.N_Ba`:*?HF$7"k"*ejB!UXpt-"+7:rm"5B;(QVI4@OfkV6:>9"AVu;cg4U)a8^XJ*#M^AM %g$uVnSlanLC5fBEmE6h/Nmc$oJ[$]5^B0AX(#P^)N]o#>)dM?"-!0k"Z_G_Kk/MsLIHs^=Y//O< %j9Ou&CbTK(=b$e:"u4A;j;d:k*blOQEkt$'aZA'.fu&SMnOA1?ngs[h7\H*%7&2m#o_^]]bjLE03;5Jt*TJ_oA3Yl&@t>=YO$EeK %+k:T+BQa8IK]A7)a6@hh#ouqbfoK1[c<9uQ=f<`Y%:8_/SJ+J"at['=EjCftf(u'aoQA]V3CQ&`[KAtYI"p9/Gcrk=@C*@d@BL(? %7F]DKlB"K^a%3G0_mG+RJ>\pJ:#mk5i'M3mi.j2J[MmF.a?:@#!-OARM5mN=dpT=G1a^`CJ!nq8f""Qd("//nUt$oe?GkuI1pcEZBiXu#C#*bJS$1;;eL'KhCSQO_ %RLL"+d)HH]k\(%\1aa^$UluSj&i=86%FbY($G&tdjq1c#Pl@Xlqc?)mP$EEqmJep2\q$5l?)NuHid5t:4<9fjPCtK;bi`' %`PRA"]!J-8EdK&D(5,#A+o<\XbU)77ZVpV#Sge/;T8$'ST5Q\)(7g?bCk"/Bj"PkSsI>cG\[&o %3fLK57>/:=h&6th(qWt,cBd:I&DM4l&VaL"Z4>J<#@@61:mA3dGhP/6KP>-%67lQKg3dL_[!"f5Y8u*ZBQdFc81.7%=e*q1FUZk" %NtJKuE^S'/9-S5A%hCeYX#(nl-]'lL9(N'"PDBcMSr_EFBL9.PjnXGXKWN%SG4E8"L5fdKKhDjnV0c$F9jacNiHN93L&ko)[kWZa)%-#KXHRI?.&DY\fE* %>%ROq^NnS69HQ*0ifm25o="P+9HOZL*IA;'[EhXB2\4?r_*l2["<'EIm#BOTb4@@6]rT.+V;?H_eeq(Q+FkG-jP`LnB7^39IQKZ3 %VA4e6AgH71A)f7"MV5iOulktLV<#eGWM&B;m>hoGd_EPbWE@NGEA!Kqk*/P;/(28i(iX9"JVQ-LQ %luTu7<0XAZ33#`[8s="IUNup_5,b@Re:[,5S'Wc>0JHN#aD@Z@i^fCu,*@^sMSoH&3c[upRc6k/G4>mL/qBr!c('KXVp.7-Of9=!cHOt4o9iD,E#?Ie %@\c/Zjs=?XWR8!J,G7sae?OgTN@a%NC41]3$U2C*YtstQb83R\p'L)DN\U+9"5\>@Tp5G&)RHDL3TAT+D2hfk64rCs\OM9j<;C!3V^E\@7rLgu:Ad5bc%JD?r\V<$@&(hh?9<=:[-OjIF:_raKXRJ]W+:`VJ-r_IWXgiLP+'F'rgL;>pV\TknX %P7dptUWF:NNJGK2>/-B(c4e*XP2bZC* %c)bucq)cFaN+EGt#QcKV@2OZg=Nq&q7K-c!-o'02LV2J@GlfR%jM`M^.Zfg[V-mc$>42E %jZjj%;?1r_0%o]AeDXdZ.c:Q^l9Lf:SQ3(=9b2^#'VDAY*t5YMV$JdKRa`jFLk&)$)-!RIo\(E1W#Q,!B5C8+/`B69/2bS>JB#u1 %W@kRG`G4H3[;iAOr]^h8GWRVTR;R2W(:%.etJ(e)r4fm>C,jn3.R\k8g0<1TG=@=$?O %F*/CoG]J&*K$A1\&`'\AZDFR;L0A()V.u%O8nIrjdA/?,r2L*"O[#U=O2b'j4_JJg[Ac3KeupPi8)G2WWVoXZU=_0M/ZSQQe2N9P %0/\jNJ5e%u3C_OudW)>UP!DA,R9Iso1/7m*Q$Oof(aYjoE)l-NJ[NWn$1pk.WqqUO>a6p>.;>(9ROVZ%=0bfHMQ9s=BZ9YIap;'^ %5W-(R>ElF!JPf$^Y8["s.U[h$8u8c-@]Cj-?oq@0'38(P11AI+`2lG4.X!.,XE%u@egd0?+E`rN'Co3.2A$3pC(hWXXj%%*6uQ'" %9m!?`/hHjq,''Dt.Q5n?65?=1a].4[O]<.+CWN[di<>KIXZR3ddS^bVdMe'qlLTjX:`[<*a&'H6nKLgCn4Z3geYk3i+&sEtK;;+n %%3q^,L8A6V4VUhllA,o@VBUn,nl0:">bDEZ2Vb#62i=Z#N_5h>C-XZsWbOt[Oc=CEicS7DZJgX?SPm,,.ThSCV^)o*"dRT3qOt<5UFN#OJQ.J*@Zp#A2WBtdRS)pEmF*VRWBt>E^8[9189q5C.R?lg=W;ps %oQ.98eQjJG7M49B5)iIF&n=p9Hu7RAM5ak%,[(C(3t7b6Y&,P/Ph,D#AomUXG3<#ip?Z=NF1^,lao< %B21abJGMD*R+e"I'>;2D5sa6+/Np7@feuMaAf&^t^#5rAhK/l,l0X<&j.m<9'@rkZ8Y!SsL??TRh&%[r#qbA696P!r"[u5lnDcf`4DJ3T8H*.iQ\%@:*)hH$B!uL_0Ob)rIl?1gU,WeieYZ7&H)&#Q"b6\9gifePQecQ.e'Di)= %c\8A2T"N(O#"f,*XLrS)pOhKI6AeVlM3KaWQh,RhMS?>QAl[)8m!=^Tj.s&4%kA,[1afRHWm0 %17JSb67g2O*[(gX%c<;61C,g%MON0?iebt%gKKEH>$bgX9;\BSbBsD8A+j/DdBL-4ZK3hn %N@lSZ["CL/;#fiVVTR_t?7Me5pd:q=j![D,8c(cZ&#ZdK_H!6NH %Y9CD'r5'ES+lF^nM,%h@L/SVE&>50Z@f")70jCq_$45@oe4%M%3To-9b)*J6*\UAof"p`:N=nV%O?t39=TjdR-+XX`L%H6HB3)78 %T9M#JX0gAtQ<(+>'L-1-Tce*aP"I"eKX=FX=eUag[PTM9[..:mV5'1,X#WMGa3%87$;KG$T[\;tW(ILIOHunC %@%S0kc/k&@;3shBagbt]?riUkC//&;WBta0V(unj^Jq7#'2lRPP=SF&?lZ.eKpeb-(&!f*\A<2`+U]6DQ<=Jlb30278nBU8/%)es %[+*tB,+"a'#X:01U'X`-Mg!n,ML!Sd.I]caR_$G3=^_[DW[$)&Y5^#+K^&\qhP)Gm/G4`i%SHu"b/B:>V">%[8f9///nN1%cb+([(2BB1$)-d$8eXiL<44#N7qLFi'iWfB:dsUSUor-C %eQOPqW0CZNe3cNFlI-bVT27(2 %rQ1RHrRki3ChWq %NT4%g?pTIs:]l^b$OaaLHWWP3'#eU*`SF*MN66Ms*:6eQ3kQ5tmq1K.b4PT3,uJCdknfZ!@M8e@Sm<7I5K>-?2?UlSRC`OAe@4K"h@6as(TQ.JPS^ljV0%_6!^hs)Z/:+eVb(pGno:_.(B&0d3o93JQlc %^N^42.HS^&0W?cW"O,q#d"3&-llUEf(7Z7/SenX&cojY,#F!%B?J+6"+WK>8E9o-!WIFKP>nc5AOCpQ?ZbHJV&K5g+PbGnHE%RbG %lYI7t2'Ca3H-?P;.qM+,A/?8"675k:d*cjKIgr"0#At)jRFm\#(?\Lb'V"e[qlW3IQ/@5g4cp7sU.CCTrfh\:i(%7T')Fl9Y]/IO %,5_L'5q4n"XULu?Hi6.>gFf&b?qmLI67kAGC,+/8&,cd8WG=-[1blKXWeT%k1k@j_Kh-I%:[WYJ9MKRm\C-an%)[C6!W]^c8(ARf %E3$-u+Y$$"%%hVqI)_>%[W*iYaF(1IoRm)Rg5*jg13dHL1)WXmO7'%#)gV5'mg)i1&ZM3CA637 %"qQ0?]!52`/6%%#E-&\DraN#t94!U\ED`bP/TS..JiO67Mac94Z=5<,G>TE*@\p;$U^!m3c2CL&jO1/kDiB6fh;4q&Ef.?3Y,DA+ %efM5NgM`%>_IYBpm]a,MaqM7r)J+lNmRO6dSWG %:Kt8fDJh%1$a\!aY%;Bo!_X6%)0.=e=e0n?@,/-)rV4oi%e8ccAD6a3a7.sIfCflEG="KM?b:[-qD %L3hg>&S!s5Sm5moZ_@MmZh+_p\3);3_I:uYHb^4(7=[[V^"Dp3Pi;u_6Xgj-=\#58:;esd%3a"JDLFrO!81'ok%ePF`S'hr:Gg?d %&ZrIJTGEUBS1d-9bS0dp^MbmN%'.oCm(;rj7:t.ahkUkH\bJo8J7Ys/.^jLP@s&aoD[]?I*,=IZ"Fell4A^_ABMU#Bb0NO5_iW5-fKMUR'le0c4K:@NjYEn^&YG %eSoLML1S-hjtl&&&fi"T2R5ALSdOEdF#jc4rkMJ`bUWd7g?6iJ:D$b>gR4tIX3h7G>BS"iY.J8Q4sUPZK6tQ"eVHZMU,Gc'D1UGV8=T&?d*I>Hie<2DgRI>p8fMhpgh^iFULC, %^3/+4HpZYZY9`-A(^c\/5L9_]DIic_FHUsHQZ[BO!Pln(#!+b-bo_pD$<)p8ZGBLI6n.M79eOL.@2.O<43#3U56'?CBg?S$'t\sK %:+f7>A!=r.o-mPY_n5SK"-XR%BUSD<7;I;JD_N:(e(l[rf]_V5*QfM,r@sPbR0=X %e3s&&Les^?RLK0f/FS/bN0Vt9N3t?KUSgV6.jEn.0f!._*O;!$#7N)MPs,LY/m?8Z%r$k:#>ZJi]D!&g`H\n^h+-ZnYYa3s,c+(J %W%W0C'F'iMeHuJm4P7%89$_44:e>'4+m1G-'E/7r&>gNL6]X/TOH2r+%?1\#fYEf;)a[uM7'K4nZdU?[:`rXe%.MrU(&CfG4;1@n %F2<*5lUc3CoCT"?qCp:6nbE#H;If8kWl5jiMb]m?`-JG?#'r2CYlff/ %3B)Tt#!?*8gmGp4Xr2(QBjrj<1MTY8ZS/NOkTC=;iKhUfNeaOW^B4:n:rTWZ3at$Zq/dV'`@_)4f:o'i:24IAZ:p7j2m->Td5_KLYLotNFZi")Mec=nH-:-4M-99q;>5\]Bss6[NbNm]fuW7,'PEAUa,o&ZG4MK %;bi*)l)FmI]('-jMfoX8RGel)3=h7(jr?t+5nTdgJZa?3h%,nB-JIH+GD8(?`S9[*kt'IR=AT2T_\"^@:&s>o7:YQt^hc1lNPu8V %9d1M!JLRU2&rV]WfZ9Ms,.a;!CCs\0]G^F5CP;nW"79T5#V9Z5M!R8j?kH@≫j#YfN(sa5;We@MKrejqJSghMm5PK#47;DbWr7 %&^!=*Yp0U6Chd9N.4FPMAp9t`-nKD?)1&G6/Dg$jaTU.80gVdF;-9olG#;,hO\-#J9r>-c%d-Ke.4eB"-,u-1KcOTVhFUL!KfqTt %:L]O_OA/SA#q*!s.,iZi1>92iXN/G_o1i[p=XA6'FW*Qr7U!lgIQAKYZu2(/QU.tldU:cGX^0r>Z!jA0^ue',N[X7h(LTTq#I)*( %OX]YnaTR7re)o%B+b?Jb3-A[fJPE)_lmB\F?k_YfFX[G/Rf_QD-*X`i;:?Ed2PFBWJXb)9,d(LLU(;Z %6QLpJ#MZ`u73.*hk%.7U*IeU6Xu+H'+bg]NS(ROgJQd=VT[_^([ZZ+RHkn4Z"L3PRkDqf8-c2,_h^;&f.Zk,ChrpudLm>lDb7mUN6m8^$Q+"WRE;j[l9(q#;Z&"YbMd!=r.oA0_mV7_`M8]8YN>#d_YW59hUe6k0U7]WN(Rtbr %W3/^eE$J=K>u-5A$'hZ`-Y`=T_ITtlTb9!j2+ab-i8D'j<=WLsk;H3aPi']='N-4bCEc#1;C.;FO,nb^R>B[HA=G\<^3R:tH.q,ZU %e8]Mf61RdVOhrj+;s9oo3,lP%E3n096o?ESF@F0N)22`98*+_raiib=6BcfL'$\3_*6Y>mb[rX*kG-*=?V!_1_a7oG2qDpW;a74q %Ql1UOX0@m4%_:J<>VmgMCbl3PXkVJlRE"3:V/fE<"Y@KXk3m-RR")+sQ-lInA %Jgr!u\7YuV2$5,r`*Vm@[0=$E=Um:)O*&JI:D4@!Ym:P#Ns:&Vb.t^Xb[/4:;0)r.%)kWtSMB##c;ll9a0l[bk#!.`3>$-b5ND$I %MHYhN**3C5;>EYBgOpB*NY=Dp*nWYo$S-j\^k74pU^;*gC+OCMXLGXK>/>K;9`Iti0>Eoq$!Fbk5kiK]\]A]Dr:prO$Mr)QHIS1U %p)7`R)&h(t7G;i=4\T:#)l8W53pA=qdstHE$t"&Y"?-s*3^G1L3gU%`>,Qb`l8=oclu[q_$YklfaaBLp:2\=>"(lWY7;;"-ogZlt %XM^^e0c]:d?ca)#;qKJq,([X<2.."(1]j1FXl'BqCsY]J3`$/q%bk!iP0*I;G]BoQ!U(>OW(FQMZP9>CO/gFkkb.8bd-'uG>>DX< %!GqC3/u'fAna\h^`Z-o($u7Vli2$831[#9K:2$[nZMoj^((Vuc0i=8O)$`hr[sD="#VEU<.VbX=#uVJHL.`#V:]g$g<8s@7I5"+^ %\,q,M_GqWNS&o8=SAoNM-gY5el@DO%)%40'aqD.9',*(G@[E/[(8t\->UuA9J=ShQ(\J[0An",DI4dUIjtJpDO]s2ePDp$6JF[]H %]a!icauhn*r,qO5a,V&6lnF0?=VM5D]jAng]"9D(qe&SR95lGEP@BDal%l9N]RG_N\P'(a)8[^&:2qPSo(g(0N&0gjF3iCp0c'-A %UkFOn+Q0B4j=*3n^k-l<:HJ-BVCZe9O&J%Qa@`DVe.po'Z<7cNa_Z!;l?r-if>"T\8_6_qOF&cDmBNIpG74=$ %O_QS'f*2Rg2:+C#\Pcm%27ZIP+W9iVF$5TO%:N./i1meQct%D"oXJ^6$8>/N\Wg>(G<7E1e+Bo0C0Y]d^()^b?6KBg&UGc"^_b'F %8p.L[$I[="/(3@IOjQYa;K1-qAIZ!8(c%:%(*9LG*E;hCB,4eV;b>FRBd/qS_?RPW-84'h\G-a5*+(P5>n->$l2:e1O@&n)MLSYJD.)5B?)aQ@iWp#8EZ(+6(!?1Vo!c%?u%#L1O"n %/it6-c6hJS(%r/E?.eCr9uIL94<3.Pr&M`8;@]I_6Go0c]8$_-"r9"72hK-TDIA'qL)G_*:E?C$Aier"M@ke)TT3!O@DJdKF2Y"E %9P8''1%UKGWPbi`IbYl;+OL2?37e7cpb3m0%j^=-b^`t*$-slVciODWSKntU?7L.fo6ibAR)3K;c#&^uF'VOXm-O[%\*XA`TbB@jVRaP&K0Y*3SLB<2JY[N(fjbj2pdP#GGS:7<`FdH %'9`%ked9nHd(Wr60un^-rEXHP^2aD`(M:3cSJ@[+q@qO6c?.I(4X^`:W6_F^MH/.%U+=H@0&SU0doTMOc"p_&#`'V$2F(B^%WMRA+mae<..b*U&9E8\ %m[D/Ne)QteE1f"[dQQsgJb;8:''s)EN$+>f4<[P*(0d/]$DKtte!-B?b&rXiLQ@%ol#W3uN,Ukk*N%ZY3B@(o$O/ALMbYr>1`/9' %1[)sGYn_uRhulH5kkgIpZpMHlS@;\o%3\%gLp?.dSH%_Z7R\tm9PsA<#q)^.320tTUmF['@Ra5YD0"M=;/p-NT!r8ae6X`P-Y0BQ %l50@$i`qlQVmO852!urNJ]keakI%gbdLodo7)^HI6ei4-,*:$I0M$.kA8&MWBM;[NQBB>tO;c),87Ilk?H>@"V&)Jl?V+Ak4ob %4kN$,\0k+WMhJg#*#2Za[5.Pa0qPn*`;\al-ebn^=Zb]99?7[i@+X=\nKpQ_hq0UR`V,j*PRH=cPE5ZC3,CDsltC>P^*5O*i'N?+ %`te6)&R<#i["OKBE;tl>Sp7*;KJ8BG7A1t5Zn+4!R04"a@@Orhg=Qk3aEj99"#$^,l?M(KiRH_I,$lsVHe&Iik7TmH,lldAO<.5U!dsXcD%;7$TW`0HeiTO/2PXp8"@C=8 %c`XXJ./P'a7]ip,WC(3)cUsCX/n#XY6FEO_=nbgKM2#WNB[ibCePd5).\ZS5ACK-oA/VUf<@FQp/Ic8kg%nNYQ/`1i=*on"+=kJQ %8i/heFDVKF81,e[$GE!<;#7jD;PaR34A/[&R$UFM\JnF0`YFY[;O:'\biUZQgSmgrNMnIQ-r-9/0E#XY$)q?->U)7CObF1>BbnFI7_6F:Tstm7Q#9eS=t9"GPtP*u(gl"h652cP0&gkTCZe,sUr4'(@\j--oS[8%'Hj\.P6P/7KK-MeQ9$fkc6D.<_92QC=AD=u4nHVBg.N@;os!W3Ao0#"kaC0k2tY2,'K5@DU_6F'7Z* %MH-cj'8uBTm%b&3_/[VX=#6_mhRC'PSpt_ACh5J?(uSk/$q@d0+G6(7QHG*J/dBR.c&9t*fQZ"<)`D%]a=Y;O"O[_:USpeHp&H@qQ/G!N&3/=U;*u4P"OqV\;GgU/,9hV" %l\C17,EZ&^E"r]k6nd$BVbr\CI\BRe@ti@-bSeQkQd+5NM5*iP>n9Z/qU3^sQ/)_ZOZ'=B09s3[2,r9/:fWd%W`<6a4@AdAc90Td %Vqr_eo/Ig@nuDH2NbctTc'Ol0Da_F@OZ-jJ[U?H_=?O\cr)/)JU;[/3G7VgD&)R1/"u\fn3eVMX %2^9tMh9,#,f5$q+A_E!F]52[q#3TPuA/G'MD4Nd>[octfS=h*GD?(c5*\T=uh=dT:/'ZU0V'Sq4139eYM?<=,Bp)Pqi@\`Xe_gF& %E/MKok<'4=(2MMu-f=^)h#jI",DE0A!G%N's0S+;bqkG-A%t>)=e2HNQBBij&JLmf#aGPaV'?1^@-)r?[9$3LBS8H9ej5F^1Es%Ag>?I(aHf\b9#)\_6n7<&V0Ja>Gl&Z,U1,NI[i5eq_L9W!hVK==q'LSF= %A&&/9bBKt()gl&'KKQ#5ajIq6"$L`-R:=/eZ4Mgg"U9!-CN@.7jP6=_+R?/m&C=I=rbX%j;[0du2lsrRU4Uo6/IpjGBhg[#Li1\U %!O328$t=fmE+iaaW(p@(Z[IX.6=eT9Zb'[/f87m14hCYOK6CldU`_H&ohb.b?),sR,WdY=$`A%MR/mLo(`d`6k&OFOd'SOe&u9Nk %;-_s.jc[(k#aqSno!Xs*M8J[a)!p;qTZ*`Pg=t4YJ)M@Jc.WKp&tC(fCWRXWmB30W'?s\6rAhL4Q4o]W%l7us&ukrO2!`(Wc@Y%@ %!/239^eTKBoN&jHF$hJn^4=dj\g4\:1@M06`_*f,8XU5O1K)PcV#bM_$EE2TA&2oPqTPCsQgL._V/q8ubE0E@c_1ES[B.$+c$*_F %nF=b,+?q14.B.\HVhkaCRoE7)kYqsuYlY>\e&+3L5YrLl!K[@r@uc3qYfIe9I;t-q!KR6tJR'8"eP3i_Tl`kp.H<$pA\)_^]l%EQ %Q+FZ_%GgO+0Hl$[?\L2@s$A1r,9`]A/;9mAk/(V[$SA*(+5t1hZW#Y)MIQ[nJ*L:81Q+1G%M+LQKUU5t8q1(S?5&knfjXi&/mfMSN.IJg0[uNM$Qi-6tkhGR@#u#WtO$-j6`18FR0QKd.uK %:Or]W_/&$B'S9EZMj-R@OJ!/t-6PStGR?u<#bD)1'S=p>,U`l#"=-AD?3s/Y+M9$D+_'pTOJ!FQ"XGK#Y6d`r%%[M5+pK^[&P`l- %[Q7mD,Vh\uf+CM"R3C2E.%+V=I.SUX3Kjjk"=Y2"\=>@s$k*3`7Hg+1#%6[QA0R5]&:1h?Y0&"G_!Ju@TohnNIR*f>-'D\Fm3U6l %3Km-$3btfj1;fEkd?I3,A+NUoMk3KEY$aAYP"Q!H/R+K4VU'MDPmNRFL6;D\;Ce"@_H%KRTidl$rNot\R_GR %hi))$\/-iVP[lO?:!>^]asM`R,LMaY^P':/gZEF>>5sABlQd5q:3&S4j+s,lpI<.n-1s`eO\4nu^dodE7UW$THDAJN-1s`8Ulp$Kn5%0>;.HDbHm:=C8\PcR %WFXnb0iH--&K%M.h[#0_$3MB,Oa]u!n=uf5khKUsQ8FR+[raSiX+!oc_F>TL7hKWH!-LHP_UJIA?n,J_' %_3$Xaa\ST-^El*1jSph-#pTCfS"Chortb'[m%UBL"ENb*dh>.ChiaQRZN$6_"HiYl9hu>RInP*>aSoDl'1DQO2Ea?:s"3IAOtoEo %H@j6;gSQ?Sm(Xi06"L"t'\V0sY";E^m(Z.gT^9G9:S@'h9n!.Ts&FLLV>jPEK'"$pKhNOYs8/KXGu\a6$b:E7j9-bZYB>UZaoc@' %(F)U8&n[c3-b)!5PFpb^;glds"b-RKms]A9K!oCo4F2=L1htP':`e"h#fDEFOFd%!VrkgRln[r:P\fPmmhMC]HV8uaB79p97]9"O %EqW5ke_hGNCTm#+::,"=2*Nb;LRqDn[`te/K'RWiY;+"O^DK_mF#LbjlLI+>`u?O0b[BoF=(Pd6Xd)M%F^+E,`^knu@X(s1,;2#9 %*j(A)+K9q;MheEFhRB7u"ETa3)VOidlik'@[9ok(boLWoe]7c>&'FkRXhp3r*"i0)ZkKU=Lf^-`l;$,p6XML7s&c%6O*YrB:JK7_)EuL5bARP'5fM6IejVWoIeo:m7&1)VNJbd+Pt.aAu^B&H6i^\:%5rN+M]tG %_#V]m"hDh'*0;7&dr3^loG3*7fGW;&YqY77S/Ykch=(eKk8,QWT)A9rMrM^`hN=esq#>RT,).r>;Tkk+#QcrIBV6"IE_V?heZ3h4Y1)[-n1+iF%Jqh!BBloi6B=0%kMLVu*6_)JFDFft?_$9YA+/5sY"=fJ]IT@rkS"'(!Qe?0=Z`74%Dnc(_1H%s %((=\<1rmI8Sf*-W.-U*4Si7iK,??Z\,<*g[Jf(5spoDuG.@nl>e0#!77pX,'5j_hYTh[@=%WTimA1-=saim+]#S-_SnS^O`@nPQgdnb;K>ggpUN9Be`&tqjeg1M %f*5MZRC5/PX4n]'qol`LZo^-*gVLqgMC.#?neYkf^%D+g-]QfF[`ZL<;%DDKc&*pmZ2I+\s;rfnYjnL9#$`07W(oX]$r;K5Wil)Tj3qA`V@;; %rMB.Z8pHKfp1LZ'RFC=t.0JkRcciB6U9=/d.TX"n5&h#=@`FpR*=F\)nI(`I[6gf_*e^Oo&ZH8@=l#_2Xqb]XD;;Rj-:D;(n;Ya4 %ej=7Se6u4qp"n[/a)Q3ChqkqkmUo0.cjS@#roA!W>>O^d#6ul'`O)/%Xb:Fu3r?8OO8q`J[c5p;nXB-s6mNo*1b^,+6p?Slm_Wro %4_ENMN:551I&nrjb%qEqj1a7'hHce;elnnrZ)Ae3fhg3q.WPu@=f_g/gO-uSH(5PW:U&[2"%79ZW5gR4sRJ>iWK.l8D;G-KQo %l)Fg/5Md2JP(`DjhT\n$c:[SX5&[J."46s6:pYob6],r0Uf"6>dO&RXi+K&0=^#+Uld`N(-5?F2"G)&2Y!,O^7ks$uoqq)X\U:V"m!2Qf$M53kUuL4[#Cd/o2W$ro;d@q)GB'kHglc)SaU?\$s\Egt7)XAeZ;?FK+-S@tZaa>>JcOhRcNu %KFjH],"u`P40?;S,c%[cBt^(p.1!#D+]Kf?0nr;D\^=K0>0j3+'PY2K.[ok:$r %oOY1cTAdj$fr&sR!.:m!cflZN;_Q1qp_(gT4K$Bm\O'64rY\@P?`%tW3QS0jP]XK'1l83* %XLLs+HaDQkXs0j"'>.i7RN6'\=f8:6\D,ueKN%kha8<-sFqV`.e'?f56qVlPC]]WbLAL %ou#(*V]L"gV&k+U%/Vi-=BhXQWY95,GoY]d8O\#'*a$4RoA=JQm?jMr2@4MPo6YB8@K2QFjtisDWm=>P^#fdTZ?WM^J(hH\$bd`+\762/J0&&5g %1oI$,jl;c#:X)a^4O^4`cHiVQ[mCg^/\O5\Q&^/rJ%b&qHp/&m?9]?GFUe>1%SDT30aEVCA2R<7h&W[[AXN4%?@q;A^:QbijsJ*L %6,cjYYKs?EH%gud0%B'UT``!p+XSUr&%)X+K9=g8Ll-IQ/W[e23FXmGk;_S;0jShC7,V@Wl=VBd/9OY#4T(,(a(ORd[P\.?VXVD9 %rceZk9_r'p&f%Rt`[PN@1iJ-7QRFWgi62*$5)m*a?Nf;Of("o9GlYU&+=j@@oX,l2b#E\DZa\J%H-WEsrYA_i"u]KL'H]>50an %C)QBX\c]rVdQ[9_&(=+fEZe-?XrRDU,?3X=hc'4:a3>*LO9/EVhU?D=?16Rd`Q4UgDeGE3c8(<_o5YKIQH-4Mg5Hbh&UX=KDdc%m`k@tb^R.D5L_K<>sH8nJ3m17Hc=!5+K,u;&\blM?W<%bCd/,C %mUBV2JB`F7,)]LM7)Np@RTRmV\Fn]D4pj*gM^RN]Lldirauho:I) %Y'8G!ORolOEQ[kGcZnTB,\G8Ac6G,'>%X60U!>Z47Tno]25@EfEgoq\3l-Q^N3?VW[k@j4A>U %QuVQ);Z)pBiG1l=\G9BTrmo!#MQa2u.UqnPL,B,5(@s6*2*^XMb:e\L8+drJ:U9nW %aJJfnV78)")QlfqDjL86H(O:J76YB*(HJ8PEm;f#.00H^@1NONT %XdNQL]- %W&OG3FCUdU:>WZWKL':[f]6i9f,d$5!)0XE[M.&?R)0RPLmS8BY0p&<^k:-M)%Tb7jl$N>1QQ/P0F2A3Te4;Fk$\i,=e?D%P50M< %;#)PI9!n1[7M'4gL^(FI-seFSqRL23XsDuq %0]P%S:=>nSW[Mh=Y)?I(CHqNfW3B<_RoMul-`=A;eL.^6UFDbp`;Cm,7_;W[isWb6cR>r3*k/q%.sP0I9-*J %N*UhJjmXNS %k.6*XAfC6(DjDV96a;?2L[Dq'@I27O?Dr5'_Qm$8E*V8'6AAE+)>Pa^4JA@T]/7X@%MG^\3fhIBXRVgg.?e7#$r*Q,O.A9^;5Qab %2Q5FmMIB\g8g(Eg,e%9\`bN>YBSkoWLusGDJp$+u[o9;M7m*a!UEAg3h00b&ZZ]E\/DiI>F7*+aba[mTk-`AS\t?0uLf^c2ft8'u %[(bRC]24lVY[b5GLeAiSk'$khkE-f^A"DE/f7WF@GE'ZAg#5(DGa]jd?:#Mi-tsM9-Unq(!@:_..$SeI8q4<jY$" %3p0q8Sdc\^@O*(]Gb)aVX$MeP?jp*cefU%HNa]V]MkRmLCVD"S46MM9QPQdY]_H^rl]7QSm^sG/m@H7Qc3!+IcIlYjJ2sCK7hcV4 %H'35pM?c=XYW4&m23b@%B>cgMhQuA=jN;H?s'%\KlE2s_Yq9%)m[rT>r[@RVp5T?*+b7RK0#s>24H7];m8*i@elUD,l3?I.f!^.T %f0,"bfh@eDE)V.U7W9WL7C>tWN9MWH])cX!\gO2^XKgou2>,GSlf\$';9UKU:/2OEV-a(>T4B4lCE9!aqC]&[b@-quX?4'LiJe>;8]5&f>IS)DlZj;mJK;%[uP%XRlDKrnLCO2Z&L=L-@R.j?/bMXCSS?G3>+ %q[$P:T,3"J0SMEUg>!0rLH7-m_/D%b^RsPIkm8l(^bi3r\=W2&6lI#6eNieEh*iB!$6etL!sZjt^>&@'1h3bmm\e[og!,*MbC.rq-cgf':]u75[nu._X?n:W_2.YQ`^634tP"'WQ)Nr>d5ecf^gfl$(j@ %l&q/&ICP1\8/@^RBuZq4M;sZcd93;4TR4E%B.W'S1(Mpl43qNX=fTeaC35cijh87'Up=C_Hm3nMYakbW(:@S!<-G+dWJN/(bUmj8 %%OX^X\WBpW8nGr(qL8'$rp$+Z18WIZO!NqA@LCN=Nu,6[@`irF!%6;F@T\G]^Wo&&'Ut]co2,JK^6+`FA-2`BJgpP:&m/]//ql%K %G(a2E5O-Fq'9W%To7C82_>4S^J!Nb'A%ReA`NJOl?e\>G#^Nf/*VAX7TaJ9\]-&2,3Wl=FhqMm3[,);$'XpYkW[-md8#tfOI>!q` %#/f<`fZU7T@ZdjN^3gF^R&U<=fS#m[B(]$qPsRfRg$W?S!?,H8c,4l*_Y>8%4oPBZ^@(Fh\usj'R+J/Z %qPCpVne6kX&KOu_@VfAQ))hpLB&1.@:]'5o9_7*sngQ7pc\GLj5#;`iUuO(3JCeF>_[;=NGC"-_p:5?\Cs5Itrju7egqd9BVs7>Q+pRAqoc!UCnDuPp!VbAtKHhi0ieXuj+^\QK2epmXr %^]-qke,K?1hu&8ern]7,_[le,hu;SYJ+XV-q1o"BfDk6AdXNcoZ*ScC6km$(`*%Ccd_!Vq)M:emf=r3 %W*4*i++-.g>(lrM>H3+c+R[%#7XdS=I[\@2?g,1)lcSn=C3H#kB4N'l"u>4`WMt'HU,?M.^>&;a0+=[BV/Q:\D8^!*g;9i)eW?:"u.g2'M7CoZP_=(P6&j8PHZEPm7cRQW1c1[5ro+c %ba)dtV?jN`Q@ZM$_^\C&DHq*q\muU0$"FN5$IFOHmOYAUm7>:fIVl^,dLWt`Bdcb&N$RD,M'r,28804lS3WZ`+SBHp"9i\O!;9iJ %riX`lV$.RAOhhi;=TQLZlf9%"jfdP(GNfQG"OV7?V9S1_Dmg+>L:,eZjrnl[U1^;m %)]"tn8.["!XJGA^2Ot.)fG$:T6QZ`B(+M6eMQ8LY.YW[[l1M]A3^pbV %ar3g3:rf7]R7'\U<[(7#:ebcN]K,fqlmirclBN?TAXCBlBjD,O4V,f^Cq/LnQ''u.5$HfVi#@GUlpa4%`>_i^?tWA6_Ks5;K7Jet %Wn?jA!G(nP5K[rE."Kd)9R6^daR@nD2M,eTfBdGjcO+'Il=-o6\b+X,@mBclVFu/\Fe==nW1(?3m"n9ArY.:h-dfLK-$,sXAq`83 %"fUmQbcFE+l$%0#c@Y./G'=q67?PUXdK?-)V*Z2Q=l$,(AX'9O7+[0RZIru%k-SD=\'3r1QnQRD2p2N`V)D5$^nqUYIEsf9dYY(_K.%3)#9mi`l*KW[U&`]rA/Fk>,*mjHe-8 %P%5Cd5S9.7XF#iqV)V+QBg0ZhA#ZJCqA>orA717Y+1h>2F#n:Q=i^KGEcr0Tp=o;WY?=ptp?]i>%B5Es7mSTK7F"19sS %:2`eI*N]+g^\k:t$]e.1/<%6@LO9@GZs?AkO>eAFRCT)9g?Ffq*"SUi`!EXOYWc)2mb=tYFqRbAJ]L(4$(XorEQ!LUshd\ %XR."/%S#R(GjiXm3#)CW8A%YL#9YG.K:`t=G'4WjV-QNir;8etR\%43W+FU=3inKZSjrU7Z[MLj+8/GNr\9/_Z]`bHM;#a2RV[HA %2i7W,aeIWV%3GM/+!qrk$ec4'E+N\gG[^S4JN&3*O %eN2@R'*"l$iD;K#B+bP=ge9/gXeUE,I\p`Bc6tq@#\%Q^,*!BK:Q]L[.]6^t^pjqY7ecV]XZo6ka*_ui"UHgI5(XOrabYN5BagH2 %q4-SO=fuH=Nb(??@c2\6"+a8t^%&sR9UoT2m'NWhgcC85o$[(`^kOHD9BmR*(<4T;,EA<<:Ef7>1DAXuV7nYI1n*6F]B<&Y[&k9/ %2r:`PTWTG]l-jm^\bs[VI(63=0DEOa3E+%;(ue]AfaT/9]kXKS"g#I@.%BB@Vig^IO(d;7[Yi7T(g9aH`\?$[P57d?h?H9U2+;tk %YCgXmQUI$8PkN8(NbOPg:'lYr8:/I.BRe7:&7i]54tmlnH,LZn=S$f^HDDRT#'7_1r@B"g<36"aouehNXOHNW(8Nd/0uID&kAC+8 %FjspIOJiXl]4DhFUlBZTN9nf:[f?,#;Ua2XagYR:.=!B3AF-Z8g.4Ctd9314eK`U5rZ4s9ZBgn<8T.J\bl?0aQW/pfERVsCU* %ZFMi'7Wo/`ZTQB'fc=5'%(cgsroB!9q(dW@LX"T=QpFtQ!m%Hj$4]bQHiR]Wf5XUf=gn%[S;F"r;UN3L_1tRa>_T5VoD0sZEP#;$ %&4,B@n)U?]CICQ@MumlR<-@WL;;KU)+aGlG$&*2)s/40'N$FZN@9I7a)P&VH9%:M*[SA'`:@E9L=;u$m6PB= %p#S`<_uEc<4jASk-#j>L54i(]7V^Hug4*eh*JFpnn,:1lu\)FnhNaI!84+0lLpsY5WP=qu$C1lVbuiI]`<-$mI-Gqd*&pA6^.lTYh^#oo=Pe;.CB> %&Og+.^j*<:DJNo.@q!VKLD>P?.u[TfHlp"53%U[K-?ifOpoT\i!+5*,[F3B.Jf0Ke2^B:D%CmX4CsCEq+KYI8S5j)jtK,8d)b %-U5#":d'.&9LcQbFnmBoA-rOQBKhJG_Ca(3fR@#sKZ#=E#a6]q]QF8!LLnKDGE"DlH'Q_1FdU`FFgLMeV5em$iF[":kC(A?:cbjc %B>dWPSUsOi%3D<)`^_hC3mi'3n!LmJl0ag[/ea7*f?CB^?-=$e8*.GBk>P=k/V8Q?<5h#2HN%ue+/]X?EK90*lfQW9hS#:@Xm+ZOa8*E)'D=<%.Z-% %Qm.I?BsIl;Wi(CS7Ieb28X^CZQN<_ca\lr=@78PQ26.E,9A:M91C\&$[q<[OJ5Q %N!CDb7@[=fX:6a5_3P^T:;X<`c$c2R2MLfB`[+R(Y1c!dnC);'9Z"17jAW$M'\79hT9I^rjlj6dfciqoD!/#j!;So2InLS@9[.'XsJG]=5[H\E@l/D+[YNP,u36R)Y2_#kmb#G1Z@5;5aU6:57k4<&%-m%.=jZ:*npjSCjr0 %@ro'r0!OnP>17H.2J+,..`5_H`o."XXQiU:e;?!I,Eh/n9T,GZf&MQM`\UR&DO]5Q:A%?h<]m.c?pC)IPEh!W2SWO^r^go4bMGsc %@.#OVeNMrZCB9R#f5;$LVZi)>;m2N6#M_Ph`U.sV]%AO9iijt5ZCo^rB?]1kS"P7:fbS:24JnoBe@AcL>)1AYl+#3kjTLDSZ.p]aqEo@pGkQn>=s^h;>t@m[:/2(b&I>_BS/t2+I[p5T%HOW8OT4c4J7>?ACoiIm*nn<`[`Bo& %H)P7_rGDGQ&O'>;`=C"3mV_?aS/)l2_CR`&N6FnI+%c:5Q;BQVAYQEE"l\O\6pNk:jUA4/XJ\SH\&N+nL>DY9%Z/f:Y?b'>jg#+GDokdOl\lt*JN1m93oJ'? %EhUF%]3`:2"oefo1l=*[[forT]["dKYik./>cc)E#oH'4Ak.[]U<(ID+7q7F*J/G*RU%@lTkoE$n3kVO,sd]ipsT_N"W_L]+7!_2(hRNgN$%O8K6ljH@Nf$LSHM9g?:[Pos?+\SHa[&+&)&)\Iic<-uSLP0s*,=p:85S@(SdK/LSF2k>";jQ799RGNX1g,m#`R7F^P^!.0Pk^.mFl0*iM,8/G %&j6+S("JG2qI-B&LgF45L.YPY@aTt1@_tR@'\)C$Zo`uL/`MQD^*ST7Q".9Zon2K[&^cPaH^^].Bb@I<"DL6N'\QNWdfie:5gd3o %LZR67QkETud8LBJ'4UVg'nmmn<7/uf?d@Qo\BQKiY\FE^X/).S(8TXo20=XIYh;HIh"J!EcT[ESTfj!>gM@NMb=Q'X^9-5+Z4rd_ %?aiPJ5$L3_08O`jYCMa^IE8u`GhLWYQj1IgTN^#n=A`dal\nR)2e9)>^:G4Zj_ %b-:^[9,W+`J*J5VGPI_)B:#?5Vb1m<5>&MM.7PWC(m_YK\Mti,Z[8pkRm2kjTftgb#_?f7>^GODjTrP]m.Be!%)g^G"@Eb/"#2S1 %N^>&S;Q7/serls\;C2MlE>"[DRED@V.6`qcQC,o3qp@RqLTO"`kR[/uN(Na)PR0cNfQ%M?ML.$l3al[Hm[+&3>ZVfAN]hJ@>5Okt,f&+#IomuX9I`lsK3=7gr8SB\""ph[Lb45/XPsg8e)$\3..Xcd_fPe0`=edA!Zb,eC76A.4_B)r!2]BE*s-i:&BG2c#8Fg*m/fnBa\T;pdM'h8+71(9Y1n(`QOVXE58- %g10(=j8jM;;F$Ksn;4M3a&r]b3>f0=9/e_K&%[Or %.UcHT>V$Y:PM=!o@W@%=ro1jj_-1(\;ng0JCj$7#",l;=Y$d=K%ZP[;5-9R>_i?mkWm[BW0(d9,FGpKO+g=I8fe18CmZGH:JaeQ= %*c)eJAY/Tgj#kNFLMR2k_b09KnYKXUZZ+XTSD;WC,I4XY4cKU9,l-3-Q]@M)U!?lO)J>?[.4n^_T3+,n,a-#jgj$qA/Ep(l+)\\W %$Bb&=B0O:Z(1ZXV*ik/tgD&_=<0W/QUF,'CN_&2Y2*AfZ>1QVDb`.Oe48,R8!]6AhFu:,@YFbHP1HfU*32iY:(C %_6*`FG=s_c1Ph`8b_Fa-pEM.4RqHTJ/7Ytf*(nB0$9?*&:W?BG+*gsU?m6V(VNrfMUojt)l&K>L=b>-8>V9?8OD.L %P(^SNI_^hH0Sg2u`gT*',]^I6j26j3hbBaX6WEr^Z;mfb7!_N7H\u;t_YZJ#0#.u1]CE=)BKPN:At3o$VhqFqpXPaH`K,Xnb%ImA %;.bF-_?;HD4`2e*_B;PFcfu'\Jf.,fi7# %go-*VXH`*oEV_)f4hZLgJ)?JeT.(Xg'&2-C*RYXj$+%MQ"S&icNcJ'TM+c]s<^95^mJ3ijM3Ao2AtYA,@YHXs0UEFSYm7N@@0o/\ %I\RWqZbAPMdq+U8oC,Fn[]^#C7K3'`k#A;qDSpe'lC)d %"g;)r@0E3ZXg6>7?-VFX&$8G3.#_EZ_dHK0ctS)^>/SWJ$"N$*UYKg4.7>Y,EB9p=]DLZj!)4`MG#q*o]1XUTkG;2]q,*]*=q#p- %HB+oZ.k:A*>1%;T'KXrRes`lbG-WBAq\-`g1K2`bd,"Fg,'GLa9mp2oQYOT)"Xs1__GE(t&'9+R.W2OCi9)"YPBMnmeRq%,j$6(% %RGmSqoB]F&/PFRcB>@?()9#@N$2=oYd$rb_oI*VI>TfD6K:O,(km1g=g"N[iBW;"NXX5CWa*2^NV:mcdY<:41&='MUQ&f[sV*L#b %WoQ]g]0aY<,Guh,q]Wqgd=So7rf0O(jOX\&.GOAp=]_-%&^2Ig?nJ1@"W\tL]-e(fY.9/l3<)`DnB&lMHSQSfL,-Ko2"3_AVO %OtO'R!("D#'?eDp2KFDtcid/-00;>06$n+r@4:dc;QmRfS7M.h&4s[uN`N2m4!Nnn4P$%UPX`9%"-#VG/r$X%o/)/00Ug^'Za^O< %ZT6=`B(k!/l.0SD#iqYWP7oGfT.Fgs0@P1'XP[b%qHLq'X/qQfNAjo`dBoR'XqmaNG %o@>!q30#\[3$^2;gC\5E\jT;e5YS'5]';Tct4d+Vc#q7#3c0VrY*^nrl3]RsG[pQb-$1M,.T-AQkeFh\mlAgJY<2KHqjh %K&[>@fC<+/b]HieGVES,;Urr)Y&*,AqC<$V0q_Kk^_%&+6qpCa+[7RAW:@mZeq()^,eMH\s9s/SjB2Oth#VMT`H-X=N %OKced<>a]'6Z+QT_s"\MRtYF=:fc$.EadCi8:l"g>:NOE1JXDVb+mIp6U&L(UHFNh1Laahkf2)TABqEFb$A]uZ9C/^%ptW:eK2W( %#&%GQTRX<^Nl,XeT#]=N":'.)??Xq&6hhSOcOr+53O08D;`X\H%Wmn;VMP&Q5f7H8oG5&']_@8!lE7qEi<]W:Hkhh(9LU"Mg9MBI %W=368S;)ua!c_?7VeW4'B,"8N`@Eo&io.7].@R#Joc?*n_V9b2KL6UHIC+T.U#>>b^m)[*?E^(?#o;iLa)ZD`/li^sa@a$F2c0Se %50H8kHgFgWah68_>HfoP!8D&4,]le*Y5I]2mDIllI*jGZMQ!/6qN4MY8n4kC7hA19+:8];G0(]/?*LS[GgV5`Mn5Hn0l;'MW8`7b %=[1=(_XTlIPF^lX7=jIW&JG$H2=>l>8B#-#L:`?(?tm#q*W6^sFQ`'(#"!?h&dI9=D!pX/cR9Q6LYp9aD4.Mm=rb![a2Q"r/'CN6PY37SXSE4(O81NTJr(V9LpT%:SZEO^o1uU,k %IVkIPY.`%BEgsZb)(N8-P,0NuF&(1_GU3)Ck5`bmo"J')2CpDW16Z/A%Sc^h\8YWqX6Ko%D@8Uek]:/dC;Iaf`eg?R@i!-@j2crB %p87A/hTRcl9.a01GCsb*04Dp[$q*_?$oM>.2?7GRda[7JljdKU'Z=a\ef=o2\cSngT7jhAK>iCk1%?87="mL4n?if@bj& %A#edKf:"CG7U6"*cP!1nT$U.I`W83EqdT0`=lnj=-Nn&0;#lL&>p]A!4-`X_+j>;CK=irkK,@DY3_"I2.;S,G]ZdN,%0?(?O=G1g-.!^/0ht%!,A&UsK'%4L'$5D2R?"lIsUJV`,t- %q5#o*2YHS00"Ait7<_=Tb,ZX?*9DF#"9Vp+7]7%c8>TQ(c++>-P1bMKDqZ3,@+NS_;fTdKs2n7*bli7YkI*ZoHO#R?a/P*2X-lS@ %>1I^8kN/:tjMOPs?'e8di^]*;\h#h[3o%DUOrQ3n"kW7h.39tE!d"J,[A-$B:82OINnJ8Dp%3%#&E:$tb5!05Nt9QAXVF!cK;u:K %ebbT>Z*>@4\[O^(X1=*FaR(cq[skrOuM'!e4^GYqW6J9%J;5Nr(G&'s"9;[5Pg"q[Z5(bg].5m?bI_><"8or"V4IM %Z/<+B?CA#Iq6*kZ[cbh3o/<5?HTRO,oe#V`UDFBkLDk_-GF:'f9tX\HoMa0M@qYPR:e)Bl#1>U:'XaCoLeC7^0T&&P4eeBmY<%=N'NSgNjGfLD=]EEe0om7BN95kPh)ht?)5&t^]AMFH>65/`ZdIM.EHn\[oN^(7TYI^i8Q/%":008 %h?H+P_[(@-=r;IUPWj/LG,eHLjEYM)=D#9cFnE5b,4F)(_,t(XP8a`G!mVoj7H3mrAR"E(*b8>4<8?LoRGt79lYL5oBf? %8bg+OO^s/3Z:qO@CDG\I<)fo@oC-dXbIr+cAGj4iUSXX-V:aF#RT8%aZVie'6\d=Lh %@/HRRc/sKE*h[T=U:9/9Z-eu7c;aP+fZQ/]M_"p]+b6R@+$06_)qOA[Sgt[Q7?NrR$2D6tcbFZiJnC:f^s;_hKRY(%uQ-%dtg:F*\un"F_YSiG!3M3$G'75QZ5.^bcK*h_4A*n.LpaTHsgCHF)a6LBA8C?V[_ %p;:k=hXF-8M[tPu#cZ=sqTdUc-s`lcLp*:I1J/>8&Ue>ZGrRVe#lN>'jq)Z)#ZB",;II4aVMsSl4Bd[fESa_PIg"Q6HfkckR@YD$ %q`ou*YR%,:5ar'H^E2*i^YlUu`mT/n2ObjH,Y2cT4iHK]30)J*]tC-@bHZZ(%+UHF9Z7+"&@jZ_AZEP-?(A:=3"BA0 %=cUNd9+f7U1KU.9*JX&imR(ls!^fZ4sm+#k:fXIRVV94W>]QWi;-ULK[PNdsWH9FS(AE %/%H@f$ba'JmInasPj]iZ^Y@IDOsO+&/1YFX7Tu$jDDd&j'o8W@tnX4kSfP %h=@bt;7p2LPnU9UMt/(J*+EP!TC[4<78o.^GWh-8dDlpE9!YCJ8#1(hS[-6T#X)pt-2Vl)lq;"mPtrkHQSUHbG^)3Q=t@5:,TY:< %MK(R3XU8>f=<&*73lI,2ZUT=G4D1"WCY=cA,+]s:[KRWCnT&nRZ&Ge.'d]/8)@A[7pm]X'BA_PZjY+/,P;BXV8^O9O[]ON42M;8* %JC2d4cs^Fq<*K':=XYilAsJ^YEaF`X=Sm",SOTp47-i**[QI&/6(BrJB9D.4nam^TKRFmX5ZG*OEN,kf]i")^,r!3@ %?K-2^\IS>L-L:a"<'Ua.e"akK-J(LkMSJW)P"g,!h&pN8NDf2;G:T4`6Z!2W"7Jb#NO8&-8Eq:H(`g1O9K,5i %__C;t6A$D>F:Yq_jCXFD=jA`6mWL+u.#Bg%KbU=2[AGOa8s*9kXenh%<@K!?@^E&WS?SNpr=>7->*e,DlL<-T\p6Yh%gc&US>B8* %L6d?oig-TtC`Q$J]ED&@Ti]?uc$.D6>S[R%n2_j2bR[8N@cR'*0?h)KloS+L,EZlgEG1JfDkqNh/WT'nYkf,Z?hV %[Rd[lhMJ?X6C^7kp+(p+P05=M<]`Ih9+g+E*,i;+Q79'pVtG%-4Rm8%FPV?l7.4]WI9GoGLB/[LELTTTYaIZ"OY!LUSFoiiAUnRn %]t6H=oqpk>;DG>[lEJ2d:_Waf%W*nronf].m7nGJmFeBu+rc,cN0WY!;<3+,%fl@Ti(@F_X5--Q1ldJP!1R+Yi)+BII,?;C4Na3P %q$%-dL/)EGOua&O8l_LdYScP+s#m!OqAH$=[mQaoh!,_\YD0H=gH4f6dHk^EMUF4$31i[9HC@&V=hJrSN)esg_lDuQ:%+=]:iDgS %h@475:+ORBW\APkb8(he2!U:/U3cL&b>,C1$)82PdAmQ7<]O-ba:l5ES0O/BVY@jD'geWnA+mB4as,WXE9&,2m`J&6&#PY4HV[g=>.cD2W$lJS;JXkea* %Nm`KG`t>ne@Zp.@k@lA$_6cgW8&?%dQjk;D#\I0L4VtAM[E=QEGI/A5!3WREO,j=HG<'9FFY>hmu0i %1^Q*=\fi.lI3cHT1^6,+DBd=4:72W?q1RJ8lGY;,Xfclk/6>sAW,$D7/ZXBS/?^UYLgdkLqV-lZ>a.1mZ\CjQ/7Z0uI#"pVgV8eZ %^?P'Il(a#!-gi3ITPn(f#nh?\5JMrc=Y*`Y]adqYlgXc^nR%kMr^9!Vr`l!fT %PS%12^)-oSIQj.FM0_o7=dTN6W*"]$fG'#fUd!F2,+&2G1.A/"$E:[TG\as9\]_ebnYGI0H'Bd<<6M@cbU%jGF5(l@p:"n`/hb*5 %@gIpYGg@+u.C[[(^<\C,)t1gICp%Bt(``'OU1h$?;>U0K.\pskD'$V9\ct$a2HTb4+bV]@ih]VT$?_20>nZug#:'of7,,3CUJu-+ %etmA3)t[Vi!c4CW<2m=5-s*]G&!J:Y>fZg5R(j%4/a65]VHih+Y9mO.Eff_6#n#s0Cpob`SiI5QLh#G8L[ccm&k;\Y]_\krAk\&$ %2ki:)+L"'/+>'IV5<>.!*VhdkBiG]op(p3;>?PF"7=A,TCHFjThMc %&Mm\`18eW):"f(d[Y#Gt*-mu8V.pq2hiCKD&W)Z*>(;>L8Y;$Qk;c4.r_uD1ZZ9%a=d5/pUHU?E8lAe\R\maRaG0VK,HB.i2SEYM %hW"&X@j7C1"Eb@KS$;,N2:'\\;nXP(q@EZ=nS`Z!R(E6O5'UoWn'b&org!5#POB`Odp)\G9"Q/_a3n?qKr0MqDO[I:>>o1?)f-gY %$MHFdiE-0MBIB`DLX!F4Q^6ga6DbC2VJNK5ql'8,m?))GDW+lHAp?kU,9T!=;rTKr3Q3;lB;"IU<2h@1kV\L]>4H>Z_=OVaopa*X %gjL&pQY>#c@I2S$U'_b&E/(EOkhA?WnIIWrCb8sj>>&4$.^cE-/qZ2Bp6=d\Gj;&'A#bTP8C?kQeL7jM?]Inr@:-!/%e%S>XcTMn %78>HDBP'Z1r&!95IM"RcFSo7mLb]d!S^qW>>t8a4$UAT&HE'eie>V!ca6T^5oThCLmJXSFetZLC^L<_$nY9rGB1*7RUV6=[ra$Sb>g<@<\BVT]S.&KoY,GX2j]X/S32lrbnC*j8Gcg9\j4WR%Z-, %[tI?#(Ju\3NYiEe=TK6F[DQb,fEA6`HM91%6DLV.'_"5<4Mq_=8b7qs84/2T'M/[j@WT0XibjkkSJ=Vsf-Z>'<-MMG3IR-D%1'Vt %^$nTf6d5S-UrlngJp@l?$nIL-B?[hs/s&8Qos7*;mn=T^F %mm+4mMOXT_I+VN*'D0il9akO*M.%ehYpT;%8eYub0ngt*P_D^d0t>/?RMZai8e[Dbd)>:<8e][OAXXHj8e],5VMR1?+,)&m`#-]T %0i;(\1pP%1Pk'l,'DoGlPpY(HTDGFA[AfQ11pKLTGbKtfJb,aq@BD@@/8%$[9alY.#)+BNCS?U,EfbI))G"rK5.gr-ha!R@h#dHV]IS5JeRHlPo#rmDnY/K\hlN" %:96tIo>HL-;K-)Njh]h6Ytdk__22U"3&)t&S60^i$RaN[rIkp^gt878M2>MEE+3+t@2UHDH[FekA1T\p=Y`_\_]'tX[Go-/<1Fek %2bjbgHGt_`M>h%Uf_\PFk`<;R>5jKp_cUke3\'1.0RVp!YSEZFL4U*99\A5^YpMkB_ML,b(bSWePOREF:(/7k_25EF(7\J/dDa%n %EFKb22\A#())=sgTlp'_'>p]\=Q%+O'V(O!h`*>6eG5'=M)FjT)(4"6]_TF$21u+7Mr"NG9sV57-T2DO-anu*ltX??$;d*rp2?H< %1J,E>[I1[(^kjY\_MM!Vj2CRO&l,N*Sb.mTC]11k0cBhuE+1lq)^j4det-hi9t67;'>s=VM7)1i:9:Go1?$0;+lUA:0lUTLGeo6q %V7ghW%C)Rb'5PO[1JVa)1/;X(""2YFO-X`omC6I^Z)41<_ML-bKelK*Z)@E;M)C"U'2ImM9I`f=4l_M8_cUkeNQ!+%`;6pUEFKam %:(0M+M03MM=.C,9JeO=kj2>L'`ecS7$kcJ53&-tgEFSds %Dk%X`hguMOMd::2A5U*]@f27<'B?0G'@X\j)^j47Y+"ChCkJ9t@PW>k`+2P$1&[Y_@f!A`S/B#Li5E.fJeOW.KG0i`^ko>VY;ieI %@`Sp)f!RhVS62]gG9FIZHG %0=l+3n9nY'Z*$ErKG3[l??'FP)>V:/ad@'W11ZnW5M@&(L9][T0GL$Z=8CMc:5is<3&)S41JZ06`"u1MO/(XO$uh_U@`sk+6d+\e %m&lYnKG3D#?T9c0:;Mbn4e-M$du\QYdhk'LXq$AC',03t)^iY3/iYR*qLoTPIq>/&1^6^6%k0Im&D]"0=D-*TEFQQi"XdpY2AISd %+e4K)_bb;]rG$8@R)4Op-\e>Q`9`;;'-ldEE+3)^S-^Qt:&!#'/RNB9akO*M91in@PW>[ %`'2@gV28X%1bo"/VMR/Wmn=C1-lcfe=R5.>-IuG3.;32g?"d^$qL$c10G^+E)%oY;V\)>=1pMc>@&Ac<8Ui%T(uak@e`8'qcqLod)<.hRM_>_'5K)qs/(W]/Mo0jKdNZA?8So6n[2%(CD,CJ1pKMojGP@> %[EuiG<1;I[^]#+>R&kugVDC#&9V;9XM=Cr\9rp("1JM[(1/07B:;qt"Q2]^ %CK(r]R[Dp?9G:Wr9G:'"Vhqg[?$2U'I`@9m->T<3@Au(V9m.kH-sR7(7H),>%hC4*cIM"S:g!%bX\'J2@Y?e[]Db. %Z]EEh0m:*GRM_1=8eY->Z-^DprOllR6jOH#9S(/V':X_C'3eM4M071TR3kB'iCt!'>%qGJ.S[!=3N>ad_cgb`Z4rapc@"$Xg=*cL %@bedl'3gbr'3j%\M=E&0RTR2)T:q*UGqCj-i\HcGQ7S4H[VUKqC8s\J1bklA2bcsJY0b+3b:65fabBblM.*MC0j+iX9P;(Q@^6c< %=Hb(WVMS`,e&8c)8eYuNcjEJu=V=GF=bA'p)22ES0d9k@RTMYS0:E_ti^+;om*]5tYpSkW9G>=cW&-41IkR6-LLloV$P_6hKXId] %SnVZ974mpiN^Den'2+WZ'3j%\M7&ar$CVghq4`]pD-Ua`=@A:=1bi->1bi,@9h_0ZBO^h+0:Ea:oh#lB;D'>Cd_q;[dDV3qBOX]X %QHTg`kkq<729L[]9s"$NM^I$OrA-8bXDaP0$PCo\'9cp/BO])HBO].'1pKNg[*ZaY>2D(jQKq-V@kU\n@`spK@`oZH0dc9['-e4f %U5>!9X#)Qj7[5;iki,;M,7[ag@\!7kM%MtO1bg7i.npFpfl*=HqA0N6bTqcq9l*ug9l(`=-Dmr;6kbd>n2F'8SVrm_7Uol#M7iu1 %&P;s,Bjs4d"Ue&+n&H5=9ZIm:=B@*=2bgC&A6rqYCiCn!N4](dM93o/(GIQP'de[s%272X/2/e0"X^*+faB.HfVpR0:A1Et`!E]` %?t)Oi.SQq9m0b8lJ`XUR@RP`&9T/sGKo$DpGf.J((7:I!b:kXZDjZon)()5r8V)_,H,IRb9.2JKX)gofZ-L+s?t(<%'UT`bU^@c6 %j7#!$9M4t'DhB?*'67N=]f-dH7DRH%tCq((h&[U`b/;;=Q<9>o`n;_4lod`8P,g@Per(j*`)%M5-&2.l=CN9?@Yr3o=^i54is_4j"sn%@9+9jo[D`cB+g]*@BIfNOZ'lflM'^_r %0*?B`=Mk_K_DAI8<&C+J@MBnVm)N76tSPMquWej<4\=CQI-@YsWc0:#]J(j3($RKCQg-.^T?o#26j %baM[D:#,'Q&o.R/I'LVW^H-:SYf'LJHhYJl@l2B\9e8#Q-SnDsM(NZuQ5J6K@Yq?2'UBSMgVORJhttY2;air\M/cF%M;\KK=CPNY %@>Qir=8PCB0pR3_`7Wi\PaLUfN"ToCJ"aekb:#(_Un-ElZ)2R0US>[\(6fY;=AWHDDJRX+*>gV%AX(h"M1^5N`7.ZVN=qFVR8IG* %b$W1UM%P,\Tu=<*cR:Mk^]c%(DLJi,k_0Y5;)7@\jM@K2&1B7Af%?Ni@SMa7#pk>b0P\&JN6C^E'%:OtciPNE`51^H-)Rgj73E79 %N"ANLM;c9B\Lp]f`)9ni0nM(_-.Z&qRo!Q$*IOX#X>qi*`43,W-.\:sr^)GjU2^HCj=%8k77IA*L/7A0M(+^^:h#D4;FZL#WF^RQ %`)o/P8k^,2JeBj]p^8D!JkS+#@Q;_QPSbcLPSe=_7>\GP=0j.bm9!=4Lr$I8//0lqYM'U*5Ditt1WKea+?qql%FW*MO,VcBc,h@\1aWrSlDitsg8eTT9/0lrQ %^.Dd>3R:)+,E#So@U1h>8eP(e?m1@]81I2)70kQ0=M+#TOr.h4P#te8m2&?q9*6Z+`9=S/,dG'J5=6(LD>PN6EFpMRFdR.*,dE@@ %=!Oc]@AtM,/8p\R%u$iO''nI6O&E7],NH&sMTi+c.ee?71R9q#)CnOiOLJ0d?%N,\@bEDj$IgCGSOUnbYumj"'"41"DI(P*e:H$;!o-q]^l" %Sh6/EA18cYSbXId+mE*"@]J&+,dACEPtVhV8,jciWM-,L`(6T78Ra`eOMn_>FGV7I'DP97lRH;f,dAsT/X+,;8H'rmF^^js8W97# %8eRoPiCsq`SU)H9E=nH]7a&W;,h<,ZaWrTYF=)jD_s0Z'ZYlm='#RU=@T_J40s$cgVB2O"&sMFH,c5[+-Abl3/!Ip$YjkF#j(B0k %)"0d7M3.jfOi/RIH'6,@TLojW$Jm$_Z[S+VaK&s:(k]Ja`7/Vt,)MEpQ=CUO0o>F4OI0_M?Q_'9`#0htB:;+qN8,4?N;&uq`4AED %!f8X3^Hc8.l:E*Q.ROS7N5b\u&u18]JAf$2j"HK2:.>8@O_;o]0b/GZ`,Kf+8?=9'Sj6c77t-*/g9F_@(t"ZO&lVm$2b8m<;#uM& %^5tWiY;l&*)2.u:!/[Zjhus`l/O0>n.J'/t@PYS]@U1"t$RE_G/0H\$"CE9+N!1IR6O&D#&RQY8I9$Q/@436Q$nm]E+3t(Hp#E1t %1$71+8;oRDJAc]m$V65VY89`g7DFAkW#I0.1#D<8g:,9&SiL70&BPnH$nmX.N0tn;6fs3hF1sVCkfFX$)!,Rf,;s3YqmON(is6MLiG_7,:9t`092E9R3O%Gk(mGjEPsOHNn?TE.iH^BBb.ZB`=?JcU)VBgE'Lfq2Y %_MDoor5OOAM3Tf)11Z?2:A`%e@E]QC75H_h9RTIh(bpaD1.I5.Kn9o3hVj/#6\hCD`7.>D0k0GGqSn?5Qn`&*A;lnU+hf[?j@(gn %9RUmu,M%J)OtgD[$Y525GJ@P(?4ZGD?Z96u=o#pjd0!Q,@QLZ"`3?m/@^6c.Qm.k7,M(qX;-QH#<@V@=+0k0F]/Jp4n %fSU8N$h2/la]^B-rL/=@NY02"`e^Te]O8[bm49*Z*l?G2,Go='_2,?"W#.7t,&`EBQNCg>Lf#m.0k/=h0k/8i)1$Go(Q;H\B=p03 %`4Ahi)'c#a]o3OZ_`(&$=T]nG+&t"(9V-0]R&gH9-;212@H`2Q7T"C@T`dX``H3")#*kG %,:4FeJe:qg.q?M`+_/HV2)&L>/^,':5!k2kA&L@3@`/s?.i>Oo0Z5n>N6ktOL_5t*(bm5=DiC(CZ3;JM%9UH&.2hZ8&X+qZ`%Y/L %(m[*M9S(ZO&X+AJ`9`:uN#;*EJe96Y=tsLTM=R!t$7]a#s1DhiL1Ib%c(6"VEr#6km %3VS1=CMFC+(pPDsdl0aT?#[c=O\r;!Yr8S:)'c"NQ%BU3V-q6CRcPJ5->UGRa\jg%qTa#<(pu+&,K9hb(pRYo(br@/N*):u4Y^C[ %`dV@7<4oOk@ZoTj(bpmT?PkN^*YaR#lJXKfN1uLP7VmqmbbNnbKb6,a(Ii3Y"!a[HP_'LBb3+`rZNA+)&]:ZL(pRYo(pRUoN*&// %r%mhM9sa7H7Z:PT0k*Op.Rm+^7PB^fX9Bgq9?)crG[n[\_O_VieeHKT(bmR[N0jZB)'^Km[t53u+nCU)CJpbL(btGJ`J>g5Jd3U& %A&M>s=tjD"b.TN=C25C<0rY3iN7bFHN7bE?7Z;8a(bnMQ)^E?^W#.8_#o+\n//][Eer139kb2J(RTeO]0k/XU=,^7>(4_5RPHa'T %,:7-FKFsE0A&3u#'D7%k_ced(==Qd6a1O*8XcJ>O;r)o=Ljc]^5D'PXR]@8['kS2>=L'32=L(O(JkrB`0u!1;&^tl5N#7;,&X2=1 %&Mn4BLriOK@eM%]0k*kGYSe\*Heb8M5&VJnlALc#Lrf4J5MO+Is"1#7d#UMB7O&`XTT(bo`f(5s*2_]'ht]jnm7;%?JY %@`qY]JnY[Q=F6'c&[UWqDiC(J#A&i2$AfKB7`tUf&Mq7tN"MO>iIVZZ+Y=P90#`R(&Ygf=N=ds^`e^$/A&QU^N=j'0Xr&lr&k5QE %^G'+h4_K]jL5HS\0n3]O-su^$>PEg`P?))-L_YgT7s3Yr,=_IB@)V9;/f6=[jPLe/[QkQPL8A@t %Q6g%ZbaL4pgsgofPFT]Q7SL3P)'d`0W#.72QX:RaN!1FQFlnVpUH/1)&]9tj@f0Lc@QNEd,:8PYthYh@DnNo.Rn5X1.H'u"!bf$Y@,;EU4-UjL]LS9Qm/[:,;q+k,A+rK&QA@7`eaIUKb;eTaquj>qLT;(b57/1_j3#dqE&3*FOE*;9ZE#'_b`$r %(g\%6Y%V7^eA7\0@dEK9&Mmq6LoEKmA&K'cqo4Fh85V'M&rb'PZ*$:+M@l%]CW;1h)AJ,I+ibBgX<1N[Laaq_cH>rjW^ci^L_6dB %'JZrs$:SbL1.?!sSKarrQV8"?[s_2nPT8!`0ara[-Gqc29ZBI4e&Q!VfIXDP'JZ>rKd*BTThH&&L-uVX7]2(880J-YN$._M,,W5X %9G&N-?798gK`tft0c@_T@XM4NLrn]#'X;4?'X;?\MHEr07](tr4!]]N$<)p.L9"Z0@V5D0LeVAU`$G#B.:R*'?50YfSWtBg'i(HY %WGh-m,">8!:rLjOqFqQsSZ,H(Ljg(r(tC]$MAT4464ot/,ZDY@mm7VU`h8,Z-_jMVkb*<%`7-H).:Sp_jqgJQ*?tJ/"47'A&c6&d %@M^Mf7_>'"YtOW[AYWAq1#@o\?]rXhH7"I,^HDD-!+NE0Pg0FDHR+So=+1u'@s'R45"o5AV_<@`NYj"Y_aLrb7b$C*_AqHCZ,>Y; %?G3)NDM7/c5tGu(FF]e]CgIcJd-I^]YZ%BVM]$\7SKaS`+iBP%Hgaoljo#N;bAAM.(e)!e %EE-*X`cg0r'o'Qo>)isMF%4n?.89;Ba0e0@6dhB80Yj.2NEX>TBk+UE8I7c_6CMTh$(HYXUmf;[#_N[H(Aj"f_Btha6jU\9Oo3'Y %MQ(MV$P5ds^j-q8&;G1CpYpg^6$i0W#D4thqHiDo<;h&AYGh^KW#s8SRd8@u36t2$CQ_1K(Ds5h$bEQMoBuec$X4ai)A!\^r^lsL %MUtdX@#01YXqJ`kJ\\^?_mbL%g>Yha%QRNNggB!CP5t$5^gCdSISmjN@?*-@^KS90!WA`Fd^``nqF.HjM_SgShD,J#< %KH700aHp^:cP,jqMr+&uHsuj+[BicFY^W1b\L:feg)0"II&Yb1W9PU)^.S>!0OMF!!66:.iO%i\ba^=q4p(8aN?n25T$o,qC7&D*8<>Jm`u\caSFIm; %1.-A%F,N)p6XHcJI=a8qOeDZF/bmmW]54K_9M3n8+pA[iPfIQJ4CZb7WYZ^m;o'7XZ#fDeVq[S(0E1B_N1.^FLF^V/Y>`];cU:b>[W,'.(]>C75T/[[ %9LT6)>"-/M.]r%9f>L?aX4^ItEa!+-`'7Bj#* %F\].a`^#[P7J_oGDs-G4,\FKjf=K&24OAf2#' %QOJX8dFBfs"+kG_rc2)9Id@a)`Ct:C^]WHdR_<2+U)`6).a%65P'l:$aMXi/5cJk)l$GqrY(!gk^q2:LVP&:Q];3'VZOM/Ge9Pqs %hCa&>N'>ir'0`pP+7H("7`dS&=soIamN4r:L@ %H5B)2qt"Mfmh3W?bA^:g"T5s_-CO(']6.?7bK=,;:+GI5du`g"dhq^0WK5Em(0n#u"B"n[mm?+%ZYDYh.$@E%+-YP=%@Q(\N)&h> %)2.k#SBODOqr?Q*_XHIscL"c!Y?_RIqj@:68UG+l9)L:Z[3RcI98:\>?cqEqP&Y8=iHJ_[mQC8M(n):GcL8WCBfbjtUrh=!=Xefd %OM?"S-CW*^`UOXk(M1XZ3U'X9M(!b2$1M,Q`;*P*%jK2T2.W7P:1u.TVjR9cN1H0aHQMi:gLCE%CDntCCDqi_-+3eKA<=@_iO3M9 %IMYd!%q-NtEuto$&(//'_q6I'gXjF\%"U[g^]aM`O %k`O9)UgA\3RdjZqUoqf/>ri@mR_X.#04RjNpb(,0\L<$t@XXK%')8V@8GK?%%").*G4p"/B4P32GuX8II$Yniq>"N(V3l?r$H0Ua %'he86i4C6lF>GX4^5J>-HTm?cJ@PYOk`[g:97*8V`NGttmVAt6V#=pCb%i$;^iub-:S!ItMRj1maO_eeQYMn-3!/!F98h@hk(W9X %%7WDd^.WGI]Os`U8\S^#B?#-ec[`JMNnHs#>=F11`(-NcQK_\BG\7-8V8&GIrJf4^UDJ"gRHXP.>m@it^\Q[dmc*]+Ef7m'HLuLG %`-.iX-h#`e?"gQb%hc6BlhIe^Af!=2S.WiFds%g[fVNuB=Mug)7XH3jfYs_B;3Q92V`QefldF\F4_\3",_90NFjXkcN\O[B/:(qj %-`Tg#;P,6oPIf+p\D$"c#t"6o&V92(^GD]:C_P5CI9M>9S^A`]d<8PY(XHAkgkk73dl8DbEZEJ\#)(jPK':)*/6M7p/nnE:(___. %>t+Em=Z^c;Yo^rn:ILO;-FbfYFQie)@V%lml4A\V0dh'7g?Nc+@1g(M+`aqe$!k.]9So#=U'lmuKEBOi$'G?q"jnWs!fqord[:nM %X!i*;ATY`.t`.]H'D$>-k@lE\(AFtQ[Z/GQo4e:gn?D32=SLVK]h6K3H;*Mr2*S%"Mi.[>OUUm=rTXpH> %:gFhsoVeVYLA0Ggab&eUeYo'ATXpr`FiA?HL=1E0Y);M-BU?s\Np8A;?XFG2LbX=^kGbC4-9FYZ-E9`3VO!*[<7eEd<7eD[Wf)(p %ZXc`6([oUk[>O7TV=_8XM,i2PoU!EE'0uqkA2sPrtYO;S')]Iau.\?*YHqm?4'D %cIAYW.:)Y)T?j6R@6*FD"f4ji78K#XK$qW7q3b"BU0c>)9gS#9Q:0t@et@,Y>@e1Id'k&,cP/ndqtP#(7o;MLG`s@M,j`Gq.\@#Q %1uKhs)1\k?dNZNj6F>iR^1$!2,ZjbC_k[!3f4?T#`,:tIpo&9e#n7sM1.q9DD=V(U/OMjG9k09qa=[lsEd!Y;*RAGV[-2fY0<<2P %W*GSYDVOj%KQUhaWaAn7[5NgRHQom"Dk&tYU<2sUL(6*+_%*#-.a_Q`]fAsg01ieG>dYZ($#R^'>fViFg]r4B=YbA?=TcCWE#G*e"2;a1nf+pn %>KRC*Zk`'^_END:MnLEVrF`L[hU;%i\N/;HSG:1?bNpfi+2)qS\B3:W<8Ll:[3ZS"J]pIa%9?Fh\U]V=u(MA)P+U=Af-g= %Vf,/#QV5Kn/N*HskQOBA.#D,tSY0o7,/+WrrWh[l]/A6#9&J>m"SmY`V;o-Jjda%2`DVunBDRo`hkc>`Vf+;DT(:$V^;YN0WfTp3 %P#]'0^i-1uT%(ZrDdd@KmkT>bcV[VPi4#qLa-gWSN?nk;[8HHu$m,Ro3dhCIL#PXe^88e?mVg*`&T%=Q)Ojc,.n/KG)bpDGILF`V %k@M1RIZ"JLf*c9e/OCuq&l/??OU229$@WA`nm-h(dUBV[0;NkbD6EHn)8@K`FrcLUV9$^ET-Os^(.EWZInT#+9sDIkZ3mjPTDYh2 %^4r2%iGXPg^q(T^/`K(M#uCJb)K)%2V?MEAipKF>#(MR!h2<+mn@+jlUZ\TR/c'ap?6T)JqF)#LE;UK\=h[A&Ddi"$kk;ui;QP/\ %[j9m[D54tW'GnBWQ0n&m=k[pMpm*I'L1g8sejm21i*5Iq4ouL0htd'>Q/Pq8Sl?F:ln'@c/q.rI[t%2%h"J@c\*3Y:)a;qZiY(TJ %?gKB4X4j@)HAb%Sp'28Ee[3d;OhoCK4=R,K$@7UViZ[58d9FQ#FqS?i]nKJZ)&'^&Kg1Ha#("H\/,!;s>EYs^Z9?Q=Z<6V?d9EoH %*rfGkH:`[X$baMJ=LD;9[lDe#-8Kq+p;0=0.bIrTpX#'?ln-I#@b<%"QHbV'Ogd04g/R%lXnO(\oCjn.hQfEHFr'WaKBZ8jc,a,d %j4Vj'Dmdj=D$do+9S)o-kUd4hAq0n>M9+%,@5;nNS$7:(]O_>='>2M%KN]J:Uj_OR=tXs[]eYC7=t.P\@WgT;28(g@>IC,6Wa/Hn:;@?h^7$:(.gKI4^i/j+&6(Lr@'_bacML28=*n2u+b[]ilX/0J0&W+\"d[a`S[ %=e^8Lj$)cu&'C2ddafmZ91if%UiOLlEQ=:f$d=o'"o@GAfi"[9j3TDe[M/koIaTrT)S4W`-Hqd_YZ4$UPV&J^e[G]nlZml1SKV49 %&5r'S)-`/H6e;j"fV6@@2Y2d0,p,P:^^f"C\lXUj?gI6-V;Sa`=Sk)o>mikCW\md'9+#m,S?%)/TU*[Sd8m00\_OmNg/L.X$`$MSuh)$[/LI?tF %qT*Gk)@1-LZ`#eD_OR2DiS*Ucn1=Qfg/HX,-]Z;s:NY0e8DcVQ=m@k*>6/AffK8e>EjLj$gXM!o/O!]?2_!`] %S*hpcd<6QscB:H_B-PFTXOCIWi+AsJ)bF/PB!LTqU*EUCkddA/d\0giAgJh@bdq_n&'`0H67be66-Qq)/_dE7bS'XFk_5?l%['du %fU.\%."dh.4gl2==I*Jrp1L\:FH1)/Mj8F'2EETCb>?AlP-Ss3/-RC/3IJ:#)3]2ieRD@\"E_(Q'/^G\q!tu$bfBjraGUsm/4ro\ %OBJ`'7;K0-mKObk\D^ps2T`It?N)hH=Eh)lY7/H\,KbT[Cb-3%HKN&`;YGspQf2&h[khuTNl>^5!T8($qm9%(L1=N62O)%t15+jG %fiZ.9ZjD^LU=@]7=CP8&5/C?V?X*eF@:QbZ>V,k3X^WKC`%1FL`u";=!4ARRift?;8dK(hPnN-"Ba4*b=4SA#+C=HI %YC)%K">7UY*:iq:itQZ`#si*qo-2< %h8$:?=-BCY@QSg9gA#BsQ[)Zd[7"kk?Fgi/GMX&\^X%>cQ$9WoERNV$?-/gcI/pHmVF#!bG_K/FObp`fU*\]Y=8[?D,:k(CLcSlU %qZu8JJga7g#4`,37[7*lj:t]KXRk$@?0iC]qG;Q+C:3)[G_M9&Glk0k',?!&i0>kJGno8&[b])147J-pg"k-clbG$o#*1nLY>f=^ %S_!pL.64):lMt6?Q*6mNJQKGbhJFh%Q.1p171S7@!&"SBC^G>4iBqd?!PB&\7$3?,?:gefEKL[BP+8Z1l"ERHU;Jg<=1n@,EBOs) %8n*ubE9"keIeVX<8bn%`culCdCD!a(W_6e6YKSa;n>`!;JQK/B/IgX'e@-,=#iHF596k(+eS\PUD#piiQ$i7;!O$`:mB\S;8d19E %]`WMUX.X]]!jA\0=Qumi]Me7O;MbUj;N\OjrB*s4K(EZ-3WZm&%T"<`!3`3DX'.gp?7?Z1FJ"+cg.TeI&\tG1g-Pjc[@?efiE^07 %\aPBein\/D#hkQ4$WJ12BihU3*c80/K!ND$*K,,qV/(+m^alf94FX00<(cC=k5nu3&t_@1DhqS&/42_9,/CMs*Y.1p&p6=a9Y@[` %ZoS&!C/T*])Fd$*+us4;\P0Z!5[a0b'PVNU[d8H;ig$atRR8k#MThK2`>C@]g@Z%uK(h.j0+j;$@NVK/S"?7G3=`BKAbar\,dn8-WQC%jD0ipi2'gZOkF?BM+j %Vk&ZG9f%DLRM9Mu7]U:LM-"Fa;YDgYYH5L\3fPFtJAM/7@h-'t4t$H8YZc_2J6-L?Z'_9gY@P0aVDX338equ7VS/Amhs5n)Tb %"pIDIGI=JYU5d%%g2H;Y5HV^g/M_mh@\QlB/Emm:rY#LX* %)D"H?.L`>6bIf>C<=7m$.iCn<"ResT_ZZ-R="'\J":YEWeXBK%"j*bn:2Fk7jBY?+.eBg3FodGD[1%o'[#E;BP1Y$=>tNQEMg*/4 %.)h^%b\g:di*AoUQr%k`?-,Pr=R`J(@(?^&'a?8`R+s& %fG48A0A)O8`#%bI^$c$7RYGk;_\fU.'1cK7X![Y#$G2HpH\Ph"U&KXLad?L<1*kKeIt,A=ABV2-M>Lr<'o$YZ'k=)UY'=&@D[+6S %lMiu[%(fs`c$/-,`:kd_WG,Xd5[[Kl%#K.=\QG'-[)gC5RnQK%Y'(Otoj2<5CqI*i$JLc>XK(T+g6K7JaSof*Q&KrF %6+`<=Yl'f@H8\F!B%WC&B3G\oQ258[rtMC^jZu_^af$^Jh[37@lAAea:620Q?;Kq.?ZJu)?aNRaKXr?^s&_:5UTS^/Snt(&YjC'l %A^m!HWjE)^Q%GV@m>]Ypg+sC8je(?Z>?,]rn#r6k@9pu)6)@sp@F6KmX=Gj%4=mQa %oi0,0$.bA"S5R<5es.f,I9"j`2WQ?c%G$fe#,tIjX=L_%dK(btX'IcKD!lmt7?-#?qQNdtdu[.&bNOe)[CIe=)?;;44LS6aTIVpj %f+k@rXK%HkV4hUo`Q %Y'(1nS6kk'PcJ=d"V&WnPUjK=@)"Po?FWK/i#=!Bh%6,3J+=_787>%5'-MOA0t %`Z8QIB!#\`FL@%]DKeJ(0\V=5p_og+?2L_JqJIYD9&Wke*X1b"4"^\a"*C@jK_k$kkt9O_0ifbj;)@"p@YrZC7K7p]X!cD^6DfVL %"RA[GiRf^KddLAcO[:R3Z$-'H"RNO)@f_:k%Ur0;g>gBEK]NpYNh.5[1 %ILr8XAqFiQiNTYakg#Lu0R[uDUqX@lO:^%/fW8In@]cLN;lsTC`e%BVG/cg)@au3%aGI9uWeTH1=]F'nSJ,]04C4\JJQ<$X8-1Xo %h/=I'-`?7d/M3>udk`^P^_ec!lN9F[qf[i)OuWLBP6sb5>asW/7[/`+j9P-We]hA!ps7;5I.*R\$3Q %e=^$_h3h8Vngd?PaJrfBS=4#2?koAL)t;.HqRB4[i-lPF--0gs7j3$l3kan.]SFt2FaP@,ZL>;ohtij#SUs(F[22pb$EXt]&M]j4K[VB?lu?#4QoboId,#W:;mgR\g02a %)1'6;VP:Y-@#@3JdE/CYPfZm[98ZF'dCmLX\5^Y5YZ/do.b3LH;%lPJ[FreI;Nj\k"m?s5-5AsUTe7f?'aFKWR7JXaD2P+B/fhFI %jM@V>0AET1HK(l&_k;_,BiJT0rn<$&/ONuE9k0ip[+CYRmQIC[='<:7C->Q0req?;lS5A?.J5ZVM@GKGJ-eUIX'#$V!MU4OH1-YE %7C/,)E5GFc?RKuKY`cs!q@:PB/PCQ+QSgHr]JQr_6BDao&(c`)3)h5Xe*k8L;TV^='Ir?[+0I:W.9*1Vj.ZPem>O_UJP[e>UpjnV %G,d\(=qiG)A=diaPsT'5*nG?,ECX@M.^NAg\YITkV5#Ak8f#%2cCpE?$6Tt:8h"2GGK3OZ2*hn"@&VSTh^X:OYD<%rJ5E3_;!/"8 %8uc-n+d4$J]2URk]L'O?/>p'd"%&h9QUY)O:eC7R2`iEe`M2d8STmQ[Bi(b\H(&>s;lH&q<$L63.^`5k:UqTIC/rV:$O@I_gTC^5 %C0<Y6UFm+4%F8h(A,[<\!n,92n5p&D>l-98Chad(sgh?jP; %cC/`HCK)6D'NgmWTYU5eh]j>F.V8\o8N[].OJDU.%5\%>XjKV,H`"#7W0ZW]We)\_F&!3FM7EQ)TgHXHa@T@>r&]7eW)t_0AHu(( %@c.V,'ga>_7)cnU:Y\68qI&1*!)Zn]pq.AN8kUnndI&9[3V^n;eBUXV-3=+=]G<'UT9U6D;^=+=]g@ %D==ocW8LJAe-(SbE%$EFZ"ocM%\b`+$A7hjVQ*PKX8l+#@-OWs6q,!,"pYX4P(8UsK;eRS;H#Z5$:bP[""-qhB^uWG's1/jnZ4'o %8p?p;0n0fBN2'@SGiFfUPK.^'iEt"=CJh5,h%$ci^>]^AhJO?P2JhTWQOIW%g%[BB&9Z$D"i['l+TpijDTj"13 %W2N6a@8(X=phN[F:m&-9-9En\(#&TW9FMYfni/^c$;jkR3)k9c3Js==;Ps;)a&(_;+JXY+:f4j"\9q\_QEXerQKT0c)S)C=9IU== %"C!2.2XH0sE&\1#^eh"9h-/Sl$l,L[-Td&TT7nA0J>cTCaaDW!<:eudL+9R':hb-kU0r7kl7l7-j-]G:ZK_Z&4-/c3V18kJ9b=9kQ=%l>IeTYV1-V(7tJaP4f':l=?%et %;Qp=Hnl5NKOf,&njJb')ef6g&h$lSgVppu1hsjr`bf)T3fINbQcMM=rZ1(]*\_cOK3<@88qPIn>!k_D*0;UT3MTLF!-`! %Rd;^5;AIBu9%f#"`R$(g3c/?X45d?K-/sq+M)[uZ%Ll++OcjTb8hGsc %[&Mka^WK>#(ae;i2NHcq(4Pb`i)HFFWnD\=V#pRY:T?m^C>-nK[T0#G=EpS2Zh/JXIa;H]BX),o/>Wo?70u1YW>*NH--IY>^gW.U %S&W`T:AE2o]`:FWmCJ^r%`_PR5;Tp,`oHU&(&3D:=5s0.7;WMk'5M! %=TJahS7Vqn>dlU*cFca7SP/>al`9YPF)nb+nQ8/Pdq)AKJh^erduLaf_/AKl,nIaF'jA"B=6.2hXg,rJ?+ga'%^glt+=`7%HFhM)\i'ps\'c)QlM&"r'R^ulnOO)nM4>V.)/!5]f/02B%pdQu=Mo#\MY1C-^o%4.#r;q'o;OC]d %kYd_p*2#'8Wg\N9#DnY.kY$8k\\>$fKkK@geIBN&pj0[$O:b3tXIb9ADMQ55MUN)<5tpBDr2ZZ/ae9,E([#16S(FcAMfD"'buF%J %b-t=rVs?G%rSGVDtLak9j[Cf<&>]CKpV)^;F5DQHH@1_lJMV2<:I3r\A@NMU*ESq.kd,/B/6b`W(GBQ&LCpjRDVu@" %*lcFhl5K$?^+uBb3g"6M%^QP=Lf8*d-#8:0hm"(.FB2K;PORl6+p87aatW*7H4iMo/rqQB*q^h2SgDqPiKUIm^sY*b!<,ubWaZcM %Se;0qn3crKK2aWsXR7kmjhqF)$;[q4%&u1?jQTM`M)VaoecWB%Fu)2/e!^hFYX)eWlY[r1g?Bt^?A.Ro?/d^Fk[P)=T(rIoR';!MKfKf!J9YdREd@'I%8GpM5.#bcBjMhcf3 %GoYtV)0@J/FP@mH6KL/e:`>u>V,WlN<+rnTk)V>rZ9CFXdA7+e./Zg8HWC;dkAeXqE.,OaT$O8^a;kIY99j.DVO>hrL_f`T6!\Rn,ns)m+3R84%!C1MXYu5=/u-lF %G["Wr.B4m/8$/V&"/nBZd)Pgro@W?81l?$,16oAT-Z%[_SD6hVlbC:%HDm!t_$bI>\=6BOqo0967,_jZhTm[j+qD"4k17?,<0<$k %r5rd%37NL.7Bo912Wj>3_CnF:Xk2;L1jQG;m7Qhbdjms@HWJG+'K]5lAD7XDBRAES7'H0YC^(\K1Di6?qAb5khS=C %-\"dMebL3^ESBDepSbiWERgq&^?S@.DU,>unDN`hI6BR>,[0lS6A`a5"nu!(X+3.&cPkP&2%'YGCT6T:k0>!&?"qN;'al$Yrn=[m %ql7O@kLOY42BKb+?$.b.0j\!OaAC9N%"lj_e"Z]?Ju"pm,Ob?,e`t4R7`U1'Q;l!goTK"8oiM`h7CFj2'465+s-=V*@qlYg+;R&/pJFR`)t2PDnC.<#_)!C+b^JBOfpU?5F, %fW<;J[4pcL`Oq+33V(ksXfb+Wd`fY@8Cn)?Qf_W*78WLghHu/O$3J_bWPr*V#((L8Gg&ib;^tY'&EXun?eX%,SZPD9rg"%e:OS%6p<_N: %;sqU+=K4u#P^qA.[+Y1s9RC]e:Ci[$a5:]nEDa*fcGXlpRl1_\4R1k;[';^<7Ji6O/M)BTjAcOuBdi`gPda,]tN*@@pU\ %N*3OpDP^&^glp.tVYsHF6;(Af'iX`eBV_R(nM>NI9RW9(2*QHN7$FHuhXpaQ+*7(6r#BaNsWHK.&)&GApH_eu" %*@i:H?hsqblh/)+i:iER&_VL-P%+i6\rQ"H'Zn^3:X4+EMrW;*,t%'^,Iq)X>7YG9AJGDb?mp%Z#q-d!i)].R<+C'Otj7c+eJ %MQS!=J\%^f(W@gmgMquPe#If&br0\oIBgMP.`Sl>Dd>N5X;bTsB[_4Y`_G&r[XOq,qLL+sen2=B,udOB'Esl#i,+MfR0'?G5$mY$ %LdD[L.L,c:@Hjn7ZClA4[:M4u;]83g_n`2to2-O+Rpk(5;!`1[JU/Amj/O:*17-AYDCJh`#k:[_p1_GD!mbbnOtgggb=N8YYFYj8 %Pg,k3*iGqcnS>/]4K)uk9"@WK22-XSK*UZch+Q,edQkXWBoGcs`aXBKk$Jb)C;^g$k\/k-ce5MeFQSim'8OWV:GR?"u#nn#^f.Ohs-F/a-BTC"T$"^\Ya'\bS8rHX#UM %\sL&_V-T49gU(FH%cop)/(]\1)*&uPKNBBkG-3A0:L,?#(rn(V:F]&1?T\>d]>1?ES=$UHr>4]b.Rnk8"P@\q/#HEdYa5Om6IhR# %oDkq6.Ap3ZQF\".2m8"o>o3::O!Dq4b]Ba66V%EbSX)oTMY`7r*(3+FVn$\h3DXCq;uW)Z^ERZNPGVg@[bDJ)N`1Pu;*$t-*h#;# %rYg[kf>RoVlC$PQ&pV*7%S:@n$fR@[ba.>\d:[0LP&aaa>LEI_=(fssPV%.@DBKZ6R"G>:/ZPZ"2W^<\j\%.* %@G&XH*J97Nn4OqrXOqai#*A5^e&h^`q%cjS6_J4tY^Nal\og,"9Dq*Qo.7Kj&JLJ#)ZEo]M"[^Q"cZ^N337eH/#LK?p7!>/Ud=s? %Z3ZgibhJH+T?#bb=j\>O1+af,&Xt%4EJ9Ec'#KmmZN>kZ/I8Fs(&jO82Y((6qN<3;@1'k+PZRP; %.&3at+"[i#l6ucH2Q3]Y4bkrZMOG%=bdYi<,]6-VrN?-m:]\JjTl^\6@2WZRY@+OK4S6T!;fo7nC+?&s6g:!k %qtsKS'/igAW(7"(E,`Z.LMlg/C>SucGRq&RrS&O0>(W=+^rPGf%@gtNW=SPJ*+m=f_+n6e<@@hMLrW9U@7S_;:?^g5%g!CkKtoQ< %,ZmTZ0_fg87j6us[:l<1;!LVMqqDA>6s+5CbCZIQ?GQ02g99F,a'Jn]$R<7leP`mE"; %EJTA(a2p;4:/Elj_SR"WI2(T7h0F'E*a"eC&Hg\+@:<%E.kJ;K6`!k@OU+C[0IaHQd$XnBPA7-N5#9'`ICqI4S'6HpQ>5`np:.7? %&g0b4"Q4;r-[c@0"18H/@BrA!QQE\fL&L`Cib11*E0_Z'7ai-n's2U@_"RXRp)o9!@NR#8BN!1-re!5b!>e63L:GWYRbfjH3"6 %&rF7Q+,*.?L@oOLp9c5/9LCnhTunBPS$$?MdJs>gW`h]@4bZ`hO_q(XmWE&<).0$^C#^`M\CS#8ol)Rp)'RV3l`uSh0*L8(57'Z8 %'+&S*'sh-S<3nG5WRK_P %(:@9;hWuLi1)"Q<,PI,5[)^YJqeNXkeL/?q_)Y,G.;Z%FR7jCd&^.n#,`=men#<):KJJs);@A\o<%ZOt"&d?MMNnf@'0PZLaV@0S %@A%':2'hZ-m,'`$.+>A101pc6bQ^j)gTt"p631<)ZW?RH(@/KnCEAB"I)c`gZ6E$qU:W=nqIqOQS:C3&^3rqfhbqN0 %\bej\TAKK#,g5h5%@CMc1^4es_] %`J*QT/+Fah$XLBu@D>sb^4WkbI*c;UL_DAkTcWI*gVRMbnD1\PHJs]LfI,R7/>dqoIl++)Y!_MF6B5kWM,(+(VOPVtp.@Udds2WF %Y`Dgg5^1,h$f.@=d9>;:f43cY'RQK*8.0=4sQ[p+8?f8&+`;70Ci(t0/l]/'tK%7X6D %euYTW&(@eX,J*b'aI'\5V.Ai)/=/p.MWtOB6r\7RXHQ9Ee.aUA*N0`1IK!f&bf.RB)'r;,f"W<7L[N2Mi;Lgc?*\ET?]XC>bY#gSf]IPO_Pa+M2j">I@QWEMP!RC`t4$-L3rU?5il%=_NXcMj^/[)8Vq_Cd!>[;@+j] %JB^$:Yn)P%;Jq6[gS^7q=cq<*GK/V,TI]X-9!lK7W@1`0*7&X><9/gL?56GE3p7+j0N>]ds%=4cbW`C"%E+K#6aFA32DRGoesc!C %Qf'\kR;2:fmb0-Ck\#saR5_B$i/Ag"!:_!L;5)0&'oN`(VP/ed$B$\i"._HS\f)3W)QY>1@7)N0STuS>c0[,a^e;jI %Z1\$*RP?-nb5J\n/q&rfV*p5&rB%5H2M^$7IV#=iReLVrK$9Ks[oGo_WOI711\_^cjU[H[^D,gYg_a,d*J?g\^1oM:AVC^W/0D[R %mSg,bYrs](@T%J`#Es<%(MDhF,mnt`_H':l=hOek05:G2d[^&`STPJX\kQfpgf]iu!CQeSh4o^9M_Ai4o0gpFX;\6B:S)PX$n"+;6D%8 %Z!=]_moGOsW"*D@WD5fZ:k<_u@X7QHSfUe/:hd>YIWXKM4g?GHH<:))d9D@&2^UZ!q>/TTf$0*;JgMf56m;e:9=#e6Z:X'FtqU1+:R+)lKpn,3ZYSbtr8Gn(, %WA]bES*"EO^#qj[PD(GI=S\^040=nAZ6'$;:F!;'4>QH8]n$]<%2(G]jB;7W+el0 %_2R\O^1$f*"A"Ma:6s^g=S`0!Z&%F#]=jb/CNdn,CVptl24[EqR(Nq'=Q;tWoVOX>FB_AA\;kiYM.Q^(e %EA34C#l?r4;;P:[R8PK?_I#H*)Bol0#,.oQWW`t,4<>2`>b:B21E-TW9uf)fdZ)>pHd3&SA`gcKXu[#>f2brWs1DM>fJ9YJ/#T2I %*!UqBgED,aOuTOIn?Nnu1VKf6r&FJo\::,AlVFJ=l?\;.aXS4Tel/;2`-`njE84JZVJ]Lc0cV:#dr,0JuBVUf)PlWWY-pOarc^bCX3BG=^=K)/=dt %/3i*ETr-W%?*ueh5>SVq-;/CSl2usI1rViS6m'YjC3iLRQlc,G`@DX&V`mTD7_qpe_gA!@IJ=:J\H;I7'L&OsMQURa[@HE3W-)qW %M6PqW8<)`8W([@86)16KSE>NKc@VRhN?2EA^S( %.97XsT/\97W2t$<"JRIZnsM!HFer1jK9W%-FW_a:Q,7Ri(3[^o798-$YAt67ZgP*n7+@m`#l`J0^pfun>-K9H>?Y04ZEGg:)U4l7 %>Api_U&2XJWQln.d]V`@nu':%Bc+'4X6uJXNB:JDH+@L:>%j:bPZnNY)Om;?qJfW]X%-A*94B5#jfqon&6b"%(p5X'Kufa;PNRMQ":E0S2QPAcE$4.7mrmB3-8Y$&%D?`_\=\Z6(7Y1V+Jk-2Bmd4ZqW+L$r %4eAZ3LU4#s.@LKALJ78=F_at$X6_HTj+h6*b(AY3X7lW2MEqkZD0#NAQn,4X!4Hss.Tl!@fM.(cKYh+A*es7HSB27<-I0G,)^'8i?KW_P@\r.MiM#sVg/Z?Qq4"`klH(8O86'L3(GVq:qDSBcN`@#4@io#3KJbSZ\(a7=Zkebg#i53rAV!`$aB=P`u5%q@X2p<1VsnX`Y*(1Lpoh<YUJZ %^c0ni$bFh*U7FJ*nS26\:uS&f+ur5+KaHiiE'e?Up"70Y.,gu>BJjUcUKW;s@6p.Y[`GquYZpWe+&+TNGM9;UH0e5B\fX+$_>9f7 %>q8D[9&S57YdK33Tq&Jhj=cd3`D+ZmZ/,16OSq,UjSo\529Hc9_K=Ln"ETPX#'S=d;RA]R>]cgc8dZF!,cjS-(3)]Z5o%kd8PQ-) %:)fCXL_$lKARD6tHW\c(RoYbK4O!%.G0FO$E[:[:Url\H2?[8Fg561]$(2+^c6VkIMT#<HQr.6\A*tGV"-R$U)*]VKPn>]O'/gZV0t5LEqD9\"@A3S0PV^ %oi^+)GbT\k_=.=e/Q?ZP_6_*Gn/,eT>[tJ&'?Bfn&+*lXEU5%Y_k5e/^6GqM?q]$BODt\-lsWRd?/\)=(m]p>KX,<:`AVHPV=lYP %q&P3$difK!S'SHD6=lAFM9K,$Q>b.]?aLUK"i"'`H:jGH)d_+f"bJ<37f`DWbE %\IGqTSAb[e"+7&Gl%G%=/kk$hWe)[kE-/.W2[BO;A\T<[Xj'sb6ZsWd=jfP]C:YK\'A=]7X_lE:fe%Ykn&+2O:@0_^Y7:0qI0Y=8 %'TG"m$L/AU,2"Ynf0m%j!\79;n)^0;L)5Q0cc6T8#XN=Vj2Bfgi`!"8qRS4nbZH-/5h20')+lGc#c2*WT98,KSqC2#&j$21eS>L2=E.tIeH %)uqps6nqOLCXO@PJ3[j;?!9i*TEN/l^nWp='FX?-:nq.QF0Ttp8j%&!1A#Wn-6hj`EuN)YDEDoL\]t&'r]"ra.O5Of)_)4E=WJnU %K#1noh9D-=&1dFRMrpmINeNiM;(??),e,FWIKnn\\psKI^ih[$crYRK"]B3>V/h!A2*Ntj++Ng3+X'LJMq6iQF]1Zp6RbQIO)Buq %\Z0p4Kp8;8)+m`]:`l\G0+URja;?PfV@njgm93>qI^r+F$D,HB#f`9)9<7O#43UZm+SOX%'%D0QKrS;1I-S;4Chr?&?<.B,$$AVS %9C2<+L(s5QPD(#=rSYP[WSOo+[-[l&lu)4fAeV*&7,L9JO+#Si3=lgrp3B&'W\!<].)sRB.fd&Jpg(AZfr'sbI>oH49U%"KoQ&2k %8bAj@K8TbIWEtd=G6.r<1.XCAF3-s@0>S3lu` %*c%WN5L=:a'^II'S6;cp43d=l;6&#+ghdcr&Mi><4`-*kMbdH`pcAuOm+IW*9Ot+P*h]f9$Uo5UNrpDEX_A6s!"Toe@,Nf$@SirP %TEB@A!m&V(PFh&VhunofGtVlTig]%gZ-Wo^Rng?e[Hd2@7.,:`kN*oc;/K5p\S_aPOrPk(6Z\FmUo1Vc=jPN=g?P5TXPgZ%+f=Hr %%jTr2g?;CkW.cQ[:2$b9NYPYT7,/)%X6u*83#IA3\b#@R3Ls8a,O.Yq*"fNXe,AcH:ds*/,>&7Ee(B2NN6Liq+Pdb)[B*6u1uNSN %r1!;d1>A]9S&]!LWCm,_'gS>P>4f3am.W?-OLK\oi(M5R\k0<$8u^HUC)t9G',+5i]F25<)+9uT7q]s[FlMX13poXgGkX&L9E\9> %5Y^Bp*C6Hk??]b!4=Z6frK=,ICs*bdRr#st%H>TCV$fdmpHa%&Z&QHc.]A`b>tW/%a-)8^nk^l,o2n&hb&iM$0$aDC.eI1QlL8US %DLBA6TW*IVq:M=0TJojO6%gl)]@.4_lq%:)JXi^<^itfoVNSZ6YKXunSShnJQRE9ND4gcrk>J-J6uMr?Xi+AsBTG\&j*)qdB;aXs %L'r[h\8%";M&bW(4i?QhSpYH5K&;'SoU0tW>VcSWWeMb^Z8tMS>Q!Q5*Vc4(hbFb!9CNd(*UG8Yd$O54>\e7h] %qqY"0Pq;djfjoe4a=iliZeQi(h0`g8JR"1H'EGCn\RZ76SVmBgDCtU](S:83Un&%NI;__`fVhM-bp8i@>V(;7I)UW75d/>_VIEn5 %ZWBrC*H##R9s>\$V%Ck=V.$OdAkR`jKHnncCWYk+p8PuOJ5a6E:)1u&1Vg@a'@TpJ^1Sg3pM:6Rd8m2n7[\J.?AM?4i-d5s^2413 %ff1UQ+`)\rerOUI&+ubhAd:\!c.C5,/hl`&QWSY8C"]=UWKdXEPA2`$FLf$NVjU,W)On#Z*Fm%uA[15oj[k)dRe^^imY-SMZ.!J30?'XSoe.Ei:% %F(&s7C4*"%J`@Zo^q-'$(m#8cVHo\Te37LK=J:\YfPsQ\5sdM^Qil(Eml,+p#4B#PRIUGkH;LfcD3]80"g2:QUK(]O]IUhgEI('< %2rR[#iPU_Bk-Es,N+N@mlqm[=!Wq"Mcf5/)\)N^kGLKJ^,=/:'<=^WGWk#.n\gc9?/d!@*YJlPY:F8,0ghoY0QfbgQ*(H#g%fX8; %?((4*aI*R'>>Tj)S([&*r4B.*H'(E5=Bf0EE7u;4/ue"bB%&mLEi-9AqrPl/\N]JJ.9@pAeCh@LRFU=;QJBJIUR9@;s0gpJZM8F8 %^mPg7-;s1a&h"@maD$'Od"F'qSj:ArMT0MKLEY_Jobo)]7Gf.TJDf\H%\lJC\L8DkV+@j(H&d4m'S=0l27_=a]J^BODbit]hmaHQ %6%'@+PU!tl6`KHF5#r^BO/9]-!`00ZC/XIM&9?J2ERXQMi&3.*%!sF<\WbGX6I+*8.Ud0EFLXhpbbBpYj1N7YJ@2JfE_p1T2%WjA %7=#'AU6pmTZJakFQ9!SCa[u.@^<91fZ0F5?ak1ZJf]U_+9UPiP[>r&GkXuPi`!*p2Ar9l-j],pk1+Y](??/0F1/)o3%*:+Hb,L3; %rO&e^P`ojYL8`"Ml]aEOk)daTgUgAZX=-A'AVm;r%>?(:DjR>V-_DH_Snh'?ITFM^0J#>4=:2Pq!"+S(F"<\ca/Q_)3c4" %b"PX%Fa7uU%#dT(=22D)S:Vou@pfO`86?O42DV#kAg$#!I!RsWKik6&VOqS$IebLAT"^B!%uZdRh?/:5^V)EI"M=%u5;Wn7aTPa$ %A]S$R:PJ*iXlr,P8J@4srkKX67tW);-o;&hb61i\:e!;KQ!g^_hlFdqDn"CrAPLP6'M#U!mc@#GK!c<*c0`qY_Bh.8]N?O1@0(;, %&leRN2>/Y3J'hQVN`EG3ebh2P&rXAn>/j/Sa&CJN#=lPI";u<*jZsRl$GZT`c%Ij]S4]a4RIsq"K3lYioiY]<*Wg#+\Xc(SS$+G%W6[?V %_H7[%HAlWHMTq/YY!7ubh7Zqf"@LP/a`AKQLe=t-%EQK:,"5-;L"9fK*H[F,=HHs4"i>4Xc,3@_.E`^..9 %9\ee)H!HD6<>$r7!h2eB(SGYE%r26@]SB\F_l[5>Rh)l]HU6rn"Z7,;,$,LV3CWJafdWP`"4Ad/W*o4)oA=g9bGhm"2GGY*N-A2)*$9]E<@_o\uINK1g]XjcGrp;/P"Yfp'Q>3TUA %Y>^!.*8J-%hG2*0FKUkiC9(csXA(^Y3Cd#$+JBMGogULZrSPVuL#"D`O1*d+48:)#^-o;Gq_QNX3ig&]*ok5)D/62KR %M*nDZnHG^;cT-.U9A%n!:2RPVd*KlR:l3VNfr6W`>.gl+3.:*=.\@HReJ+ipV8ipJmZir9OOP(WY,YXEr%B_dg4c1LpW9fN;+&_: %7hbJ.CfYGW2HG&2[Q_!P*>onD-tKpCS>'FcD!?,[QS"h2t0S`+bW?;5B#X^f+b %4,&YMg^YXHmHg2K\)Yq\\=J9]\$Le[)fDQBGD=l:h9'[u]ea$**Hj.OXp!NTUHsLdOp.jU3'a#.HroE''<32n0kMeSBckeZb:-E')=%&<@f9#JB(#[k%3F+l:7/\!*!>G3(pe$/J?F6CD^m#T<)Q4"WS/FLt_J(Yu72g"tq9[.8_1 %G,U78B;S,l[HMeknMfSsX2o%W^>9U6XqcRNjWEY0sIn^?B`[;FmFisA\fL2l+1`J-U>)@e\m69JT?uu$B"FOt9Xg5VV;#E$SEP.# %\.d]DSs;7j:=\9ZDJ-3BSSknc)q/Q$&VXkgS`k7n&mr5@*ihuD"3-nqG+5ebm?SZ447F)DDT>rY6atNSOQgq)0,EA]rH"mk/N)a8 %qOgNkURL@5\&1ZrdHqiq3]l0CXGL8*4'[^Wh+gS>gI_4hm0I2K\t,'Z\$KRNF?9Xo1Ykf\:75uIJ"\OO%^YCf\'mm?l#o_Ql#rQ] %FLu^c*U8=4ktcceG'oDT\!*!5G'G1DiH?R9E')?o.6H=&;]Tc-fW&k/3ufC#E'%sY%_'?E/&CTk`NF-h %*Ca'9DQ!"K_sKicq82OO_'QU^[S[o[\!/]\9JtaOPZB-@>q=s-_!S'k:N3phZkqN#9ks;1[j*$$_sK.5H,K%=aOoHpRM.L4%`Hd7 %DMOV;G,FVF4&b!T3sl3*g^YXHm8,uc43B`"geLIngI_1Um;0nK_sMuk-+FsSjo`)niQW*V4'E:2gl=PO#B!&/5Jc_\g#7+E8Mk+9 %gX4ZGi-&iVb]#Xb21*7.[&M/d]*bQPLYH[g#.IfO_!NU@bra\j\CUt'Vl(iYmBklpE'$(BI,T6H1Y`I][03t>Zrap!G#B"/%]bd6 %DT<>2\/ckB$#YO[>(YL+%J55+8PO.c#oRWY.^Uka%Q2)i3-0l0n_#"oSUNkVgSqD(_GW3rX63a,F.52G4Bach55"-];5_eY"!hY_!UnC+1N>+K%il=E'#LU\/i\a"LhV"Tn(mkI,K0G1Y`IEkQJAq %GQ0%0]/#b!*M*VM!*\=I*$45>j`BnG(kAV]"le_kTd:u1&Qps"6FG*ELb\/g$> %$#Wh^M(HL10U,4L40u?OiHCaeJ_On[bA]NMNt^;d.6H=&W<'KW4-AHEH@NYJ4/Us>[o38U_sNbqi-(UP<%?uo1Yb_aoF&.gWCq1l %.Vf^QNq`,I\!*9>FsmZ7a-e$ZS\=JRgeLIrgYn^rJ_TG$A[n;2LGR_'.6H=&W<'JlX]gJ6l-]IHmIZ'E\=HrZ"LlhorIrutc#>a= %g_k"-5ii5gVo*\f*RW(6\#[t#Itue/HG/6[B#1gkm5AO.gFY;@FpbBa\=NW]#B!%84MgFSB4[>JE''9pg^Z3Xm>T,l_sR5e+1N?W %aoo2K:/\.\$+JZR"h.^1_sJq1U`F$%EQ\T)8$"&Rm:puSE'#Z@^2Q0hVE]#]X0=2qgl<[nK%k.b#.IfO_!SLIaDa5B)*`(%%=]75 %7tY]2gFZulgFY;@G']T4geLZ##B!%`5/HV#XibTEfG#F;*SRn+:BKK$3$#QSUqaK6gPa9^?NIB60[aXX?U?sd=A@.oeD-sZ@e;Uib2pZ/!o0.Gpm;P-Y %BKMH3[R8G?Fsl%,+A$**I>LA#C\5HUa`crEc"&o9B+imXET9EpZ_;CegG,3FZJB^IN\UJ#OmO\UnL!#TGtMVZ[cf/aO9,35CtGmk %hT9q=1>*0!6af?VA36#D[Zg8*gM$Z0A38V?9X_9:V)R(&"+)BL0eF]W?,Pjk9sujMM4JJ7khY+;FsnH<*E@2Cfa]0fm5XW'[aQEI %PO8#81YM2C/-#,U*uEq3+0qHePKJh,gT_7VI3[JYCF+qKPO20Q6Nu-Q75O*Pg[SD^bh4Ne=YD/.SH>@=C^1(*6akJ'/!KA-)bOX& %4UZF'GHr5bM!UZZfo?uD7(0/f4l4;(W/5?2?T=d$Rj\3D_(VML<*#10G.,*5HOsl&)E>GOD5Y0T7b]?rPgFT2_0s^SGdAd)?&cf$ %7,)E;n3u*j>bBAdKLHR.NX4qUD+D)dU$_.+Ad@$bEJtF^No3AngI]M#4-V\XNh4%>[R8`pG4n4?ZlQl,45*Gr/"u?d7"!@)'RhF: %*R"ZlMJ"gKCF?6JGY*m"VsTX0n_iUjUR5qP"jEV\2*-eUb1+Nf\a3]#N7lK=7QE9=Th8[\KHFU$\esqk3=Q'AAI-4sFZk[KA?S %4l).,_c$-*)qrS27X)4FNSmf'gK!J/45,^X+=a*+D+C)K;dX3".]=$7NZ")]E3u/[3FB-6,bTh!_h'qCm83HK,da+AMd?S@%SpFU %Ob'r.;%75+gM'!OIVGPD1h1+(Sap>6ZlR0[$#O>;rB&^C#DEuJ:2,oN[Ss[rU[9HdJ"uBrJF$s]qNQrI1\AU)D+@2OU$]qJm:\TC %$U8;d,$6q\:1YO^'ft'o9YK=s45u#%D.iPE45*GLc7dn3*h=@ %UthEb'%p#I=!HC5N%1YTZ5n(d+0qG,Y"Z:!nbqYjfhR19QY]07@3XG\L*s8IP?2NQZ5kFT7Zd#5n5C[e:'s@.,2:Z;qjM%W.5WPL %ZCNF_Z5mR-H8irhp$dt,,hp`D`=cQ+gJQh7PO6lRKPTNlgD)tTDmGpkNAB1i;CK5Bm52"qa`c6l\!-4C`(4E#S!Di@]*d_,(Ga'T %22l,pfhQ=U0A2@PK8j]fl6h_]=PJ8FFsNFgfoDS0,2:eNqaIroPFrb'4$Z^dZ5obGM/9)P+Hu3Xp&#K/>ul7@YLuOt!tY)&'=&Wn %,29B*9Op5L&(uu^D'I^`SXRZD;SH['c,Q/f7j12CgJN"_+kr\;ZCR4J[Zg2(gVJ2/A39A:M/4R$9=E;I-'R_lA?qbl3+&s3]s9`Q %NZ@sl[_lhP9t'XFcUP@\lnOXif\V(uG&5J;fksG\38%'Wgg@?mK3bjJm82TKN#.6_hdAO&$#Ctt"5E(4?a-)qnJQ.5#Ut>lA;'d_ %gI]Xt]*8j^#M\2>r;kYEc!WW9@052W]YSd0(3ZpQG+]^hB1_b)[\N[RJaLP4,d8;#&Ke5_,o*Y:mB@R'?ot#U+0Zc/U'YW@Q7.=O %Y^cV%m4aGn?ot]jgqe/[pHN%IS6Q`[:-Ujnm?BC'JF+UoYam4)fIi^S_02a`Cknuq!o$]gZ_GW?p"3U5%$J%*Gd)HJaF_1^ihQ( %,d8;gmf^'dH%YJuUs!.-`O%DQNbmh_ChI2R*Ge5i%2.@D\GJG14Gk^ij,S5@?RL(c0f>.=_i81Nr=.ChK:"*Ge58+bB%Q %2nr`^MWPT)N\7+1[c?+k^il"Ggqe0"?JE;>SG<3?.@HL87 %hnaK%F5+NSoVfF=G5BkuCe%6K#MU[pqZ5GG@eU#[l%:bD:>at;[PRRc[NjtHJaN*"B7qjq.nn6giG5^W3Y+63X %M/1.;9jBd.2]o3YoX(/o4#."sCT!m'bI+)JC$43da%0Gsc1>;FSb=.nCT#eFbI++t.<4`Wq9&eRX0lO38 %T9m'2;DQk,dF.UJg9po2XrTq`M/0$Zprg(o`/qNQ)Ab0\:;q!UY+6=6R;8_sQcukd+>CHJ5)fsWCIbL"_V.TW@dQu*eda!7mJ*bA %ekSnjN4!HIq81j.K&CRK*O]cH(@sM/'A>q[eo"DEN7q/3CBk?bYZh=5K=kT@QO@T,d5>A"qJj9SG.<%:Z$(p0CPS(WG#H%V],l'G %M7)ZLoLr@K.:9/^a'!E&g@Z\6"HKlo_N)%Ye?GVmagGXGAGT)<,%9jmrdU4\Rsp9W#M!]@l#o`XW-3nRW/GEBZ#R<1eIKNLFb;^) %:&kD)7-ml7<;[J_C59ZpcDbt"I!Ssq4%-.`JnbOa6Q>Gb[?GY#]f)m]SgK@7#1ZKC0iRIiG^QH5RcY:6Ng3).g4(4,!\JeP8jt;=0/E,cVl]SV_*ZrQggFf?X)ag8T0J;sfmV %;scKnb7X5;85q[jV%;*OqqXrRUO[?^g6qH-g23igmJ'P8C=gbpg"E?JW/58EP,NP%^/R1;M2?!!c7;i\E-_CYm2E1s::8R55?$r- %AZHAFC/FB$<'.O6 %M/#O]jA!$Lgo5Jh3@:bsPV:RIq!Cha6eJA]G/Tkb#@;,Bg^/R2K]^/TZ$Ha"3DGrHnh,95IVbbH7]8GS= %Rqg"p\X;;sgeqHVs1?+,O`FG02ns%\2%Yd2>(9E:(jeJH4/nW_LIHE]g?FUn;XL8,WZj+;$tR,8\0cBdsfC8^K&u$0_GDn %WngQrWngR*C1i$(;=.J\J#INI>pcQlIsS$H.H(0$g&\NQ<',]>M/'MaSSDg&::6kp1fY=*VV5/Xm$hb1;jXG+Pb'/#*>#),e]tBL)q>EA %;=-@36a]9U<')XY'%P:S2K,Ud^=bu`UK;oBg.`_fm7c?8FqgSrWZ=sK&(StZ:NrfZV@/5qVe,g^C53C>U=u#h^eV:98FoK^drC4Z %8*#jdAV\f5AbCW..3tLYG3sT^:qNRj:qKGEW#_]t$#7N*W%gqA42q"Oe4sG0td]1C.CA5#AQbqeIK"9*R@Qo %Dohcn#/pNXLYD_,"KT-KSTLIOACXrgni)\7CaU]pC;]$*BF.Y9`QhD`OdlmkJ/O@J?oQJgIE#X@2Tk9LCi4/&UVYWRZkXcu]BN`YJ*J+k&CLNl'kV>4-.hBet9pT'+O'9X;Z>ObA*#=/K81CDlf&69?Qr_$N=6,pfT5as3ePrfut=5jW>LE%-ad8 %3mZ?.ATND0%aN%cC[>dPI;]%2A']iEjLHalcZ*hf3G%O46YCH&jJ>34-H'Eak)Oi*O$>pt45rtl[QmtP2G7%$^>,\9Z+is$j^c=- %K$,TKg*LRE^ad/j*;D7XsaP'=nb!PmPbfZ2TPB]P9sA:23"RBo^ash@`QCDYUjA(kV=(97m3j4KT+lpTA-kt5oVeHGV5]2IqO(3$e4.0U;Y%H-NU;pt\a"d*=^/ihZR.Y^8+aYXm2JT8Y`R(O(9_,7ZS#9X?M$RFT>\ %>RpT%hFaZ`l#HR%H_*Z_,6W+I\gVR2"r:=r0QAom>utC#3'pfpe^s<./p@"3T9qUH^K7frBfgf&`.'*ZNdnB?fcb@6a'iJ5j`.-( %k-+4B:HB"6aTX!951_f`9MYHT^S/.9R?Y4XCm;FU"sm#+op^Y8d,+tq@c*=sE=Q=/NtZ]a*T[S*CAe*[Q]`M3`O`)<"c3=Qh#"Y? %D`2U?:>6n2i.c66#uqdomFm63/S0^U/N"YjfY02$;&oR9bk\\X86f#gmWh"NEC,EP2ARQU.6AemW<%hhYc1fYK&bb)@Rep2:LuX\>!pZ/"<3M'tfEp:&lTC(k((2jLD.J^TjZ73 %E%:4Zjh/Fg<3X7dg":9,%oPfH(/*,p0`bI"N((tMRQll`h/>PgO\>>Ptq-jm&7g+s#;YULW'Ol3%>^7Q[\;GIbYm3F[@7PrLa %E1D2&!UV-l5+JJ7:4b"_CJ(-C\4>L0/ZOF+2hde*2oQoU'rE[M8Hn.V.)s%,F@X.^D9;(q<"0h^($A[64A4@QE(^Wa>Tjna(?hl6 %AX!n@2QGJN'-B;rCNu0LK\M_##e/:`_A+T'/JAE1mj[AD5WI74!uhK^8Km"OJT+LJ=)8,YPo<"u!9$cBj'4i/'NWmK&5K7-TE>It %07,L8"mE'bd.3D0KNhsW4AIn]-#t=DDCIXYDQ*YiZbLIE"a\Wm]/gt,(+G$Lob?`'[pH)9ggt?2kf4R_FaPdVg]W[dd$;';ef@,8bMVkM/XlP;cZIHETZX_:m2/dPU)r[4G[sfMO%ub,2?(> %,2?(K#cF#`Bel*T[o-nJa@&"WEh@]XJco'bBF]]b_W&B`aZ3*GYj!'jKCYnen7q$a2B!QrSC3Ja30j?rA\m:=^&;6kP$r<-J%r!7 %(`^\;4<,-\S4RU9LV]\LXdLlQ6A8,e$O/!?H3+p"0K=J<5LX%[7;4e!1R@$_5X!Y19JiQ]0,I:0lS$l:G:3)$61+OO#;uMJ\*O=kt\gZ=ipD&#m)J)G'cV_*"!BW`TRT;-#<^o.0]cIR?N(Or#5b( %Gp`BWo$4)e$i[#\alBlHqs?L_JX"N"&o3_kBuW,h %o+[mWDlC.Gpp78ihL6Z)5+S/q5skF2?UA[G)Eu9oq;;-uJJha5MS; %!Jj,"QEim7QKjPj.obFPJ*5i066kQk/fVi\Asm>=%ohFdMrj+P'bS0HW"ng9(W>(XC%[C]eq %;``tK=".@R460,&TAl1?Gsc/K&'A*2X3l8khJB6@h3miRmF6qP.;r,\j+P-e)CU%S[:dXOSg)(h3oj"$'B2t)nlG8>4%?*[&L+49 %>a.1!o%f]hO820oZ2@jpnj\>*]pqpU'X&Z63@Sk`2.eoD]_G.SV:3f3,g14[L#bBcM8as`Uc78=R0Q1JO %(hWsBAjpT=R@#orJ5tD-b6E70 %SquO2n30k7i:Op#e[!-Od50gB+IdQ3POXB*T6ij>_0RIPWsLT5]OgBr"7]FceGAKfq"R_/@FNd+JZijXHQ1ZD+P %+FD!.nHREn)Mp_liD$+T\J*i@P\RBU$#emO<2("Y2[tqGo+L"V;:VRBO6)$RYSBdn-,Q-NW_b&$NC98qZ'4ZHR/r5%Sa]*o!%Y#k %]NM4b^.Amm:fL8]&9"@'NcPfhoHgT;/eDs^l6m+p&T;,u4?QPnGUjIZf5i+l$;dBC'AdPqljN=&:s)THJ@Fti*96eN"2%c3iA`XO %9`s';oZ[DTjb_K)!8cKqbE=YIGa%>Wru_@`qW\Q_TVi!j7CHg**=j9SIjX*u%PnZLfbnHH9Lrt)]J5p_h29n-gF8"Up#?1fBfmKh %D;T(0hDD/EnX4ndVBj%Q!I3'I:RP)^]J92&bl[B8BOgbaHV>kcl=#\Y1IYJdpM6(]_EA%`n\5ChNAClAm"@="@0Rmd+M?t9ZZM[i %\*q$.a'X4#j>3jl8HQQH(Z?9Ln_GU"_W0>>DAqp2lcsT2M6582GEY9tBs?DAMn5L=G15`DaC11d1nR9S9Wu&pl1M8tb,eGfKltn! %F^oAe;ih+0<8f]<7a4F41jK)&G+g64*A5)pPK]TAs`IBPp3Gfl&prXXIu-eoIOrkremA %!p6BWiO+(DF*etcJF>$J*O2N&*T)(B69C`M[&frV]6WS_9lg;$Y7DIob)]fT#H %e@FI-tNG5kd``ik-Kp53-6#?cZW;mUeWt?o!I-J %,s%M"3-)'`cDGX3G!19$fi/=QgNJN?4.]/,$t!0uSkZKI],e?RYn@F&BDoe^e)8+2,5>unOA+]\"LKo_:ntQ'g'Y8`XY)jXM6l)m %3rs1BbEI_8!Gr0+;1B4/2XOP*drO`bkK3sBo9oAiB<9G]c_`QXWKEj[l(t9LA;@Lj4b]%tBo7$YTQLH/=Ta&as9_Z:,S):]FY:]*h0nWP79aG@S9j1<).M5"%]ltY_OS7OMb,VPK%c9iF]mX %@$)6u!7Ql5,%qg^Bqj75"m,Ce&t;L=Dgn,/ONE.&%@7177T[.l!HIB^We/bdYroe%=0q9&2Dt*cNYMgXASCI^#R$Vp]9Pm.B<[Nt %kK+&:S'JC*HpH=`+_']TNPTdXOu1H;4b!nJCiF<*EGZ2XX\pf4*F>!'uQT0+#=Op4c^>]\.=1hSTj4"o)Qg!Y,Sq+T6;-h3E;*HC?*AFa %-$X3/.k2r3EGOj3/<<4KQefVT'P=Z%o_`1C+/h%"CVQF5[>&I>?(C^&U$A2O@9UFrd>QHtkshSEq1%rM0V]KTN&2bV*r<\)-:eHAprWa9=:c9IMn0S__W$02-#Ag2*(#*2;5[fgDk/]%8uKI;XK$8;o'H=M[?G]bY4)O+5X[_/`9_g %eNZ:2T0$)U&@H=s@F\0k6\DGZR>U8UYaSOLaokjAMQId>X6H6(4a9%kNUf.=E7G:hf^9c4d@6s5rq,o,C)$2?lK@0,;-ZACaj*m:`859:>W&'D5^RP% %$@TJ;$uT=Xhf#qsaQ0A#a,fH*jJo2'D^ZBb\7u1>CVLZe9kSe3cU0ocN')a3CgaZFg`'6W!ERZ&T6j'jC/cX-Z2WOoC5%7l=r(5b %PeOYBl+G,<6Y53h>W!tjWGQY*UfcUUc;cCWk#<-uXgD2s"BS;NWI<@C*=K(.V#3+r@q!o` %1rbBCX%%TYj(I)A7DARX(KV%l5(2-!W@IqB"$aS9.ZlrOR9d"9[] %=H,,ij6^53N(aL7"^$baI\,3mX&79h>I&n3!%QV,(EEcGA/%<,D %YSsKP4gg-JVU/5;-nEARZkV-o^r^>GA\'X!NOndq631ch]kt-E?o8)s/oshB^hRgBL?HCs7uFUaWs;admO`4/hSXTC2m_CWmT?bj>4;\.(;"e-)g+9>0hi'L.ea2!1uQiNu6GC=0(Jd3u2.^H],L%i7/+"FoR87g"*:K %J)]"ci3Tg_i70Z=gO,X95d));r.\9O>ptQtM-&/JO4i>a=&ZZW`A\19>(Pa@_S4giC5$,A/DQbuVM)%)i<$3[@sGp)?;53Ela7/6 %RPnFS4ssZ2+9J!AG.O,3L\ne%>j_)*C9lAToj*ue-t %ER!FK;H(d,=>a?e#`8dd9l303'A0R);B)=!^oF*,oRC?#m$Pu.9kO&S<>T%P*NLO+K!Kr-P,'WbonunQK[8eaT?kZ"dD@^ThMl=E-H,8!Snn3E?UdBd2IS\RU5FbRL92IL_C\D^b:pg@pVd%<(R9IEe!dt`^`a&E51IK\`U!_s@:c4KtD@#?:ro7o\/P=C;,dJ*6$@+c!DOm`GEO[n1;,'[1&hFXFMWOU#78tLXgA6P'P@=RO %*N>pWN!5RNWE+No>T5.er_cerYp7e$h6e9:bk7NGhBaNb[IQ;hX!),,s"`E %Ia2AVa#76GdJU;fe5.T/&""8m<^@Cr-H3^r%T?kE=SoMi@$Q1Br:18nL:aClWbaAsb'Q4oY.[qZjn+/6J>mD.qd/%X)N: %8RkCZbN4a__ls2tPBe/1hGj(c:2L;!:2Nq#+[?e&29+XT'oI(L$SlsA3n*B7Ju;)VNe]EnQo9WKQ+-A7$6JPW2/!\%<4Ga**'?*t %Ip'-+Sf1I7C9E/d`kIHO^u22S%XIK)JSM.&Bk^Q'80J=&M/!4'Vd;,UNQ<[PM*S)7FJlGW)R*_31GdPqZ0i;W#?4Ff?:u(<<:)bJ %rlo`#HZ`q0Wc]2-hi"Ek_KmhbC;\l2&l3A7hME(/2+F%8/t1M`f%C1),A?A[Z;tHrlh$kjEm+f5`uV!GY.n5*Uo*2S[llukYc=Y% %gc0'IZ-`3_W/]rUV4ad'I"Yn;6.D-CYr'*Le0J:Z7O.7q%8CPd&j_L(lXJlb!&Y)#iJniMouF!Ah=51d"k07[pbW_H'&j:F=pPG+ %L.HL1NQ=!;[%MbCF__r.78CHJ&'LE;TX>@DS=B47hXeF%e"1Fe\<@#65IRm-(tr7H8XYr[e'T;VoC/;e&CXDG']"%K/koNJc+^>,$)cm`.J&"*^UNYb<=$.N2.@[N1(d %NST%'[,Tt)&C%V>6bD1E-Qm'e&3G6`/2Z2H9#F#p>4g8T10J9h8Lu\s[;lWjRd)647+rMkZG3)EC.FtSqUB^Dq?82Om<"ts`'I<@ %$hLH@d.!lU>>q'Qe\+QgcV?ci3@q9l!C;o(XSjkdT]l`_8_=SfB/ico!_itR0MOhu)n4_!*Ip''QXu&3a"]CUrbMl[rG7>q59'%K %2;)X-d@scZ8"]#R(`LQEBC_W"Dct.o&m.'\i%r=K=kp?'qg]a?1O`K;1A)(9>.qBG4mUq:ng&mn@\:H3/_C##2b;KeZLJ(*C3)@h&(km5Eaf\I-^k %ij^f?1r>5pfNBA.U/JE?G%Np-DQu;d7G!3`T`?DJg_kta %A8Jb3o$YiABkR9$l&81qe*?b-R<>C$(5iD%lV-%aRr;cH,U>YmYd:.PJ'Nlq>&j^g %Ai>rIW&a3=]l\7_"J-H3W/K6=UO)sb_tlX$YK>uOBB"R?IP&Vg:UF[j2C1TNPq47rO,M)phT1bWi8SOrKD %2Fj&L;cD4QeECZRn\gno! %1JTJ2LSN4]%hD=U[A;7K6r5s9B8$ru,4jY.O$ZYQ?1=[QnIo;0A$:IZ0.Emi(mb5/,Q]q>\g).fLXc[p@Ae0.,Ql-;ASC7Z$R4-O,#cH\L=+>pV!cD8%rS-.)6n7E0g=b6J6kd1XYe#fu`9F%0R.Q.h7P$ONn %L-#c[da#q=&&r[gQkcaS<'6FZB2$'bXj?$,Iq7M:-6?h(:1B@SS?J[b_`!`kpP,@Dl9/j3#btjG"--Xj7pEW;>Z$ag5\7i6-Tfdj1#``UObL2b)SR<<6(P,DF=58i6M+e %c\ls9])?Xs$qo$kJH[.OTUhcaA\?L;:b>c8\2-=l?!Ya3?sA-X:-568_+4gf1J!5J>qD[c]c]u$BP3h"['MeL90k9g=5$rb7G7'\ %GGsT\(c?qhL?CS_VO_mb8km6!4/;P/VU"+jZ-oFW^i=!1,hgoc"*UQQ4-gr:PZ9k68uDgYN1/F7s4.[4i8S:ANY;!/^p1G-9p]%]eh>$a!s#O"ieYLmQ,QnoKBJiF%Yg$KNq_(If\Kj2`mKK,0T/'BWuZs0gK(^HR* %@0`;s0`Yj'3o`6XX?1AEiQ]lq<8Eg5&NR7ndG,:PZVTf[DoSXR(MB69TE"Wbr7h8Es8LdQrBG`YfUr"YAY=/TEO*4F=qUr@9e&9@ %WCgS,f.khN]h;6m3UE-kT_3rYp%bM$V+3loH)gDtpE8,Cg/W8=>L@n+MhKXrF-Wq8=3lNa@8Q#<,R)A(4%B7:Wp1Wi:XsE-&7&,' %ih>*:Jqhi2]".a+^nGo$6)t-q7jt2Q4\!I4eSXK4mHLNFliDpD`ulU19@lm@oE1udTsHgq'Du=>c=TMh2@1=Zsn;i.2s8/(u[ube'V-=2D,]aUT&.8fk1I+=3sbeHFr>4_WRsDq)A9EgR.>2 %kpuMos5kk`T6MXZR-mDHS_,]+Z`2^fg9jo-,`T]J/LpLAk0.gDZ)keQDMs]*"KGY^f2:8BS:(!30+QT6<4HkUF*1=u %^Lu2/.>?,&8f6MZV7K/H=[sp621'Eh8K#:TD+XfW/0B@6]ptI5FotP*gDVkb.Snm!BhQ.ak>=J!11coe28pu$G>s9"6a8.Gh3r=) %a.TTUjKq)A'[e!.nPYV]EC5'h01Z!)Z%1_#2_uf$crBpWtU8[`)35jiooWZaWs* %X8",9-O*6eo=Gksq:i<9>)r]K %$SCI!<1g=8btHb'GbL1:A+X@Ic"jV)K0+):S]69dll0.RnABBs)Z_mRAeYe4tQ%p&7 %lo:1^cf2pQh4;"P@4IiUSXMI,pE!\VrKO1U).uE(]?pb(qKKQ]ELM"Ad+iNe].)&-YUrk@b1a5d02RVPQW/&mMn3pNRpq:?`O6W+ %j1#Fg7%Z?<`GR.!=;\J@Xi=f8Ge9sOkIM)?en#JooU?INdO`ldhNrDM]PN.H3 %FP2pn7c6oBMbP[:1`aWP_YgDcQnBXJB:@@!2/!On4>7qDg1RBEiCQ$E,"CN?==<\7/G$'SZ9A9o-ZatSM4-V8?:kuA`WH3+ue5)go8]*3pJiXJWq)L2>`G^$9<@e_)[LkuL %;Me&>JD-9_*Y]?lKQfNH4\]oIeUdrAZuCqZ/LOplJAYTA3=flTX> %p82ZO+.Lt9i6FAfMcsQj)Ue7(H9^.^3)`:Q$jQ;_KsS16e6g!;Cam\BJNq\6\:M*f_S]ilpj/%0Gh"9-P^!UQ_&Y#[$fODD=_%Do %=ZArg93'9-4*MZnV3M:bC_Du-C!T]DWt)2g>K7$NH41meIQ===iQ?/@MAb8'P`Br%6sQ-CRM.J+K\ZgeB/SNGl\g %1n'JE$5Xdd:,e-:,[bksNj^s5F>).jp7AZGk?Z()V-,hLg%MQE6Et6:Z?=R`qLE&(ghZ4"<\*pIW66>\CeIcM=lp?L]fM'u1]5gg %8e`M'Gt1W[p;BgETeC2U@*LH;!R!k=grq^CKDGqhL@]OF?lT^NT%.uk6fCd(4Ht>Th)Nfk:pl?.lI)b/[;F&M&kl:uH?3l7J<4K! %lGb4*(KL_-1dt(PRmN#!juUipc$)d;?eV(lO.k2e*\3+f_0#4L,nU`TpeS_;W"U[Y%CurIcKauiG:AQh?UR+D2*.1?[880ZYK^4S %fFVmZ]rgPP'IF-9[nQ%[36OQ:9ljM6@tB=h%Tg/t;H3-5AJ3[FJ+*+d@_laXY"BKZV[`<[fhfg=bq@9rTkq/L@.2O'b1>*4B%qpX %YPo-gF*5=c40Z=+'=AL9n9Z/s;cNV3-B7LDn4350rkr7*]+3=UG>j&(X]g53:1M!ePLCjY"n!]q4,g#N'JOBP %*$,437g5b![1T!P\iFD0`K&t"l*FO58dJ+[IKAJT+#aA9*VZ(7D5Pc8mq`mQgUQdd7OoDBXWOLABl-nI %&?\D=_p3p"J.e7OP!L!.q7P2VJu+7`Q_fcOMO*+F_BtmL.a)RT2-Wk5KqqS*JWYYOC2XuX6F"SU#O6H%WkV+Ra^0V]h,LmL&`T@] %Q42+;$Tu&?.b++_Q]iP<=j7J7.C1I/a!kbRY1jn8A1*`=LZ"TP;D7]j!2.60%]7%t&T!;OWVlIueL$*b0'WPbJ %DJt*srcM0=eH]-&k1=V*$"(.>TMT5Ll3cl65_Z(K3Jibk0u!p'H#[U9V]0rid?cV\3\mH$30g*bHc,"_%flV^nEE.bVC[!iMaem* %LI2dC3W8eV@uj=AN*ma-%1&H_r<+-IKOEU6JPgNc2H=RbaM@DSrVV6O'NO %gZ46rZa_(bZ#.XN^#M'!dM3^`,l'gBD?ao8\]hBhkLt=i?e\kX%\WY=>cOe[icU.:(QZuoYb.cko_hp70g$eMS.'n.PLQM)L%PRq %/QE5fR%op)asYc/V_k=no42^fFDj-gXe9ho*,X(VpAJX0]8 %Hm;u&WLH"9F(:kO-pP>kh"8bpUJS'EK'"C-%0`U)]^_G>NA2K.=*hAgX&D0bYP#@V5C6LGYuUE2d;28'TV]`a(L2rrdT5^M,a+Yj %^+CCW;bKe2;?ZEm#(r,Rea'/"uTPYSNd*heh/2L'uPr]22M %``EoS@*bIr/m:3kZZjQ$\Y8_3\(4h^e`/8;1:U-qjtec%G"hq/d`=;IJn)V9W2SJ8qi]i=:+AmJ.#[2aGNe@04@rMFPOYXC7cm). %NPu'/1-:AS);b-ZhSE*jWMHtnoT7H=+->$Jcg%fL,nk7%guO6.p2t-,rulk&^.nQCSmIgmE]WHT-d,46@6plMUTg-iirP;cOJ*e* %ZJ87egPU<&>VEST#aCem*7lSN?m3mj_,p4VD-ZRP*WG;G_?ATl*k9X27>3if,]Unt@^EZ:$+7q,/]$##cN__[#o5^"oeL_++.b5+ %:F/!Dd4VU\[uqIar_)9_d=3m-3Nh6f_WSEZ_D,9_91;V%Y %*qmcEWs_dO+ol>*;5YiZr\pSbB^p)#cRkg`Ar_Z %"jT`c1_pn*848?/;TEuBM_Ro5S2af[-XZYTrJ^T7Z>e'Z/9&2%-)gW %d`nL"-*iFKl)#83N8EBTndg`dn`,&mcgJV;%Id6`9)IVkX,d0'l9/c2/IL/00sj\ %O:^7CiI.0#F]hPdenIE-Li+Tr=g3(-j^u4KjY),Al[k$o5oA9L'C")Hjj_dS;nQSb,aAX]qY+&S<+0/YNdZT!sJ7nF0jCcnNM:?eBDXh:Xg0&sgo'KoAP\Q\99f$r&>'I9I__MfOk"Y#]F8Dg1bB1?u`9ZjWMoQ]DHTi8-NSNtm0qm$SnqPK\,5Lpf(G=&QQD+&K]]jX+AY=aa %iW=EEQ="l`T*.9//Dfj#0LKkEO;NXH:@g!>K[t/(H0SmnM0kUcB;46DQA\d?MG*QNlgVjKgW+B*EdV:fXpWmPhQX12oAJ;0.+Q%D %)D-l7::iV?s5h6/i1&#fQH*kE_+Zsf>WA9r+t])`cb:Ps;"9utE'Uk"%6TuFl;h`:hm%426s1Mg`0>c(h;X^5N'/;[F>#tJ22+(g %$i-M!RYU4kC@5T?ir#l-tcf1NocWT^>ir^QJ1l.O*VE[b_Ck"SGa0@.Xr9Z-,?7.&^c(`$d.QVY0jNO"2k;Tg[EqbU`=Q&5qa %23)(NR.`sd3rZ0>Ai(*8OL&h/WPX32/Vs<.FhcNb/o-:\Z4\Hn%7(d&TMOBR-c-9a;X1KpU2oDgMfb5"_;M-K=-.0"o4l<@-CU0g %U&;@p"=7_TkOPeO([P[bDF3-jpe>U %$=_%+Ii1]qMqB)Acg4N=NQ8C9A5KgB"D"k\;FRZlSKu'+c3+oC1*&L"i58?b$mb4^r57re+jX42Yt9]!%kSfZN,9"oJtU:La)8kc %/SAq:^pt4#N[X5R=f3%U"s)(gQh!D:O<?\3*)h#4&`LS$`)P6D)-@d^$^"*l_MI=YI#Y: %g6i@lT?Jg.=r"*`Jb:a+k3*#C_9_+JLKAP[K5>c*[+%YFP6I2311>0I5Y9q0Mi5Snn>3VkR.6#jULm(/p[TPN-qF+DUQMRnGe>W6 %oZ>E)p3'PAo1[sa7mT>5BQ0g*=n77Blr/]Gr(:%aK7pEr(VlK,>[,p`WK@HRI.cSG3OCa_Ac"SeoMHfdm'1qA7W6`EjM"Wc/Etr9 %op)U?'@S7j4b6O;DjqH;0hNUq9oQiuprNPkC#0%,(W< %AL'+\K:+tGkJt]FE)rGO(-q;.T8Eh-,KOR1=-/7V#DAUZ0?[n-)ad@M.kfFAE<"IYNF$>.o0T6\:SUUB*7KbY#cW@8KMEar:]#_h %LJhuY`KD0HS4XhJ0Y(u]nikX"QL_6NZ"ge*P9\&'=G^'%qJ,8fi"IGgEb.14d[.A=M8HXK<_W?\X;ZY+l,0AO7U1cAUh"3$\>XGe %j+N1H;kb7!G(X+N#Kmit'Q&+9t9[u:PVIlUB>#6&?pjp:J[OEJiS3B3bBY(&rM)gSY_q? %.(q-b*N.Ta(0U*41DsbL'(8D;($F/f5Z(=8Fe@2&Rd%]P!gSL*MOXDI<7Vkb#!t`8nA4B(;7\3B,I%2edcF<1E_$A. %/eB4s.iNQ,==o/6jruCb==U2F"02gAgj[Ya[dd?r,l<`l,:H83U"Td$fn@.DSD?!*n8;+cIbLN,dcGGK'6$+:ZO>k"GWgUgO=qkH %osXdrTZ_$d@)+T\N?#@ohE]LrR-,M4p!oWtk]/4t.)Alena`J:Rjqt^1NBBs;tE,u=Tuaj@oiB/Dba[):"\0]A!YbWQRee-!9R+# %5=O$DoVp\$38bu)6uURm6Ek/P3I,'i#fhgPf>A=I+LHm.?-f*=EmkJ0,fSsuWEF!O^&.(h6A.m!0[I0K$SH(PHbH"S@DF6;\X_D] %XTh^T40kPKHHU9*RuaO-6_b6].W/!LH`POm&48N\r[#W.EctQBe`p#X./*P$^7J(DME?kN1Pki]Q%lVOa.p %7I())`;QID[=HG_3mUm+*d1^9;2\u,5/Z_LUHAcrLoj/!`^pFu$h>p)%;UjV1KHLR(]i3h/D5ap)XK*-FFXF]8g[ %S@mN=^dV*h3Bbcph\MDSLrYZc+sCt*P%2Y,FQ%`C8oDX>NUu,uegEQ;9&Tn:)(KO)-8-,WN6Jrhg;;#*:#o`<@Tn1aom&gqW`%&1\Dth4RloHS %\WU!i=pCs*qjh-1/RlE7u-eC2#@KDf;!bN2\fU@O[+-!sp9i;c2,Z %5;&cAI!kRFe`/[dDQqsJgOMaNA8AtL%=J7$$gS9\8^*fs$Pn!;o0kalm!qY79SlPW#U5@0r9ReTX,=nul@P4agRcf]GCh66&QkM*M=;H(Xg1/J@ %&9!7`))Sbdl\BaZZ6T7-FHc_T!9V@4W/iN2-X_rs#2]#La]dUAeAsU#Vn`KtJYV?Q:5sM'k[#WDkk:fKoi5Hp5,Ng;Du220McNJK %BbcQS%h$5%?J;h*[`rp8YeO6+-+7e_mQWhHO2lB=$g%(lEg'PQbAd5S"PU*5ld(hn1l`B>7 %BeEVl89+doA0K;Y#.L'On!+!mc'NXoDO29lC@G%g@2^&O-rD5J713Q-b#Y^p-6O`N0Sat"$R7a/'_C4r\&?C %)enhW0b@RoN]V66qo:i#F(]%WXmK4di.c/VGqNSuBs%,g]P-&2W=% %mPk\\Pc/\*aF4pY7FDM)&')n4b4[r`qA]^-4-^pTJ,]bd#g^C%V8n85krG1G=!&^F_rFR'9#q&hLDohu31<\M!C1).&NnOP:WOM" %6#.dV%,\fgGY*/]/TS'Y69s]*3dF8sGad8%(,]\T;KkAPQ^tU`K$59fRctp?#-lE`Cg\*<4S7EpCdg5uj'abf6abI^AW/Vuk.oKn %.aR^5#l`X?j^5rn_olZ\B4$TXeedm;Bf9SO[dkBJC+fg<1[e4dGjb/Zm@Titck9MLTt--1r@Et1/-eqmAB[WaMhua^Q&^P$:@J+3 %B9[@cP[M^^$!".kH3Xo#dX9Ja[.hHnX3k[[_2BljlHl:o8e.5isJV %13`YKqhQ.?RWM,oTHOS*-o1kXUJ$A)Kr93Fbgt3UaF!r5R(rQM0+7m7e+:U,Ako<:&#g\,G6MV@4`GJbda_/;K>ZNPJXJk/(Ek^h %mV'..gZ\e,<4ihDAKi9eZmh4?5UF?#%lhh;HnF3k_NKARYKdlU`eb#Vho6TiMhfW\$Bb\*%dk2?-E*!hHB3X_bOlu.[p=lEc`GfKcd%("G(*()a\r#@FeWj:b''m0IC8iOn%M,fjI5PrGWeDK%;]2%*3#*rNOLi%b^SA+4^[n3'VIOn6#YA4mW5Q^^A)A=u*8 %!iY@NN'?R2dO^=2)N?r;iJ[A,*NQ]pMCRSc(0eDWSDomk$frpT4jkJ4QZI7t*]lX!HpkI;991sF[('L?4L`$6fc@O^^B)^'),*1T"iiLS5ho\Zh]`W,S3Rk)>37_=:pO28 %-ld4"D?uNi(tO,8]+Og+P?&%frUE[Gp3E6_6b=OoQoL4D/@"pa^#`t"ssG#8]W")PFb%^S?jHPNC*d;rER=)/\K %Ccu\M$OhR&#t!h$]o[A7X\46=f"LOMGE]aXen#ei[dHSdl\DkXVjaeI041Br92DsJ+Xp$^IeK7eu?!Vkq09LpkH! %`V@iP0`KAG,:cg.%-TFs(;5b"GUs#h0FIVrdC:")$3c&eH'EI6^fL&/@f78to"AH%tF]j]?$WWk)mnj!A*!.Vd=kd4p,e"1h %9i!'p"B/=?*)ZU6>$D^fN8X%^4YG62?R.^Kb1*P#N:e,f_@q(SWf=*OeT0$2>u?hofi]OJmm-uMDFUP%o)H4*b(g\*;FrPG.A`^l %:VhR^=J,$'Z88nBg4sV0h=^TP9GsPZO_8`*ZgQT=?;\:F'?DoFh^!\VpEJ9&!bY,%RRj^.#bX]gAOk(%l?u8Pb`:#gqLDY"fhj0? %0@.0kEX)UOfDE_8H[lgJWCS1$hR7dtXW6.HM^+r_7n8Lf,u%:.ZRa9=a0k+O<#3YPb?ShtU#7p#=Hu<;k/+>t+ID8eLe[6p\Dilh %H>q60XpeYQWiCVfN_:f/AnUCGRBX+63hf3"3cgpSfcE%/BX&4)4#2aG#GO`'8?Y:E(R&iuZ'VnFiq3K":9)q8FmI1@YO4*&CsAY^ %TDVE#'A\/7>"N*\MA%)'2.c-G_6-K>rme_rG''XuHrBeH4i@'2m,m"btq8[Z(Q6&GBQ^O(A;HIYQJ/QKmWm?WHo\h$i %[.*<^_uK#l"I/0tG8"Mbh:jij=+8=BXoXOGa_npC\`:+IUmO*$FgiN+?aD(_0P&oD[,bA4eTZq@'$SPi95HF[PQK"L>g;f)I(SddK1\(=P_i"Ff7(3P\S;(jXq %#2Me/@2q?3qH>BR6Yh)Jd.4tS')pW7.L?$\mQSP;0Z6.3ZKL>O6qPIeJkZ)- %fkkJK-^Cc&$*j&@A>iWKXGV0fR;X*_0B[N$4s:7VF/:Wo(9/PFHHo'd;\naSO[[D+-/;+[HO`tn*(ZJC4&jIA;JF-:.j#c)1iqp; %&NAP>^6Y;3M6L>NJ*A9O">CmcXg'K=W/k0&$ugIYXR`tUPb$?thYVIg#'l(dIMdZIesFQrpkc;O,;1nhGOsHs%@76C %]OL;=9Kr<_"NjKo=`VQ"*WPVV>,cNu6lh[r']bsHjV,*ErH#U=\Z-Ei;%hMZg-XIE,.c,hB9%?(4nldS+e>O4S/3E7fYn)jt"#H.NZpnd+2bulacG?ejC3Me+(0=TZdFK'_'C?R0b"O-=8I3RA)3tc,Wn&niB,`dG %W>"RKbA%3>lHRD3*7uGP4kpa/#G#HsV$M>_p[-78[?@b3%$q2/AUTat7o>lLlt"-jG!j&Aq\SOCYqXA7OEShp5b#+nVf'19k-Oum %:Ud@ELUr==_Fa"sRB)3s=p*":@(Qu7jZ^M(+eEn:0%!Wpam#.YYl_;Z5X3Y>PZh(*j;(,QK)talSc%5TrC;1Ps"iL!T0p*b>%W.L %\!*9FG*USESShMCMu5lM'ts!;%@T]5e/Gd'o^O %EMqQ.b/R=`C=)@*9R0XI9Q$Cd\M(N7E8R4(VmFNf]CIfE#I226&BR?H\/e1ngQe[b"1Kd;^Y.Rh;DR$&$GFq&geOc5iHDG]'ARIS %45=^P*H%e@c>^As:[&O1-eNKpgDL"b3#CCg.HusgebFM7!*U:qZ6V)U:U.,KFq%"k0%[#Q% %^tVH&Ge7ulDhmo#gJq6DaQjpm4(6JlhQA>$kS%l9e^KTA"G+%76CmUh9A/iYS*FFm3aksq %iU&JKA@u3El1N]uG+5f,G+3/i4"b6fgJqfb^$p2C1YrV<>oVX\?bZ#Q;D[14!ef7sG*U@>T6S!%l3H0@&FbXfgQW.c\(&4Jkm//F %-`cZp\#TS/,eREJd?j?G9A/iYS*G71._eZogPHgI_V8(rrHGn[<@>8/\#Z=RIcBapi`ZY,=&hMNn94J]r]!!rY!2ddDcbJP,iS.E %EIq?(X`1#qXt'&F,[Kt"+95Ba\FI@^t^h0YrVl&leo0>*jiRuFgTG#?96iQc],mA+@,*M&`6h@\:h>$c2GN6YujeH4'TGfGWV-+h@=\KgE@iT*JaR2gY$Ig]Ud>3j6`_Lj6`-L %GWRo$1>YcjX>f"]Lf$7jY)*s_n916DhKZZ`b6Ql6Qu^'uf`_&+[f_kbn92A^)/m!K*H*meM796]9u>YmB\8gDG"nsT$#eG63_=S. %VdOUo>AQV^f59hG36rnTO:N+*]lY^V'&ZW!RBtP43Y^XP_t'Uh77[oW3_TPOc`Jl.e&N%N'E,gY'40M74-N/)flSp:]MR %2J%MED5qsA`UV5u4.X;/DqAZDEMVun&%p^rG.cX1-f2"'QEoQ;fgmACd-RIg?CmtsJSc1_2mGte&GWUnnDnI)XAA[*KT./ad2J'e\/N*$@N8@kk@rq,VhpCaMO[Q[b %M.!+5d0o3&DJ.s(\)V[hDTBIuF?>),M/K5P-.D7IZIA3,)K`U2;LP=p@39pGm*e;J(*duAl#s/U??A9.R;QZ[::K8MG_:1N?'U\=\!)p;G&6]CgJp<(m<#s$ %c4@KlQ#GeR\#ZU)2nGQ59XjmSn@t[OTdI>k^YJ'sm/'5\X/pP(]%r]qRd"uof]dQX%(]_UG2)8)p$Qb0?%#nRgM'43l#uUk::CT_ %k]W51hG1P\172Bi];f+o7(9Ll\'s_&AY\!32<]3@nq2R4a-F=$G,U78-RI7/UqGr8ok>Li4-W.B6[@)HUh73/:,^Sgl5c;d45Fca %e8%/-&L=sD;KfY-;M/k"8(d'L>(+0MG&f$E\fFPp7(8@Uo1c]XmrPD]iA42M];=k9];6G%Y)*=qe*Z5XGgl&UB"FOt9Xh(/'A6-i %PFC`Z.#Di^04/h5qU?%eSSho6gF[!7gJ)h=mIX*u\m6?:)nI'=E2)+/JX#DB93HAKWD+q/ih)WVVh+>3\)XS`F?=ngR;ODPn!e2B %2:Lqh'&ART^?Ba=M/HBd(#%nq;VlLWSQhuG&8aFM$6OKG8Mi3@\BX %4)MFTmI4^7\m:j9noqZNXc`B@\#\nKDRYk$DRZT?\!*.9e*SVpm0DI-Y]uns8MLEkd-XY9F?@u?[prd%DT?>&k]R:KA@e=Zr`J!? %DRV'QDRYHl\#TXpG*\[]k&7h:=r3IFISj5D.L@_ZZ/ZdI!fok]TT.\m8pYJhOY.bUERYcDJ)7q%;s3u45:;Vq$V(q]#3q)]Hk!-^>0U\N\EtTgK@/+ %#.N(IpP.E?4Ca0$d5sJ,mAS_;K\JdVGj8bmO[$Lbm2GNV:UV8qnIsZ;.nXV>g*OGbFu3`%Ccc):M/?m&`_X#`::eBP6V2)UMfjEQ %m:Zs$fQPj6IV7F"p:T(%G[(m9NWsieD'q9^Rr'N+;J+[7njmRYg+g:nG!oXMgQ%rScF21Mq.AC'1Rm'@n2all4/nWb8#S&Fm7:o8 %Z0fV$88LB2C=q3_.+cOR3s$Z6D5WRgBKLfo0=78e,T1IN8C?;AFq#;:-eck#arP?>E15-smt!I]u %lPc):G1&/":.e"1TtJ`qW!R0``Q,?))Ri8)'`McutDGL)\hV+ee;u %i6A_t!b`k+G3k-Uj;i)m]q!Gmb)],-4#oF\BKMWk)/WFm %.!DtgP'a8`qi8+K>3PDhBKMB-'&&@_oH>Th*GRpqEJ,Q/\$[($^X,u+BA4jI-*uuTIAc_I@,'5<^"ISO-HU)99!['g[]9aK^"@LK %jCbo,NQD'/gM&h?B%p;s,s0ik^M%*2iF75?m4,LD456o5Ed"\SjN)SNmI5!=[[iZ,[R9k$gI]V*4-Y_AB05s#gZc?`gJ54.Z0cL! %]\%Cmgn1-SLW=CIgJu4&5M:5V?"VjUBk4ZCS@*:DSQl\nD9"03ZgAIQGdHe;U8`ud-XT\^gXW?Q_m\#5QJ$H8=(^2eKrJEq4.SrT %gYmWSCc`[/c*g!qfldXXD-':=:2IOg[EQ(c]=#!4.XAh%Cce2$B%na>&$%bDG4-UFO.A]*duXX8*?@Y8!2*B[Z^qSZgD9<]\.K)@:n8.r5rh;>dZ5nS^blle#?oe %*Qj:W=/..iAD>cj2n#9#rasp8TWM"u?'S9pZgB51Pu"h/@rc&5pn7tPMfQJM_heclXl)i!>hV!)I582eSJuTY, %gJ0-nB%q#la_X%-MDO!^1$0;,NXUW4D5Z9&[[etK2qq(DOP+dl40^BESOV]Wg.lco)/[FPS^;PfQ8dM-0qmu2/>pnCG#HDM8SC2b %)/Z9Mc"K0f[rkI"l<7/%QI'f/V-7#84"@XEBY1!F+:2md8.Fu+g9*R42e]h,6[tcrW\RHbg9)p_"ZPn1[R2o!V?)F")/Z9rC.?rLH)'aV/LPbL*LR0>D'stoNOD2KBKIXLD(":r[];6egX10I\.dRkar>2! %Bd^3]mA+:"SP5P4g9,0Ag!Ou#67'"01>Q8M46kN4g.l>a)/Z8S^c0tB@A8^h>>^8CgF8]jNOEW4:j98eMRP4u_r6BCA35X)CaWX9 %gZd$CfoB=S7(1!gPfS$"RCpXb;DZu9kXcuQ8U6NeUh6nQpFq`s:d3!ENA0]g[SpQePO08nhFt@&r@sH%.P7fHZ5n3&0="k0(9j"i %oZKq:CQpZ*P3lGP+(RHu2J07c8f$;p]*9^.-emmPR;CJC.JtIG2$F$pfhN?Ta`bi(I$*gMEIX);9\IO2l%bI=LRQ;-;DQp#b+!5! %Ai$P3gU3f(OR;\"^<(ODTI-rbB9C8Y%2e[afoADFSSUgX5pG'_lLRHQdjU="FrGNZfhQg7DmCBVSOBoe;%b_-G&;AEgW4Ps4GdmP %0/\s\-mX)#m8/#4SV0D>POKdN;/MK;G/V*.fad,-Co8b89X[m>IjWn^c?tcAb\t7[m3n#fA@i%Ql]Z-T(X>FWRsgfZCe)1cMen.d %QH45)__Toji5qU%3s.)'A34;Klt!^4FR,-,8(N&3gJN]iaEF*@Mem#l^n#:SaG?C'a"Le141`KYZ5k4uM/:cFfTXC"i%,MoN]NXt %[VKM$^?fAlI[S9#%8YqP[VNh-5KS(0O\E3!=Dg4RN^3=dfhQFc9X^]Y,*D8OMY0QL,7?_um;ru/Ca\D`Rqr=`,a%Je%rGi=C=-?u %4"G1&a`b1K'%r;275(s;e=CDGNE.7XTmW$j#cI-%3t&XeA35ZJ507uZlpS;2pQ3I>$IQT/Fq`Ola`cB8-JRbnhIJ]H5KS(hrU",W %^#tf"7t'BTCe*W9Y7#/:KB=1jB6AVE@(Sm4isfhF;b^X]]PT=+S\Bdd[ZdDO_0-a.hdANdOERk!;HYg.:@nB&Co=A4%(9*cdi3,T %8E&IBFp\R(Yam[tKC*1WB<[qm>8_7T]ZrIg:)Sm+Ca[P(#2<"1r;t_&OHmY*paQp/md8!m,CSYQ$=Gq8ZS/O'8IPoAa7\k.4+nF& %Y#-4RJaI,3QG@YnF*`K+Uh6hO8cmc#2P4A=p6WR<;DQm"ar>0KqQmt\oIimG4,q:!Y[&IiHO&;>>f^;7K'"_jS\D'3[_nT#^ioKC %]Q-2q%#JaiZ:j32EEt6#*GXTfTd6c]qtfC-WUqW\m6I'cXrZQPMebgi2J_XsgTd1a)qSsV4%F-dh.$U!^pmTsRB3sh^CUXThf5@S([8SHcbdCA#Tip(2`jMT5s0FO_NB"-ECUYbi %j-XRhm>PmY(Y0(p)g?8=g0n>uPQ]PI)]UA#_i'tfG1:0< %Y]_uH'@s9gei]%6[8+C!(g(EUq@ILG*Kr;1Xtod$@dPZCZQ3g_akkgXFsKntY]crOCPT3*m3K?LFuhn. %g/XTslrZ=uDlas#XrV:J1V\UNZhNMoCT$6uN4%-jaB6&KfjIiR%BLR!\-ZrKPe]6/Nlp74[A3J+_V/kLL:(6#@-r&hN4%,mrPmRU %4ig_eXWB7KDCIZucIKVu6gJeNk[AStkdh1J>43h?Vg.B@f4-UQ4cIQ\sX)JVj %4Yk>.@I:.gnrC+VhVeiXVb\RHm:\nWY]cHYhH2kjO9o^#oTY=oe?VA`RKqOAF=BDhutZ$+]XBuer,]4K"92*<[e=?GgK[:AT9 %BKBShA="XESao<,ekV?Z2qH:(*G]<1NjU\)'5JtZ3FhGQ2QRpK^T_n"^NZcMKT*=&IK%7?.>9*YmBi2&=?CiM]s)ZX1Y,;n`nI]/ %qnUq5aY@5kP%'i_qV;NpB+7*bXIT^H'@ongpeRu^<^I[>-RE9i2J'e[RCZnqFB:9LNh.aSX<$Oo$#A-rs1m?fp\#PA-T,E$kg>s* %Ft+VaA*p'=XIY$'[:>C:erI0q$#?H;?,kSIKBJ6%PFAb";DQfuar>,OR]pu511BS&q[72;CWKVi7`N9)[6o4JmFHH3[;4!)$Yr8M %oae-0P7N/\g1a+"=M(Er=M(C6ekU"rN4#G4_^F#1M*;ema3E>CG"^JlG#JgNS_RF2euhGh@`R1GDHOMONf:Bp)Z,5rPF/Rt#RP:% %o"s*ppDIbu9)HEXC%;5?g8ts5DH=d_enuoueo%I<[BfrdXI[r%DlfMXT/+t-BC1_ePJd9W[?D[mA*n6d-EQ$$G-%7644]GadtG,E %.d)%bmA+?qSWnf86[3&,UaE/`6GhIH_\^m!:GQAGF;HaaDCHOUDM`qP,Gq*;G"njg$YsC]muFe#drWR`/Rc]RD/+;CPu!sTFrCM@ %=?GBNKXK8?Og0*#)8ED!&eih++^sd5h$\"RR]ps51=f4C)f)?-gTYi8bO8QF-1"_q;g5;`$)e/GLY(sJ[8Tgk`nJfN3+;3Qg\SkB %d>9ejm::6JXIZNQNO@5Y$#>=Z;\(*dF_"XgW-2.l-)qsh#Dm3).3$fTWBmp:[3ni=39H-67p%uQmH?ZrW-0RBWZCA"[:<9pC,_?u %'%N"OMaXrt)_+_P2J&Z;/N'JMD$@/6<_#++(Y+NcZUD2Ge,PU=q21VqN^[W-6>R92n!4.Z%n1H>ZRH %[)gBG"W:E*Bb8ReP8c$2q>'kl[rrMKVM5KUE&_k[?FZ9;sgOEI8TB2&XKD>El)CfSPka0<'0nH1Y#6C15Ta)Kq2s;`Ltqa %3[dqo<5A@-g/2Fh;sgUMjq?54mBZ^9*TI*eCA6&Jg'onQEU_D0g'o&$RlFAYj6.dUE[8C@/J7A\*Bg5MTH-IC\D7#*`D2=uNp[<;'jWX["@LfR*d_WKf[7]X %g^@Mf@M*L"nEXWQ&eN^cFn4?FdWhhA4`H3KL-h)^S&masRdKh%W^ %3cuYjbr)/:;qM+b+YI;rLin-Nk`e24'k5gPFm:TU%,SCWDJt"?YYKl,CRc8E-aD0Jn`o&rSo*HO'G.7GA6PNZQ9;k6RQ+PU%6k5# %V^hUf?("Y>.-Z.d$WP_[r@UcLr4PJ_VWN[qq&gU/&4)md3.U^4)k`3lPfLeA3u44Oa>a$a.([=2U`e'!Z!Z5`!MUf/leFaI$N>KN %kS.(bf1)I7n_jV(:3iMXWETqFVJ5PR(j'dcT%A^iUJA(A&EmXLlAGuL*PPh(1r5GmW\5fh5)7J!DW7MCKVi!ecOK_Ga.VN6-QISH %/FjcD[dUfCF0?`BAh-NB.^D_6&U!Hm\RGm!ARXauX9ukP-c'ZZ4Bc0!6e1-Ea%&_AcR6>2`M`Ool.ZG*`%S]=_K[-:\XTruDb1Bq213H@Wf-@gAF\YQrrE@]2 %.:8tKPGrWb,'DjNe@@o,Uh`9ZhTt_YGg8p1f,'mKF&MmT4:=3jG,uM_3[^c`[G@g';SO":pS,r)3R1J;FmeQ1PUGJ7gpmJaDo9j8 %ne_2CP:MOgfA:s%m[TI)a92lJ4mGenYtgk%1k]3f6g)rOm^^AIcI"j/#]gn(/eTkaN1;+Ws/Lu:Vj5.:pB&WG7"q5VRo@SKTiIlJ %jqLG#cEV&(b2'VO8?b*sAh9kAC#K11GHW"+(o,f5$9Ms>M&n(_L8VA2oA`1Z'Lq*m( %_u1elk!5qgb5eDG;*slV.'qCK39M;8-`FiB>WNcWJ7GjL1$4]%&FFWh>r\8JZG<(m=cO2L@SS$C:.s6LE`3CJSCWiDf<3T^5e%i( %_!@r%0?OY4;/P;&8/dMQS&.pb>G;5]*f@k1pWhB?W(SIK5Xfn&&5*e/_R>^meM@(*13$TZKd=%r[7sMZskZqOks(OL)TB4"URU\n-^r.\or( %^76SS;<^4F`Z1p^QcmCS%45.jE*pV:aXO-c2D5TGdXBdMmCG)IY0r3/g^>H!.j^d5^uT1>FF0(l$'R`9&^so)ka0i?=kY$"CUI1u %:/22M0>$CM3'"+0D]WmCRsA7nAB#8$mJRZ<^G2ek'3F62ADOQOj9d1CD;UAVBmnCi$<]2eaYZ"pp17snM^A\@R!CkD %EDWeCG1oELK1emFS5=>aCq1<<\Y\XL\Z&>m*:7/Qe%&E:MRCMWR3ku>otSh]S_,."SNeGqDCIYADQ,pc.p@F+SXji]KTlD@UtUmJ %PLGq)a0TdK$G=:27KqM@drL04CZig5g-k*d3L%FlF%!'d%D#;p46PWdbq1VpE`/prhOGr@L#G5cjE,:Q3h-qV*:W:+fgH/qc7KY6TS*K(V($\)\"=F])GT@_`/m\Z3l+,KH %/AuNi:2^'!E,nS\S=K:_2``X4!lf_,IqG3UOV=JXW]lrVA).M?B8qSI7$FBc;"(B!1V"%Bk?0W%.F3!n %7?_5NCQ(ZFP9[@h4U"PT4d7"!/l#$/>5D'A\ARAW#cQJObt`bo!L)9&%48R6JB:e8Y-KR0-Ds4k>&'qVE?]d&6'ILQb.SNH3SG!P %1%.(^;sROF3IXMS]"lG@:M_L'es=f:L.3U@\[N[Jj]&agk1Ya>Rr-`;,i(\@!RPGf#gT(-)kkb&R6d'O.gQcNdmQ'cs8uX_6#AUtJT00KB9u#QM">H3fO/:hR,(J=;\_,_2^#OIUtjf#l!pe+!'Q_p+"EDj%0-Shh1[Y!g_8&h7^8e#;N^DtDiG@V[Ta&LlW %EOl8Wmm+nW)j!o[O`==PO`=;.A6`OM]>oN>(&;b;AF7UN+s/WOm^XA#W=mu1dq:*k3,Y^HNmi#c['GL,70s5kZ$W84*dZPZG21!I %/99OCCui+&#!&hg$>u9m33K/U_n(uj;"%R'3DKnka%;;Td^`jL3DM%ki?ZI;grHhDE@A,u'0/f;(A&lml""^lA!71"8:5\@7\!b] %O3)0!21Hg3'BH["m,Y[Q#!'th0K)[raE-r.aju>D>.6BS.WJ6E`.O$>0O]@F+ %Hl>\\#otDdk/dcf:ah_*qV[k3M]=[0"c`t)!hX.QV*R+\E#K0U,NcCBj*9Yk5L/Y\&pTa3NKa,1le[q$NKa3]O7#bDc:udGqIAXWL_*.3D9$fOX&WX/6V*a=b$VT#c7SWs!fI(o` %lHY$-\)H?10Y/a%JX`MmF\]qR-Z`VT["eQHljfMQW]FAeX!@!sS$SCVQ'FX9_Oim%t<6&ANDb]/RFM7YB!OEO*` %6uGmFij9e^U*.C:hsJdu$&H4)ZI[di_hm\\]J,O/fFer?DJ9<1,M]V]Db1[5/Q:+fSZ0cLNrEB!Ki"Un/OVH2D[_9&bJ %AS0N;Js-Ga`o^[Fl%]f#hTg_:J#-/k]Ve]%HMN#lfJ`Gm>4QhsAOK\>;4qNnU9*[O;3jbLO@1B9d.L %'O"g"D2@ggL`or6"qC"fNXeSPT;B@=.r4L>#$6,\)1r,pXL$]qBQ-k*XsFuk;2BQqjlSBZX_f^IeXZoBg[E6;)\!:BaZaZ_;Cl2g %34M9moXH[eNlT7t))sT)rGe'/+h9jW`S**X:2^`De3S^;<".27c"V-;eXHp/+a:_bmV4?-Rn\*jVWR1pXeM$HPH6K@Fn_-&PK.$Fm;2$K0faCqSA[mZQc%`,i9?ge3*O"VULtD`:,]5g %-O^K]550ZFU$/X*(nB*2>9,CWb.5i+'\P2_)oWEu:4=^gpc/]lXMs+tSHUAFlB_O$B,7$&/G[.1$P)e43>0/[dsZp8\>/!C#%Obh %;/heL5q4g8'V#A!_KcFk=82p$[SUr6Pnf#E&dhA`=XXpeVm#6qZdFfiH007H7*U.n/L&AP6@fRr#E2:eKhsG"2%l'-4,\]$28k0i&&ZAVNaVj %%0!hNP6=r8GP2`!RTH65_glV\6n7kFBXP>a>t.X35:.dZ#FUG[EWBmaS_Dg@AWeo9d+Qas%FWgWZ0DnDQO0],L@ %f-g/aAq,T2[PQgJ4Dr@h_0j/,WR]^5^>U;"l^aG^ncCq?BAgUR/+BA#[?tn'5]l;#GN]upMd4dn0Q1,LERUHK`pIbt*"W,')r7jkB>r[I!LZ3cd?5b'%6%co*r5fVBt-Ak_sDb0TF4rY"l;sFJDU#<`duL'Ok2P* %N=rjH'kfQ%[]M-]PMK3^2S=\+*$<`(q!bSrfXX^JJTXnEpje()p$;alIbSlVW#H^,lEZB57U39%im_cGWk;l],\FHHb4n`.7lo#a %;P,bCZ;$p[&s#">Vn(3lGZ`j??u?UKl9]_^0,ZLR'oMP,.0&Q`f'&SG-H0,Sm %.3Gr,C?HSsVHgX7FiX;fkI;ss@CB0TguSCHaY4*_>@D[*5Zb;8aK89-8N**&g_bN3dbIE3$AdX5RNsg9BBM-!a\?($`b?0% %1Z`co:I#5LRjq1P+=62pitm9tMZ/&fG %L09uC2F2O$8t;WgWg<>LVHrm=`'&`emk3fejfT;p87;epc0NS %+_Y_-LJP9nLUE+VCY$UB1H=g5=Dcl\br_r-O%@K8;O^-aZJ,H1G5>>g:n'jn&q\RZi@8tYg+4,D.bZnj(,Nr95OMU %<]4\U:\JZ;g6r(4LF#iK[;p1sij5V^`T\tD+6tnd5!E!RlO=LYm[W3Obrm&1c)0ifIbE':c7/DeV=@+-CTHb1)ENI\`3Y.U+)Ao^dq'7^Nln%f.28Km%@!,N:^maIR(C_BMoL3!>6@H,#kf8;R?>NW+(b.#Amr&#qk>Oio"Cm032 %$eb;j7Df9p([%tNn71pOo@K3Feu3WAphSB'?2(o)CPof0X?H>oKdKQ8PjSB+Kk>WVs7#EX\3TQ8$;'1MSb[&Tp=68trYc-KK)i.G %958$^!h30E1)%JN"foHND#3at#]E5;.=H?c_^,k1phiWB%0Tn/-5X>nL1$3;P2Ja4'fo]I64,=W.A_M*fH`5?#Cqf'Ls%"CCa_n% %h#V>G0W.*"#I#YEG#uhI*Pb^+a7ce@fLQi!f2r#2]d8tk*WS+($]*@#!4ILN^%MV;dk<9h+olG51+BeFD?.,n:CDkM!1SlDn;^0B %>N+g\?+U3k$96Xd0*%JjBp4#HfSX'_7[;X4CkYhFh>JJ#l,r2CO_-KT`gZ8?NPHm'ZB@de1Sl`)>Pd.YYb>O9"Fs4h.G)K@YSH3$ %h&4"/XR/ql!4L>2/su\tIAF$#J.`p/hGU'H:nZ^rA%0PJ]jt;`dTm2$JPj[!plb+L%!V %bu_1afZJW]#T"cm<2S#;`!L7;XB95Z:13+K*&@k:"j\2,W^^A0GhH`ZNPMD)0j>q0C_b.\mYekMCmhbU8$FE\=38Sl"Ij-hbQ%nO %RjoX8D]h1Nh+1e#-9XW^f]VtU-4"Ff9!B\W'A+dR(Cu2XnC>4\r&u@0;8,IVoM/f#@^*EDCmAV;a0bn`;LCtRJ5*$i@2aZUZ6o0j %3e.\$G.?9PYS"[J_ESTJ(@BQ+%g3i:*DD,*JkakQ>!3[S9j`Q"+ZP*KYu.hbFpOSRV+HPa#b-!kd1ZpHSUq:R4+kf-9OLepS[tfB %@+1T_98[,];:J+=qT`JIW7VNUJ?[Erf_UmnKrm9-@3l>OK#cG%+ZO:#>M:#!LJ=s+Ke"Y#*T>=r7*09BP*Q+c% %JV@_>VhYd['>at&De'"*(%>ua%TLKK:&God"2*`hOs[urkP-ofiBLR'3476]ZTEY20;W5]#(K@d %M!br/,*GhCY++@QTd]Ybo%.]IiT2CBr>?sd"j,%sP@@;?i3,]qbrG7F<5lko5UQ-`j[U!!VSUo*OEUPjAd,Lt!l(TUJ]uJDs/^;s %ddRlu:"B>^;C6ie.40m-alSI6_J2uio1T!=<-$`F^P:1>^A)L1X5@OoYc3'M(c4LfK15S1!8q+i9)5T= %e<@X:#I23SX"5T@rn:7ni7FheIuVJ@4+@]/^aFW6@Q5H@gT%bJ0DK>TWM]!u`a;*/I73SV:ekZIiiJDsXcWpmV'O^Yrt, %$,2/"_q-0Hi+n,T^'7+P_:PKqi+mY(142e,Ol5W&Wkk..Cm6dF;#WoU %2;E!@Ec1M,3B??'1$NJ-^@X-+ZIg@Ye?;PQ,D9Z?^.r$&3UX?>C]%)UX[HN[MYAmiCNr[2f0F_(-51)6mWKqm8l4NtAD %o\016rpiRn/IJ+RQ,n\d;q^D&-:XZ[fM54hU=Z1TR:$?7LAJ9(U"Ae*[_B#uUbI'Ap6n*"?IIj"[A#bcC8$6YV?Ttjrin&t.K+*F %UTFTapN0cJNO7Ul_oZSU]nT-(X^J>(iME%1[7[o$,sgtc29OOmf+7QnleKqV`Eknlmuc:=GQPr@%ea)6W84f4CKgI;ejsRdY8(5q %;X<<.2.c)r7rX)e>J`j9Rppp"kUqC82LoNN8[^h>^h[-8=s@IT,RbaGjK@1n4_**0kgVK%S>.Y#RYFbAIbC]9W+<:@FU\LU5u?1/ %fX^J#2:dJhO+e1H'YMjZc_tWd+gm>>)g/:Rh(%+ke28iQc!M(4[AE4-*1Q6C2')6uKbcd.h.Whug:;!@X<8uH\!*/<2OVir>JeZk %gJiq;ON'i1COk"D2+u=*1;I]%-1U^9?Gg8shV0("K$_[2G4:q_PE[L$G>2E&Je'iVC\%L7ZmY>]?=D$fEpt"53nBu*?6^H\gh.t; %Tbb\KOa/1j]YK))P="Y>6Ef@Y`?>i[23dMG2d?Hnc#I=iRQT/lcplC6jR9LB1I5ApO-P4U]\OeqF,-r5!R+s:kdAldcV%025X_d5*R!q`nNR%jr1N(1+%%$['-M`iYn5"A6!N_[Jm[O4*YOUbSFo8i7M-+S]Xq]UoS:`c*m!(33U=N"3Xl %AjhNjGJK[?Mn'WXi-oKR)q;7,G`Zs$X3Hq7+^TrU3!NRRntr-#==p>aW[[+bcs9JumT;C9MfeM4qcHNL=\dO-+IHn:fpQSJ%Aqj# %7nKPPdPS13;hC"-VR^5")eP*/<37^CRaRTnbqugi]]9)l]=gSTKW3@`Eb(E'8jr38"A)>X>9`#,;PTFml'\<$"2"5_;7jMr@kuMX %'bi%J+_l8U8-!U`RZJ%JN<>l_KT2HX`;ljY/T1$jF4"N@)KTr:Va:?"gK(>Bogtbk>4_3BS/,:Idr&ss1MLMHc)6"(soXdm*IRf'g2k:RdqdV764gi.KcMZC1jDX-[cf+?sjVrY%Y2L"4OF8o;i&CBOL:W9kcVknl9/S4"cL=GSuF*VOk9J^t<(0 %g;52)NKn[49BsVk]2!/'2c49r.j?$3,,LjeQt;.YW\H=8-Z'2P->eT9dS=`>2'H[SK2ShZ1X^@HQ;I%/[.@VKAO3+`^hhj6Bo)Mi %!,3(5a+BAlQ'IL%BQUDRinip5]j%hU#tLK%c:2$4UX=#dkk7HuX]ju,QJ8H]8IDu],,+Wcn^83A %9SHU8GfQP`^:TuJ<+V&6^56@IQEl"s9+.FEhVYG4]Ba%D5$[^gRW1Yd7bFOgl_El4h;sT%0[eQE7%KQaOn%:`20(\Z"X!'E5ohjaa--cL8$,r`FATC7FO$8#5j"G %d0\'dmVG]VWSZ4CTkI=V.Y@h\K.Z8iSX%as0AB=8T&aPIo+(>W^OH=<="dA.1d.-O>][^!2q %NJU-B'ggor6rO5JN`qX'VPG-"(3V$._=;Z5`C,p<8NR8+>-[qNQC2EbhA-YJ)F#cJOX&8=SOZJuAQ!5k@Y#Ul1tCPf!d#R4:rnXL %O_AOB5b]!*YnFE"H@`E^>XYqCY<'ofI2aJRhDP-3q#KG,IPrD(;M0e&Kc*XMM)qEjJQDCLM5JcA]7Y1:Z[(UqQtVtp6.(u:<&?V, %#&`Y_U6UNRls)A8lb):h[*lXP3lku<"Npr$_._85F:9oC8gt.,L-Q/k#GZ#%p([fL9db6BTEXjZX)hJGmprdc9$bbb_\:5qN4+rk %N4.49UY,\E,,8kCN/bN'd?Kr-cFcuuO8:sPN$_o=Xn[&n>+l8I;&1"N=9m'Tei?CV_.]]l65*``dR'oU#r#Q187n-a)]2;L2iVc1 %RM>)IlsMXQ6=W(o9ra6p:.@UE3HL;0$@kZ[XA(I=*p$sCOce%5(Rr$bM(VM2j.]7"Y\:u-:S;<[4"J+bjOW1mBM?25Gb*SUfmj(JX0n*.qj`Qd`"'K8[_[+Tq.;1t3Gf1GU%_c5_;Ra;^4M %&YP\QVGm(nMMjsg3&*_^U+Kg:U7'a0^9BR8`fGs<_l%)mcl3b&%*tB7S&nV***+1k6dYd66=%I&d86-peq$8Rd6Y>C`1kB:LrG^b %B\L`e/KB\'CQ^lW_)in9l"E@T)p;N(%HZbr`R@=)(N!)/0%s3UMak9Pn(6QnEQmSJMak3^lhH<*X#,$MSqTU#+c*L8d82Dqls)C@ %j_\;+n6fIOqi4+/)q[2W"r<1,-)+1d7GF%9Mmh-NU=Bu]Enm'fcWMutm'a`WWq+#jB/$T(l5\a4KGt[9Q(3XNMl-GUfCAp:@;1lZ %i*?]a4,NB5?R6CYhe6CVGGcs!fr$P6Kci^2XtWKsN0>;C_nC0>_PMh:YC %*WM7Nl2Nt7d/N0's6`\_`F&Sqm6CN\J+u+_L]0L1pODu(s5P4#ql_OK^V;Dp0E/iLJ,B!?bLbU[J,%K"s!RcgD?'0Fs3H2m^])j; %c[YcBJ,`;/r/WKUkeHuCn`-gerqGm]kth?S-`(^WA?Fn4J+N=Ts4`n4:I"]:s7XM5pcfc`r_?\t%tFG6Y;M1Md=i;R)OpDrrgICM %e("$^Ve#TT^/K %TAT+lYIZaTjl<",:4(Rok\H=XgN#@=Hf+Y!s33e-8]`aA_6(^`Ot9T"c%Ln)N#P//qn7]Ks,o%YK_5/t\D#Dq8,R6@:.nepq^T2_fRLt75r=RQ'0?6nX,3pl3E:sXj7fo:j_>>!DRO&;KT&IDS.A"[:doKM@GL>7 %1mt.h5M-uPL8#e(lXbDpk/mO*IgZ6Dn8.:@*_',8[m9onqsZ8NLU\n=gKl,T0rmAqT+WS;2GA@^G@Y``,cXX]o?[,XY2LS,8&)u( %JeF5bC[T:ST^MgWI`0^fGh?u6Cj?%2\]\O"r>KnUjAXG>d3:>8G/di'2X.I>lq=Tr2lpgHhGi>m*]*4W+.9j/I_MqYlM^s&PX2r6 %ce)csi,Amuhde%eSc2NNR:\r5M8S3B]A<'5j%QnbU>596`]%lDL%4O>pfjAd08h+.a0%5n2.f!uXm':V@a)LGh6UtYFq(e6D%s:] %3u\FjQX+35-4ZKT"!:h3rOsgHCbJ1@itGD]M$CqFbSk'ZEs;DJgXa^oST5u/,OnR>[d#Z*J#qoLES#G6T/chj*RLqa=sX$*)8';l %E\_k=^KA<8)8YFT?i?mPQ5)NZc0Foo;S)mpRChXkb2ZE=ghf7#\CspX^/pZ@O22?qDP1)^(q[R\Z9oF*XkU,bF&%9l(bPOT_qt>[9bM!e\*-@Cn %hTKM-IOjjlIIB6klt;d'qa!/dh`DiEn)'?'K>.)N:$dAlT^Xo?n.5QjYCHRr5HZgckWA_*$jllok>C)9rSQ5G.XYgN-.dTXX`U?& %rS2l!S`[]cAn5:f1r(7@?lem8:D$jmYGp,A9WYGt3mHiX:IR]tJ,Mg55.Xtm^P6!m %hc#emlqk;79&Ba@7N2:AnnTU;IIH74p%X<;qq`&N!X>H,b/0+,=F1o4_PFI>hX0eq'-m@mcXU47Bc@gNO4-/qSZ/R$*8T^T&Ug"< %l]/jlitrLaA,l7Mj#0c,i&CZsY.,&=$(B'3m2#gZI6Nd7\4G#KmGO]1bN73U:VQ!m@U$b*Q.)UK(IsN,d+$e!@dk\n3)lSMRqYt% %r8Rk0Q0%uDl4<;05%'l#FfgRu!pB;Q/$&2(gfbZ,51Hc"DW=I?4NV7%eXr>"j2GZX`aLer\Q"W.X'@^CD/Fa1[C"!#6Ku)OC!9)K %?r5X`ZhQ,!S_#OdKMT"6Z4BNEfO%p%H:*g'ZMY.,lMcoC^#NaFgp-8*:\2!Oof/PTq;jd)>4H58=KQ%qn%?WRleVJ]Vp*DhE&@Tf %Z"i;7G"I3oOi0QJ%PUF1b %g>Ks>o:/9:].Go\_o1b_Cb;\FAB3Eh(+@)Gp0OV,*M(go'&l]8Rfj8K'0ZSV#4oR_=E*^Au61'ZdH^T=sfNOIP? %5PF'2:+c/WfJoO*m8oXrI'j8)"s)fV*5uhG*IiQf^Q7$XqSC2FiT*J2:OFeU.%5C']75]Qea=X;hV'e6IdnEeT@ZZ1pJ&?)\'EX` %ri4u2(d)"_b5D4u%+N`5+ap96!'H7"qX#$9>L9g.i19\ojX*(,hqR\r=k*/TpiTZ1h`J7.4DYtg7pO'cj:^q@n/M'^K4!ac4j"d` %QYHW^OWKs1do\-jYt`c0Tq.7FD1$1Vgr^-/`D``-O%[r_37')olOgCXNLAtOoe?WILrCte0!?9A*FY;HO&J:C^?eJJC%\$0Hg^Zm&f7BZJGDFJBrr@E2+k$I(!c8fKbS3`)LO#:_4*sNa69td-cI34#T %I>IK1*q$LJbAkHk6,TW<:[-eKgCC]]Q(&Pt/W%0uS\X..HZk`#F:Gp)gh^tBeDS)EnJ`Ge)?,7e-Hp) %qj?j?eOPF4h(mEjmEDra%WNEGch\jV)>r/d.s!.9VC>L!39-cYcJO*h.KK#2md&*Vd__LE4.kUpAYLN#DgHfs7mDM'dc;FX%nQX" %Si/gVgR";:7iN$:C$X@)qI#]s/&A[DN,GQEAc);3\fmqJcsZIlW9qoYeoM*VA'!@mdc*s5Y5%o7I:i'7bKVbCJDq\oH^P)oAo'gq %B;0fWEddqYR`&eR]T6rlIbf9k[2p\Lg^[6m@p`;V4tUqSHjAr.dsTt@hPc8j\.J,p?A$_I1\_jY\GXXtYNk\ub7FO`kFMEn[dh`+ %A;XFk=2M-npKDsk:q=Njf_@JiXQ7FfL1Tk@bWeA#(-^MG*RAu]U\*/Chcd#L.*n9s9"V"r*i!H85DTqf2F@6K-rY?`(NeVBIlLYTG+Ffl&gORQJ[1^:L?uisoK39^H?E8r@B(Kp6:.4DT4=O"eK,qkYgAcb-W2Y7n,M;63We0Mg\t %]IXrqpWShMKg@mMEB;(WBQ9>?o_d8W5L9#4j'#rp.IDsPid0aAca3&touu5eVaZclEEmQ$F.mQ;n&0[XrEaUVKCd$aEt6LAn]]$2 %VKMHg[=^Km(*>#JXF3qY(HW/'R,tn4Z.E[q[I"@$R_dkLAm%(4TGTTLf6M#44$JDie3A!YY4]%pJ,/WST=KAc;jAG[Gd_N3au@Z> %\&OCgcbDUtrZ3<('&Mtn5M457j#2T(im5"8L^BVa#-gWI=(q8A;mam/jpY_<;1-)SS%uGO\mo"5o#,s'r,lJnDrbd61#p3@cRs6< %p=OGfddLa83Jbbp*abl$?LB>TX`mTX)rpn*Y5J:INcOtr`&jmIh\eL=mW2^g*>@D`FL'_l2B@M=gfA]<[14]82fYrLCOa4q[iCK: %?X9<$^"a5?f##["o(MGjcKRIh\@&pX(@ufuqD?#@C[R"bp5F2kfc&u+-LWBJ_mcM>EQH2R4DY]$-eVpLeSSGDhjhWn\@H,28"J&j %io[TNQC,M?d);+l5`R=0]PR=Jr^Jc]/9(%c6jRGhu!'K%OLV`S'kq'l:\k8q^%"dM#fri^T1,_hIH5. %Zf;c.H[`S25@+Eu'=P\uF,3HC,"@#DAko]5<1.OBI,Re>i>Dq_@QC/'4OZ.\=b)h+G;^N"-a5eH#T6oP#Y19)\SCPMSVq1Gb@=OY %54Lq*H+L)kIYn"uDsHHHK>\N`SQhBJ'8V!YDW+$1eG\ZQ]B5QigP5q'2uJ0G-m@1)R)V`L4@C9p@5,_MdJE!i+:.bS2uRa6o!HPQ %hl@]S$m=/_D_HZWl\E&oeAk'FMJ%DJ\_hHF<@l>3EL\Y]Cr&Or=`N"sB[L?0V\l#gVH7Skc1g&arPZi56V!J/)Lln?Nels1hf5>1 %;[H<^'Cfas)m-KVqo*bubQW^&d;9-;fmFB'qsFm0"g-($EsA+r]13W`30"]BoM&VRGPA]ks75P0@qo#tBWUl?OoK4gVR1MZbq&ROY0BAdu"mH1Uq#A3DmY9AtT2EA^[<9H?RU$n%%CN4^TM#<:rm,e!1=f^YCDeg;IN4Gpf3W,sjf#lT(*l%`b!e4'I*p[fT+5q]l\U!n% %UA;7eO]ZEWoZZWt;s562n[41qUWa/\lS'."ImtFWMOf3d5T"rG[.19T]C=E$+(r[gU.M_Y?"18HYJg$h*OIUR5A`JSaN*(eV.`H- %3/oaflTgBlnb]tH323;hCHWQIT'2);Ck5leoRWS.@Zboiq>C3mTA/5Qa'/?;!J61gg#NT)Vn-Xg`FTB%#c]>4$$MrW:=6,K0BB[8c_9h-oN,f^!H, %_2`iffA-LtC/+'(k"rI+Fn)cE/%dEQ%G+AnZ-53+rf/T-#f"A:'BZ[V1KM*(>kN?p:Nrp[Y]r3&aDnH5pC!iWp=h-c %XLGW&Z%HZQ$p"WCCTfC<^E2iO1h%.NdB;55qR-;95lGZeD"s/ZQ_:7)S`:ejTLHlM9gr.p]X\3&iZW9eDCX2;kcGM2JM1-7u\`$4EYLChkSo;I`3Il>V %io_A6,*Bh+PfqAY7"YBE8)ditlD=Hf>=,:6Ie]I7Nr@Ac+P5=uHVe)nq+'%9S*mJ"Qk:Pj3#+r@kkT>haJeb4lIU]cJ`4&QmVUm^*&jH %7U.T9:3e_@-6]!=hKLthm.DRIr,QGAlDQhT+TH&1?$oe2&R4m`a)?9ERP3lhg3^hb7DdUrkptKN#`j#tC-1LO7E!U`<#*OOqX!n_ %;qn3'2BESI?H\Nh,El\!NOhW(AXd%HA&%bKq;fA0D2dVkLBIpTLR9QEA(=5CJ]V=Mlt(kaXm3d.0!A]N"tqSUT2k-=/kY*nD=tDuB`"iaR2H^1kehLUkAulrVsYWgDlTo[k`=d@VSCn0SW@ %"Of5uEF,QTn5O"%6G2tCa+!?e0T7cDh)ZP/S'_*+UAs9oO5fms_YMh](/\$7BWX"\PnH/AXk\Q*_7[*;*!/g5rd(u?:[9NJ'-jdN %=nA_`lck"L3W)lXl$8*Z=^n:1O/jHh/U#LRbiW';YR79BHbK@)<',U@]hqgNdYp#[T.;[m%Dc?damT9Dfa+TR6EN1WaX^eXI%;602lu^a?(,i\sEr&=kiY\lL]q9e+D8L\$aZL$BE-7ZqU42>?H6#fLr"lgUQ6) %S3%Qgr*bqgDuHTWVroTne$RN2f,Q]KRE'op*RbX=:Rh6`k%s%XZeo-HnV^+;9=Y];p4u06e`WL6+rmBpp5YpR`KZDY0s?,S;drqE %j+_9(Gs]0\@M6f7A%dqMO:f6.[.?$+J?%c.B8qF5Mcd1XFrm9*XGO*:`B*rp'Ok\Yf/iJ`CZOUL(/mqYd-G1S=$(dCZ%7E$[O[Mi %\1'o)pc7tPB&M(-4[rt.AAu[Aq1XthB]>A`kkC1Q;SL`q,Q0FiN!7Y8HG*Frq-N7T^AB=V&l:C1,hCE,%bb&j?FI?(B7-*8l==Jd %*2:FB-2OW<01&>I]gWMTmo@'f%hq1CW,\A1MpD[_tG,t66FqK2-is3SuFN_'ismE %+'2='^\W8iC4+CMjFCTb`8u/H!"*K'6(Q'SbRtHPU>Y0\=Dl!7?"*#jSo>sd\G8$u=gr1W=c,)FNZFW7`q@D^e6ZqclgGEI%56pA %gU1\n5-"'PeRa)>EnG6sFVELIn_-/_'*UK;n\bp0a2O>anMuBZ6@594TO![S+h>TJOH7Trjon1oK%e,-\7Y(^edfcWZoPbk\a9[7 %WV]?C1tTZi7r&XiJI#qe>KRO"Bj,Z70`tDpC2*Wiq.YsP&j,;u#>CX?*n.!h2BXj$(X#"!6tek+kgDEF7%^3\%Abg %,,-2kk*\U<&'Wp5`HfShGgZIt"*oNGd>`*]N(7Jj^GtqFt;%(E^m,7M(QtNucg9b$D/+\+qPtUn>_.GcBi;Z\RM^cVQ5u5YXj(TI>-Z'^*%Oga`'DiABudZKV2U6h;NJn1lfO(%kN>tLL`bDqTG>AG!5C\2?+*aTXM.l+ %e_g3kSiY1?JrE;5Sd2l3$p'01[ct0%&bGJiX@jD:MNlo^T5eGV3kpr,HhoA3R(K7D>=%XNoW1JHigq_rl@c:)aG9BB&rFtg!n*M"%k=GdRps[7K_%O&jmXD1n'Zkkr6?& %h'4.#WuG&%_ep/j2E#$P,;V(b&&41N`!nV[4B&KGlt:%&/&8;KE#T=X.7J45]#iXV8U(Lc]mKA9>"0cIL^g:()bFVM!H=o%rQ;ZD %((cdIGlLSnNmB'L3uX`d!h&P[:Kjb<[!m?dW'^Sk:T@fqtRek;D*.(=Z)-'B(K1%EuM:(`BXBci+#jpj# %/`V2Wndm&K=d,KSB"rRM!Z[L(Bt4Kg^r$!FlKlOIeu4NN$gHbf/MUk9q=E/c6H1%H,JQf1[qs2l',H`FEjbuQB5.%l&pA:/Hd;3L %!dpL+37i+'f,<9\*qWAH/8g!7T/$"f698b1aM'jlf-F4is-qg'p8l6l3q'*W]slWOV]JP.a_Nq/YQT<5>LT7q(dVP(Yd[_9XJ!$' %@Z;j+_-W$]Ak]*&o3fB9+Zd4n3Eh599FX.P'!Z4%`J@.,-Yo#@=,#>SRHK27@"#*ZfQ,3"Une8M:*hc^rWQBN5"RPjb+!uO&.G#6!=GFa`)P\'N+f?@MNtgM-3SkfN4'QXQ#%YaT``sA1'+!I1=oX@-QH?1beUFnuHdhS^!>#BV62Bl-nQs!97HF %PcCJK>Ct0t&F2=\mnB,YS`01)o7WFXSOJ`!C9%LDQ93b-%>OPL-:5$8M!=`aC+U>=ec17:^Ib+'lFP-.fG_]P+td'C?Z_G>!FW/, %29J]B1V67DL!]Eg9D::eRbold'f>Ok^m\!6-`^NbQuZ9A9gJ)$`,BPrXMTJ[ftM&ARrKn-/:tScSH+C*K.>P`J=7J"2GsTMoq"Z0 %#TujB-J?opo!\i^kL#C2g`(7U1$cdfX2#Y@b2a-jKpcoe8FOfh2T6%.NF.\SEU&Mlf<+;6Z)/ZBTW_.RKiT'7,4a9)D[Q609QAHa %$G%P3a1a%%K/AQMU!_1CRD)5nMh@rnnhDN_%.'+AO]`$=7)`9O91XK&XIN4;'i!RsG6JYobSQ$>-9,#@k4 %bXuWY>>VbC]nU=J0KGV1%%DF*0>.X:Hk#bNCp.C(t*e[Xm5FFisC)1uPY#rB#ZTJb6cm)2eEK:SBCq5L^Y.I:,qD?Dllbn1Q;tCfm%F>LFAc%\1/u.>X8gmR$_9$<:_(*s=-!IO#(p37\HF5Udc4V5re0KZ\ %-D3J:Hk,PWD:hh2]B-&3+i^KZ*%Ur;+K;B\q.cI1ARn/=9B\b]gR@2]W/,#XUqLi/*@C&Tt=A7uT@/G5a0U-?Bmc/I.7)OK5PR\0YYUiFC%$8?2&1m#UG"T"N[X@!ZFqbb4IA\Za\2KTD7 %B5eIg(qN0mb$C25@mJaX:YqNWK8@f&DHOcmJ,iY,2g&GcIY4]kg7X!g0,^Kf]`jU(q?`VIe7&GbD4CUW>"_6UTb"C_FC\%g"gmEd %dHbT+S5&FY*6fWa1j+atabEcIHA9n;`/FmheM6LR19lnD?'%hI_Z?->*dfjl*Bek+AT7s^.B;&mFh`\Y96IO$(9i!pOCe?Oj`FWG %WM0/Vd@7$L,IHAe2P[82?);ZD=&ig&Y!-&)'t[3()]`D2QoRF'&mY]7--n+tY4oqOPY1WbiIM_'_h3oP5@YM7\+&!)`9=e069M;\&_JeVQ'UCr25*eJRgR@hIh#@^U;!7YMm/#[R=]K=0g2d(U5u[j2-?,?2O?>-4N3?A<0Q*mWX%^\ %;5'0,E,r**>;%"!AUrRcS)f2fWd,IAp@WLL3&@9?XQkI.o:oBT1Du0brkaE_L8.crOtEUA'l36T0\Wq.*mE6Vc2q8j%0gmB %9U&hk4:/(_.Qn+*I1ms7I(HFp*,;o&,a1$4HE'ac[d(,ugS5[\W3+RCF'pg0$Y04!Feg9R2^BmA!NZ3arE"lH8AK[A,Y1b]tM&ePZ6&AcC$i3dR(qlUd2mi,c-X2AL_m[ST11d %!J?Y'(oJ),6"3.\m%lVS!,H-18.F90Qt28$hMUVY[6(,Kf9!,3J8a;RGeBUl/7:j,+bLKD(*G[@ai7AXH)*s(f$VkSaK9ooTkrrc %?-E,@>1?qjRqV\$&7K*[LVq9A7>2VchAKe"]KBA:!G,.U*d3?P2M3u:"9^an%&PI@%#Y1iV(![&O2.Fr\t(->+t25o-sk's0n43n %^D93<-$6*;PC'.A.]_%S%q(Jc%PiU@6le0B`[;'3+`Pj[U`u9j=Y%^@NP$h#<%As\>$/97#Ak5IK'Xf.Z9q/OXX*&7c![Uc4Ce

0fdDLHOn' %:JsSa!D7lK'61hPAlns+N*ObH=%dTG7>s<,A9ePq;:?`*hH;\)$SgtRRZl'2'SB-U13&Dc&UD-'$;d-)@-;@3;H0RpX$qh!a4U[< %_R25KEmtQe:.i9e]0h$I(T;4RUh>]JrR$;cki091MopT-K#O;GDph5X"aaN8AY,Ps!LFSoU.;gZ^Wj>'LTfhO/UW!X5PkVS7TcC5DI)ruLO!e/D)TCO7u8/p,t%!F1WY7Ai72gd3<6bL!Wu?g-9.dG@0/0j(8U,6olDJ64TqEb2;U+U+W?]f(,#62\+SeeKI^qSeC7 %G@ngo,&&)E8hPJV5/[$QDDFqsA2hYo^gJjs_9<\$<.O7-1[4Xf)V7:jC+U>B7Q\f*d3t=_Emnl_Q8Ohrq9:Tp9o.'XF(Frh]T&in %.BJi"#O5.8#N9h?uP\Qb!0?9^7f2'1"_Z4IB>^uN#$K^>j%gGB%E)3 %JgCoD6s-A*61m+s.jGn^:\!kia()63Ft\=k6pfMQB$JS\>;#)9`-mEu&$6Z!Ef"_bd2JAchJ4&@F3^f+'T %"nP^Q&GfQI`:=GsIu'C83ge7sB1:'I[hM[J>)>^FUK.E8MMK\`D#dYDcpd),#neIf1p[P9GU9V"haY67\m&55%:)_a %=pJImi1br4MU8TtZBT(e/T!\H8*c.d_h?4L=\4D*)oFAG!Q?.NA_rA[.eAbe*K++o\Z[a%^.IHo9u%,,%5eW2'K!R%E0b<,EnG3R %r$`@jLt09.9N4\aIPiC+605SEAdQSS$N%(t(b@"AK@USFbCV"d>YR=u"f<2c<[C=f7rsYmTcXDoHL!Ie'14gU=H$'3\V.es#-Mt?6hS#oOhg)N)dFCh'CK'dP#dB5C$>%^W$rH=`pPS=EEq@Xe)ba5uU(TQ@9-@P)3#qj^Ai- %%q)\X,%:+E5B8QnY*,B%k_C&V"/$_-VFm&AAu-6:*T*?9mJQfmp'!TtN&i@D)TR'gRDq %D[l.2W>En-7*ROWhbju>>[?5:h#cdFMl!g*pPVil$iGbna8.]*D7o%eVK\8*9j5kY.[%!48s_uiWC?BK7+B/EmDA5TV(8 %)R/q9"5')!2OGJCEqXLO'fiWj?*"cUF3Si4cYM6C?X$W1cF4fpZS>rsCaV*N*j1qtP7lBN*p,a@!8#T1BWX&d`g:Bg+B'9Ar9[l4 %;_4i-3@$I_as@-BVJkecCQ/-5c5%p[CoKch[>5t<70CYeMUZ=Ncs)/o*,9'i8ZW("=?T0!O3DkiXWH>6##eO:>XN@D>EH*j3Tt8/ %=o_'NhIf&'8O %k0F>%Z2C$HeXT=X*b9Ce].Uh[h]i0"cH\bS3=!`TF2$edbieY.Wpr(kfHs;//)Zk\ibP-s&)!+Dr7&%tp!^k')O5)?3sL[fA"=3` %%4eJ9Yu[tS]sDc8h`G_#XhpYKY:g7lS8B=c=@'/PF]OP%7_u)Zi^B:G'.-@iY*NH@Dq526"CC#^a_>71bj`eA0B[+L.1gDSE6=>NE(IF+c"gS(Sn %8hE22.fn,I)/OiB$slp,5)ts%8eu+,4_Hk*4OuR%aP'T>=ARo.`_5ZBVC,6aXF1fb4Z%AqZr*j2@>-(JeR]@%$FBFH]B_Pf_Zn.6-.3)C5/8?1X!,E%hjPRDK=6clY %1's?rHDBEG=XTb[EfBo"PcgP[ZtC5fugJSU%Lo#jMSIc(K3m&,]d\CdVi5$`uN,+kbD'.8K/;SS]Fc#*61eVjE@3)[2_gdS#af!6oc( %>'af-0LLc%0cFsP5a,q%6i2060,>#^s,4#E#sBp!@lJ1,s42)\Y$896+3NH6aBp(j0I\uEY+b&aP#FDmcfX0%91te]G)2-nBn4t/ %bs*5bb>kbMO_f`;dOCNCiF")Nq;7+Aq`i7ls5Os)a"lOsqut*7H,T:fW:MX$G))"hW&_+"MD:#WnaGSC %ASbW_1I9.`KD6L*FR!/Jp]c,jEP(6q]Q<0&=q[/PgfG,eeT'`@Y %gjITX31E2AY-XZgD3m-;J;`)4Gf)*H"`<-_-B47AWaG%L:@uo %lu\BK*'feT^X"R=JOr04PgPHgHjI5Oi*;d9pOh:)KVR8&HBp4.o;N8SVf>o&M^&7dD,$MJhY4MJm<;(f4bk:Z7VM"YConLD2SfKc %=ocEi/n_H>1\0qo?A4a$()OQYrZUG>EnFP[f;="$qI@&g9JJ3Q@rVl6YO7u_b%p-6tS=BkPN4Jo)dI4ij?X+t.qXUi)rO8in1j>iTfk)r;N>WqSO]$^\l-sokjNR8X\0.e^n^\/mnYDpg9&1rTX:Zq;R6hDm-RhCISiH1^(ger-'3o>-d)rR!d6$-eA,nYFe,c`Pghc]>;j:Oi,hVq9gUHiB;bG!/n[bEJ!g"OI"h(,LChAFe^( %rRYtj05iKr\(q45Fj#EFmsJdg4mg\+lhUDTp#WsE?iIf!AJ;MmfYq&:I"f%R?Tq^X>Wb@3VcCIndso*C^>,;dcJJBT/+hRKmInfL %+"eV[J(S1@m409+@CU@4Y3l5Zopb:7,nkWQ)[c5'WOm@JI5CP3R.B@2[j3?MSDUUM:\\1tDBD0jQ6kJB%ut4&\(e(Imeb3)o7ssT %XVWh-nA/3!jkZF'Mp(#7T7?n.e]%6;[DQ-q`67c3mcODYf2iJEgmt'H*gDhsS\hQp^O12%a[$)XMJG8OJ-QhYTE9#+!lgk=$M`oc %]Z@tA^V@C,rQLMAXYp!.%eql'^od(e5mKO9J-R+aTE?6W^k3+V6P^K1TanTMReB)R4Rp`d2;2Uf:L6'Xm.,qTlS$"9IsLeKceD+d %p%=eEW8W5Y\Frm5ldlY#5JR-Tl5UJk6#UFDqFE@CQ2B_k+oM'3c0Nt_kI7'HMN^h5^qP0glLj8Vj)]^ipZ^f5FT:IC+T0tIA:%AT %nmh1K?)[J2h#9P-rp8OUGMUj:k53>[2qR6e^\PqEGINpJgY_r%M]Z7\hfY&7mVZArSA3)gV\_Sm,.ET6H2Zn)ebR2GQP\i:gDc(6 %07E?/@=S=Hk)o8f5N[%s<>E?`(O+JTp](*M[uX]0>5@WZ]:>KUrGs4W:PI)cUorI@e37kPg3#KYj_66o-[qDir9)XHq9P*MMZ!#4 %lLs1Q(R*NJA#m9?;L.8i'"Rt)No!E74a8&4LA0Yp$4&^GCL>SfpMd#m'q2AuM*,p,YdJND?.aHLGkAlYQ>F6r7nbB!6K428ah&ee+GhI@t9r!5!Et#C+*"@/H5Ub=+F:2PJ2RjC7Pt %Q/C3_h<.rdi9RKkZ_pR<]'Y3q6a_QUXmtFP44lTuHJb_CCk'Y%KuNI&rp0r(g?5IFT5JKUIduh$mHs$.Q^?m#rNQ7KVADG/+nH:`gGkk7Y@/^&IX$-Kla;,"Y%ZRZe)fg)mmY"j %nbf"`YGq#kL\(D6Gaghq&_mJtgY\icM`3S5*Y80^Dc?8M#@H6Zr4#n)IK&tG`4!jZ^\)\S+:i\NX35]_=k7nAIs84^'B[1S8M`BA %]t2nUb5=Xf.f3NNmc)oQc"t.XI8Q&#nf_i3M)m!p@5Di^D'-e4I.<04Ae(@UkH!CQ\=)`"9C?$BbkCdI?^U0i!mmP.VF0:c+`QT( %06.;Xr8[rm/tPeqbk\nbVfq&mNHG27kSos#XpF4F0TPn&^\,PPahmQkh %J\E/ggO[*+'n,u(I/t>+[qA.d/od`nl?8h<#O4eDFqEL?eEoNW%b0mV;7G+no[Rh&)paJaD8#`E(4YLRGmP"JBST5;r1#Ffer)at %U;J9l;kUb_Zuq1j/Gi4)6tnMsHuP57B@Le!OMX4grT!JFO4WRpr+`^:he,C`mk8VI*\1I#?SuP(IugTdgTG4^C=6AC^:\i9Fo,jY %f/Am^VWleJsJ7*/a/(MXEU8[OjqKIBU0@Nnl(s4*IV$Dg,Ics-*#cr:cEGLZ@Qc.Bmk:S#7H&ID&98 %ngC"TYfg5D,un+sN&J'>NXE8sI+7Fodqf8Kf/B!2@ %q;?aOf0Z*_s*;(gXU"mt'DF^Uhju5$s7:&H#QOD3s*X<#+8jI2g&F`c'-:iEIBo(#H13gY4er"mkBubZIrlLHI[En(gZQ5EiUtBb %8gr$Bq;=7,ccbY?]-"Lfht>MYh`d:>T3S&akgiC3^@l[)!ACW_]mB;Ho#9F%&b9hK-]"ht555b5#1&!KD-]p+opbh[7EO?PcHT^B %l=[LXbkWJR6p)3%EA53L9Q14MgeZ8F%t0cd?d6CiG;-jM:Z]&%me>NI-YgsThqVRFhL8A`QHN&2-b0$8mZS`qm]J2b5.SFUq8qIk %q<_[@p4Iqa6Wlh0]j@63_3f9tk'URJ&(?LTF4@K_S'Jj;o>Ge) %K/)Q(@*JE`']g\M00!(2^/SBYIn`kf1'R]'(?Tk]L5Ye.g:fsPmW!N4?,P-_4C-UR&B(8!`tJjO4I#"'R&jqII!akL3NfP,rcinb %R)`q@)!J;D-*tWCoXtBsVp7aB's=,H)a.01g']h8Car[-)gun[X`fs?IZ>t$If]Xo7alcGc9kU4k?$4!k>hBCbAY^6hYm6@mQ:%\ %PPqsCjE4#eIo77t^Q\Wb?G1Z5q1-$5?bY=[I.lZ.D;F^RjjsBRqpT[[2P0L'To05CV0pYFhTcUHb,1p/2Yf %Qp729]un[?r3?2e%d&f_:'D-iO(V#;&*ApcF"R^h`tLC]r/;>*-ufd\3s;QH7htIBrV=FMq=X4FY-q+>OdEO>A,F[Z?J!/6MYSkr %P92h@oQ9D.5$sqs^APJ;bQ%>!o(HO>.=1O8#@HEVh3SXR%i:9D*F$K%:]L7UHA>bqffL;4rjm5on*QU65Eu'?_[]=T?[9N?CgZha %MiS`jpf+c?U&NK6rmIM>dSJbInf3g;/K^N)b)aG]q%Xf+>;\r"tTh=f"9h:#C1?JXMpCsSOFn@hk#qFN50IsuJ=opb8f)tqk4 %Gc1_N#?c^A(ao$q'`9$*Ba6H\4"UZ_0FDZP2'&F%SO&Th#!Ob!nAII+7<"TY4F'rrJ)/qor9"!+HUdfNot[-(R\+iicZ?1kZ*c?o^\'IUBtEbSW3Ges.)YY[(NLpjqQ>Ml %l@h@*H6F@kJp2[ba8HHkC]O1j`VC"FB_K^V8$sGRh'"6H=rY8LCk88($C@rEGXM>Yl@nk^IW9T/qVh@Wrb/F:Z$c"m %06,Srek_fWD&oMFqT\u>o8CfJY2&rOVg_\D_R2S5me^O^7G&N(ci8QY`r8[[dgWLV5L\6R$=$j4'mOTQa?TcE@#K^[])pRf1jq#nh6$bR_:HtQFF:b$m1?%Ij %-$T5:4WU8upVs<6N-X`9/F?hFIqiT"Vb\,;k47Cm;N%DT#p+N3$[KZRh_$0ZeMZdJ/sp482e[=oUQkXT0YgL$HQ)uV1$FOt[6*'*6^R&UZk-(hDPoN\TRT(\@q.VS?W %.j,i>i@\0AIhe':DZdXhb674)5keUQXo2Waqcqn?k.D,1F`!7hT^TWIYJ,HJ;J6#Id-e8Lk6ppUl1f7rs0q5oKl"A+rna[o\pjs)rPbm&W]QJVl[WF+-+KHM`-C#FhVUhV'3k[JtA.9A/[&O&lVRc0`KBp5c.7 %4(LDnNk=>D#J0m-J8QGNh;$>1\:+(5"')91TrPu%n'>oZ^Y6EV`RD[&pPcgN(em2[d6nK23==R1UJ1$4R^^>''1V#1H@>aUUYGdH %6go40pB=Xm1^s#SR)Ag.Ykl>:^N844^U\bq>?Luk!;YpSGIN&Q6a2BmM1@h&r9!:QrPR%O^ZQG2rq,;:Dn`rt55OAZ0CQY.N9=84 %h=7E)s8VfQd@6m[pu?;m/H>L;ji;ibd#Z6;pl"24rI;H>Q[&'s7jm/cNnMB]+&9Gqjl;gTr6"t?+_MO1;LZ-C@fb-S2Sl7LD`O(I %*-J0M)uJ[`FNEQnHC(V`o91SoS=%r]?b;6U)Q_Ush:5?2Y0f]b0(dgoCX/sP<(at&f.Cj[A6^\6ET8.Bu?HJ,#=4>1";`F>9 %O591uA&Q*l1>@o.Yo?GnKRXJA)NXoE<$jSDeQpj%I`u47JV;;XWBe$nf>hpKAM*kJ6MX`O@BZ?0XKIMO$Ga8`llGetI#%ap3!sr- %C`#pMXLIN3YE0Pc#hauI_nfLpk(5Fo?G0uRR.NiQ9.uQ!P'[$L-V7qSSA?e$p8C1":=tjgu(b! %>Zk=bJV'C8B@*)&UDu@g6,>IIHo[U^3)8hP0k(N@:0;N-<#O7W&B&V@LnL-l=I-i(m=O\V:OTdF6&qe7J^;_R+3I(oBMR5u:9D`' %Q!MD_(!Q,/a[]<`-th"!>jq5c*m-VjXPB0&%?(,\g[Vo6RNFkTS;A10Dum2]&!ri+I7K5I0D!uqK!n!KSXt8'A3r-\/G>KBY,n;D$;P6eN.SKk'N0ba;a)#/1s"hq;h)iEQZ5LS<;FHDZ,iMidh.h--]dMR#YkXT'(YSM'@G`9qWU %JLf+W\1>,]\FtW2&c4hII3+5,\B$>-Fih(0kfY8:,Db!u]dp]h:a':XC*p1;nol6cq3GDLW+-+kTER5uhP%g/qok2=)=c6DiLCln %62n##+emaf:)Du$oKE6,B4)kcKH?r?@8E%+H(hF((VB"-M$tU8BmFXdfGk//cBI*2E:H8NGYht%11DSa0?9QQ9:1:rL2rE-!apL[ %9>Ne^_.'gdG@51]C*'mpEYKYlph\#cE7DsT,8KT!0RB8 %9NbqQMmTi(WE)@;;DPlB,WR^F*bXQWSqKC9P>_WL'l$gG#i<+DN/Ge@;AiYpDV;Ukjm2MdH`%^%6<6,[%K!k%,Ub$V[_P;B!YT\< %L&t7`PC`i>''%mR6<_SBbUs.7=8(%b"r?>rW<5JB:lkg2Z!9CB-$!/33P7]jff7s@TP"sJZQJ`%DWJMI8eM+(VZ>2))u"*rNimPR %EABN!@(6%j;8,$[&8XhMjbO]6V3"$
:>\)f9:A@H7f>?09b6\nY039a$JPp"+Q2(3E0/VX4]dGd\aoo3ecl!sSh'f3A %BE8E/;Jmo?8K`@iC&q`[F&mF6>eJ/UapqqWc8ZTT.,$p>;@)fAj?"FBCCrT40E`SD*t'eQ(a9$?a$e'P?mnGteQ4M^;;(>qI3N`f %+G0!AJQl"F/)ppX+W$;jiJDqC-jT+\D[IV,o3ZJ6qN)j4$d%@J0\=\C9Ga2jiggct2Rjc[snioE'>`HNjHUoTRiMMe&Y %TO.j+Nud^AoXZtL6(E=sOB@;R">I&[-jd1>I41<_itSJ[[)%;uO5sAVe*am/RMCqiqB`DMSCe9h7MlL<`f8JMn8mQ3LY\ %Y,s*&8fc)`$7LKu!W]J>JAAc57*q^!*Cu%1%e-K]5E561&UY%6B.g41?U^C.NgcR^7#-1n0f!/?C"d,!`*>GS3$>0A54"gORa:5+Ei(HL,.1>+$ %*3V3,B7?i8:ERdZQ=ksUNMF_4TTJ=SGG1qEQ\^p"3B.?s>47"2XV]cJd$Gt/qbW)N3,UZe:ts!;Vr!,b"ePmP)7f'bMrfOV9$'PS %$C67+Q[elpOJ9ojap2n3.Bk.f!hdKi>(Brrf"c,SPGPoW6NCh>cZbOk2lLY?n.``#E^Uao\fgot^n&?=mA#R=@tFlZh"9)XEc_n3 %+`/"N'\ceV6N;qU,_Wq6)@LLl+MssGltt!#2XJ==N%S]#_=L::WJ41gL5Tk@'Seh7DANar)k:$Ao&lP)G&tStN`HJ!2?8N %eqq-(%_3Q>3uE7'bnr.gR?^of.WrpW]\>81V$hplW-/8A!fmgJVd'U5$*_&'1GfaBQ,X"\ahani0i89S\G+dS!GG3n9MW6l+TAn! %1fG+M!sT5'\^UcS=O,os;Wl2S"iJO#b-f%q2E-n,^j$V7++YT$"ub)L*7Rj#EFAV`'dJL%#k!S=i)CV^r[eI-Cj'4+V?5[#*@VBW %oqElL_-n=)LF:7Cp&$`TI%fRh\0&]0jh.4'hO.J+bJ-JC#$:C13LiVAK,AotLa:bkb*e*L!f]^_pCL`;kI@Ob-flcS8?L-`iLuB5 %M/SK_H/^(D-+)PDZ&C*>\V5V,LSL+@F_,&ggL3T0`,rZf,e!lt@E5@5/`0s;I!)g%hq\hX,7S`T%Vk%A/HgU8hVXA$?$9ZY-tIUr %$Jq7qgo7SZN[%@ia6STs?%>[W0FQl5&1jL%"sE40"l3m7#*/D]oW6955_PCoF^]AtXnC[e[3)Fi>OC^pd0:9Zg.X[dUgG)Z&qTS8 %`KDQnd;\C\c4ot"E$Bh2$l+:7 %'L7:d6$';J"BnTTN?sI70Z_WE;E-NEmK=BaQ#Ee/kJbgUa3HU'iG=34*3JVU.uX)KWm(VY?)XDs!)<$[Mk[nAG\=Gn8A^c5+q=l* %HI;6[\2H59hCd%"97uo[W(j;SWNa15",4I&_OT-_L^o`]3idI&oPu,XDPUQUJE_Kun-q/ji_k;E#=hQlAV,c6-YSrB' %ASs@S:pn9lcQN-^mt=0\J^J,:SAQZW=mW=OPQZco$!e/MC4-\n40b.a6h-*h6)l,jq-_solI8C7W*b*4-Q1g\^0%pOt&#EkIZ.@$sK#\$R4%ID2@E,b_OR?W(:dR'%>SD$<#]X.13PY8=S^arbJCH'Os %%EEVb/h4UonZ+=Kd)q1 %&N>jc13LE0nY=l*_\*YG5snlmZ&HQ]87.Gl?&lifdRrb!oo+O-D*jbA.Z8:jXF+Oig*IfRMkRC(NfJ_r#%30V'U`7tP^E_g$^D/`sfgtYP(p]]It %\gs>m&_6,5D'^KJ]o.[KpCNjP0BbKl)N%fJ_-@/orG]+enno23[rb2K*3K1jCY/7a#Pb?peH$=2=q"MCaD.B+UCI4r%6jTakPiFi %s8LG6qnpfN8++OQ]CZBPXt6*jCPVR0[rteLTtl&1"0=aM,X=[#iV4Wk58?GgTH%S+8?,]!Y`qTqR1dc_1^/gp?rhL55dM3CQXGT1 %4VnbPN'B)7L5YheLn?A]2#MW6O?Ct4Gf6o2A;^m>#el+!'C2>lQJ2XHjH^;8h]N%O#V=C::GXCfmpsU@5*Eb@Xesn_&=U3CQm.l9 %:j[]J@_O5\lruE:2goZWla'cckf(rhE/%rF_oel0b[KIT?i/t%%X]E2n3nA8*@05L1-a8EH%[eYltf&P4@5O[(VgU@32b[F.pc1D %qldXaANLQJnW8G)_(nS\1i4^pb"KJ67Bd\je88pq'R-,c]VBOW1n*IJUZ!F3n)8p?ZT(';C1Ush7.\:K6K/@E"i63,"GlgjC``ni %F@1fK"LY2X"$eBKg^Mnq$7IYLUJU1`lAC-amK^aDA([Bi]"CE6#r4_mLc6@uWkPB/(DrQJ*[_9dU7WB".:n*1puo12cW]\9d$FLY %Y7>2jJ._t6'mbYf"#9kp"NeF/M$ZQNHM+2C?qYT6iL>LVXLaA(&=tTecWJ/)/7L_ProRZ\_YHH%4.7&Z6h?LBFs3__)i,-f^^--[ %kd*ZT23J1[Hk7&QW,o2aG`3-pNk;#si3]h0-eRH&h#oHNYL#SVd1U"k82WoM(E8HWYpp@5Ed9WIHjGP2@sj*"JX6B^65J:2P#]<> %,4%We_BLgH'tgdWn@2kV7oKA_L&m72o`%0gm04"V)^J+1_$2R6/3+Z&*G!lL4C%@E3Kg0;/c;k6Nb3J">@L2#I+cfH]1\3?_ %0Y&E"*4*G6!E5tK78)-T[k=s8g11qRZ&"Y>iFj*%Z&5qk7N##SJCquR!/XG=<=pkadHl3KRk.f=K6sfa^I1`2+;Y]C-@Ihd %=d#G#N*n`\b&+g="-cFbg&XI3h'\%$:./f:W\V(/TBtfR"th*[^on9#R_e!fQD_8QDa@I-6HtWL"ZjI_I:X#1,N0r,:nL`Ad,G>g %br:Ls8@-1+eDZ.u]G0ag8__S`f>/9DV/=rJq)PMdC3c2bJ4.(%X5HdUB!S5">D3)%l&8J#/c$/+tL3%,+bc\*Q-.)gi?WtPsR`AfVN %6kX.2Mt,[n<(VB6FdcSO1L.%j\PBE?crS8!MC>u/e$&MD,,>ql92QBEnkg,iYlu@6`MHR.&$;C\Yb+p'd)O]],nd)'MM2>&J4j3d %e(Y&sEi2>#/:o=m3F!ZaYo^_FU7D>,jPPu#;fG\+$B48nVVTn$kXUT,N_WD65KZohkr-HkXhp#tJOmslV2NGD$bRM!bpcBtYJD7s %<[=L3(GS's,hAOEp-:9V0=Mb61DrJ,SZ&bifG164"*E%.N`UT#:85$$Kdu8Q@"G].O%;S#=X6_H*,Ue&N]F+;B38,&R %[LeX2h)Il\-d;$j<[RIhJc]MC/-nHAM9.B"qI$Ep4AK-ijN_$TIYqmF[QC133V'3V:0f %5bt&rpStYSin8c?=p;R`_r2BiE\CI_oT%j"giYY;PA51unBm07Z%1=5/tjJn#(t':LfIQ31T]RV<\Y1&jf3%5N2''rS1Ioq7Ud/N %SgQ.!KWEaB"' %>o]uAn2:F7/]+d^efnX?("BVur45/SOdPWiR^SsET`NM:R7/M6?a4YV#]+QE5jkAd"C]ESO8%S2\M/.1k@GBjsRsPF>_linC)nc]%T7iZeY]gX\B]L3Km9m^WVd18@ %eR>\*&$0%BCIc:b)mSs8b\bl#1%)ALHP>R5ZSpW/.m'rIZEscgNQ#sc1>aMg)&SD>eE&L9Rt>4%/^9bIYD!:)K9:7n/`TJj+-U$4 %6J36jRoH[t)Naa:_T&r>67iTo7/2IqAV1_0DAD*s)JSOW1sq!m!Dn>uJbWr]%Vr;q9P%Pqe-iAt#*a7.cTLN+PnA(W[+'B)O#H:B %$f-*)@"U@`+e/O`.TNmZ!R0(ak]LqUF/a^CZnRU/$Gh*lrf`ti;(e^(Oc82$"S %1@%i8SI9NR&8#&Zb:JQGGo4^uNFaHW/Cf@rc4h<,6:_N6!slf!C+OaDM1?60`OL%2/_f$r_$p3G;bP %&;5P
'ELli_r?3e.4%"/AT7TZTI0P\S.#ft^?\0mknjRF%:8e\S<[u?q=s>F1YeO"/ptNuerqMhp3r[n6dRmRnd#[UA %(5aPM.1`*@CF04@PK8T'rh]b4*cQE/Pp4/f?L_[^,_Jnr*2nnKLC.ed)&oCRoK-T!!Wg=IXQuR45d1m3GWH?;JJu^Z.``rQj"+6, %Z)h)KUhD@(N1oZYqnB-*Y\nslK$kC`(k?cFbu\"['rTtC<5])BR.[/GGKNCSJ8#)oJeTCB"D*f2V`A21%N#H[9I<_)2WHjF@SPVZ %d_84J6"2cLbt"-U1K@$,E*k"WT1tB_4=rCa#f%XP9V>_R[-#@(<#u!T_`*.eJJLCN7kF63iZ"Pq/kY@Y,le:t&YB %9WUPNbAW4\UHFcdS;tu"2kUUdPeb'[q*=eXO*S"fJlm,RFDClUH,9Jr_k+!FK[3#0EtW%[8,(Y/@0iWOcke/nYUs %(o:Be^-"P[^N-dQgROJ:CW=.^k--%OSP_0W/g5D.2:'*>,agXeVA<'D5[kRJ?a[r@$YLEmH7#oA8L$2%Di.:VRn"V0:+Zcbc!t'# %JRfY3k?XRnMAG$/ZZk_VqMDQO=*6!D3O)nW_5Tte1Lc,#ErYtM.MjOlNf7BU/L]h+2DCVdaJ4Du.Lls\`Qgr-3=>8ghoMj0;9eJR`KlIefWs(*%N?j!K-#ZhAn=5R??cNHHNTl %idP.L3c[(&XM.gZZO`S.^F<]H"f`t]8uX<8&NfG,BA,pbh:_E?e=`mEc<5>/$oX%gg=CK8Z20<`%A,dn&HX[."MKG,]pX7$=6HYK %!sB;e-E%p:6H#``]k,NCHFoO$P4*`H1C:KWQ&O!Q&^6cBm@6n3H&]5Ops*ZplNBgLc0WFG<#u!T_`("V)HAorbL%uWqXpc\&$n%( %^\I)Xo)JBNWC3a#2r.=`il6r0,M.#FG/p5';`4fe5[>OW5*L%q %-:NJ&Ac,uX*Z!5b^YRhqiLQ#VW,%);IWg;6..jKo"6H)kIYM8=^Dn)\r0CtcW+e\WjMRqV#-m?.cQ^<&&=CcbT5V:);!J/F$T[X] %c[LW$iOYqI*DlaU@GD2M5XQR%qHFHbdl$`gaPk+1BiO6XLFZM(jlC9gEam+11>C7Y7OAtOE];(KLb:&u!,m3F7+eHE+:Q40+5EW$ %o5%hS8Aa*;nhg,Z@ANVh3&2Oqo@"g3K.hQt:ErdbG&JCJ(lL3llI_0!ZD)Y6ZT%AIMH6^tp>(nF8Lg!kOQ^c417/3tInu7&-RM)A %?tTD=ah?"5Td$6C:@GLeP%`.o+&A2@T5=ABa_E"IX1:,=H#`IplAi!FH?6G_mL9t?NPI3-B"'3[`aFGeaAB%S?6%4-Bt^XtbF?5M %R`F]j2(Nt"0'c34VDK`mp?f-1/527%p%V;k!9aKJ0+)$`%`X3]:mLUs^X'1&6g-Q0i]34#f4FPI[TdY(0>?/In-SsddXUf;q^oOp %\*NU7n^[MR^b^>1iE0WS#_n(7H,+j=d+d;TmqH>GQ7/FD32!6h#>@k]8Oka %YE/^*H1=_,p?SR-hX)l&Z_f'!-QicI-#F]"Pal+maVX3<[Ns\7%D\$*A2>[JnmVc:+mK`L!ddV4rTr:`Uh]hXYsm]\GZ8i) %R,f+I,8phc?QH.]$oo^)`Dk0(Za+a6TD.FhrM)t,n+TD#F)nHU55"':`i$<4D%CuXN_Xo>;7Bp=Dh$F-V!2DEol#8'(jcB=f[Go* %UXG3W:56Pi'A40_=aR#^&C]uj72=SH3T-\n_fgtpeVICJMMet;9lVE9%/R4f#YScB6TU86WYSL;R?2SY#,$mgN]IVa.prPBAr3#] %+4"9nc-[6eR)1QUgFu`f.87pg!7'9;4/i=jqs\(*0o]LNLq;0;rj!4uQc]CU;b53+6Sb7(+gd'U.5mi_$+;n:j]H/t#_22qoH_EN %5@&^9FjVm$b3jbZJ^aY5ges9o;*eSW'/H(p?o^l8cm(!nS6KCh97%.kpBAaG]8kZ)?)[#S'>B';6a';bYhV#K:f3fE@^CUEj!\!O_!`e-poMY)lO^D\eBG[a"PE %gK;WgKaI!$a<.h7"5I&=L*D.^PT;8(`5-3+3/KB;nDf$Q_CW*M3cUr+L_SChJmKWj4lVd8-sVY)W8#.89d40+Z;C_"R%'"Q:RWh$ %n5bcgOML:)n45a^*X1ul!rHA!fQcY0qqck6=pU<=Ah9TFP %lkfua4T!fET3bd8\bX_1_`=UG>\&$s`l..a)Q%\q#U`Yf%rC9l=V/*lL/KQX0HqH+dkWac!Ju-E9>)FX8LVa$Zjc",NAT(M]p=!C %)PIP'aBFH-`Geso^W.`+_<>Q%3dsQK>f6`L`#Q([1EFe>(!iX/O^t&W5gQ]J^`(tgZ'tRoRd0\_=IpOU!h$U['&+H]`W:p1.("aJ %VigMu.#*FM@Eoc)ksC`[fYK9JQ&u>#6im@0@O8+$J1gtnek&!5G;1fIMH/PrhTV'?A8.aPJ6\n!aNSlE-A>_M*C-p+)M\PLeiG(i %7ci$KBkRcGOQ)NB[Lbn\0k@*5*:\!)OH15L8L;0d?t4p!)'q4\m;ka+HBq#%8;`>R!$qh&PnjbYhuHoK;_!k`NsJ8gKClP94if4T %8SM`HMKD8+6B/Vl$UVA3_\PnT=3!JA-9Cp`1mO7>M$oG6%[+a6'?JYPOHg\jYU0Y]H78fA%pZXrfraC/Ja7!hN)huEpRKqLL;b8N$3>EG*Q'GVL-N(YS0)if]P*R9=8EibKO3F2MM3S'$H %?D/BY&N-9\+G^g=$&Ci/(lNgKNeh0\Dm)ljSdj2 %,Qems,\5l,5`9t@quW3^)PsVbW_.M8VC\LK(R(Z-Fi)/GB*n*IXK31>._S4.*G-WiDakm6?HF74Z=c0uA<3CnZ9+>GE3+LE')@]T %3-FRX0OgH`P8q6@[R!)%"=9(\'`8GEr!_!"4Y%J1gg9DOi'!cQJch\/%>-aa.fnVr'?eaE8f+dH!)pKm*I$W7,6PBK?[J'4cgVdpTFKB\boAi6:1*PH+o]E9o5'`m]:!%\a`OKKR5(jLC0 %=c_\>C,sd@MD7Z,7b"hU&IupSQVEg$UTA,Np$*:N#,d]]\m8daGTro,)Ciuo#?J]QCg8>&4U._T+\5Mr@nR(QPIKKQg7_H9I7 %UQcc#A"=<1-;uSiP9!Sh!1f5]R#*#Cl:7.9iUIUSMh96>+N7o")EFk]Gfd2m,"ePUj;j3@>d.Z3YAd_'+]SO5qB.7r_;5I)MCpk' %&[alaf?iK$.[#TLe^D!!j!b$g$^50G#(>^5H8pM7FE1PU*0JX2,>$N-/)=eD`HI'Q;cG:m9!'GBq8^[[2/i@;<<*EkP)5nL<#]H0hJ<33;6W6"m\emL!r0LU3iO[Y!D'Z/r;Dl:eGK;1<2qC'FdnbEaS^h("jt8=?/uP`PQ,]b?>aZ*$DkOOZA'X8YVqK&3FJ(8T>_ak!XM=.=/5L %0V4';HV)c]m$W\^e7o@C[K-OTnR\_gUXcktbi/.[^0,@U.3!8+=)AU."\N>MN81:RSY0pKML'dUd?4:&XBV' %km8OCQm$PeXgq';6P;.V)i.&H+RtJ\W`!_Ki;kc(EMY'U#,4dddX.CKbCsq\Uh")AKTQFXXkkM-]M!SUPPNiO74!Yd\]3VCL.p'U %>)b]hn9Hj>:0)qbGikpHhM@0p!Ho0!A=b1V6]?o;rMc+EOG)XkWb(/7ZT]g@5>1Pj#?u1&'u^L1*6i/_0#$Db?1*t#(0m`C]BaLa %%nTKq;:7!di7t:(@DQ0%-*pF9%oOKMmn67k1m==H=r,n-%R[2e;OY)%!M9!%)RaGQ!VYCW4XKl)jA/f/>%ML-30dU9+Wu47O$tDZ:\]V8Gs[\DRa"&i_uT`Ym=P+FgObXc+edYNp#Z:/*cUfZC9HFkW6N-nc%,f1;W&l.5/mA.qOP@f,h08N@+ %oO&t)!\,t?an8.gMg&tIdYTld`?"abtJ.tfH."T"!fRZbtB*W-BEU:*-^EB93M4s)1 %i)SGN2!<83Bg`@K[a`igK*_W2JkE;AkJ=G2Y37<0S!8r)C+@Gr^;a-7TU5U%lm-c++b`!778?PJ@M*/-Q`Sh^rFjEsD"H't=RS#ibej=\#(ft?Ka:6(EuK\Tcn,!]7BRT8 %CjhVLpGC7_Bs@:4/bH>V2fKcI'_F'__4cI#$udO]EJBqs"UQ7_LKW:<-tUV33;6n<[,VPXmQ(4%F"aBOrTdsi&"&PX\V %%('>5de+deNO %.$t40&;)BcH8E_lTkrq%X&aM5S#$O]>gFU,A&XTpX>Y@&rE@-gKmE-(SH&63_r\Sce3EnMZHYa2/W+H&au40U7]2s>a$6^IOoI!N %14R$Q\iKcLr;O=[a8b=h5@-L#HT[mIH$sgTq1!iNo@mt9l*a/=?$AE:Wh`UhD>nf-s5a3M*A)_8&)B"RcQ14/rUPI*I`lH2>q(Vri:5OHg3SpZle5Ap>10R51'4THsk9O)1j"6gO&P>pd"HBnUUcIVAq/igO&P>pd"HB %nUVni%^$:Xn'+?1DZ97tJJ/93e)?#Fn=%b[3;UPSc1YV4[oB3O\/D,HS%l?L@9rL2RdlT5KQUa%/+5cepY9g%(0nS?Y"fR(%,q?0g"2ErMS^#%.UcQBGHMs^'PfDM)rZ/BPI>,V8016(f3Lp@Y*1:Yu %S\2.)P[7VqWeL^S0-HUZ2[qT=gG/fKYfUTLq5-]fhRYHCd]%?.:%5Fp"_Q)W6(X9<'=+I9W3.7)M_t4JF"GMQ:P_[$95cFcQ&G=c %JaQ;6,D?PV.!l$FGCtIPm%_&?_oAIco=JqjeVZ>qjY=BlI@noD2&VVE[j$P<7K56-4!sHY?#&'lk@h=0ZR+OV2-[P6AWXRkhNh`l$KU@OIC(f8PZM#Rjps9Po`E>F/\$WjV,'*p8\g^ %e8g]mB6,L%=TXU+C+YrGYTll\b'7Y9[0^B"&/N[H9pBC*!(jO/dB-K3W'pc`obP>*g1AL!X@qi:&HjhuJh#nQ^O2%^(bhD#+QUeq %N=2$g'C;Ni`R"TQ(E#JH"mLcQ8JS2K-odT2Dt9ZO1[<*W4HUf=lXl^i$GE %<1Ygh=mo(s6N`F`>juM41@PUcb'@+0"!G,T_A9p$!V58=CIj>;@/V0N6!]pa^r>`?u7 %7[]%TPIN@RXA;;d(sL5^KtIDnCS--*16/Iu6mJOUdd'JI^2CE)BP,;ZGHF"j`n4:QX^)k2bthY*q[g]"G-1C7^Hk2%0W0/ZU_tUH %oTTD&FgHI[rpg0q?O=1]-@jOJ&sPf<>635&"-N:e#1?SLmH3aqmhTDY=b)UQh@UNQMD3Uou0(-$+M]YX9>9u<><&LGA-I[Qp4LZd8<:09Tk>d$`t %Ji$Z"hpW+kh,$?G_s)4iY>1%5:&bLa %=-,mtWk^6";grO:\io0tV4LVf%lu^bGpRcNY99Hs9sYssJIFd>p,U#Lh``J3"H^*bO?BoG9]E$n;.sP]Q=[=Xo1YD@?edlaE9%%;hR=*C^TEj@W!dW*$./05U+$`:&aF4++qMEp&J-9gJhBetof6H9YW8U;] %:t9"72$MJk,O%NK!V05FPscS,-qstId`I>W;FiQTDP2p,Q4U!qQb&/L?sk(]G!p%\7Zc"fC#?qp9fV*7LQot9_C'3C\6,NK'<'TK %$!9-I5lgL.(*.^@'WeRp*gha%ZU8<7kmFH/[U5edo7Di^?kXckTgX=U1rCUnVd]:51L\etTpTF.(Q/RIb,8Mr5XV,[8IK:poEq[a %80XpV&>n&P(\Z]WK?PgDkP;qP/$S%E)?_c^.+<'H\-#*"N[l5(4L5'bf>[*_U;mn=-9ZrpcWio+WBC\O[@h,--=GXk)f46dqT\^V %lJ1a9ij^*C5pAb\f[R"9`?lqjOZ^IqZ33pECr+bgICk2m763Q>//:BZW%>@PRF6Gdn!u\IX,WrG0%if9)h/87oaCn#G>,AIZt"7! %7-S;S:j'gO!%_Z0!6m,K&Q=2gB(0ED63S5C@T<:'\^'>LP-u2oD&Pl$Qs._uH5"@Je&JZ(A6Mh&au$o$lC1Nk_:Ha+8jF`TN1&?" %<7ag.5,&$OqU>WdV_+?flC,O:#$HMXgm09b5cSV>AC^f=f*li)P?mLS0If6e"4_H1a2N,5DQ\7sU)LSHW9Td:DZh_KAY'ci7[]cl %B#)Z5^6<16@6fHm_E9WOSH,IWR4(5:Gm87DTh:Ae!41o,UM[R;>g-Vc+MO9iA9%U=e;!-6`,h*o;ctGFSMP6;Ki'coE)<$5ET>P/ %;aIs6c87e-c>YU,e=`D/&Kr9\DaoB#!Ar\m3lVG'T1]e3\q3VJ*9WASM[TVdmo$#)"\E%+dWPn:'6U(S#uL<=7*V*W\U%k^"9B08SUAjk#pA+a=!l"A-dN4M),K6g4YB>!$3StHTtb^C*.+K%1pr>hofpaQ %R`^=*FRR^:P;IfqJBTn"J0rlA"ch`68a:td@s-$AQ'Z`]GAu)V0o3>g5%KTSHc+lJN7bqU>TE1Gh %Dm3FZD7!]Ne"!,3Dl3#7&RE&DB^=%W!Xs\2GVl3('7eW.+fQPg[7O^GP"Z0sKJZEi(`SN*7nX;h/fWr\A;Gg3.T/6CA#o:@X!<)e %ZEZe2(HqZ:kY1>rO[bo.S=I<->fXe%##]:c%88?IdQ((%]!F%"6!6UI(>tF/RoRWV!F$[]qXUY\)+`X!/^o6YFD@R=Gr*'8T'HG+ %/l_u\-j:j88\ZeXeVoI))QYd,0&Q2T?M1:V$Rq97q*CPV`el=A6g]W*2F!SfE8q-1rb\j_@B[`p!$o(%J?bK`(ZAY^aUn0f-Nt!"'_e>R8)m[ %2arT,/@KI6N*j$/.XfeK;>E&X2FM&ieZf.5DUPR`II4`,V`?Y=:kMU[3+8Bid2@E,]e6%u@hs3Sj82[C\D@R4k0IpE<(12YuVKK#&ej^,4fM\k6EZ1DiRe(Pr[,"*t#RQ$Xt)'^=E?k(Xn>U %_sj7Q)%XLmpIeg)V2S$a;X0j7NFu`&[ANm0X>VnJr+Y_<36!Jo=JB@S2lope>Rc%>H:g!M>d)F4M`+ru7/O9UELF._8MXV.#m5n6 %R5c@\*bRg[i(\'+iXP$Zbh3\[d^h>GW29q[;Fn?iC9M<"`pb%XOe"_@Rr-*D?%fqSek?DZ6R/]VV?hDH?raD<_=,`qNWp91!3!GL %Kf&+:eIa*E3WQ/s+e=f+<)jVJE>`B&0'TArH^W-jj:g'6/@C.c)/]Y)h)Ju`@9,aWKc-a`T]S^;^j:&IU&uOM?4<8._sA!?a]f[P %bGs7E6Z]*C+)IUM(&A5KX/?G0Nbn,.B5?ThOR:L*-4j!J5Um3N:(^l'lUH0)+c4^>!NL7J6<`Yh5a0cnPS4+/QpT#CR;5IBV=kXS %Q11QHZ@FEO5hjcpAEZI_JcVo6Qq9=*bF((;ZVO-Y#H-#F8uTB)=T/.qfn8UrBRgGYq9:G:*)r=e,9YN&,sH![q;e6lZldPQ7W2OY %ISn6=TM.( %n**l@8S3.#b/`4?Kk>2&j-Q:^)*(HTXLJ=0WG^pHq5t[rN!j#Cb#0U)OgJ$S`)Gru:Q21T<)\m4HRAQ0>M2)7rjo>JrjIG5*YRXOZoWAf%X"#+]\XF`cC)#%*MH:H> %9sH)[0O"s_.+U2*!\6T/ %2HR6(Q6A%GMP.u.k/bcPdN!(j6n*`QKj*C;SGdIi1Q&]0fkcBjeWa`pU]iM+GP5GW.;%%=rQ""T][Ham[;=92PXU_s`@m`MMfTXog\3>Qo0C %\-h:N:dt:G0:n@mNbSljN-IOh"$(a6"`jCJ%-6nt6Qh/FX$@.:=+M??Sp)Z8*'UM,3?U*f2-?<@)Er$EjR@.(aPl//OMf*JJK-kV %!]bX1"`jCB+cp4-SG<)2>Qo/lenTaU5-=rIHs?hqpp_K/_l%&gLJOs9%\GW^Eqm!KjR?juaPkU&5RsDeJK-kU!]bY^&BNhZ.ZhQG %@g6nG0nXHt1hKpeQ5VQ0 %$]UPjEiq,![*k%u4Yls+&_oTgCOQSI*Z\_+I44PQ)9\BpV4/N/T6Fqgf.2b.HuF*"R_0cR(= %QtJCP)De>B8n20i.!"2X3/kc7_^^YAQ,^I="uYPrC./f-mE#K7C!>Am\]2jWQtspCQ-;)Ifu_ek/2cPn6A`]E6QX\o(Vi>Uh5/-H %I+GZ+:2cg\="ZCF_@8]:TU!OPm+jMN;Ic;h6Sl3J`n[)aT:#(N@pYg].*![f/qGO4fjIP>6`VrRWVV7:W]rD=trp!'Kg-`'HgR'qsbMWB=Sdbk6R4s1$^RuG7R4X\Nm%]8Xu&Pd0]-9J&s_l:)7<3AZ4hU.jH %'<#Zh%5=[UVUUS]D-<,`5UL@$'H\+MGCr'A">orB-I=_hd0*Ec)(VB.&klM)>#E1k7U%e6L^R3eQM+D^Wa:a^$^d/iSCW:rKTP%s %GRES1FlhKD;Q-U-YK^\N"#O;oYN]>i/GG=iL%:p;=74J@L\jnjjiR1"Q/GuDQCXXn/]U/#^X9#N\ZLjs0D#dJW[ku$ %-hjSib=Sa18Ugh*e"Msi2Tg&-!TTWj#IA[qi1ZAc&1G?%_a(Nj&drhqDmI+=M2WBB5g!gnWj22X/FXouXA79TM2&l^G8KC!TQ-X5%;!'?[<<+8*mC1XN\j]f>d %:[[TW\'M?V.\*V'-fC.b9M,ab?`B-S$G^Wh-k6V)(7pC-[LEZOf1b+r+]5FId5kBF9'"<)h3MGrM-dju"(0]2@3jeK1Qt<*P&jP\e`m %#q,-%3A9>:,2;JGT!G;19/oL'8iJE^Ua`]g$)bpcV@;,ae-&cH^fn]KHc\-FS9jN$crP/OZSF&9ol+2C.K*5c8OAIIAF!=pCTBG" %J@_D%)iedRZN5rGbI+0sHDQL_;VcQ%+mc(;WQ*WTkSB^G.In.JP]2#6NQ>u2\]icSeSCld9u3lt!5D7(?TNc8i0SI0,,kU)rkd>=IUHkSprn]oG+U?J+Eg*qo^Rj_NAiu&$_r64(R.Mg9(J(1OO#16#m %,<)gfAA"_;jlAops&-9I?A.a!kE_b;@Y'*mBFG*jt %mn%s;X27@i&!]oEC/.AMk2i+,^M^\b]cj>mim0n"8laf&HD]j`#\k''L<+d8@=dor7HAbH`4A"A;q4;p$__W5%rr#NS$#?mTqbdG %^YPk5F^sSm-)CpAX.VA(D??8GB7&HfcoG[01L\cBI[j[mGi?O;8g3Q-4_fDQMd]1g&R-0o"[,ToH^b$@AT1QZSTEL'_q9LJ;Ot.P %`,8O+=/jpqRNT0Je-;%8?k&iOWLG]V,gtM=0dc.jfJ68_5I7BE2%HeTX)d$$.ChV5P"q1Xf=[%\=\a8<'M5L_3=E@kg@T$@.R^+H %71ZA%4Bqe_R$kq?q+48_*W`J4ap&Zp8ccCkTC)io\XAF$2:^I`ge\]sMj]+M1QlJJ6+C-:1Ej!P^l5 %"`!Mh"`R:Rk4DqrXjt]lH,+eBg4QM5X;%.qD92oq[Vc.IH6hTuGS&OtX#aL.$@(eZ4$VB/L?\K0[*T5T?ju;N#UOa2$Xcthl[["& %l:3pK(>7scJEal#+JP#t05H26/ZA).$e1`:#+N'1I^;0A_h`V@P8I,We-2J*kGZn3]Z#XU1/8=1#1uhZ)09Rc)'Xm>esi826(>P/ %?@!<0;H*PRT-s)+cg^nIZ>2.b:pQ,I%DhBH@Sj2RWq&E6WDJ/N7]]S=Z`kh6aA0;HL5(U\ri/5qZ%fd! %/1ncN^4rG?RC%Ur5"re#_Tku;:s+b1L/*^UCqo(%eX-EMCfQjZ:c&S\B[&#JC&*2fC&&Xg2!ZR&].(^W<"-H>]f2iHRP8c12$Qo$ %o6i<#ZXGcG[&oLN^>/]-S6MT60Zl;\k:)gg'kZ2c/RaJH]e"((&=(`uG!F-L`FZE:Qu %'kX?#+5aIJ!b=`";WsO>h0sOVf;`9l,RAu%LgY^g2gj=H3_4!nL0^uq^W4k%QmYTdI)5$7L\]Ff'>A/*2;8f*[q5b0"uf-Fk@0^D %+e+.^&^k7N0q3jdV+@6+`,,\jnAn<]KMjTMH_ed386FS5D(?b5>!?P=(G]J.7:TfTe,FST'-lRS,UJkIJoku/O@J_ %\Zlo`:MnP$NV,jK(qXQd)$,AZ/F1=Z*qlOIjtO6_f@WhRKc7;[=$uX&F&S2)0A.GAZ_d%4X,q%S#g>;$dP>^&"ZjNuP-U3ARngNan\gg-n][*%WON?Co!Q=SP0=:lK$n]pRhnP+=>MNNFh>'nPc3[r[1X150'2",;)H_ME[#i[0Ujbj(tiD^k2JX8K&W3ZOd^mu %TGeZ98Xb:[\X[87VTLZLo@;9)TX!=q0XV(inj\b==>obT^_]e=nZq:7,&us?jihk"BZUD$E2unFbr^r2E&gWcd[uq&%caO;_E`nK %Qo<55B$.HN=JEN4NO)@&^1'8-7HPq74[MS@\(PqXMU^ItqDl5d!&0RB)[l7u^a!rM@m*]p!_=\Te/4m/EEGq=a]@O2 %3BkjQD<%dXcu_"n?i1VUItjfh8VknePU3GR,-0:<'uGb$8G?<(dY[=M\`+fYBbXLYUAaSeBIV'E@hE_3_?A?idfe)#d0e51cN\8$ %RN!l(^]dNZBNA+GFW"9bQM+Op;G#$:oe4l%s/MeiY+>Re9&&s=3W2PD$2'&"S"'Bi[6@%./XYdL5!/n%1s\K'>b9Xr$q5cgr3!7: %Zq"`B;pDA$:)M\Yoq6?M^I&NictCMp+!-XCS/g%I%2o#8jCKbg8`q(;_c!`4BheA=Jn>8dJHId?+d\ %bU[:2:=DO68\dq?qUbjfkl9@J$FYHa-&Xe'Q8LBB]`Sq>3#tfGmE-2C1#r]:9io1u'`r6'rT_/A/DekZ=&eJef3L,=(H&4s&di7U %T`$Y;HZKkWgkU.Z3nq-fM,,&)FY9Q71Q7OfU24Neg$g2"`1^A#5%PUUau"",#kTH7"F;0bbD[=!&IbLcrH$?f5r:mS#@THO/:C&i %bQL/rJ!7eV8W4f1r0J#@\<=bnoLBHELfQnOB&1?aU.d_<8SF@*Cc"+DV.Lp[O9[qSFP7V//K=ABd\heJ/Ygl,0Zu9e.m@ck2aV[G %KN^oTPZ2J;1eMX$EjRA-4hPk\(aTe6)3#8tKb,ir*_S-]^$&rs1&hEQ0rC0k11NCP%GikW>-:5Tf0m2/a>L!EHb&l,]KmV/.@")= %"Ha+DkNG>m_#iCt-8+WGk"0jFC]$ViL83u8?9BkO#5):aFk(;-lW;VWZdJb#p):?6qTkGr3b]pr'*moUV6P;LV4ZR)D+ONLF?3-4 %.A&QuW]/8i^%ZhqE:pP;kqr#!Ehuq=d^nO7XgNUlPN&fDX7u9fG2W22\t.]n!4ti%(J9CV/)e+p:kU[d?M!P&Ko*R@f*iO8RluVb %O:cV]@5>l(I>+b(Rf)XBcd5M#1$-7oH>-gYjsTtE8H/BM*hcF^r:nKiCLiRr0&c;2+U:RBb]HejkGX_e;GY@aZ^CY9PW*"\C1r+J %^<4=GTp;N'6m+4N>\XC-X]p"$.n7sM,.nNpP$3c'lTRnIf;8H+^*/uBuDTL9SeFeZn^0h<7=<7V<(f^K"9=LW\el4CK %'k5&#`Qpq'>"tWc6qisZ(E#%]:C%1hQ0=C2Y[l/7&D1AFRL%hCZ9ft+h+3\pU?*=L6%H245_0(>^;13`=PT3p %JZ*#$fRXcEGoB'PiAF3.ZH:S\C"\RLc4!fh;PoT7E;bN8%B9IqprP3XXJ,/a9i2[o%1--6$l0NDbc*;S<5>mUj.&H>rWF-B%CNaG %Z3+/O1hJ!^C4T.`.@?5Nahk1dH;`63)4q0`%>gH/1l9bW8-aqu^g.TEUQFV?q$h3k9^j1D$X2AM;!.i%23KtoQRd?uMSEX44)]\: %d[uZ.JGNC;baXdRJEE]Y]Kfq@P*05h8LoMd,H.@lj?34lK7-c((M!@Qr+s3W)QRi"oK/^m\-=/#+poNPfqDE=3G*+M+_;d:$2fmi %DPg%OW?cFN8S5O5aV_8?*7f/H"\qrC,cI>eFb#Zd\8ZCuiM.YFcm3;@5Vu&?f?HmsKd:FdBb#j:F9+?Q$([mkhNCpl5_UcR.e[SDoppJKbD/j!-nhA34?i">SC`#+q!>.9]Rnp]D^Ji.[%'kYbrn0j[D5=a#/eRZ'`Kl*o#m %OGkBfaD/LOgnL#"_6`JM8rDcSJ23!![f`7ujA]5V`[QjWMW`(tEg#PF+Riemb?Adrnf&dEAZ,qDPcd7gM[3Yi]>2j9'#g?al7sl/ %$d&eF)fK.5Hb`G8L'jkb&a1GWW*Z=XE%)A@#ak$!-C'_sq@S%l5V4f4RD:"*'HfJ'`!;+;o(o\p=pU!B)^#L9a(/%mlrU+i)TB+cg>>o+C[-j__']E5?WJ2A/3^Ek!-ROK99 %!Yj9lG[!qS-aF1).Z%_2,tg_'(*kt!Kb`Ykl<6S2'5?e9i"^$uX'-hfKm?V7"!1*q8i3s`5GCn_$77sRNiE&Y!hKE.H=iWHFp;PV %Vt'4))FR,V.tSC:`C-[FX"PW30e_Soc0-cq`=,2,7QLV>'3Q)L!D7N$V_X%OO$6-D-?qU7gn+qca;(Ab0o,X)c[A=R6^Rq7S:g#r %^]?X7eD/toJ87ao--^!)_:)42!;],3E@bs#g5H"u*/NNa6O8[L\,?F3ORj*T3QNFFbH))f(G_d=_;q+9orX=l.o[8Q`(8l&2EVU, %hd23:eB;eoM5`?U#sRS;/L6,2GttLL=K4*;r:$2/3k_ %q2.N]5_fJ+O_."/J@VOC!.t)gpkY\8O,=Pbj_`'e5UO?r$Od>tE"*,$Abi.,_gmZl^aC^!s:;EcSHPs=tolR^E&.OI7pTs;RJi"%)UZ_,0^?&*0F8I6JE$:\Yo" %b!t6X$6-afe^;,Tk8^,RP<-b%1ki2l@puL7W/DhThL+CMb(g4'I-S.PrXAY9Vf_AP+lY*OrOr)K28bNI$2(FiMe6"E/RIDE8mjq;dlAE@/?N\TWY>I %-_-(L!DCcIE?:iN<>M89T>=!luVYVLuiOC^<9m:h[3l8F7gR"-Go2"#m0Zh:8ck-K&P6B! %AWe>_'\L5/8jC61fjOm9+\:WMnGlBI0Y!G5&Pl4#it12*eEIAu(@[3FFTs0h@Q#K.?DB.kI&N3-/-'Be(0Kg8\hS1$Ypt9U7`R:1 %@dt_(MPi5-eScS#8P8"7R>b$sXX[i5PfRms_#pc:-L/F?n-H^e_6B=AR5BKJm?/;8/SXGX"dN[paG)rpU3Vnf %&Kk9kOpQYU!I#@,&YENmLqoi`aVHkXqFn^aTdr-Sd.)7rV+o\sd(sL:"'Oc#kiePE6DCRu$bJ)OE_YLZ2+ %'eM_fUYmh>Q_WOJ94U(L!U_Cu?R\V8XWqappHiYfgg1F`< %fTJ3Mf\A:oV?f3d'123`'AsV6dF3l$4dWH)C6.EjRa.,>HS"E=6BuM764F(1G;]k-codt4X\L"ZE]`ls=rc)W;DaXQ %&Rn$MTgC.S/-T.5#q@tq6K2YaVOADt %/HMRW]$\[+QM4.MR8T^f$C3M.A)9jB+VD&,XX;^^Y1qf[["tjs"Zm;?q)SNi#d",*+Y-SG-TV5poUm4^Yk`KVG+S4Mj %a@aQ:[=kiM`[Q_SjAG9=Z-]@bTVe)Y!8IR\?\>LL:IqUb[3eY:c:kV;@)\)(f.L?NO.1Fi5@03Q;GR"4RLQK3$&_^Xd`9\F^#cf.T]G.EOV*OStZu[N2 %NsDd/P:XKa"BPL)_1M)r7:p\`'^Zrl&7#nVb:/f9<1mh^HHfn-PE7WoGmBes3SK?kBHe'Z$Bmkn7;QH-WkJ]V/.i8`9R-f(ad$Ck=7eNY?jHR@33$I%9S75K?W %>r&oJ_i$4:Bo9P=isQA_^Z$Oh*&>`j$'^3<2qSB9RL%eZ4?d.E2"Mu$MF$H!%V5i+,H3@=nk!.'@/!NZ8-nl'ghGH;CRZWlT+0-:!*eV.PS,oSsT\+)mDJMJ[SDseRh[SKa?Y$'YR.i2q0V+C>+j= %AJ#J&W&0tpjr9DDl!r!lOH;atk@k,tA:9','rj6N5A]%WWF?RdSEg\6,FEPjB5dCdin]-@uqg)bl!t(6r4@Tj.[1Oq`+JlN.Aa'Nd4D'eZ29L*hK&"lk=6+>dtf1rG'g %;ff-104F*607lsI`0gDo*,JU,`?:(iH:r3GFs]4H;cLI3>(_iL0FjK=#e=ID?$=aIdbnI=%V19".H;_B$s08JFsN1Y"DSbhd;4?d %bW0F7VCWX+1W'<8U*M`[?5trW/7f97+I+Gs.l7N%"j^+7Wlf@a&7J*5o+Bprg>Hq?@,#8gI8UWEL6jA@#7e%CYbt*8NtXcMLaZ-) %ML:;e#SJ*Y1kH>&5@g2qR9 %!Ft4:Yg/B'oNiIh0%#]r;834c%@BI$m=R6r#c-WVU)AZ&.4s,sYg79M]G']ru7WX.*6j46eQ])M-UQ;OY;?$(W[2+s$]u6=(-5bcshSTKSr%"<"a4V!@XBa %Wss4iPRZT'JuZBp9C`K-gLsd>h?uH62V@@?o+."OH]hl'pQ!eVD:66mOI\"I5b=c>b1RlQU7 %8^YpR<9V#X_Qr9[@-A6nMj+?lR[g:]C>.2^*JjiPHEoH'9Q;=fmHGlus,_GWE(>RP$3>8^&CD3?ZcFUVJCMAuZ&;GDOQb(I(8?<(p$,iH']BTp6t1U'a!3(q=pLc*_nUqY2`<_t66"<(DN1)"oY %M&`Xa,gero,1&?2LQ?riG;M$nFG1$rTU%E$@M6VS-K-FGU!]"$j%ERX=-$##2gV8;qV1fj9cs`(n*+` %OA!iK-AqHp%ZP?3;l6>mi_YNX<<*Q$,di"a3!V&*0`Qg)?iQ"i,ZU#[T+$rd9YI1-IDbX?;ko+*A[o-=Uc7ni&&6OCq\"Kk"g %5CjtQef9R7<"F1s@'eG/US&jIrJ&J;4:C?j#iDF[r`Dj#6(5S,`$_Ne:]d7>OSgA9`Xr>'ib2@IfWfC<#IjJ1[Kpa^i4;t:99`*! %)T,g(Yb\#;NZML_m&+O5X-$&E/ER2[&WnOL16p/7=s5S@J[&(j%-krR$I<-g=_)HHB_8mP1^T5\&H5=7:/\.V[OYSggRU2&=P/Wf0J/eq\i@=ZO`(-^17X]^K!*`LI\+'-N@*!M:F1,VkFbp>XU4@83J9Yh1d&B?E1 %m!uAu38`,]RkpS-\T"t*l?7pL>.FT8maf:X:ge"?'r@MQCH.=8$C_HCfFQ\&t+.l/;LiiGk_me4>GQ5 %,od:]XWR&h?W\8*i@]:>4uiG7h"5GZqmJH&/j.i(RcT+OSri);S#k,;V-OkKpal0>ST6M+$Q&*(7D7m_;6KEo+U#IjG/7k-$,gco %hQQ\=M3W%MXs."lb8O,B$aV*"(T\8o0s<&(KLLXq67*(8b=[Qio:"H&TLF:J&MOfB#ZD7d72CZoiZr+GefYq89/Ii_AIAI\rpu%u %l>m-%49CHjTF9[gIg(l"X%NI4CE$ZqZ_Tsdh+#DL*SI%FTb'tPYM8GbX'Q/aM6Q[q^f2Kteg`*<;_=B[GhD`!%>$J]Xi%e+*3s[* %ED.Vqn;(&ZY)URQLeJ-9)e4kMQH45Z=FbA1Z.KI\l[NZO_ij[?c]A(&bJ:qLi!b+sr)3.r=fAC;cXsj48fY6#J%"kP&O3#SG,N"d %:7RI^,"HYt9gk10lIsu\Q3fC%7[&cPg(RA"[)96OIC_c._O@P>;)*(>kVn;S!$.*nE&B%F^W,I\;slTEV?(em[:*PVjO;@M3,r9m %%30]))Y?'tp#)SVn3urMa$(b3R`.7<^s:lD?L8;E+EMcKHorkqmc]BJH$,#=4T]/i %8=S)2&)-sd(!`A9MCjP*Z4QDGr.TuB&-3j*SmfJ]qqYl[-iN;UVF&?ZWh"6"Pc-J)7/9F&+iR>Q51,c\+3m+sCF3Q.VEP2LVQOE7pZqW>lKto]m2r5<\@,Ig.?49&N(&4=sW(YUZETWP6(20ed_s3npf2j6Pop>^i,c3[4nf,rsRi?s1$:iNA%Vg.u&5#3s[H$+]FicJuDr78M4Yn_1/uYU9U*C %K$2Au2BZrbkAPerjpJr^WM1HfohHYEF&.DPLZKnf?V"34Tal %3JG5e4S^Yg))5IHN&tYTN[KgeheF3X>Q*)tV81"S%s( %-6n=r>cnioajkmELOgrR;OcD?qVauPar!2]TeINu?Uhd?aGg,qGl5eqIij`d$0"1%+TD2snNZA^'Rts:i.('+j<;&r`7XTt-_sEH %8<+I;(Qtd`(!'AFD`56,Ar+2>i\0ID4SkNHAh1XCm30RsDH\/dP^/5JJEkM@DhdhPU&6i)Pi$ph^QP9]((!E/"VDW0#WWY!oko$< %%jq3PqY=>sTDn"hCc_@Y&2`O_AYIRhPX"H:`N.n*QiH4&bJ/%@C,E96fVO;1jZ!59jnoL=68#7%)8?!m_g_3]!./fc9[%r]r\(4;]T\4%:9.jp^K&L-%?it'XKu0t%"#b.b^VX2r`9sL%(^KoEYOQc6^ZE+[]S"5n$[S7GME/oF%FL(_n0OGEM1!:1+<+E %'SkSCahNu04HcW(@<:pS@Q7GKpke]tUH#H1B_FGM*.9[,L4+fQ\a,%;:IF;F %dq#2^T8c.moT4i`R3l>em%J$#MIoZPO2@7VRbl]pr4_$(G5fE]]^8^]BPhVb%;1!NrE7]Xnc'sGl4dp^*U:LF7ugTme!:\1dJ5GiUgg]V:>aMr=Ie)1Y7['#grNQaDk&LiQpZEYIFd@2PRf7T+11^h!fCaDfGY$foi %0NZ(WFL!f/8LHY$/3lkMgeqVI'k^(U[M&3^aVo!K+O`L[53]sZX40R7)"2)!d(g.S&Rr;%RK!Dh7j(XSsN,/c!>7G+-*2iRp&`s&hWh"5>fN^s"L(XF?=5B %J<5BY]Z05$.;?.pb1]N8XcgfRAk?bo"aX*;S#OtN1,O%hS767lg-W6V&7%aY=do^MUDL&WGaHecen1Gqk]pAgaVh%YX]MCOq"PgG %.qXT+gBO:Xb5eP::f(_Y7bRlRm`["uQqh5U1YHl7)+P#q`p?3Q_H7KW.1:C\&,\n:puFQ4Mklg&3DRTR@j6;hV//Y-J)l@/P!aoA %4^6\ID!'Rd3?#_/P&QiPkUTiU!4r"+#cq@1>4;4-!364=m@'+rqPFb"H6V6)>4<3,!Nei'4JZ_GZk,91b+b#&V6^rHEU68Pum<0'I\(t=YNh<3n7Ys#faFGTF<\-[,4uW_P2b3iXaPK5SU/CmC<-Z\1*'C*F:[)_oVO4h/oi, %VNr%a4#02fXFn$_%u/p00q%KlXA&E%diEUGHW;tjep),MN=T1^E3J%Eb$s]JMS;]n=`.:YLrA,knS+n%G9$Bi3;Q^WfdbGB_i6<1eb)6ljl.ZJ!Q;s %3]c'[Qbe1Xk:tY!6-8Y`mu&^;RJS'^PlHJDg40.o5PR)7LUTPk"PnS'.MKK,9'>IuEc,ssXFks=A;R^[s""hLTgl::np^3,ZVeWi %B>2i(%KG*al1aL]e#@EnjOaL0kDUh]NHUDONILKF:,9r3Gu!j7\\A49Rt#`>Z(qXoE..K4cQKRiq&aVQ,MTiq%"$NN"tUepq!h,i %WIK4"Xnn\q,LXrGj%)m)NeJCX>6H)s;e'@+Jg;UaP=@$,mL:Y:Ej$7]G++t.=9quM34s#_l^iY$kRuW%P:9O^L-L!D>.Dn+6S4!Q %;rMU3/D9tkCY6S;>hVT.APmUm'd*Fjqq#4mH^_\74'0+lDk@57Hoj1pPuko"W41\Q#6K:eouc1\*=p0$R>HER_M[D)A?eRkS7V.,qe^Bc#IaBGf$U5p\p>%?1l?e5+Fk)eE:-a)3`.NpF(i1(3h"hf,M`?9!\ %jh.[ali:fKp&8V!&oDqM*fr)uGH0aON3/00S[b]VQ7Q@UGE=Vi1qtYo*WT"Sm[u+S %S25$+YOk+hfPG;i\uGH#A:Wb.aQDCqe+/aXK1kf/[f62&I$a3Xf %c6*MeIaZW$$d2+i\^&;:]6,sA66Y:=999n[IgpKHA7$[#l]Ec07nX5RZfq%3c"c'(gkM(X)%^S\BZ'&"CGf=7A6+FoP!0/LLP(U^ %;Z7=1n]AGH,!Qf7Xl\1cr!9dfuN'nt8bQ9-"IPH=N.]4+j8sahDVh"Z:Zbm)%oRL[cQFI&?<2&ZUj0=*m'dQOng* %0oUb[1Gop1;Mma=("YBU5Jh0FL2;fS?K:9MiGE$o.6c9%!(gA.s[-W(i(!c2)dkL4`7QGBC3'cN*Af7bZEeSl%ggj:&&B.mLq^*oX1`mj3KjN-07_Ias0/pI;kFUKr"EAM0V#Cs>G8**]+I %m+qrV7'5.i=: %r"WcNX*&7R:8Hdn:@J5T6clT5\'o9jY\aa?,OS-LX:;eK0SR3n>@AA=esC4,DKh:?6C1qm9g?^J7db72:.@'2JqosRQU4Ceu%TRg.8jTB=V(3eNL,>NTpUBC>398qSG5cAo4A*nbKr2EJsROTk<"^p$?-MRP^O< %IQ.W2:@6[OBP?F$oOYD)._^,MB#B74O9T)n5c]L)UH:@"FK6Hf"WR(s.% %[]:G`7GBM;MFLT0LBr?-DRVM#KOG`:C#u6Z<*L]c.XE,MMMH-9Q#O0amWq[VX4suPVj6`nJr^Pr,'';I3-8=FdK\2Th2L8I*6mbN %D>j*ib`%8sRN5J=^nALW@YrN:o<;Xs1YYT66VBX^r)I[,f6am7XhGH+;^#"CdKea*QHQAbXta^eQ[P!F"DJRekoTd/mB?5EXH<3r %rqpMI;"Q8f=;i[V<[d7YGYWLLh&^*FH.=NoD_%#+(D5S:^bm\J[`sC)3QhiPQY$?*eYWXb2DAa?/So'q]/+&g]J:E]c/+f>MV@>. %b\K(GEOuWk%<>L#RSD%e+)G#rQeE8*:"Efq,8_W(R2Yp]`k,7NX3i6I:toL+5r5arPQsB%@#p*W]m^t5jg[#U4-]ml@@FVNDd/D] %pD\le\D8lW,f5O!hDg$d20q2l-%hA0./K,[h,",dQSo=G][55bH>/.pjNG(l.ug(p7M?_%c$OuLnCRjjLf`\&l6jL3TL%_-[M$(F %B$Y)elk6JZ"a/O4ChX1*=%r# %jk-N=I5D-TiQL/84R'47e^%R"e3\#IN&nJW,][]K\KkY@DL_ %JEqEGP6*:\g(mpXbF#JP*-G*Fe#Qm\4s`hq-!59e1!`V7P0$4(;J"&&-$`:I#(u*NW:keGn4aP(rVHRi""lY^R,`f,%XkMArSY6B %cj0NpgH8m1/uidR-`R[)Au'*]b0aC<9o6L_>%^_qP,Kj:O)G7>Y!ONnk'h)`"/U+14<(#D@cGhrL,L]BOG+-Kp %^Q+(Oa`J]c2=[^JdHue?*IpKjbhgo$2i[[+CfsE'ACb2+XM]\:HC.tXLC'l4M>+o;Ib*94IeaLVgN)&=`$l,i%@?t]fFZsuLQctM %9EMdNs&qM]fboOVA4=ChX4A_K&N&nC"&`&T/:c`c0Eo7c[@-F3S($oWX?6U[pVo>Q[#,[e-n"DrPQIH+dNCDJFJop&5(kKGW>U#BR2Y`!FN %oIMIf&of>`giQ-2X'_>\Ph5m]!`HM.dD9ES8tJoE-EAprVQj_OR^S[!arVNJj]ifs&me2BB1n;$>IWA1S)q9T6ZM?AQJ(R=>FuiV %mCC-Ogj4'&gF1,>Mot^A?Yf-W366L6 %?QANO8bK-#@sb,BMoV/K7R/!GmKl!5=,:[k&&gj&a)a^rLomRZS`>1qi+hbl[\GA^$TVqk2Y3]SHlIt(hRUO]@qU^7lE91#d:2K+'L?7EhT.^>H[ib01X3Vqh8Xg(F--?"+*\/ShNi1^rqLhYCNoT?p-XSicb=e>FN@f^ %hmnBn_-A=Qr3;X'MCl4")",PS@47<8&RDI"X7A\9q^K3rDP\T;dTYdTrG?C)]6mo*eq^:f2hqd5S(29L$iXnBjkl+`.:f#CPgs)M %nSP&kE`gLA,J2.(hV-F4I=/Hp%HCgKgH>BJ6P3o$k'8W9XtI37[SJdpC?oTGTrNtK]9r"d&,b\m=<1$m:kQ)A$?G'Z!fH_0i.eIh<'c3oB^f&NHQZ($O;?,n$ocrSc$'\g\oc:rS2:/D:X0+^>MWK""*u; %ARl"!1s-g'"*c^.^dkjeTi#+4BC]:SpPPmrb^EPj*g@bsF=Hro/bbhrqTbGNbDR77Edb4#T6oBcQThI&o_Dth,[D$NZMJ;.q0mmB %;gZUC^$Q;P'N(mWh]:]pRa7/3-?hFOLKX`=.a*?Eu6HKS6U/1DN^ABfn/ %I.cfP8HXJ^UfjRRH0K>ER'=Wujn*,j]4u5-;;N\eDcosk5?Hn0U\h*8-t6ZEgABL8P.Gb$4oR)(Q6Tm^.JKE?I^,CDQ\E %KCIZ>SSTac@XH:!+5VKM:)_U5X5jgDG4Osql8HK<`@]cqGDg5ugPUf*doYj^m;/P;;1kjm6'G47k\*1]fZMAfp_N#_Z.c)"9.,(K %9_4@(_cf2Aqbp5W2HHZfRl[Ii&++0#.,)h-IqfkhLp*Z>?\aaBl6ptf6_9S;bg6'F%,mMl2lpSYI2L;g8&'+--O+-o^1?=)(V>V$9EZ*\!lKP_TG0)@m?F%$O@A>$%"j,SjA$T_r_j!UZ>U`=o$ %)$A/Q?VB]iJh.5RJGuCiMS1nI,Z*8%_iH>ik)R]m1.Yu@Ac[c>Z7*F!',io*F,%\p84D5dc+.'*.+r$toG\!1n%q+(o=$^8`uPOa %k`5__Fj\T&TibB]iXU:1@jIF\g+!O"n/6$B1Qg+ri!SK@0i/mL?4c4B4%RJ(EpO`niJhd>2Z1Wk7#"7]\1:8R&GD!%VYu2^Jn`T" %P!+6Cl!=o*r^15Z?7Oc+?bV"0&[Co*CHF5uV446'@?9Td6BP`Qpe&I;3NAHWPMnr@X7/.uXmU%HkAtG7S%F+9.#T[G`!MW,@+URc %m6VCa%&iqfNo2dYC;^?)sV&.qD,0:*F@kHb\cO,oYs-KI$0H=Xn?J_Yg1<1?>GBKd(,?aIl@s)V)(\dV"9hO5&9&j+ifMHuDG; %LjZhW':eF%WTn&s"+uLLnduOFYFBE(\pKsI`5"*S],Z'AT%i'Q4E,D+Y&EqXSA5+?6PCi?PcZJs!#MgQ,BNu&3nQuEo6 %)P$7@q?]uX=5SiqSejA[.%T#&]pN#LZ7.5e`pt&# %[u9&=oidKYEtBD,aLYnHTB8&_G)EK,)J)(PaU6%K11)DE7'o1.2tlSB=B]#d?c)N,nNo/;E#Z2cP9WKe"0*"ZQIZ,Ze^-DMPQ\pcFY%7n9W9@[X68i"l-ecfqR]DIlTed0BFZ] %rQ9?YRK`i*pOc:_@HG/4=ie\q_V3<6oBL"M!OR5Q\&YB%RlPrr7!t/?fhi67\bK_f[^U8Qj%DV29$2OTSRnZa6@?'+GGgQrghlIn %pfssL53jk?JBpCu>VW_439]b<%*-#BBq=XQ;p6G1S4]3UU%glLIG)rMXX`e:'?d%1+=1T=iB+TZEVnSEI,D,TlttMmb[")+9m-20 %,o"0/HY`RdfuLg$B/aVJ7>[U"W06h#fZ_mXB?)Dq-k")D!^%-:8#;Dp"2&s/4>)bKDKdi8b-dj_n"nfd.$@s+S.*m;?MZB`4`@LU %`$K#`r.o_4L74Q4qh`dkFQn#\[UCXD3r#i@?8%T_VU$n/cPqk1j?$N7gJtO3-Llg38)">:0up=_5^Bpn]P`0Flp-8qmhT'eO1Dsm %h.kbj!GaPd-S+#6359sLcCU.E-Lt8QnN0d-G#Bj!=+'-)5VTdrcW:tSBe7_LEUSQe^)iN0NO/Mqc#/C\SJl8KlU"dTac"HECEmZ$ %;6*^28"2WZEa7m<\WEpD?g1Ikb\*BdKd8%IIlI'Zc7YQq?mZ@>6:H,`Z!G%i,b$-)P.iL7I?2gr69j5W53_NQ'I%+"=1Khn:U.L_[UbSDp.#jk194BbFnk<9ZQ-$>t%cOt5rZ"eB7;BL#S?LImA4`7AQ %7UCYW\+5g&6e=EY5IDNC3NMNPk4A]!0I-Plj;?RTI6 %cU:1V41HM_/@SrKFdjNpD<`XB0;[4Kj[VphbI#>91Rr4o3!d[".]pYClQoh!gD5X3[/78?[F;f8B4\Eo/NIoMc[7;T%PuQ3r:U'_ %PI)O2-/?q[J[X-bkP'ZnDX^9L]Nlu1Xfh7`KtW4Z;?GN3iZ$R*]1Gr1ibERh.[OmAIF7Jc %p*/)B2hm"16M-q9:458I'J-OIJ6%8Dfe %a+\03qKn,KMVoL$aN;T]8M5Jc\RhMh*G)o_=C#'2L_qC+Lao[]`660FHE);/Y2GP^C\(6E-AYs$Ydlr9..AHF1sQnjE[u$me]j#YoCUT&=r9D!jBh8Ie``3,/(5[eCat.JP=Wi%!]\re\g/+S %W?!WO0=N9,,ZC7%2.,V7a*cU+Q>W>djgTm<9P\LeF?jUuAs,?$:[c@s2b`u>[a%SDDIfV`TY/%&7GM8K-6i3#WHKI1qu"iG^+1`D %]Ch+>bRdL(B\Ff(*1O=08]!dRq.Ad0O7U'?61&-C4,cW:E".+Ymu>c?EXP=2r*\bs:4mpR,guIdn9XFH_(maR[nm1<>>JV-^60/8 %g>^BDpi&4N%N^O4[f+#(63NNfC#ei^1+^)O#VD](;85eS0U'q.4_%t$Yg4a>,2Ccp3?7I]\bDrgJhf;(C_pEInUq' %h0<)7K);2uqmqS6D35),;E6<\06^=lm85'u/G9>,2F%DVKC[i)J)tQ3GBEWXSZ?\BbSpqE1B3h3Np-3i@388OAYX:S'_H292FWk2 %rVaV!i&Oij>HX9/Cb0L%E],_V\eqBH)6TFI&sc=q_3"_p:doLYfq'1S\FG1^F;8%.plnR)/u*KhE&rc5A,edY6Z_t3/bj%BCAcO %?u5"Qoe9IXX'_%G[^0>RJ*jrnO4:Y"$g.-$@KZVa/O=RFom.du7u?)MEOhZ& %S9sGC1SB`>]Q3WBT#N"K&33cMCjkW/$&o[c*^8;gpWi@KRZ8BTf8S6mP$f:_'o2>I9D[j\-#'GE\,\)CX2Fb"jOq7L8r;khRt]Je %Rgn+WoR9F.NpYK-p@FUKpadu6X`r2KAA*Vu;G;;Kq[)c[36OHDmMF*VeHQ-.3%WsW)"Y58d2,4M4Xhou,DH)^XqhTQl#neQ4'Z!O %c&eEI`I,)!?3;j4>@Ej]D9X`M_S:]8[Ul^c5HB.#0eFl1bcTQb?$UimeC@3CT %c3V0EYEAe8fHM!;Lna^^;Xq84\0JuUQ;TZ!EnL.`9!S6u+[6dd,X0tjnm^nE[R\?K%lq$QI'td(\4lV>g1p:Ba"><0oZ)'F1Iaka,IrbD-3nS2^83TXreLBm4M0N8E7"WM?>p1]a1[$D,O/nc[GLp#4`L!UL[r5@!" %Df&!n;i13P8T9NoP;U45#9s'l86ZlLUAj.=rsN1MMS#]NL+!PNYPj0um4oi?q]5X;YdStZI*SjMqqH1s`%hp%#]ogqRThe#8Bn8d %2TVr.p\M&M5;"E(Sk8;";N36pf?@6S[.g2g#)'Phd0#N420/)(1b&ZgUCB-4?R=]kS4b'n5 %/jT0RMHX-C*J(rk^0S;Nh'YO[(u9R[T'Ot_F+Ah!kPhngt4?3P'+$mdd$8nT_!jJFn)a` %S2gTZ7C^5+F2;Fjb!P0iI?J^T>3:_.D`>s,Md1S=*`_Y@BII=[n6f[QQN=d\7;W=e4dEGnHLjp>"Ui\4/ac`#nGm[]"uI%YcgTII %b%3R[&?op$:;=i1%qQQMb(BIi/%i@mc#G,3cRB!S.^4&u#N$JI5C05oN^0d+QUOuK8+eBpErl]=?[@ZN=0F.G:35gK+77ZU+!4OX %N^.NKgE3R`YA'q2BELl"+P>:u=PFS,]u\aXS.!^@CG+LX*BF6rT#TpUp7>cINtJT8htBc#HrXMkd#,>BgGCDk %a5p;(.P1$VpT657k2',tdK"CF!(rma=OQStDiO""pZt0BSY^0-FKiAhS*A^,q/M)ic.qmq<^sUUlX0,)&L[cuI$?-%`,Mj^BQc)H %$MW]u$?VV!MV/j*H<3/(-]PXGOZc%(!/5u0m.JMd2?;iT5^U1d]qa!DiLC?j?iI=H:7C!uMms50o:>_^.E(;&HMLRG%Vl#il(t`F %qY'o?Dr%q:rT*\0,"(DX#j3S:2n.l=2-GR.[B)9h+*H--<_;kc-2+eIPoSJB9)E]/cKRK'MWY3`:TeW"_Wp6PqqKHfbHd/5dJ%?` %l(RD=p3<^Q/%E?rS@rhZDf$=i(=)'CQ$o"&PP\#M>M"<"p3l`uAc)1IXe?'!n,3+'#fa"tLKA>jpQWk_f"QI5Df6kc`16_ZVqf;# %L,"JXDikiYdIlmf_0L7^p$L@jOL[(%NaSs]hO(A/+7QTm8\#K)pqC7gU5HuJ![jn`jbYQ1+V7s]'9kbP9CfU^:tO9H>^tb*;R03rN"RQ\CJ,K14-@ZZECh %e3225J!Al`3'8_8Xlh=CnBW]ODn>X3Gm&b$^E3OU[qH/RF(mDVlkG1;`a"h4p1ufSd9,%'2u_Lp %7VaQ=N*gEnamRaC]iECbM"IXQLf(5F5u= %RG#g0oYrnA;D_2Dm;SEFPfSriccLec&86j")Kr(7cIfC9#3SW["R6a]119NHN^W@Y+NRcfQK0m$YLJ,?;!&q7%[RLdSu`=C]:@!' %AhsZ9apGP)*bLH1O:M;p_,Fq%@=HC@Y4E#iN#CV>Xt-HQhpoC>qCUq&>@fYR1d_g\Y<@s^I/Q)sT2`-&Lb+V4psmTLJnnG]+QT[K %CGRjaAJoT$3KYb%'q`4\a1NYRM/`(%.!]RO$^le"Tf:gqm`;]>Ss<1(o9-Sg*mp8GK`"A"s)cUD,>]Jf"bB=2of2"",nDa>6a4aY %f(85"+,2kkm>S[SfUOJHG2&9qO)piFrVZFh1S8,93H=ejFQ/)@imACN9lM(CDTt'io-n:?Udb%F'"o[^&:*GF*ARVY)QK?h5*5!=[)XJNVSsYjdkP %/M#J6GR>3rXC(M1ATU?iH&BnMg&]2^G%I>lX9ZnXj3hgi=_IKc9$B8Y1eVsiA*gT^6]>/.g6gpc>4""^C2ZL[*UNDGP`@?i04[3B %:pUrPXU.k#c7ojXPY"Xibgjg_85'HAWQ\$\/\nl*$c;%_2Q@7!`c@Y#hN@?jT(]S(# %l$KIU[Xg,)*Z^+K(C2i/Rqt)&:40L`BcpAF??8-$55)g7rA]O,:+moq:.Dg5O7:r.`(^GQo%*ohI!uJ(/k-9o$-mh;0TPM;AV1tI %M]JM43.kD%O9&Io-#C-T6,`Y&%a"b]$jI8Bhfk^MEWD>ZJg&qo/,7jTm#o"ilhbZ%Q[6-I+KF4IcTh/^#%t18_Ds)0/il"drD,-r %IBjeB04Y7Dii[#,C.SP2@r?8oZLf`/?\jW>YCq%N+2V9a>MN*Ap9uXdWgsZ4+n;ia*84,mpX7r9sS;EVN&Mp %Ir$p_+o!@R">t,]>*=:^LI:C44Fqd1d)!2A'1,K[OjsfQM-)]($];tHpY,NJ:Bc^+s>dG6&E\`YlE:rJ"7 %$11h*]h''VmWCo-q5eiq`4Yp`ksMnSc:sTNfWcH=IcleqQDJXW*Hc=([;>QoJ6A"I6&<@"f9n$I9?%VecfRAOkIW7Be'<7i)YaZ& %FQR1RFgAGRc,.`^$D!0]q4.+(Z=uXfW@o]>e\$sU:uHf(MWB#W@<^_AiRtRSYhJpD^ARBDL&stZ=gHB"##:YU>2[G2Z_Xps\ZqN<.,rB]-hMklDWVnfV(J/2,Q\hr74-EYb$U1Bl"^`hF+1$q9/ce)W0@f:huB=G2[`chMro>HeVr%Zg$TKVf/K>E84A# %S.m)ME+GNqWK?=!C6H5_+%Kud\o^8F.(/SF%CrLOk"OJamS7fr\Mk_I.&8rN;*iJ-;@$bZ0qQGea) %o`2I>GB_NgWblp.db2">gGCO<^$Y3&m=DN-ii]_Q!6%YW,&8&,[*LmQ:U:1r2[L#<<<.5(gQ5Yh!e#EC\!R&$b/Rp9a&4ge#c(N+ %31,BC?-Un_ceWZe7GfI;'7uo5^uhZhBBO,)3ci!HdB,Pt*U64/io9+JnLQ4:"Cp_A,)2!d,-9j@4HL#0,54/#o63d3-85ocNiG %59l'YNmFa^Da1=2o0Z`S?fYJMq:R<#U\c>sdM(XOaX-N*a)^9!,c?_aR*/StF+JR1hW>/Sq"BX_5W'D%'nlFE3BDeOD`2bp)ImB` %WU3^[Ym'TqK`VIj=ZmqK2%1ZTP;Su`@SDF1gobLq>*<6sS%F.7IGnSnQ?c8=&;t;gVhX8Ld0u=3iF&3Z?*O+O)k2`Sm2,R8N+\C` %@k#+$/)A_3MWjIp3ECqb`kIuHN&pU_m0U(gm]pt\Ct*RhB/of]G&:h(o'Ni[e*I2r<^g)pb;BXN,UqF,^jO,(^i=`h59KYTiqP!P %nLk7cUQp1>RX5U)[jXE)"2DMI\_oBE4f8icp\".NJIh*9:b,^$R#^JK1la6Bo8AIq+pP)l3cm9d#go5`oALIQ1/;K]'H\<)O8Zl: %Sm)GC+2nPtn4Sa-elg>!&M-n!U(r"9r6H0RUiG6,&E;hjA-dILU`h547>Vs,H`n9sOAD6bJ1FEcOE\j2d"m#0+\-GB7pPkb\Np4[ %Rr1^N./Cp"Gig"OfSuOC>a?*:EY]="PrUfIWq'tIN4;ZhJj(4Z[36XN2KGn91-dt9":)#QkgR_O=]qCA5L-&jq!Lr %=Z<\e.HZ1/.Hll+^!lq4ik1"VceT2Bfmd^,dOZq)LM2gV+4@W'dGj %&bY\Y%2+CRT`_q&I";8QGO*ZoiF=+8$]`VdIW9L?43`e3W+'";5^trC\2mRPW(3Yf^Cg+Z1J*jGpR5Vc:KP7$d9NL:/Drgl`OrfC %-I!kY%\V%_Vp7@FDZ'EBPJk@!GsS(3AfVC@7@_=6nSheUWj@V="0;*Z4"ro^S3obBf-%6WeUE^K3ofSsR3?(;dKd?*-862q)S1,P]>jNJJm-]1GHcbBYi+q5BO %>+Vo#0cBb>qTU90p$$f]&ZO.'/0[t8?>TIo<9Rm/&ZO,QYVa]bQ.X3^%l];kdaYOmN)jD(or[!9[p*#jk,l7VTiXu$$>7XMKY_WB,S\P?WpgB_iLK:F!VNdG0>Z#Z$I&=0]`Ofi?%#_*A;%G7A(eAQ=qoK6$bDK'=VLrT %OJ+K)b][L=0I'/Da1Y_37AJ`F]Ya3]c:_9Mdue9.nIKNGa43>`VSfY\%[qOiiHR'M03!p8GCmld!)$SbS:)0B2s&ZH6>`)CU_`]2 %$Dj0lmPO:Vqou_rr&?tu/=0NVc[fNnfj4eC\7G'$s %$fB+raXu04d4=L`jW.d].@".h/fiP.CMlE'hY$XrmbEBU:EPLtkZr"_S$-]p0<>b/\>j)WZR3JLn5?P,:o^V8XujASIlFad).hu&@k"J)07Xb"8YpT$)ZbG@*crOCe_V-%pp7-*Y$)RKL8\#";3BY)=P %0]PXO3U$QJ/^E$0EDBVDFS4P %:$7#?bT`M$#oSIS5-&?X^IYN\7+408d^drhRpH,S)%*%5^=ZPeS(t&hN>AM#fB*>Uq"3s[fe(:33c;?A-EgK018Fs+o$"[OS\&tU %$r;M`jg";c@*.C7#r.j^Jjhp;YQQAa6p8-kau6&gX<9cN3U=Z66ph$7O[4t,G1gY%cAiUA*6&(V*bC[D==0PIk)RP;hM(Bp %/osNmhg>de"hQn^*mGhRQ+21cHS8jt3/aQ"\L;T]%$>nr=<96*m?O@:l$CMT"mUJ`&,k]*_WX71p9_U?$D\'hd2__<0Q_Nu#TR2B %TQmseNoT+,+$?bd'^7Cjb@-ps@1pH\R4hIeGd+M)")'b-'d0=#kk-N5GPpIeWqUU#dntBA1 %^!_U*]MT2S:JKWhLUu@BRRq%IT)!VY8Rf'-j5I'h(m5]umT7>Xp\shfKrWsHhk9JmeD^Vu`QP<'N.,B#-%P\FD7+-4Mm`q_1)u>; %X*Pd/OC>40hN]sRD0Q^:O(!/NNOoM*Tn@F*Uii`YX)R5:q)H>Oe-M%6\=6'd4PtCX@$U;[N@3.)j\-TL3MD9bpiHO*m1i[3%\^iJD&(oQYYaYb)6sk"(LZ)n.gc\oI:O:77"#gpJ6bgKq\ClE.7b$!o(IuI'/c=i6,K"jPOu,N)I;UniYohD&IfGJm]!Y\ %]5f,7A6/sA@TqW+gP,)fouanOJsb=ULnJpca%8@a@!K_$Gc/X*D\EO"OsSu@di&e(LiL\Zh6Vuir\A@[]!9C@+tDF1Z2<4NVRjh& %[i*/phRfY^)IJ5uoZ&HUkYio`0k$$ABn,Dc(]gA&rF9*SO9.p8Hc %[l&m;Zbie3+K;Mq)-r>qfqQB&%CO>K\%0WD=CStC^\/@e:&C5,cCah!2,G(dRab/d&rQZ=!`K%8H.AX%Po&6.$J0\.[VGCcVS+70(0tRWFcK]Ws]oc]$_U %X`G;Ob!JKWc+OuQ=F3HkWs@#2U>cZiGd6br";L19-20!bQ$/ge??HC3DVTg*o@F/(B,:T\#k-C<^K;'0E-46N?%&&_@[;(PB9'1V %hGuS`!IA#*kR@%%0hLMT0A2%SrN_/\H`W!8f#(7a+*7P>-4*T3'tb!]<&*ugS.'?pPJ4NnJPEio').K`;:d;L+TWn$%k8MD[)kP: %WB[H+/83E'WQZ")P*GQ]X`@^YOif3X^stCsBO4P[[`jq67&B^(BMpC8K$feLdVIY6kuMSU],SB)UZT=(*>d9S&A(t2hS+'G*#pVnCo!ZA'P5t1,FQQ/YtC"@kJ/o">Pq-rk[cjLQ,YCC1:c\VgM53?*A\E!CGA(&V`E(g7jt$; %8RnCc1N)&b7K5WD^r0W]C[>/7ArP%5Wou"gUME"RZ^iSp@E^Zr-hnsh2j[HPbdX1h=;X,cSm4;q#o@cJ%N385MujD+!uO!.M-GL4 %TGTp)n+6TWJ3dZF8+"FY6idLO!AnFK*'XcaBFH"eXXB,1[#g0#L2$C7*A7aRBFH"kD"8u>"/"Ft_]!#BDA6L*(dM@sSgXrmAOn%# %JEH`$3hF`%9ja,X7pS>t %fsW&:Xm0Q@femqt$E)MKo8S*f8R4RLWdZuT:Kc;qgYpj#OZHKJ59kX#M&'rRXsU=;kD_`k?tW*!Sa-Oofr %Ho'D=H<%`ElgY,b@e._!0^>\n?7A'b7-\l:r@E]jOfEje@VGVLIX7rW='a4QlhYmb3A*-HG$R?$Wd[lZD.7YdVR6""XQpZFmWA_V %rOf3-NEqT`U*s7c[iDO92gI*iWN)Qsb#EN^7SV"eWd\hgcGm!PkO%,;42iPLlf[[!A@!^Z>h@;1>te8s]^ruDYNn-Xh9q1cnRJ.q %oZAWJqAG78WN+johLi8JI\%6^WW4e[>sE8DOD:uJfCe_FLh.t)e91_kPI+Ea)j//BB\smlV*UdiRM\^'UB["!"g"Ge^j5?nRMLgXg:<7\#5R`u= %X"-4p:G&%!E?AZIK`:-S3E?XQefIU'\]!7>$9-uB=Ro$e+CNO0VciTQ"qT> %lYS:!-TCdd:^fuIeuhc4gWrdr<;sUgf&%9^djn>aa*d.Bk\Hs(FkmRK\Lq1Dbf/1?p?%$hn!g^:EI!TqA<&EMiOsQY'pYW=?LKH\mIc[P#Q9>mV:(\\ %O6:hbASH!C&\F$\a/O>9m-R<;f73'NZ+8?cNNF8`+dVoOc%k?2<4[D'"bg,5!=AEELMqQN28+3]k_(KT#+=me$._OMS9(5O7PmTX %bOtI\RtoG;@_7sT/.'bFE1pF(X$J#qTb\V/2dGfDVr4b%d`.Zm\TFNEMK"LH)X@4_*NR9<[;@!@[I^IKB[3ikR\iR,gAat'\$,O' %,MPD5hn]a+WHrQfc_UU@*oXgXco1I.?^RcGc8[h"ot^0@2iZ %lKsZ$k._pcs4eOu%psVVNIsI1J,*,lroXgLqYZ?BFe?*L?@2S1Zb(^:o6.k;?#So4hlU%l54arLqK'JM`d;(-nab(]5<,Z%+8cI@ %Ie18!5JM^@Xj?Fl`kVA#5U"sKnf"[O=rB\V@3I#cTfa.ePFMihK_EDSPe']Cs\Q4F$2ekMP$7n63BHNhUT%\LWI'jhm_)4`L?1Y?me!nEgU=YO5Z&5990oJ+>P4 %\F[<1iLTMPpZCr3^$s>IfYm^TEYfV.rp8K*HLBO=?!SQ/\`hoLHN/6fBl@bLmGG'"^^a=.8q1&ab34DgSW>m^H>38gY:kpE5Ir>* %I.s+_LAoTWjF_ls^\$5+Ug&8S0+T)d6aZI4K&j.#h!sbBpf!YFro-SK[(:JIlG<@ir#GQ?5J>(OqTJ^2p\*!1p['KSjVR4A:Hl>a %f!T\3F3!k)$a[PHbuLkQ.*Spg+.`!"oO\Vej0t$9>l:YI/lT+Ei;#TE\U*H#5OrT6inrTD?[[D1lOW_m>lN`H$d(C%^@[$]^'QI* %o#`o#mU,ta4b*:TpHRCXI"#oYS\KIIpi`Mi19k4"]o*^?+F'_>Q_T+T1p4'aGk(h"W34eqB3u:(`7EPo%*"FpDMjlMZ %-GjYRMiZ`j_*7_G!J_7noQML+)d[pfbG>0Lq<^u<\Y.8sp>F3E^%pUUe$!pIhR\"'h!pjUJ,8o+hYM-YNR+kH^V\2QPl_JGbH`V, %9#NV-r8L1t%KU2TFNth4A`tQLHMslTI_GC)k;V7IpVu\L*hnJX3ZN'/l$$uFLig2Xo^@nbC=]qp$Z7YSWJ(7u_rVgk %s'-%_IW#2DVrp6k0tbjS4C"1FqgU)2G.G_ZE-bjfcZki_T&!V#Ifhp=GHK3a?0!jK`G:+qJ+)iR#2sTLT,Jc6E;&O[J2i/,iV()t %]M#`#F/]*nGHplp+V49jGA[0;)^FQn=%&K^41t@E^of,0a+:/Glb$(Y]7'J!cYn9IOfq9uP.l8RA9cF_SNHL51>_dHlI:k:5RR2q %h#!A+%#4cU2c\maqs^%^Z>[DSN]_p8qWEj%kC0u'DXZD%BY[=tp\*np#EIo@/#RL*o/4?eHVC=X/*hYth9F&>r@>(#o%*QYpD8=i %q8XS\*ksZb1;*;VQ1mHaHH'fOq!!!BeNA]I9&oZJJT!04DW&od+9'R?Id86+,@CAc^H3mn`%J]K&#g0`5D0MmB2`U*kYG/-pi(*n %rHddO"6#e(+4,>!-9g,>h(-oH\+3bt?h0O*gaH!S06Kb]E<2\=hkiGIBuGQ*>W5)2AYgD8bX[*n((KjPAI&iK-=)u%''%Bh::hnAOLh`LGK[nkmc%GP9]Yt#W"faBR' %n]rjq`&q>0E[0uI[5YE4eFrs4JiCQsbq7r4fG)7+eLa:@I\(G@@c7NZKU[I?1+(uKX3uFhj[W[,0W*c-nWRbS'^T(Plm.6C5.Yi- %-fNh35<,.,N[`>9?C4<)Fpe(J:/->qB0kt#EV[:&$+I\'J*rqQSq7Iu1JaCJI.6a+6fK2uGnQ-%GlMc2n<+KPOFI'K5S#,Pfb@>s!f`*n"&0gn3\GT=tcl2uX+4J0C.=\6"`d7)`q7!;BH)8Mj=8^bWWH33n(OnmQ8co_eq]IS&cT7#- %EBV8pfS?"rK'W!f"P6THiMh"]$SU?6qa]@ns7>Pn'3G1Xof;E\='!%_lqBOP&!,P%[aO^Q1N@!_L]0GNH0&c8nk&`*Pp^Y7dn%Y4 %rl.+qcLg_/LY(EhItecB+20]4I/V@[t8;/S&gbVm3m*m\&.lgQNT4kZRe^@:(LigY5XeU,EN!V^mfU%?ELdqhT"P$ePnfcO\D?#6rW!J3rLmHpI78?d]_hH(iWJu@c[S.DJ,%[dkK_&lGo&O2i>ZRepXPu.i@W>6(?>ub %BJq!!<'embH0g/JqBI(%@)ZL=+8GegrppVh]csVJK+G^*oUXDGqt01(f:IKRH2J]L]\cHPHUk,`q&B4R2gq"`(OJ(O^4#+^lTbC> %d[aUG]G:Hlb5Oe&m@u[-i;BYqJ(/d7Il[EWbqu!;)q;(mEX)HmAj/!h]^%otJY?k$ibe:X6f]LZ).HrLXgje29X5CoO %"lK$W4DZ8`jOeYulnNm\*ea"M*2lO,]=X!umc^4brEinmopL7&[=>L+HXPO8#=!^KfY>.D %UHdZ3QX2n&9j-`Dn&+dQY:kS+l8sFopPV(uT-%S^\D]mdp#R:0^AO&0s2h`6fXZ7eUcr-5k7Et,1'V8Sl[MKT\`H+.#7p:kO,k>4 %dldPSEGrHJ0(j^Blg/!9qe<_`GG4PH+5t+e`\[Qb%mR[Kjmm1?Qd>AsHiMYUmpBnjY^Q'@T4NbL1@K-!`QofAtgOIJ#.GiJ*chQDe@%)9R50QqHbl@Fk:8p,-10?Z5o5 %_[iC=n:)P:r:Tj4K-,Pf\9iYui6>%-hg),sRm.nmqY^r:9Y!dQP]a%Vc732IJbP-_P`GY\2uh:^rqZ9Z+2@[>c$q;=?CR75BN;fq %qYPt^s7=Rk3u>0$?G(7ErqBc+\E7^XEoGI65Hj&/4`M4YVL!.TQdY*?o/D0oj2Rk'Y.fDXq5FW(I73Il:Z$VDkMf^Ha7@*lH>qisjYu#rqX0'<+$K?WN:1][_s8-4 %h@/:K\G#pXgD@$jrqmjWK[s9o]]cQa;Hl)l>PIS*.t77D`TrOP\_XY8Isd5!%@*,ZG)W`ZZ9-u?,[Og*J,SsDWX"kj+*d$o>]b&a %WrBY[#p-J.Hi/^7pnOc^r8Z)qLUMrp=k4GS.`%`+i4=YI-S]d*i4ApHPcF6>MLku3T1r=1G""^*b%FWfSm>4G\bNZtrM:n.l-H@S %W#Ol5>PpG1!u5`m!$Gr"u<\,)0rGe3Zn&P(2_U$X]%_OHt\!f4[\OY9(CJcG<;#+7>'(n^Fo3 %V<6,n.XFRVh9VfUC^dOZeQuj?n*TG-_&Mi!1QH@r.[^M/m5p["csBZdHMba=)>fo!4EQSMNJ!_h^@LUJll9?RRSnWdXcTPPU,RsH`'>-6hY7-'($uALT`h%GmGHN#M;q1a3 %Wk?n(?MQ*6%9*,gWRlJ!*m9_Wig].Sajfu#4ra2?g\*%*]33RnY %@o(jtgIKTglfEGA"'QlM$K"e*^@V6kp&=bcM*B;:pFiMn(!M04%NOP5EFdL2hS/f!DK<1O[>7E/jm_[;l*: %O8ZiW_]Q'&\7nII*?X_,H"CaM]<>(R.@?H/fY9WMgl!h($;OsRf3asGrq[S;c9H7)H>WZWdF%:OcS%J2A,^b$pW`Nsak&Ip/o#]U %EfuZm?M;BAXEtbDj3?2ZhS4F/dC4$9*Id[!HX8iWl&F4:p@iIZIfCci+`X3ZM4UoarV7a"13.)L^q]R8oiKWYrSWHT,n^L-qs2m?eSVsC@Wr,rDWK?uJ %8X9=u3L)&3pYlklr"#Du5n_#rUrkKa;h5gWk3VdX%pfs,V$lPd?`\3>(KX[K*aa6dP:Lsfmae-H8h)eo(6qjk^\+]7QYobV_rHoi %/A!LYr/W]UjM9[.qsl5_euc2&7!u/Ns!nW4iI('!A_=KL];u2*d]J/nCD*:-rVgp=dq+2Ln+Rm[hcY-[m/OWnJ,74Cr2p"bB)g0^4,`gkkFG'=e"?Hnro;i6O+2?:s6R=. %p\io$^KPfqa86tIAEW]RP5O`S%;pZpIeUZRFo-(HDM=*O.&F;cZj^c!oiuHaq&eg^b]]Qj87;KEMM:BI1Q4Q#<%hb:^Rc2gUebRVteGI`5Vft:M04SjU:ta/f&5#@[:_qD8(\sTIPu-a^R.+jg=,L#1co3V] %Fscn?VU.@KVO3%h!<`c>'C4]HB0-rI$R#nFQTdeZ3YfKAKVIWd@7BsiOGdZ8J9@4$k.+6Wg;9_pd[/RKVQ]^M`W"DA.r=i1Fun`L %VbqPFa+0k;H*mO\e?HmC3U'B4V/5=t^D`"\o,PfLEb)#b"K`B-^eWS@nVPO=/L71mdU]F>pD8KYS1jYP+0CSU$(+u?1'(rX_KBSW %bB&D)Btd:&E9fJ$_Z9/hAH,p6:;C-PX;Wn8%F6G6gIX+,E39j\$Ka]\MoIY'DnT5fL=Z1*DC<"Pg*O6hh@WB %SdtEN^D&k541>DFs1ZNqn_72&1siB.JRZ]Wm<,,[(4E@JhD2\%CZNt[fc0AHFCse;CuC/qiO-5/$SLhjMfFD&I_%5oct]:Sn)>OX %<]Hda^UFN2,.V(gWq;jWE+#q'.JcHC-j7^d`,^i1Vc9A>mD`m:7oT!lu#!nW@g_oO)B*(0N6!=j9P[Lo*AR-d@)F`YM %^<\--8IG)F&1m]O=9;(AkTul)q')nu]XR-d(+;:!k`DJ`$SG %rC<*4X7*JhI7i5f^?;:4#^rSA9`&I9qFS&DQ=_18a&o;=6S)+9&/@it]mq+_Jmcq=F49;[P#-iJMl>A< %f_mOoI:$?7qQNJ*gRY%Pn\C+GRoSU`MHi.'8%VaOkI`&"N.0]qj?0p("gWq\kOQ\qD9Kq#'=?g,K"18]g?psg4[*f^:S`K`>t8%h %P5aWS^?@9G#pr#JiR4Ck^ii$;$gK7rQPI7n(U\E]i`_ab#re5DFlNVU&Tgai"HGo %+p`1KjON7(-2$(DGD2>)NANZ+JYg*Pb['Nt:SI;Yln0Rj=Sg?L5WM[7pQ"nE4megseDp/?s$Z^Mj?e8Uaa3C)5(W^Zd.EOcs")EF %ra"@-:*skl%u@3mdksd9^//9C;GCM2Zcck+D"&"%oeA%Me.j&+Bik@U?.4oH`6tUkLn^E`e67%lC)e4ZqL6Xacu]k0!oF5^Zm0ff %'ZJqd=K$EI\DElTG,Y54Wh%Hrn"(QanN!@o,4U)6Z2^',5[R>f.W!18l2[Q!0&iNC8t=*r2\WIGG6U)1k_g/f;:nt^3A/LL %ETOf?H3=KZK<$rm.Wp1kkcQu[Wcc^CTs.s#As4q8=7N[QZR(a>WQ$<@;>G(5M %V;Mm8hoVHo4+.>g,)20HI_V)e88-%mco\l+-O,c`hW]%\i=PKOmHh6*-ss]0>&.)+3Z*8<]7?'>XkFp'/&==))85iqdDq#$1TjKE]8mr#CudZ5hu`" %p5^juT;j.S_BhO#DB(r:hEl>'l'i%R*>KVo5[>P7!qi*aHD1>d%TTF1p1Z/7]j$gPfW)VRoa""]\2j3$h4R+Q?Mht]Fg*oU'q/7O %='PARhnbG"%1F/5;RB$6Z\'lBTkO#h^]A0UWcZ;ccD3b;,ZED\LCg&`kCU"4/iA"kSdAub..-[;2ia0#P@jB$C7L/@C#'UVGChXd,?+B:CI)*HP9C@lNP=)(Mt61>>! %ghD7RjDU<#N@ndf.oW;'0Uo0=(7`[s&u/(7OE>rA2qcjn21;R,O,f:OA8h=ccGMY\bXP.U6NVG#k8;ba!\CY6>9)Ng)m\>tVt/OR %Y4p;3oemB'dE"_&6!gWAgY,aBH%,:lW$jJ'\`=I!4%,Bc023f'=o_W^:1G#3B+*fNEPrd-/jP/d8Kd3UlYLcpPE4#PjA,TUBHqS\/*MgYb?,10LD]#2"] %M!/6N>^#lZ['.2$;_)%RHn9uE)ugP>/G8:>?2(00Cg#N4lAb4[)98TcNF_J!,/H<.(S1!93`7Wi26PYB?_FYm)Wt!G8=/O<[a-+; %,4+87Jdbt,bpa@li8(3`H1,%@nm$#9X_UYDKc"PR\mRQ$kTm]MOj2%e.s*8`rj:!j*;(V]U;-04:@oJ7E,[mDMUJN*W)Xr`9OD+^ %MBBtn-_YP_:Ls:#EnBRBUR1)/N6W.OI#^,-pra\VY+6?:O+Df!:Gd^nEjsjL_2>3[_!q:TeRMG#Biu#CGE?$(]-L=25\^aRJrjm0 %L,(WXF$h72inX^TF<k$:#Vn:l[s(EI<#pXPh_WOjs>>nNIXj+8O_3ROh*PQD1=Bc3H(`(%'69Tf'W)^BYE?C7p)!>:o\dX)r.ZbcU+F799[R3LLK+GNuD`qR-\(oARst.LdBgPO^`KB;3W. %=GY':#uZG@_K)bjqh2!)"-ILI&@3)8*]4d7BYnl4BU9u>-EhTH8kD:[J3p!aZDJ%a0X71_cWQE:b9Jr$,U3]*IgDTV5Y5>Ml=N4K %Q3F7TAUY+59_Tqpn@/i[S#T3LED5WKD+*]/U+gLQWC`t-[B[.6`KO<.7(UL-])]BI&OTNLVM,p^LR(6dWb,NWl4p%R7:)8W#\lD\ %.A&D,]WcuSHWLah4n#js"\7bC%k$]*JXi/eN$&C\#6^gej^n]?>2md^lF(7NV"%$DBMMT0kdoD%bTQa!3`JPHFst3*]7lb)Z#C:$ %L?@X]PSe1O?#c"Bo).#AN#Xdi"';kS(m(%#9:?tp?gX%]:-IcnnJ_"M',*TG;Ro?S+)b3MDbEkUf2so.#4+\A&-tb*8\%B8TY.kG %TO='=']U6:Mk8+pQm+f-7uRT3:IPkuc+[B$T%G<;Z%\opGQr=Nn5&Z4BJ=%" %;"[hn;?Lt!XD`3!PG=J;_kIi3B[R?VNZW2.MNl)L6)^4sW>&&$#"mlrfjGsbq824*Wf(u-F-]-LZZW[@@/_mj[K(HH32e[0c%/07 %0Q3u^Wj9!KX+6-J9]0BR%L4(7>+OIm>uLr%4-];:b_%TB35,3@VJ[X@6$kQ/]^T;rNi)'"Y^YZ`,n-2:B+bu%0c`\AjKZ_*k/KtR %Fq#lqi/)tVC8b<5(6TQL=^kW@+_+k/8\BVu9e[SM2C;tdaa#>D'37YeooLH:;dO$uUhGeXeT-N-Tj.ggiije&)CbNZ%CMMIB4Nm0 %[S^col]MB8.DK*tjpTc'S>PN_.a"o"c.,n[d+iYDU^r8jh\uWlPC#j-(F>i2>>9+[&AjeUfc)tdSUG$5l9(n!'^LqS9ar5n?q?Gi %DF:o#I"JYo+unAG_'[m`aXOG5@e-hlkY6FQKS&S^9AcSQ.lH'n-NX %&n=\4^#X"uU)Oul'has=rGrYRR$_dcVQBMseFLF%e>+>3Mqat"4B,_M_aQpLi,-UKog2ip$RH!hPkPL %/>F"hb]3\.etA+L8igK8O?/m8==Z#gL)%%345%?:`7h.*F2WgsF4QW.2^82'cL5_'WdW6Ik$&)uTrJA#PLmAdWslsd[^Z0GiNZ@^ %/bLN?D<$7hH:%D0aojBOd@25S%("5am&*$/FIW2#oJ'od+>nFH%)ihnog.]DJh/KWT%%nn: %I9$4f(^*!@fNV"s)6'o?]4!n+PD&>'N6-0HS^-drT_;n'$@&+Yija:"^8Y"9'+>/Ge>ZocD5#[+"tm.q/>c/5,LN$[&eAC=9TP8u %kNk65]f6B9)SLghWT"eh#;[bhIYa.QF8!)VFECh^Zd)p5m%6Ht5]*sq-gf^Ho4Q@U[!p"pa?(ZW-_t]InU*$ASNDMtNcsL-d[Aum %p>ltbh5;3PH\\8iKN5TAL0,N/nUBMk%Opc.Ifc>kQGZ1ld@Mmq<_#[I#/Z;B><);CKp]0UNZ@_jA(\on6P %4!J"p\A/>+"$m00a@(>dN'.XjS9-So4r6hS]W%uSp@n4%)((n733+PW/^Sc`,R5.AZge6*DN8<0-j[oGiX![%7%EKQ;[?KJ1?UVR %)":WJJOq8-^(A_OK%=Hs_lI&CM(9:h,*Zf_?.[Y@blOiE-7IANm;b'8U!1j!&e1\_XjPQ33j2n-_`ou(f:agg0gfRX+TY+k6>S%,;9=n#O=LI%QYA?Z@F4_M\.ac-M*RHbYdrM3;)/'Jf:P^O2WH(_'u(HSF0(:lKW&$"T:`K %SGST0$43n,P/R3%ZXeZq27UrWI'oA`FmWIEc;g=Rd%'sFkHQr:C92JChJQnr\IQ`tSh\.RWW^fO;RPOW$1_hWaM>Z-uig/rF![r %%Mq,0jWV0?;b2LaJA_m'`^=OtMT%KWnI,S^-?,^(3AWg\J]Vo+K>NhYd#pdS$X>qc]>4TXSu"TG'302^cSGVgT5%P5@Y(e&lduFT*GUfnSj\A8q'!7*F)$9h7b;G^r'DFY(='T:2FGOp%%#7'M'r\O6XE>JKnEJL>L/c-@p9;B"X`2g %!RS4(,[>!.M(?bH-Zghs;A7.D?mfA59BQ\ooe=rkW"*O[FgcjA?.4`H%.ZqcX[]X7Je4'+jU*,+/Xf/-_;HH=:!odQ*MnGWW.p/e %AF`ntWaJER$Zfo1ad,@o>pW'CS#/c'En)"P6$Aem2E+d]hNCSiakQr^\.B;FK"7FAno3-m/rq8,aAGNV=eG;OBnk4&Yf<^7k3eqj-d:1oH#4hqM!;0= %"_'_dk/uN0=>J'00Y^M6^'^H&HCsu;S*#e5>5XJmE\-/@AhYD7b_%akV'1ifJP;%Z4]2IdFq%1_4jRSW;N'f@!cREQEVTX97&6V(bqOpKB!AOq0c+MXFcMGtPr,Z5$-N!<.UPMUI5gQi/@2]+e6)k$)6T[fjZU7(qLOC4r_I6nQG %.=`>gVP]d0k0ph%;F=A;U"#h'!0V%V/4dpG3noniVQ%i#0i5c(<,Kin$t8a)V^F^\^*-e3RCq%%':g*m>8WCKr6ZhUF@^;W+.qn` %L,<:)2RQ^R#pM6rqa'4-3"*##69u[a"C%fb7=>;9HY_%l<.mk6^4<;Jk+[__8eHcC],[1]6`MekF %oWhkd(:D>OhVFWk-n6"o2d6ZOkZ!c7'<+bSC<(C<;K!t[R,><=-^E@:RMqKIB9n*pUl].dW_-A=>>3J)AZUgOZAG;)RN[k.(HM=? %b$AG5cD%j#,^U=#n;DVN\`;d?e)6`^E:;&-+8t#GS-`oRZkoY!`2P+AVs'GP;0.U5Dk#p!.eY?MTlnH>Afn6'KVJ_E#q?YI/kKmup'i.n0T`_HN=4iI&P"!bb\EYe %W/5"LcAd*pQOpjEC+bLE#CLd'b64Y[iilV"LX)(T/1*\iZ0<4I"bafI\p62lIU\c!YS#s4$9@C<[Hn!+S2JEe2uTf7^jV@9oMKRL7'c6ifYcc^]J;l)@"Z@-fo2jNO-)&VrTfo+lTa %S#jGL/>@!o3KZ8"8D!GbLb%0`_3?d%[D\pp2c2eF)Hr94K_u_9)L`VVag&h$(L>@)HDEjtD+"A[l4'tcj#\_4Mu8d@ %6`[\!,psHscmV2!Hu8h_+2F0Q&MI%eJi(q8fcCV\Z4fmV6qkK_^&Mm-at:4a.a;h(9)&W!Jd?4^8l-@X$ago %YRt_<8o';Ao7KOn^",%0cIp`i;Ln%"*KL;P-N%RiUL^tBBXUp/i"&$G=lVK&#b;;@?`S:`fGjIQc>3b=+n-ZOsVDOcmkB8tV]j*I"VYia1jM=Ls(g,+2@W47F8(mAkn %N%uoID\Al`[(#1e6q)_J_X*a[RYm;NV:@M]MAK/2@e*5'E+Xa/dlc*P:%Q>7^]t"1kc7hl9MoRlAf7CSmWaqZOQ)(l*/`C+MN0c! %Xje8Z1NOYT,\$c]$F,IAhSc[-RB`j]Y/k*NZXFqQ-o6M__OE58gu^?$fS['O=]a0ACmdp]:IRbf]e_.C!#)$.)sEYk-5]R92Q!:l %a:Z.2H]ADOXAV]Z:5:HB/HL"5;^[Q)MN1ia:Y`6b9&IXOR)%A"B!(AQQQll#iA9g8cb\E:i %;M3>33JiRe=r[t"RM%G-1HR`Z#$sPq[qLS7OV6/m0VB^FK!ec#m&[%`Mg)a7`18aG6F&pn_XpKDl7h.YIrMnJ@o7Lqh8\#Y1t'UE %Ti.al]Z;3<'Q)+;b*s!LRl6p7#TE="-raeJ+\i]f/DF]5XJi@8YqD@,?E-1*O:/pVk/B`Nk+5'g!a/?Z.O+/jL1Wc2d0WLBGtq*, %UWg,o97/$6L?nFFWhQk,bgWW/X,+)'\Se&1adWrE8rpU_&I)/M$Q,b$]i\#KJZY*S"FX>EPBm7(PF(B*Sl:qH@qIB[Cpic"(]e+] %Mo.okQ:9!`K2V?j!=>WoYT*qBW+mEFEedmM;Ou:@'>YH\Yf(s?fUG"MHHpCjSR@IO7T:^&iI_BR\ts9^FBk&E`%3Jm(D.0rq@K^X %+7m`($/sZ]OEqo %XCL)^f>D3aK$`lV`;3^XiFH`*fn#ghPA/NG*'HZ'@V:WQrD1VhQ.L#Q`DWVSI%V[g']U7@QJ@9`YHs^;Yb:*G$HZEkf0QIUPGP0j %R[bBI*jc1%g<:\]:7iIEabt.`291V0=IP:ei"P24I"f7K+?.NT2(396gjIV4>l)i,DX2CAN=g+7[o^9*%Bc2JQk=5]]Bc7I!K44b %0tH:0(YrO3J^uGhZ4'XYG4l7L8\)ZlnZ%\B:+N=WA.XYP8spUgO_#^,I(=3hft^1-,[ec*+\!@H@,BRr2jeu=Xpg5:Zt9\Xo@5T1 %JC2!^NMl''/^o!H@l^`61)BgLF$hq21H^?38r4^+PZU9obnM1=CSgq?DC^3112u>"JCX46`iF,BF61ORADB7t`oU-7b:5cdP';TG %0VL?-;f,Wn%U`KLb`r5WCY^5_6_i"%8q;c@.0ms[ZYJ>0S7q/;/Vp@EIj,B$R`B#B'f^bWcR"W[9<IsWK+SC6>W[SalX%GFZbI&R3C%'2P>:(#o."O#uVA@]L"FL %VQVV8#WDEp;3Nu!CIqp-j_T9p:SukmjE(s]*%.$.lSMHXnC=CMa[70.dCRt""YDfq"Y'Yue$9N'"OTc8@\IF"C$[CFE(!lr\kc0h %PZM],.[!C4```%QdG*6SG1H$GZocu?M`T9V;e;JYRQegqc!f)/K%jGFAcP8p-C]Q%/+0Z;8?idMla5>[S#83N?rEB6&?-29R922u %Z0R7Fe&"''8#qZaZ3VTi[]C21WfEA+#d$[p@*B':'_WDDM7A#bQGZk!FNXQMOG?_Gs5ek>S>2;KRmlBh8r7m2P/S:a8suEB?u(u^ %+TQ+i@4^7`pSmM];9G+-$X31bf>"gP6$P8J".J8\Ce*PVPVNua,AM.W;Pp13q\l;)@(;qg]L42IR=[./V+amM$Ed5u>j%f0%#\#\ %Woi%UV+eBaXJiLg-tTD'.&Tqb$!F$f)c5O#Cs9ht6n.ZR'[/k:;+bp_'[%(Znc`@u[C8US',-7GBE^^BPS3R, %9Y[hd-0S0rGpsT-"LW8iZegkn2up8L2[P1e_Wg7[>T1O7-1:9$aZcA8"l;$oHm9&0J\@RpPIgsZPRX"tPi0f"0hD[MG)3\]HY]!( %=`M&69UVWH-XFWS]UC84F=OiPFgHfOV\QY[.49(o8L?[/aE,-W^i4HGO%@#ZW4;Q;aBa:h>4m1f'mV %M%\,1Ru&9%h1Wq363ZS#u2>r(CO6?A4=_ok>9EN[)PpR>,*WaW"Lq1p)HGb+L/8uM;k%eVIs]$6Br\`G]P(6 %ZY@Siaas.G<(V,+i="`p!ohD7QrWC<+UqFh0F:`SXC8A+IWSS\-03-oE1D4CPaOrIN`[S3W_7Gna%*X/.h`hd'H9B1D]^KCeiXY;[3[cWXrqrSf4_Z_n5^2bu1%g]&@ %e71$h[r"bgR*=Hp$d#9[okdS/A7Ga.$5BZT?4Cpd %jS$,=a)]uJY8m/M5/:_D]shHDXi+XD3TA9Mj%55Gj_qn'Yir"J-g!^i>.(U %6tVce=-,p\fp]BB;#DQQ)QdC:P,!]sSQlH?,#V"PWg@es9PUMZ7[YSd9FQmQbI*'=DN@*6a$?Q8er\n`b!idT%4PWQ'mUO&eI+H1 %/1kB4)&@n&fp^M*;P61DjT5X,;FHLk^T/ZVMEj0`/Q#.ZafCC[nOX$9c;CmJ'7#=5+]5[<#q8-]=TL,+E;^(U1)LIb&lS[,jDiQe %=@:6aX$!l'er\nfTZEH<;Om1nOr@5&N(sLB3m]EqX=,qU'pg5,_T-]Y`&oe\0;Jcc4q-B84b:tM6,#,,T,ff=Vq^,gGUOnk/R]U^nqjBFG9%?Ot.L+<'Q6V\@F=YQq'Di7;+\PHA(BS.\g03._&cre86cZ2'H'S %8SC4?,a5GZbQ]Sb.O)img/5MVZfm[`C[!6V^5^QIAJc %HW&EM;7`a!gAK3P9Y(G/)lT$sA>NohK7fo2>j7.]Cne[-9'oZ[#\=DaV=L*VNcMEqo>KNi3=:l)5DrIc@uIKnP?&&]Ojhc7$:dro %"\CGq_GT0W?`0?HUV*[VVd`CaF'MqpMYjWtSZGi%I9HtJl+.jgnO`7&,_`#%Qu7+kiBiR9f=,EnP-cKtFM^"2^)'37:nGiSi;BqKLk!.Kc@.3P\cmVPmIXcjAfK_jKKhK:tO+;LQT3gQX"Z(dQlZ"d5PL9-Qn`Mudn^"O7*;biZ;+dFp2S_t:3W_kPXs)A_ZOlV)oXVsX.-7RWC$ %/CdFT"Dj!g^_;'cCTH;=_VDDm7f'Pn.BY:uP$rDhrSd(l;2)/DU:9G@j[:JeNa)+(uc>4oYnG6Bi31 %9dsJg;gMms5Ki":5cRTC*A/=s>lD_^e4s%XRu0DPF_.Y#Q?=G7!Q3"$Z.Tht;Mr32lWchFX@ZaKLj:R=q\cDS>5iJR!nAKq,C/A" %D^4MoH$#W/Y`MSnZ/?'h.!XX8k_-GKQeNSL1R%L.GNSHW//@C/)I7lnA'E85&S0ZgM[`"U,n,Yj]!Zce@Zu3HW]/L"(cUrY)dMN! %E"s<>Lt72[]j1os]\_8!.ZZp%k/CiK9-AA-mS7%2]ZPSF_WJBS8r\:O %h+_pVQLkT4S@klu--!1YBZGW5+-@cR=l?7$In=FD=7qae!"):7Q`#Sj=.(,t><=\2("8$fi#9K3hdMqVHC %!QKg=[Pr-2WD-Gg(n4ci8QSX/3[5%Gnqtu]Css&_#Z\Tm?r2$.C^Gnj79$0QDI&rF'aM0TP**'>L'lPtA-C%I/H-?j\%6s,?NDdC %ij-m2d[jO+!Lg+!;!c`,<^K^!8-n5`8[#)3JeiK>[3`[\Og\I781I2,*u<,4\0fB(am$5ol=5Y>ADKYakK5Q;\iZ?.$LAPQ`2*K% %Sht5C8^la+gU2ejbL>Pi"HPJ!\sM=npCn\WJo=J$q.'T%Z4_).0;`c2ThB%,]?d\]+?\)^odPf3OEWWeJPWWUKXK#m/#-ju7;(JT %F_7^3E&1N\nO0bjkl$i0-*=0tPn4ZNc7B4VQa57YU0%^LY#(82VlpRaa[=?'HhsD00+K'rPH2FM1H![g>*J0"2(si#RO#=%DX9]! %LsdTLOh#E3-^cD\Ha!NkC7>sj/uhi;IbTP\EcW[jB7u7g"T2HJY@-3!e.It]ebkq0-+4S"2`&e:[(_,/mF""j"`W)b>cklE11cOl %(0fo1@tFrH#:Wk@YCtG&D3dR&f+U9)3g6i7X3n%nQ>pE^F#2hp1YI;Ah`M.aj0EOhbUPbe@j#?pR[9Upe-?,E+!Nc\'fMpga,SD0 %3qLWk*cpC3X#`#->GUDoDLp_1jP38+.pQ(aO6S0VSQD+af@\9@]:5h$9i!+a[WG5s5dNPMWucEhA7";.W^i"_J4"<"T:I-Rp %C0t7j]K3\t7?5pAX",#USthlR2L-Hm4,tYV_4n*cYa2A&m8k1*)X=u?7#-k76HgZ(Y;53:CcFJ*j"_lS;V+(;aqrmiVYR>l\s0f@ %4pl&D]Q)qj;_%C)a5[N]4YLQL2e`^;dZJD-^_QQ*Fn,&s5h/0iV@c)+dSRsF'P`(31u]4,)W;FIJjZen`.M)J"pIE(M'=:C]GS!N %eeum[e=o"cRJouQD?m'uM>&:[oM4%q?qSp`(/gX7:+ROuLj-=b!%Gcji+_ir2]FmfoW,@WR=.>Lm$l\_S"4\D8$">aA*--42^;us %*&?Yh_uV&^7*X&6@n+nWiK:tIc$B$E#bg&c2>Wh%f,V!oK\49f$t",_gbjc3o\pE5nnK#UjJJUdS-LM>&;BTsaed#u$p5\HXP(P( %:*tfun/O0@F/7F7:O'`,/$%#g/:q`pP8X0?duOBcf5YeTH%\Sk-jr"k@gpLZ=\ap:[U[1N$&Ef7Wh.f.9jU48m#I!C@pF.fgQJi0 %h!)UD`-%jk&fAsbm*=D?,"JZA?X;`?e(d"jKhYMO#>LA`YQ^G%nttZf=nc9\k,PmCWo8LI@ch]/T&k5JYB+"PAT!_/7V.!'Wj==_ %,2V!?'#sQO"]#8#^9De^H0Yati&QHS]uA*Q]mI(%D8fO')DG/k=!q1qEsPA`:9g@6GgVW7fnQr=?8Nq@-bC.U?F3hZRk_QhYthG[ %o:et;l:"(;C,.6AiZ!?a>`HbU]C8[?e?*%6jOsjnK#G;k^1johO2[(op#;FRfo6d?im#0eNJ8m%VR21!%2ns[J6UiC*D@B91,g*o %B99XN->7OsXe<2K@aZdf:]6f"S24,NI:rY,Q,td*[:&q?9!1WM5"T!1qr9D='f4r^!uCQ;n`X9/P@?Xg"%[@Ui5&j)P/UR_TkP]e %Zt`Zh;Oee,Kqo@7-4IblhP+KNF*b+('sRuXURea"80pOJh%%eL.t/Qq\`>p3[(HrFms3,(;VbDE7?Z:m"j<\/7U?F %qD,pX/7\/03B\cl6u=9VKGfr0>E>`KF)Fo?':Y2M!7fr+Mh1%DXWu7sB3,0nZOo,md'9e,`"/fXE1092RnD&200]Y7EgCD$YfD:S %olF5\neIoT+12-K8XYZ(#r&neSK/aq5[r;9%%fWqMYj9'IpYH]ebrX_c+s %\Z6:uKLrk*XI'p92HIbO[Ja^""0?Rql;2-5!3-oPo0DWp$)tM&:",unaZ@+['k`j"\@K,B=N&L#FcT.]`!#nD__]AV3k)!+kPS=Z %>o19Ne2nu34GG9);V&*FX`ook@nu)52EtV+-["J.K,?Bq8^mN9UP'me,L+$F-+VCL1'U_`,lCJ\W8fmLOf9pDUs1:=jNc/\32UO$ %^pnSEcu=.pf!R3/D-\sHoS0>Q]TOF38,SWS1Gjp!JqNi6CP,($XONrR,'VPk\LT"c5*0Iq8!HF->;W'8lF-kpd>E+8;]^5Bj%Q/E %V8BQ]dH]mKEWI(hS#`Ipb`XfQ0riS&C=+0\N&/pe+^)dISZmCBN3?u3=\j9\^8`&KF74tj.Anm7c&C>7[AZATc&!2lR3rL?B9lW" %--WVDQF9hF$n=B6\'nVVQJ+TVi[^rrdc]2O7+UP)\e01YHDd%]k:nNVF>o2%)1I*M:)<@:bqlg7:$*="`65;-<[j_BkZ<(%d^o%J %Uba0&M)GkBlZ4SCN7M$IR_H@Rh<<\;RpujW%o6[UX?NLl>n:H)eo`cCYgpXZ#SGV>T#e<+'3SsEahP8BR,lJ+4_9%$-XQ%;>BhiQ %;cS0rA^k[\WqHE=_[0?1nZ*+A"BnPg`QE2S5c^hQQ72I8A&?&">o:%72)/G;KLRC%(4t1*%'Uc?bi#LXU!@8Xr9lH"X9P8m %p7+gi80RQ3R0OBb<#IMkbsQnC=@HDb&.IT&/W&J[Am26]\kliJ\?"1p=CJmRbM%B#ZCaR:H$p$1oFP4k2TE7h[j\k3P4V7#9m=B9hE""+k\LZK!O'el6lMgfTo0$'$KhZV=mM.m=J>/oh*>1t9S<=taRu5r(]+5,Hng7-'tB)%itm`KZU'Vdb9g %U'tqKc;k#$&s8Z[`Njq,8]P;\C)O>V*[!TY>X^>\5)j+"=oBa8HE1/5"KE=XoqSsgB!8ZeqA8B.'51XT.lDpUe#mhG(>,4ADp]ee6+rsuI>WBHJeZ\`U=H@_C")D47]@LVahLkZSl*9\2r7.tO`nnr2m'VdC"t!i(2t*ok#fD%l_ncR %]na.RAM#&?,t4%n>XF(9EL\0$&lMC_%:ea`:J0S5ebQ&["-XG>lrkU*WOqFZi=&_].0$--X*U:Rd3OWRCITA %67PT;&i*hu.5;G`a$p4]l@0X9?7SP]C!;S>NLON7qJ);]1f(T>phGpn*>>5=R=4b&;X0]t:I7UF93j&=\P:@k0hhl8V)2t'I7iN& %D4GspQI!`LN"oO:L9-/iP,5fJ^$1B3[]J"']rfWuX]SJe/71!9U3#(RS*R!k*1`Y.db$^@81BJ#NYI5lq33mSGVJS_%UrBf76p?1 %^`56b,9PN]RAb;S[X:4!5VAg(Vj3Ag2SS5t[ro3S1u>:pcM+,8Ju/f5b?(hjA:Rc_?r^DGl)r..Q8*5OhAgpa=:#O[L)$]b_?AN! %oV*WscAkOl(%`uRDl^oeB)*$p1*he[Xi;pVB[5&A#_&UWtZE9HOO:V*h3G'7Y9?] %OJJd#eldXbA*c6'GHD<8Llh@$q)"pI*]]/m61[(Zd&%dMWu0_NQcRqo0GnEH9.;?F4I1[%sRrS8dck76`Qm %X^=sGaN976oA%%Hc&bEf@GQ]T/u0K73a5LeaOP!*VohJ=o'&bTUh3GZNZ"`k;L<5E;d(V&AX=1+\9$eiP?9`r-Z=o&Oj-jHJKLP" %^6,a2#WhNa2Z;ne*3;:dAd`!]bgsnuUOMS,UN3 %&,njOaf\-:h_YL'R;kOtb78>Bp=e$%MT`,d?$#u"W'@<40HURfX[HbBfq$#R8X"eKS\a*G9IEkM78pTN^WVpo*%(cMPBj.PO8q)D %3\!U5;OQSbXcCDdZW;Q$PMFp4+$$LUSf4r"q9;Eb=5(6O1p^lf4q59]1r^g/TQr0Al8mc^Xe-kr<@$jCbp;js?j-6&S_$\R&**>U#'=Tgc8M'kX)'T$ %?L%C22"5[SD5EK'Cs/6@l[g4C\'4>u5Fa';D>4Bkba.(T/YKqC'/DOk_N_mg090U_7M)-][PIlcN#EAhD&o9K8P5R7d8dL=<_tQb %XL_uLEt`D2YgO'e[(9=UdB8mDpbLl`aKB6"G-E`%7r+$d+\uYE3$Z7K=["B0/Zgc'+4Y*8i?A).VA<;UV,iF^Ss#neJ=`>m='grc %9)0>2M+9][3/U*q\rF8RZ_W6W4g$&!U5C7CAW(Fqc+pTI.8HW''B7Whc6*W\92d00-&EA/FP]+k)?=/kOO_;#KN($\,W2=S#%@UO %gC(AX'^*C-D=RF0daD;C9(TKWAeu/+9c=!@ija0'$7I=A9YaXo@905TV_ggH[CMX37$K!)%BY=uk2_R?XfR?T%AK-j&s*\@UfEBs %/);@BN3--]b04Shjg$!$S26@`ZL4?^9>m_Wi^ekOJ`sYRF49qD4k\$7PaiNf>H@ACW %cP/rQp9r"%%2'm!O+rXYLlta\\US..kS?MFluWTUe^[C)lW %Ec)a@U/V;4EXA0+Y"9h/lDfakaD5+u1@bGhg;]$aKrt%Y.n"C:7mN4TS&\-\W)I"BO$D1n1-A\`djN*"IQ9^<%%>kdRn0_MV]4`k %espG'%okHW>6P"4#T0A?c;>U>F.mUuWn>7C0cD7dTe$4!g)WmM;53Wn`F+9,'LLPk52]^MI %QAM8MFXV(IO@@8PJs241;D-3&bN\W@6W+pS8`$J$]sKg7F&\])jN,a#)[Z4-FXUjC05G\YQ)6&gjTht$\8a8h1mq2^lC9_X3[HSB %UNl)_*OR`A7M7CNERE?_I,dcg,=fso4K1?gVdHVWYe;Tl%\f3P0Jgu:*-&14WBeo(EN9Vhgd;g7dt@2'(@uLbH;P?:c5ZQnS'$XW %h:C8-YQ;EW?,@.L$-2CeF251"aW-J)!N4PO.+2TjmF(_$F26bnS\&tr359ocm#NZfKrS;!m\2SFh!X!ZH&#/R4d.nDK$M$4)@h1% %V):Np-\q2(LCh@>)lT]WP)HFVj=."@0AmHf1&E_d"_/j*LaVQOnaRju;O= %-A4IV41&*=)Vi9LD6JReY.3LT9TXoFKe.0^_EGG8an#m2k2ktb-p#75+b3[:o,d?0X=RPEEJ>+&2"4c->_5;`KYJmY4Y;QeMH_qU %0+$>P*B3_;buE3,+L7n$-[4RDHeJ!;7:bW@KLT:/@sFU)pB6EJ,d;6_P"$c8V#s$n7]dC#C9]eX))kNEoQGP]b:>0W'C68mn3##;YN^%"JZZ %M$[?7[Xt/gcs*$9YVk[+80Gp@ETr5I$*4P?I">b$/I;6.@!!]T9FD6Jufh`?L2OdNX%7kPXUgu+/a %:lPfKE["hgDPOEt6ddH=Js7oqS2%cO'/E.dJITH9'.md]Nb>1:p?b@Jeq697m"4k2t %#@PV<1!k\ZI*eXt810!sfIJL:OsN7?krlt=PsuB=c[c=Y`#Bq9Va3C<',bLq^AX'=LM:M[itC46RH)? %NjO&Pgs2X"[FBG$=nE!L^&D8u)S$kfl3Gn7iN#X+."&0eFW9G>[IOE[D_[:Z:feeRgWNdh#[g(@2:1@p3H]Y;rB8Dd6V*q*/IRS- %#7]%"*/do$(n)0//rSTZNCtDSIedK>?^bh/e-Ik9j7 %nG_p'pG^KcCRlZeq`8CbQktg+g.gSKZ3=idt"'-P10Imm^d(7^S&-5&miel=IK]%qg9j707 %/HnhGAaaQpGcKdBJK/.5&Mu.EG8qE@YSC>Qg4YmXM`Jo/X9.r45t]<+Al2W>]4IYePMfXd\NUN08pO-S!6uhs)YgdP4[R?NP+nsY %QtT&OgUp'-Bb#@1"6-/:,[=u69IRO<"k#_'HrVFk'B9`J&;M2JjH]egakigQ4I5E0(:5oRdb003(aC.Q^up[Kpq5S'#.SpXi6=J- %hYcX5iD75fo'IP!]6h4YQhI)fZl7`]h1JKErpeGj5OMjhET>=(j$sVDrq56ZGkU^r[Jo71rBHN+;%uTHFs6c)m+hGu1u1ljs%"r, %..;F(9(ic2e`0-:LeD1=ek.kXUhs)Y(2 %$1r_%VOp9VB5-Lj*:6_EY">)D"$Q/kqE`m"d(UgFq#_S9NdFQTh6C!=I^ICY]@"\iLp5@5%[%mipIGK#nKK\1l75Hi-rsJO3\dF'Brke$h`a0la]sk"St>Mdnc_BCntF^.8+\Bo.=_?CsL[B5%*4[""BR*m%7q\rT-/lIBoEW'heh3o'g.-=t#5*o%ul;^bNW9-?CcN6!Z=.mV*fENkZToSX_" %&nk-KElm(:#'L^^f*DE:`N;Hn<.s@7?.5_D6=TX`\^d\I4:TMKeZ,rc4[*cc*`%:B`tE0:3qAn%[?%*_1U[-_nip>/O6Dsm'E"4C %](+k0#IE;bdi[_*99Qp+U!V9i,`s7-K.,:)?'OU[^uXF($^sIR&Q-32#EpqR>S_YF.[V7X!qM-]np-Rr$b@M,k;8,m-tf59:(9U> %$oKceI7_T`;M-r0:6"i>]V.QHmbNCB0g-i=c^E;'e,:.fIKJ>tTp9]e"+^pVn]jIJg&#%prbla./j."uJ_g'Dh!Vd9JK@+I$,uFn %#PM@tS=](pZL]AqH0^(:nUGbt>'@[4a.P7_Y8,oncFp[$[Q`;u+o$]_GI$E"lnn)d7e,nFh/(NY!MUcGRtN0S"0],jtE!oI2BB#APhng@M%'!p[@j6+doS"hgiOOIdTu6\rjQob8)O\Sr>rb7Xj@H_A(jjgJ41g9t!8SuVk@[]"^3`M@;]3\SC@SJUCiXQ.1lFYL!`X?h!=XN=_!#8r*XHc[D %oYsTKU\`@N:JF]P18LF3(\C_Iagi[f&?eXIJP_StN"BMKFt]GeWY"VoF@[a?R8c_DA4kV>OK.O2\Y(LP9+>6NE`"$Abt<>+hmLp* %]7fB("2sC47k_80JH]sZPoG?i(aY_o\I37?dJT_8dX)V#f@4E>@;HM[<0Mc!W>Djo\/?@YX-+kn^lq]),$g<_P-Q313-lH)Lu^@g %(Mc9L:ZS6ZW_hDVgq+$S'9m4,8-L-eDj+Tf=n+%laN9OUD.sY/SKB:G"ACFJjd[KZ'TcjK&W5qfB&p(UY_U0a2U=+h.0Na`]sfu8 %.J51,D/qG+FbK'DZt?u\6uk+>d;4m\CWa(DE-EAUgY8HsciiEm;i"`l=U)SsSMV_s>V/!r;%0$J`/8:"jpLC&?l@37H)r353aXcW %$d=]4Q00KO#3saGY";OJ3&u$pL/"DB[/g %e!.p[Wdg/_(d=aKNS,`_qP#/rMl9b=kaKS)(PUh+.s7$?Z>,XjE7^Ah.8nbh9\5c26AR#GAB>=?Q#4%:;pua]Z8*b?O^)"6Es6,! %)7V3._m=G050B8'm-l`C?[Z^e_%[Wos %@S.jg&dE(_K&_WlbJhgTn3iS7.!M=?Z51"KP0o]*>L1\df*&KVMm8$su$^P"[%YWAW`C %6Ipu4b1([]%@'JTI":9u=?tXknZ(43Sdd=k2G#I?hY?"A,1\#4gt5n`@NkgWR(!4g@B(FeD(^t*UcP'_S%]qQAF3U*RK"Z[]H\2/b("/[O/ %o6sJ'RDH->P;3K!nmel'%N:*ALN4gmIYhPP3cADrgIA._=m?*7.*1n %YX$IY)e;7>=(?H"NWid[IPiqI8.*8AM*6kJrL!#R.ttjQ%Ah(4b14M_mc=MM@g^]a8"7*j\Qoe><._!$)@Qt:$lW2)lfqfcMt"N_9mQ*_j\H#9YAc)#_iQeUM=d\#2p,[2p7#$pN`@^iqbXh/UBS)k,XCSZ^H.FY%X:ZGV'*'6B]=A-b#Ulc7.cgV!02fJ'+`.IR%&EC2Q%Y;Rsg4E,&psi#S()e>1<3AL]s2 %j!'lP$Y=9QQHU:5WX-u>&L.=q+/0%mA7$ou:J;D@fL!tH4G162QGFM2m\'n-R3u_bb*uD?Kd^R]3J9eEJ(Es?%Q-0;7;/YmJElXe %Q,ZZJ1ZtV^6.%X''sEF"R7]6!TPlTB$W%i*"cp0TW6NnMhO+_4`U!beQA2G8*A^a32(]XJ1KIUl21BdZJI/EP[aM*OT'crc^+*/5 %cBmoQ+Fi_eBi3pNcFJE=4qbfn-lhmR5c%cLrm%O`>Zj %;W_9b*(@Zc.?M-OW%1Fm:R)[P%)b^`Y5%4&1D(EuL\`Qhj&$[S+H'a>.&3Aii/'aNOEJJ6mXmiPl<:!se'3aD/Wf".:e3\p/>^pP %4"QEZKJbmmZM53ESSVY-@Vo'P4^peN3U=iJSJ_QM3g'kMm=QZ@ha2?WFc4@Wh2YKi@T6Q,QB\%)-?k)70;PdcHr(;M#iAXMTI$$> %[7&dES8&:3EhPK2qLL3O/#UT%LSol,:t_q;:*P-(5N;6d'61gaUi_K(Ofdm-L1@Kt2Uh/+2dAg?"qHh:oi:U5A3#Uk]sT,VOX`H# %)s60A8_C2gQqYQNkq%esC/:_"^_UJpVmTF58ZG`c)W;SnJ^W'UZY^*7"fa?q9Uk07U,c's*l-X#*[,mUflaYbAr,J";'Z;B=YSqY %bb41pUCPA5htGLGGqI9%Il5nDIqF5bCs`S8B7A1!3RcFQ)-8!MG^uJu]>\.^PH`ok%Z`65r>fHV5-a!n]&C/C3/t_X9$m\?5fEP* %j:]^I]Wt>)05=rVSdZji(TfXs8?F=nn05O=rmYEr@KH]#G.\58)'lhqj+4RL+ETN^$e_"uJY>\$i[uZd0.`K`5"*`T%,\-[7)sj' %llT!*?>9i//DX^A8KqV8Zb$je!sfd^0i\E2!b,XZ8XHqiRt5Wl*ql9.9CQ]W\Ed\[CQN2Dfii%KFf=*R8H/'^%4/,_:!\3`]R:]:BS1o#m=Q-4[$Q?FWHP=C.i4 %9TZ/U!SP\jD@NDW"P'ot1WX]!\(3rCR_Pj]QH?2Y]-\K`1krS4`KP#;FYQDa1aa"jm[/0qRB)@6h_`1"ab0q:PRq5">]qrdX29YT %rCg7E^_)4slZ7\M7VaM19j_1oc8rFTjqtpBi+\i7T8s;He0sN=uHCo]ek'1*NX4%L#Wu=eb9iO3W'N"lmIO=RUI3+Po>l#-*W@ON&K&k@M*6u[doiJY_:GSIa4"X8o#q99j_2:DY.i.bqXsU0mX$^ %r:WmW+%@Y7HWS1N5"Q=p#(o$#A3iUW,l*V`m;=F0RM1?BRG%AT0XgbR_k0Y@W/uSSM,QJ_Y#:Km6sV?%\#,sDbUZm2KM4u'0Y[%b %6Za"[BlMcg76P=P^OP!kS,X38)Z$AY=-_ %Og:%B0S0OapqGbd"=Y6HEJ6],F86EHpC.^=/&IXmBeieDZs67uIZBRE>Z_GX"m=ok9>omsL_tl*'1_uSq^FGE`>IpJn9#PM\bT^1 %[qPh%NiK2;V`u;?jj^mtZ5grT,EE7W+jsK_K`GdeC!,[=_A\JMlGSWDRBkK!_$2H@[Mtk<7C.M %>o5mbV\P71ia[il"#a?(W@/W&>-m/eLI?;0bX:H'+?Iuh4V1R&@=#EhaM77>DP'<6Bg&[2gc":RnO("DQm\'e0NK=i$`4GqT37[$ %0,t`FLnD%j&.&uG@qK$`f`HYP*"`KB:4#Dl76p^1gj0aoa'/mG$NT/J#N08G&FSfK(s33PhP>V!Ys=+mCf/p/E5&'K#J"`.Am-F\ %Z\PL*"Z)<N,"0EXY`XmX>:+uV:89IbkUVq0$TF$!'Ata"28Z1ZhCHUi/'5uoVQUWhH(`joPJ#uCf6S$%Bu`oM5-ULZ %d&\GmeR1MB$T+fKDP]hE>n>OoT\lT@o<>or)P?dKUhLhe(VcEJ:(=:CkKiLn$KOI^qJ.L=Po1P?_)F@EDEb3,N>lpnA(gLp`JI:X"9j[iLJHA*?3:)mfiMjNY %8s!$);$(+UFdJ5&nS8D4a/Z`km_PTXb'+XlD2:87`TKo6)2QLB];+p=//c6)1?NB2)rZ3cQRae$([L^0F'0:JEAPZE_K"aHFV7CJ %i6\"f,Pa'fY1bo@94KgO&R7B2mJA?e %b66Lf".a,tC\V1_kd2'bK]L1('H]42#Q[o&q#2&Q1sUKk]*C0W8RIts.sCt:/U`5(*LZemP'>&c?C(fuc"C#Sf]aBmrm9*tT_WIR %#ID*CiC"r"opq5*&q1N;i><&6X"Q[m"ta5u&:%s.UD,&_48cmA:t1(:3Dj2qGL=X1kX/Hjh-((1KP,(_p::"7+;[,Yn(Q(0JMSNR %?pC?-pJjHuE.mTU%s%/Z_p&iFr!gGZI@N$HN2;Hjfu[5&i#4>XiS4l-F:Me`L7"HTX!@+d?"s@l4"Z?ZhCb5l^(2AVJj3l9"a(9%k]#%0YlMGljZP[f/UTiF0>`h.#'P\, %Qs'bS))US<&2ObV6$YJgTm+PR\GXAd52V#a*l^<: %>hqXZ0p;fPK0[@Y3>rST.rTdNd# %4BN)F/W]=E7XE?G:[5Fm.X_V0oO393Rrb$]-&rbtJ*-G-SS!V5?lUDD(7^HT)Wt0>eob7W'J+]m%N'MSq`rV0<>Zkr?[(>-R1kGX %k8DcRoZ_3(MX=K6[_-[NhBnGhqNf2QH@l2CNOKBAk$fQD1"&Zd:':'2Of81!ZGs2hSCmlLWMDh))]/RdhBBNPpo`%TgV4[eH[KK# %2'OQ*\nABQQF!VN*"rB'(Z_PTgk)Q2*BkkGJ-67O)$`/>_slsI)4@9Vh63)aB`fKp($q'o;OabrY"0,(e^MT=OXt9ii6ZBTV%=Y>'9)sI8-2&kd %SpXeP%pJ;Gdrl=]*i,^s1ZaMbL'f'L/mM2EU+5$b4n]90YCOgsk8g'\c]XbQ`[7Im$lY2.fORR^Pq=m3%9<&/ %N_Q7=9Tb.98T].7\?=Ip2N-:!P=rEb_<57`kMY4:$Xgal&@0t<;$_]Nh'1%_8"RMVhs*L`5U>\m7:-XTGF]po/Z0lLc@S0NHm\og %&5WduI?)sVE*#JreFnG0Gh#I?6uciZ1X=$P&Rl^YXU9C-/'O;H!ih,IZO+qjGaL+j`YeP!YQ]feVo8=;Vp4e2.Z0e@HZ\1X%D%T_69Q3VcKg-`mMpr=uOGu %90Q])i;bL6`A92ARY_';QfD$m`\qe62C(E$"^uAb*,#oY2i7'Ej?,HkGA/s$6!+qt4q=L0aYX9_3JPd)#S-,k_JC35EO6%p@m]S' %S`Q+OM!ItY(QR'[m4fjfB`rN\)Lj,N3Z*^!lU8&r>]t^"D2Md9lXG.<+T/?Vj@IDY6aEh"J/+Yk2h^p:mf>6N(L#T&]nC4W*MEpJ %jnUHFT8P@9Ke'cqr,h_,d;n;3$pu0/?jQ3@>``'\WJTd<-7qWNE)_UL3(!SHp<7./&EuG>741q7eQl*^mTU@YV9D;\A"a:tPXa7$ %+;=F5$>AoQ\eVSOB/*GJldTBP3,,],4d#V!K%Hn%"t99X%6m?8WXG!a1UaG`VAW#o^Xh'"'VakMbE]P0Hu=692'DF!QNDk=k-.E8 %_I.;f'cSpZi9UMLpG$er#qQ?GZl_1p_Of?Z!]d4a(U9]I\r@Q4'/>T/SD*Y:lF,":%C))S`4c#5We.WB*9gJo.XJ6;I6OjGg>sG. %)9C-r1C^2m9.8$.]pR>>TiTDu_5g6-a;6N5?KRfW;s'_Rfc*S-3^(JM^fn\_G\CkQCcn0GF6T'O(fdWrA1-4*r\de[f:G"LW`)=Q>A=sS!-)depF#6#`ut"r28cie %'X:.<*1hcs!B&mCJ>H_/%,7b'Gj6E:*Hu;$Xl4=nD!L!RfBKT$[I\%9g$U!*!JkXdF%XNqAqArp@d4H$s\_1rCIU2Q```fBiKQ(H@O.Y3 %bpc,2qbl9&N45%!?'d'MrE:h@rMd?3f%]S#4Lmhi9XeqGb;mUR/c$HtAK8,jhMd8'@P]m/XN_fg);XYFB7;XSerS&[/j0R#1i=[Z %]hc=ke)bdPP:f%8lf&k=NA=([n5[_+$]Q=It[4%(Ug5XVi8 %m-d&iN#G#>U]=(d6"F5o%t*,14+Uf:gN=NngQ@T9GEqFKHbn8!gS$bX7)Cq*HLJ`cq#'Ab3dUW).'5j(/8(n!-&btT`b@Ge(5=5G %<8`*5;9PMa%S'2LeL#[GcLS5dV_KcV&r5JJI@G]?g1lsu2n.Vj=6\YLIVQANC4Bb^mLnEr=$r1;o([aoXNCI8,?6/tA2lB]Ub1+ %QEiro#j3(mV2U.<3eB@b),2TXf0V+Hb-icQ.neQ!Wh?\ZXgraob>Pe:`7MT']0nihP\mX)eB=G[Ca79nc;LB@foRH)/7fc)1<*J> %2I.f"=j!CP&LHZ8Tp)#2@R;&^j"8A7[236KYuN@lCC3;T;)Ge\,NCj5jeZPbj!MR>6"9,Ss0 %^#q0s']XAs$(7WKnLaHQS>M6j?o_>d.:]g_3-W-6[4D;\r_8;\<;CdpqcI$T1hCGdY\e*s(+84&N?F2ql:$0X9N/B7g41bL)7itA %P@U,fW@.V0VJJhA\"tNXFZjH9.:YL\7Dl+hb&t%e.G"p]ns#V_jWrTG?K>2)/]$q%.;,N`%F_q-WQLUVAe"BkK)YQl;jB)XdnZ$( %PqB)1,E3*F[E_gk0.U&UJf3%H3`R'/OAB8aZF(+&3s?LjOQdRZ.P^JTH<_7+J,*kNe__qW6p#\*/q62=FLU %9QAq":%@IVlOp1iI7mRL3a0NinV@hRAM%LS*P4kAb(kqTb&)$eX2IAllcbT']H"?9\]X]!b@`0_.cWlrZ+4n?0d+I'T^6<6Z6XLV %0tK0!AX'9T`E-*cI@`4TH'%%%[;C\W^=;,_8*IO%!f]lS[Vg`,,qG`0jl**m=W)O248atHAK)M^=inh5E[d08Q.Qh+6qgY$P%bs` %-S+).m<%ugaiY/p)e^QK+!N'_2kcD"D0\!6BCGfg/L++fX/_07NH8B^JDlIerIsl5f^I3HZWu!Q9YT!Jqo1YY,F4d2U;7)IEj!dMd5kMd^H!^OQ7UX(Q=0?n_7P-$dF[ %Ag#KSls:)o#Q'[`Ig:4ehNqQ)/p7>"HqkhIR-+P>dlH9g$^AV)$+i=dP&mq:nJ1;`3Bpcgf#Ed.15!^B9_TjfhTa;U[kB-T-siXX %[BO`5o=>oOG!-1pTFBb?!hoO7-.u/rrM#>qptg=;8E%TAn)0*k.YOP("G[\_E3V_*$TY#W4oKLM;dmK/f['FU)7^u["J:"O^]YWT %d1"tWK!P"!,t'15IdJm('`NodEG!JKiI$%ND-u4r;b\gKbf;?Lo^q2bFc"4[1\Wg.L(+Rakqo/ %630N3Et1W)72)CRcE`9`VK@O6bYUD\Qr`02a_r,e_\LYro$h[DX0k %@kdf*+9dr`4IdO@_>5;-JQYkG'd1PD+Tq+[iK_Af6is>!J/e;q,ESqh-@A_r[g/dMNbegu'2hu`^I2B9kOZ:Cj#'7?&76SI;Mu&K %AQ>(CO["^=hi`f-@eVj1,E%4AVRX>7UI#$2(lhCN@u/uCK]jNj&a#X'7QK<[h]Z/[QXLdj8M$4J3DN^e2u:"]CrB.919T\u6DMir %ZY6A&3XRX^)6pGT["n5?k19or]Y;A&'1/Bsp?R6o(TU>R;;,[`[;gZqp(RQ^q$(7jBi;niKf9m--;'d(LX"^BAB\gDDkNJm\C/!' %E.X;j/,_/1'B8DEgoY1AZ3")_^JS*/ma8!.HV*@u&?uZr8>:-_(4s`J;:+rY,]ON7EZKn]M[HFMjt)!89h2%BkZ.l*V;Bb %4fm9nT'@dbg@MW,Xd\#FX2,ZZm8n!?:)U%V@R=l[p!SXjDU-M0pHCtsm9?ea%@S%)(@&1mf^9%5!c-OUV#O<^P1O_g#g$9gmf %NS9'u5H2"$C(NY>#&TGTd=TdEiBHjI%6Y5!2;#R;Zj2*Xa$Y*6c1I:H_^[4@X\?9Q8aJ]&R8mf?%kNrCQHJ5ibc12*M76]\4D6Ge"0=B)RpX58"0"^A&cp#HmSOno] %17Qh2^H>A32M@#%00nj$CduJ>36D8-F7g'E9r4;5"*ho_:Us?"J%[R&ME[h %q(67lr"O_WjnlMmfQ]<&V,6&&iS.kmFGA?9)4*:^*_lIiqq9RA8+Oc-'Q@[]:m&o=#W!Z\TYer6lt+.$V#0,_GQ`+o8K0+>X?Pi2 %_'DCe+l5*5Xk[/*0Fn_g"W/#a@*9*iWR,d&d+0KmAfQ%&)o!**)`"Sfj;1p` %/u;tMja48#'UF/+V*/"JKkNQ]Q/Pr&:'miX+u*i1.:q232AW[TOZZ:$KLi_U"/^quhE92%Meel2!hA]';4"tsa6_MJZ0--F4R)X"0\OR?#`D#OP0TB/M_NeANZ]lI2jaCqSsgZfb>!qJ+#HDRTDYRqWPLFIJ0_T8oYmdk&Wg %]s+a]q\"Z54fT![#8XO5MJc4+J/I"p"PZ:-FkCUk1ggDaP\64NFt`QH1$[^K3TfJL811rHDZ %;C*)SjXiL.WT/]>jnhYP#M!Dt8^.S`S:T`-fND8$12JKs9\IFE)c4-ff1"WfGlHEp8Cdm<0$0@I8E."6B=pmJ1)Va>60"s@7W'^-\-8>a2JV$%oi@uh/++g8`iP0;Xr,$ %XkFj_]N(f6D0[O2Gj]hX]4XXjppFd+#IS!VQC\9S_GbjD[[6(gW %PSQZ2WX6ur %BCU]K9)f#/?F>[g67ZpK$re1L3?hs]UgR7:1k_"ENGg`b$nb]l5_ZIRNY#dX`aH^hNI2=DRaQLXoXN* %8g(<)mEY]H.]I_XojE3srcV]a*a,$^1hg9)7j,QkVfgqGrX71;eTF^oO5S9'a@SFNHE0\K4pu2pc$lEmT?-d[/LaZGt)9m+7Xj/NJjs\q1>Z%jnW]"(, %RI<\L*]&`jhfW4"?$Xo_CqTSL_ItYLVk#`#d/oF`MmL96n%trtPf%/X3\=eXD%j$*g*T5? %X>Y3as7kJo`q_I7.u%*m4$h@f=MG4_A)?[hE[:MACLQ:X`N>K5 %@f(<505hL#&Cp&,CM3JROSDsgC22$FqFss %Q)O#[o0JudRhI59osP2^*9[#>I+^:^#CT'hLl/opaYnPQKD/55;O/$hqorISVeV&0)YU"Hh>W*XDmA;s3+=k#.K0@AYQlSPIWo'b %Ugr6-\MZc6A'g/"]cP^A+#r6*\1YU@W!Ri1.NuA4E`OW)4dp"_pkY#jr%4KANc&oO;;Ctb?&n)Z_f"E/Z,%:.o9k47XS]'CXNSm" %Qp.V=+$)UsaRifIL@+]FdDHp47a86^bo)*7M;9J$O,8t:-CX7SG9PQ%rbFG'TDMRI4M\K%p3*pNJ*S&Nb#5Zd"kPgfqAL$3@cJ%\ %Eo;q<(rR>$J>W"hS-a_C"(mYD"Y=b?)/E8)U-<8af6(,VoikImrK.KCRBMo[\NV.DGQ6%\GsKqaaC/:gAfKU4&]ST)b#[N*akB0D %WCrVB^O@b7jO6^qa7ZBK/IS0:3j=Em8&8;RH@:Q)Woe41M/petH"TtQI@+)1iJ!KW=5GO&JLo?K>2)A>pQa&-H.gsDR-,E/(@3r!J;bX0(hf+;]`Bq6EA9&*SAYNo(Zeuto.m8$HY>Aok>\\950GlQ>o %oc0.&*cg2i]%I:4n_rOs<$/R#F=kluXh.EY^O@c"jO7lBE;DOi7\uH\nDbZcRKO\61H,->7]a/b_5%M6kX=NkEdnhRU9#3.Bq %*@-.YE[c?UgK1Uq>)8^YU8.hk&]@V$"P`ZhRrIu;JnK-Cs8?*1\UgAcHO!Ik,U-S[o4&TjQ&2-$\`\GkXL+:3&=..5`@Oc'VVP2$ %L!2tR]Ai@34fY5Dr2&]j[14fGU:A#\6F?1VFn[3`G60pEHtQ'^/\BGX"Ra;jCSR-4uu %H^f'i^@&jTAj2:I4pa(]Z8-^s"%&@SM`hDtV8EJ)!.Y*DRYSF^]TVdN@#kp-d`]-;5.Z.!_Gf9oK#7EC#$tU9*+agW%qD('n[7KPMY<`Ip!A[iHa%8?N`b'39?!E6&]X[q+:Wbs)7'Z%OrQ:D^0_o@U$$?LD: %h6aC^/UN?8!mX(">/1]pA@RH/#M?r!.&8=9U'Tba[`T7eZ[u!f;?35Qr-%-K8UO'c-lr@dbgA;0cYh-0`$%T`H:IEX%BfW=ad%BJ %O:k9Zh,-,kJikbY!RuKM"t?ZcJK!MN1%2F.KK",KmDQYLbVUm %!9"lN]f\VN='bP%W:n3=r9K)g4HcPi1fBFsP>5Rk1CU+-mm/S/(NLf-,&l7*rOPmtR6^n*kCI">g %-.]#Kj(!5V_-Pih3=5ZIUefH5F^l9_$14m,=;1..5jH@0XNZDd+JMN+2f,5T,5:OP)(`)_NFnBm8S\,On]C2pS;F1Omkkg_gKo?3 %48k:W+'N/o$`W47$HAf]m\@@\NRm#X-j?$-2+%tC3@3*I/iohG`^.4YE5n0*R*Ob[IJT/G$#6@.k4cbmn=i5e:QlscbH8*TP]3Vq %\h"Z5qQX9Qqa5EfXd@42[lts:kPhID<^3`1nPW`SQ53mNhIS]f)Uc9;U6Z,>-8R5Rc?U>7YL\X`o%UX4]5?FRf&qH4Z8cla=N_BPba?4>-GS[lq)K[^*SO %f+AiJo#2BpD"Rs;)Mp$Uqn1RUFK7p2&NH`&k-EG_oMnO1EX>d6)$1dCU*SYtjU9/?l[m17&%3mEuG\g`4V&JH/6uKB&O"jk>C`D,e]KZ34>cqXB1NaUQ\^0JCn2^)s$t&jN)RQp< %;2"M3l=Lb*;TVXrR_-\;i9Q61$pGQ'&(+G9mm_=k0\X)E4(Fnd'P?f9#`81o5e=LDinaa<3!b:QKibs$(Xd(iVh)"]k8n"7<(Ga' %/*.WsT@6_X)!(j'CAo-es1q`O$&\)!"gl?`F0S+6VaNLRp24.\, %,]gZc/k")CJ'+XQ+P(e5LhQ6N!!"'N:2Br/ZhOeG;%X!6J[b@TEC=4t]PfUg'8+jO7?haqa6a'7QTtX-#;t8]_Z>ab+qcRM'VHr# %:MEs]7C;EXOlLPc %2$;,CUA*7(ZLIN19K>06,9e:-,:(7'"+Y^/l4rU'aX[Ql5dSBkP1VqQ"Lp^VL:)N`09CVG7kGi %;QD^JE,\.i%"^Q&<"X2KqO6b$[Aua);jj/&5To-[tD>4"[2C+@G::lD2-=0H"81Y2LUcog+PAsO?rcV:7LliT5N%DD4#%a6OglBAH39.Ll^W^>jP9($egG_aD@0sfatAT)1YiFUBqY]ZJTjHRdUYG6L*Q2&GERH9^CmFCfO6+=Z@otJ5uKgB:=a%XODCW(E],a,TkRi`!i %6^bp\_YVe9p'er9\r!UtIJK1ul3FY5CNP%gKTi6*nHgr"4u[j)DK!oX+ShjQ^HG/N^)$"!T!s1u<.t#ASmMiVm@V/lO/TBks7tDF %s7EM^huEW+s*4M(It%:njlP5m5Q.3]rpnhDrV`)_s7Y49hu<3@?iKB#5Q10)^]*UB^\m-$s*XjiTDnEYDh%f-hgYUm:OiCoJ,A\r %]\h_lJ,8EUs7S,'rYN[WTa1~> %AI9_PrivateDataEnd \ No newline at end of file diff --git a/code/index.html b/code/index.html index 6e2d88b7..e71ed3c6 100644 --- a/code/index.html +++ b/code/index.html @@ -7,6 +7,7 @@ Project GitHub Tracker +

@@ -14,12 +15,26 @@

GitHub Tracker

- -

Projects:

-
- - + +
+ +
+ +
+
+ +
+
+
+
+ +
+ Made by Ida NΓ€slund on Technigo Bootcamp, spring 2022 +
diff --git a/code/script.js b/code/script.js index bee722e8..720a0d05 100644 --- a/code/script.js +++ b/code/script.js @@ -2,6 +2,8 @@ const projects = document.getElementById('projects') const username = 'idanaslund' const profile = document.getElementById('profile') +const formRepos = document.getElementById('formRepos') +const sortRepos = document.getElementById('sortRepos') let API_URL = `https://api.github.com/users/${username}/repos` @@ -19,9 +21,12 @@ const addingProfile = () => { fetch(`https://api.github.com/users/${username}`, options) .then((res) => res.json()) .then((profileInfo) => { + console.log("profile", profileInfo) profile.innerHTML += ` -
${profileInfo.login}` + ${profileInfo.login} +

${profileInfo.bio}

+ ` }) } addingProfile() @@ -31,26 +36,37 @@ addingProfile() const addingRepos = () => {fetch(API_URL, options) .then((res) => res.json()) .then((repos) => { - // Filtering all repos I've forked and that starts with the word project. + + // Filtering all repos I've forked and that starts with the word project const forkedRepos = repos.filter( repo => repo.fork && repo.name.startsWith('project-') - ) + ) // For all filtered repos I put the following info on my page forkedRepos.forEach((repo) => { - let updated = new Date(repo.updated_at).toLocaleDateString() //Turning date and time into date - projects.innerHTML += ` + let updated = new Date(repo.updated_at).toLocaleDateString() //Turning date and time into date + let upperCase = `${repo.name[0].toUpperCase()}${repo.name.slice(1)}` //Making first letter of string to uppercase + projects.innerHTML += [`
-

${repo.name}

+

${upperCase}

    -
  • Most recent update: ${updated}
  • -
  • Default branch: ${repo.default_branch}
  • -
  • Link to repo
  • -
  • Number of commits:
  • +
  • Most recent update: ${updated}
  • +
  • Default branch: ${repo.default_branch}
  • +
  • Link to repo
  • +
  • Number of commits:
-
` - + `] + + + // const sortingRepos = () => { + // if(sortRepos === 'alphabetical') { + // repos.sort(forkedRepos) + //} else if(sortRepos === 'newestFirst') { + // updated.sort(forkedRepos) + // } + // } + }) findingPulls(forkedRepos) callingChart (forkedRepos.length) // Bringing all filtered repos to the next function @@ -71,7 +87,7 @@ const findingPulls = (repos) => { findingCommits(pulls.commits_url, repo.name) //passing the commits of these pull requests to the next function console.log(pulls.commits_url, "commits") } else { // If pull requests does not exist = display this - document.getElementById(`commit-${repo.name}`).innerHTML += ' Is either a group project or pull request does not exist' + document.getElementById(`commit-${repo.name}`).innerHTML += ' Group project/no pull request' } }) @@ -93,4 +109,4 @@ addingRepos(); -// Eventlisteners \ No newline at end of file +// Eventlisteners diff --git a/code/style.css b/code/style.css index e8d2a54b..e1fc76ff 100644 --- a/code/style.css +++ b/code/style.css @@ -1,8 +1,10 @@ body { + box-sizing: border-box; background: #83c5be; /*006d77*/ margin: 0; padding: 0; + font-family: 'Patrick Hand', cursive; } header { @@ -17,12 +19,18 @@ h1 { display: inline; margin: 0; padding-top: 2vh; + font-size: 50px; } .profile { display: inline; - margin: 2vh 5vw; + margin: 2vh 5vw; +} + +p { + color: #83c5be; + font-size: 18px; } .profile img { @@ -34,11 +42,28 @@ h1 { } .userlink { - font-size: 20px; + font-size: 25px; color: white; text-decoration: none; } +.repo-link { + color: black; +} + +a { + text-decoration: none; +} + +a:hover { + color:#83c5be; +} + +ul { + list-style-image: url(./images/GitHub-Mark/PNG/GitHub-Mark-32px.png); + +} + .projects { display: flex; flex-direction: row; @@ -46,28 +71,58 @@ h1 { justify-content: space-evenly; } +h4 { + display: inline; + font-size: 25px; + margin-top: 2%; + margin-bottom: 2%; +} + .repos { background: white; + font-size: 20px; width: 100vw; max-width: 375px; margin: 1vh 1vw; padding: 1vh 1vw; + display: flex; + flex-direction: column; + align-items: center; box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -webkit-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); } +.title { + font-size: 15px; +} + +.chart-container { + width: 50vw; + height: 20vh; + margin: 0 25vw; +} + +footer { + display: flex; + justify-content: center; +} + +.footer-text { + padding: 1vh 2vw; +} + @media (min-width: 668px) and (max-width: 1024px) { header { flex-direction: row; } - .repos { width: 20vw; min-width: 210px;; } + } @media (min-width: 1025px) { From e6159cfa274b9183ee8f51f2f67cb8376baf57bc Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sat, 26 Feb 2022 20:55:04 +0100 Subject: [PATCH 17/28] tiny fixes --- code/script.js | 23 ++++++++++------------- code/style.css | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/code/script.js b/code/script.js index 720a0d05..4cedaf09 100644 --- a/code/script.js +++ b/code/script.js @@ -24,7 +24,7 @@ const addingProfile = () => { console.log("profile", profileInfo) profile.innerHTML += ` - ${profileInfo.login} + ${profileInfo.login}

${profileInfo.bio}

` }) @@ -52,20 +52,11 @@ const addingRepos = () => {fetch(API_URL, options) `] - - - // const sortingRepos = () => { - // if(sortRepos === 'alphabetical') { - // repos.sort(forkedRepos) - //} else if(sortRepos === 'newestFirst') { - // updated.sort(forkedRepos) - // } - // } }) findingPulls(forkedRepos) @@ -74,8 +65,7 @@ const addingRepos = () => {fetch(API_URL, options) } - -const findingPulls = (repos) => { + const findingPulls = (repos) => { repos.forEach((repo) => { //For all filtered repos I fetch each pull request fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`, options) .then((res) => res.json()) @@ -104,6 +94,13 @@ const findingPulls = (repos) => { }) } + // const sortingRepos = () => { + // if(sortRepos === 'alphabetical') { + // repos.sort(forkedRepos) + //} else if(sortRepos === 'newestFirst') { + // updated.sort(forkedRepos) + // } + // } addingRepos(); diff --git a/code/style.css b/code/style.css index e1fc76ff..e55e3a67 100644 --- a/code/style.css +++ b/code/style.css @@ -94,7 +94,7 @@ h4 { } .title { - font-size: 15px; + font-size: 16px; } .chart-container { From 382d93f4607afc6ba5f9c7141ca09da791e1f0ce Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 10:27:27 +0100 Subject: [PATCH 18/28] removed console.log --- code/index.html | 6 ------ code/script.js | 23 +++-------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/code/index.html b/code/index.html index e71ed3c6..9a9382ac 100644 --- a/code/index.html +++ b/code/index.html @@ -22,12 +22,6 @@

GitHub Tracker

-
- -
diff --git a/code/script.js b/code/script.js index 4cedaf09..0600fc8a 100644 --- a/code/script.js +++ b/code/script.js @@ -21,7 +21,6 @@ const addingProfile = () => { fetch(`https://api.github.com/users/${username}`, options) .then((res) => res.json()) .then((profileInfo) => { - console.log("profile", profileInfo) profile.innerHTML += ` ${profileInfo.login} @@ -72,38 +71,22 @@ const addingRepos = () => {fetch(API_URL, options) .then((data) => { const pulls = data.find((pull)=> pull.user.login === repo.owner.login) //Comparing all pull requests from Technigo to show only the ones with me as owner - console.log("pulls", pulls) if (pulls !== undefined ) { // If pull requests exist = findingCommits(pulls.commits_url, repo.name) //passing the commits of these pull requests to the next function - console.log(pulls.commits_url, "commits") } else { // If pull requests does not exist = display this document.getElementById(`commit-${repo.name}`).innerHTML += ' Group project/no pull request' - } - - }) + } }) + }) } const findingCommits = (myCommitsUrl, myRepoName) => { fetch(myCommitsUrl, options) .then((res) => res.json()) .then((data) => { - console.log(data) document.getElementById(`commit-${myRepoName}`).innerHTML += data.length //Getting the number of commits to be displayed on the page }) } - // const sortingRepos = () => { - // if(sortRepos === 'alphabetical') { - // repos.sort(forkedRepos) - //} else if(sortRepos === 'newestFirst') { - // updated.sort(forkedRepos) - // } - // } - -addingRepos(); - - - -// Eventlisteners +addingRepos() From 36d3806fe4107d5a0200649ad7289aef2c57d4e6 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 16:07:23 +0100 Subject: [PATCH 19/28] last touches --- code/script.js | 1 - code/style.css | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/script.js b/code/script.js index 0600fc8a..b47cfec0 100644 --- a/code/script.js +++ b/code/script.js @@ -7,7 +7,6 @@ const sortRepos = document.getElementById('sortRepos') let API_URL = `https://api.github.com/users/${username}/repos` - //Get the token here!! const options = { method: 'GET', diff --git a/code/style.css b/code/style.css index e55e3a67..f0600b8c 100644 --- a/code/style.css +++ b/code/style.css @@ -93,8 +93,11 @@ h4 { -moz-box-shadow: 10px 10px 29px -5px rgba(0,0,0,0.72); } +li { + padding: 4% 0 4% 0; +} .title { - font-size: 16px; + font-size: 18px; } .chart-container { From 9503da92418e99f0e8aaf0257cb61de0e0479f79 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 16:16:41 +0100 Subject: [PATCH 20/28] readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1613a3b0..85f55798 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ # GitHub Tracker -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This week the project was to fetch information from Github about my repositories and pull requests and display the information on a page. We were also supposed to compare data in a chart. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +I had trouble with fetching the amount of commits from the pull requests. I used my team for help and also analyzed other students code to solve it. I also had a problem with planning this project because I found it hard to understand what the end product was going to be. If I had more time I would have tried to accomplish the red and black levels. ## View it live From 94bff75236c54cf335696e2e002a0d61a11087c3 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 17:07:18 +0100 Subject: [PATCH 21/28] moved gitignore --- .gitignore => code/.gitignore | 0 code/token.js | 1 + 2 files changed, 1 insertion(+) rename .gitignore => code/.gitignore (100%) create mode 100644 code/token.js diff --git a/.gitignore b/code/.gitignore similarity index 100% rename from .gitignore rename to code/.gitignore diff --git a/code/token.js b/code/token.js new file mode 100644 index 00000000..f76549e3 --- /dev/null +++ b/code/token.js @@ -0,0 +1 @@ +const API_TOKEN = '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' From 0e63ef93948de5f4dfa54a4c15e29726717b10be Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 17:20:26 +0100 Subject: [PATCH 22/28] removing token --- code/.gitignore => .gitignore | 2 +- code/script.js | 18 +++++++++--------- code/token.js | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename code/.gitignore => .gitignore (70%) diff --git a/code/.gitignore b/.gitignore similarity index 70% rename from code/.gitignore rename to .gitignore index 3b56b9b4..341741ad 100644 --- a/code/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ #All files that should be hidden: -code/token.js \ No newline at end of file +./code/token.js \ No newline at end of file diff --git a/code/script.js b/code/script.js index b47cfec0..d017a499 100644 --- a/code/script.js +++ b/code/script.js @@ -8,16 +8,16 @@ const sortRepos = document.getElementById('sortRepos') let API_URL = `https://api.github.com/users/${username}/repos` //Get the token here!! -const options = { - method: 'GET', - headers: { - Authorization: `token ${API_TOKEN}` - } -} +//const options = { + // method: 'GET', + // headers: { + // Authorization: `token ${API_TOKEN}` + // } +//} // Fetching profile info const addingProfile = () => { - fetch(`https://api.github.com/users/${username}`, options) + fetch(`https://api.github.com/users/${username}`) //, options .then((res) => res.json()) .then((profileInfo) => { profile.innerHTML += ` @@ -31,7 +31,7 @@ addingProfile() // The first fetch of repos, calling the function below all other functions -const addingRepos = () => {fetch(API_URL, options) +const addingRepos = () => {fetch(API_URL) //, options .then((res) => res.json()) .then((repos) => { @@ -65,7 +65,7 @@ const addingRepos = () => {fetch(API_URL, options) const findingPulls = (repos) => { repos.forEach((repo) => { //For all filtered repos I fetch each pull request - fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`, options) + fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`) //, options .then((res) => res.json()) .then((data) => { diff --git a/code/token.js b/code/token.js index f76549e3..ac1bf3cf 100644 --- a/code/token.js +++ b/code/token.js @@ -1 +1 @@ -const API_TOKEN = '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' +//const API_TOKEN = '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' From 709da4f468bc7baffd5b20a6d9641c87217aca33 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 17:22:44 +0100 Subject: [PATCH 23/28] token --- code/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/script.js b/code/script.js index d017a499..9becb3ae 100644 --- a/code/script.js +++ b/code/script.js @@ -80,7 +80,7 @@ const addingRepos = () => {fetch(API_URL) //, options } const findingCommits = (myCommitsUrl, myRepoName) => { - fetch(myCommitsUrl, options) + fetch(myCommitsUrl) //, options .then((res) => res.json()) .then((data) => { document.getElementById(`commit-${myRepoName}`).innerHTML += data.length //Getting the number of commits to be displayed on the page From 8cd9dcd68c6bc8d140ad9a80d0fe7e1d39020d61 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 17:24:32 +0100 Subject: [PATCH 24/28] token removed --- .gitignore | 3 --- code/script.js | 14 +++----------- code/token.js | 1 - 3 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 .gitignore delete mode 100644 code/token.js diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 341741ad..00000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -#All files that should be hidden: - -./code/token.js \ No newline at end of file diff --git a/code/script.js b/code/script.js index 9becb3ae..65ec08ad 100644 --- a/code/script.js +++ b/code/script.js @@ -7,17 +7,9 @@ const sortRepos = document.getElementById('sortRepos') let API_URL = `https://api.github.com/users/${username}/repos` -//Get the token here!! -//const options = { - // method: 'GET', - // headers: { - // Authorization: `token ${API_TOKEN}` - // } -//} - // Fetching profile info const addingProfile = () => { - fetch(`https://api.github.com/users/${username}`) //, options + fetch(`https://api.github.com/users/${username}`) .then((res) => res.json()) .then((profileInfo) => { profile.innerHTML += ` @@ -31,7 +23,7 @@ addingProfile() // The first fetch of repos, calling the function below all other functions -const addingRepos = () => {fetch(API_URL) //, options +const addingRepos = () => {fetch(API_URL) .then((res) => res.json()) .then((repos) => { @@ -80,7 +72,7 @@ const addingRepos = () => {fetch(API_URL) //, options } const findingCommits = (myCommitsUrl, myRepoName) => { - fetch(myCommitsUrl) //, options + fetch(myCommitsUrl) .then((res) => res.json()) .then((data) => { document.getElementById(`commit-${myRepoName}`).innerHTML += data.length //Getting the number of commits to be displayed on the page diff --git a/code/token.js b/code/token.js deleted file mode 100644 index ac1bf3cf..00000000 --- a/code/token.js +++ /dev/null @@ -1 +0,0 @@ -//const API_TOKEN = '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' From 070b2095653ba6c84ae3d6c621f3064d9fef74e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ida=20N=C3=A4slund?= <91630469+idanaslund@users.noreply.github.com> Date: Sun, 27 Feb 2022 17:32:42 +0100 Subject: [PATCH 25/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85f55798..159e173b 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,4 @@ I had trouble with fetching the amount of commits from the pull requests. I used ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://ecstatic-ptolemy-db0375.netlify.app/ From f519e652b50277c42399a28e1ed79ca7a26d0642 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 18:51:56 +0100 Subject: [PATCH 26/28] removed token.js from html --- code/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/code/index.html b/code/index.html index 9a9382ac..c33762a6 100644 --- a/code/index.html +++ b/code/index.html @@ -31,7 +31,6 @@

GitHub Tracker

- \ No newline at end of file From 1ba6f7c55ad8ca314b519b5963ac259a2e764f91 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Sun, 27 Feb 2022 19:25:25 +0100 Subject: [PATCH 27/28] final changes --- code/script.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/script.js b/code/script.js index 65ec08ad..d7975426 100644 --- a/code/script.js +++ b/code/script.js @@ -49,8 +49,8 @@ const addingRepos = () => {fetch(API_URL) `] }) - findingPulls(forkedRepos) - callingChart (forkedRepos.length) // Bringing all filtered repos to the next function + findingPulls(forkedRepos) // Bringing all filtered repos to the next function + callingChart (forkedRepos.length) //Bringing all filtered repos to the chart }) } From fc436805c7ae363eead0cc13c74f364c9dfaa4b0 Mon Sep 17 00:00:00 2001 From: idanaslund Date: Wed, 2 Mar 2022 09:08:33 +0100 Subject: [PATCH 28/28] changes from code review --- code/script.js | 2 +- code/style.css | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/code/script.js b/code/script.js index d7975426..a98b59c5 100644 --- a/code/script.js +++ b/code/script.js @@ -57,7 +57,7 @@ const addingRepos = () => {fetch(API_URL) const findingPulls = (repos) => { repos.forEach((repo) => { //For all filtered repos I fetch each pull request - fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`) //, options + fetch(`https://api.github.com/repos/Technigo/${repo.name}/pulls`) .then((res) => res.json()) .then((data) => { diff --git a/code/style.css b/code/style.css index f0600b8c..1868e02a 100644 --- a/code/style.css +++ b/code/style.css @@ -1,7 +1,6 @@ body { box-sizing: border-box; background: #83c5be; - /*006d77*/ margin: 0; padding: 0; font-family: 'Patrick Hand', cursive; @@ -123,7 +122,7 @@ footer { .repos { width: 20vw; - min-width: 210px;; + min-width: 210px; } }