From fa1373fc743ac18c272d04bb5c1e52e2215e40e7 Mon Sep 17 00:00:00 2001 From: Elian Gutierrez Date: Sat, 20 Oct 2018 11:12:46 -0400 Subject: [PATCH 01/84] test: fix assertion arguments order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23787 Reviewed-By: Denys Otrishko Reviewed-By: Michaël Zasso Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- test/parallel/test-http-remove-header-stays-removed.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http-remove-header-stays-removed.js b/test/parallel/test-http-remove-header-stays-removed.js index 6617a1775441b7..337fcd3becd177 100644 --- a/test/parallel/test-http-remove-header-stays-removed.js +++ b/test/parallel/test-http-remove-header-stays-removed.js @@ -44,13 +44,13 @@ const server = http.createServer(function(request, response) { let response = ''; process.on('exit', function() { - assert.strictEqual('beep boop\n', response); + assert.strictEqual(response, 'beep boop\n'); console.log('ok'); }); server.listen(0, function() { http.get({ port: this.address().port }, function(res) { - assert.strictEqual(200, res.statusCode); + assert.strictEqual(res.statusCode, 200); assert.deepStrictEqual(res.headers, { date: 'coffee o clock' }); res.setEncoding('ascii'); From 86cf01404c24406ff888f36db681a651eda35c59 Mon Sep 17 00:00:00 2001 From: Jose Bucio Date: Mon, 15 Oct 2018 23:13:18 -0500 Subject: [PATCH 02/84] repl: migrate from process.binding('config') to getOptions() PR-URL: https://github.com/nodejs/node/pull/23684 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Sakthipriyan Vairamani --- lib/repl.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/repl.js b/lib/repl.js index d71f636cd64dc8..dafbd20d500383 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -70,7 +70,9 @@ const { ERR_SCRIPT_EXECUTION_INTERRUPTED } = require('internal/errors').codes; const { sendInspectorCommand } = require('internal/util/inspector'); -const { experimentalREPLAwait } = process.binding('config'); +const experimentalREPLAwait = internalBinding('options').getOptions( + '--experimental-repl-await' +); const { isRecoverableError } = require('internal/repl/recoverable'); const { getOwnNonIndexProperties, From 4112a10abe323569fda1da0ce7639a88d8b1b6b8 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Mon, 15 Oct 2018 15:15:26 -0700 Subject: [PATCH 03/84] crypto: strip unwanted space from openssl version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove trailing " \n" from `process.versions.openssl`. d3d6cd3ecad19 was incorrectly printing this trailer, but because the target buffer size was claimed to be the length of the version string, the trailer was truncated off. 9ed4646df05b9 corrected the target buffer size, but then the trailer started to appear in process.versions. Added a test to check for regressions. PR-URL: https://github.com/nodejs/node/pull/23678 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Refael Ackermann Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Sakthipriyan Vairamani Reviewed-By: Tobias Nießen Reviewed-By: Ben Noordhuis Reviewed-By: Tiancheng "Timothy" Gu --- src/node_crypto.cc | 4 ++-- test/parallel/test-process-versions.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index ab3856b23a9eb1..14b2dad9376c9a 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5702,9 +5702,9 @@ std::string GetOpenSSLVersion() { // for reference: "OpenSSL 1.1.0i 14 Aug 2018" char buf[128]; const int start = search(OPENSSL_VERSION_TEXT, 0, ' ') + 1; - const int end = search(OPENSSL_VERSION_TEXT + start, start, ' ') + 1; + const int end = search(OPENSSL_VERSION_TEXT + start, start, ' '); const int len = end - start; - snprintf(buf, sizeof(buf), "%.*s\n", len, &OPENSSL_VERSION_TEXT[start]); + snprintf(buf, sizeof(buf), "%.*s", len, &OPENSSL_VERSION_TEXT[start]); return std::string(buf); } diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index 8f706c6954cd2c..9a211286770586 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -33,6 +33,10 @@ assert(/^\d+\.\d+\.\d+(?:\.\d+)?-node\.\d+(?: \(candidate\))?$/ .test(process.versions.v8)); assert(/^\d+$/.test(process.versions.modules)); +if (common.hasCrypto) { + assert(/^\d+\.\d+\.\d+[a-z]?$/.test(process.versions.openssl)); +} + for (let i = 0; i < expected_keys.length; i++) { const key = expected_keys[i]; const descriptor = Object.getOwnPropertyDescriptor(process.versions, key); From a666d3ea240400e9993e925fde8b80fbcd9ccb11 Mon Sep 17 00:00:00 2001 From: Thomas GENTILHOMME Date: Fri, 19 Oct 2018 23:18:30 +0200 Subject: [PATCH 04/84] test: fix strictEqual() arguments order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23771 Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig --- test/parallel/test-http-parser-bad-ref.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index b44bc3f453a325..aca94361b493aa 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -82,7 +82,7 @@ demoBug('POST /1/22 HTTP/1.1\r\n' + 'pong'); process.on('exit', function() { - assert.strictEqual(2, headersComplete); - assert.strictEqual(2, messagesComplete); + assert.strictEqual(headersComplete, 2); + assert.strictEqual(messagesComplete, 2); console.log('done!'); }); From ddd9ccf1d89efdd25f0b4b064e31e2d37ae7bd66 Mon Sep 17 00:00:00 2001 From: Romain Lanz Date: Fri, 19 Oct 2018 23:23:44 +0200 Subject: [PATCH 05/84] test: fix strictEqual() argument order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23768 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Michaël Zasso --- test/parallel/test-http-write-empty-string.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http-write-empty-string.js b/test/parallel/test-http-write-empty-string.js index 35a7aca61b4030..d4ab070667ef6d 100644 --- a/test/parallel/test-http-write-empty-string.js +++ b/test/parallel/test-http-write-empty-string.js @@ -42,13 +42,13 @@ server.listen(0, common.mustCall(function() { http.get({ port: this.address().port }, common.mustCall(function(res) { let response = ''; - assert.strictEqual(200, res.statusCode); + assert.strictEqual(res.statusCode, 200); res.setEncoding('ascii'); res.on('data', function(chunk) { response += chunk; }); res.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', response); + assert.strictEqual(response, '1\n2\n3\n'); })); })); })); From 3b66a8d8934eec18e4cd4f893eda2e0d4205d75c Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Sun, 21 Oct 2018 09:04:43 -0400 Subject: [PATCH 06/84] deps: fix wrong default for v8 handle zapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23801 Fixes: https://github.com/nodejs/node/issues/23796 Reviewed-By: Anna Henningsen Reviewed-By: Michaël Zasso Reviewed-By: Matheus Marchini --- common.gypi | 2 +- deps/v8/gypfiles/features.gypi | 11 +++++++---- deps/v8/gypfiles/toolchain.gypi | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/common.gypi b/common.gypi index 50f69563be6d93..1508097e1d2a44 100644 --- a/common.gypi +++ b/common.gypi @@ -33,7 +33,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.5', + 'v8_embedder_string': '-node.6', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/v8/gypfiles/features.gypi b/deps/v8/gypfiles/features.gypi index 35a078e8af2fd2..618949124a71cb 100644 --- a/deps/v8/gypfiles/features.gypi +++ b/deps/v8/gypfiles/features.gypi @@ -103,7 +103,9 @@ # Enable mitigations for executing untrusted code. 'v8_untrusted_code_mitigations%': 'true', - 'v8_enable_handle_zapping%': 1, + # Currently set for node by common.gypi, avoiding default because of gyp file bug. + # Should be turned on only for debugging. + #'v8_enable_handle_zapping%': 0, }, 'target_defaults': { 'conditions': [ @@ -164,9 +166,10 @@ ['v8_untrusted_code_mitigations=="false"', { 'defines': ['DISABLE_UNTRUSTED_CODE_MITIGATIONS',], }], - ['v8_enable_handle_zapping==1', { - 'defines': ['ENABLE_HANDLE_ZAPPING',], - }], + # Refs: https://github.com/nodejs/node/pull/23801 + # ['v8_enable_handle_zapping==1', { + # 'defines': ['ENABLE_HANDLE_ZAPPING',], + # }], ], # conditions 'defines': [ 'V8_GYP_BUILD', diff --git a/deps/v8/gypfiles/toolchain.gypi b/deps/v8/gypfiles/toolchain.gypi index 7f497fac91e2b2..ea8f1c2f00da56 100644 --- a/deps/v8/gypfiles/toolchain.gypi +++ b/deps/v8/gypfiles/toolchain.gypi @@ -1321,6 +1321,10 @@ }, { 'inherit_from': ['DebugBase1'], }], + # Temporary refs: https://github.com/nodejs/node/pull/23801 + ['v8_enable_handle_zapping==1', { + 'defines': ['ENABLE_HANDLE_ZAPPING',], + }], ], }, # Debug 'ReleaseBase': { @@ -1405,6 +1409,8 @@ }, # Release 'Release': { 'inherit_from': ['ReleaseBase'], + # Temporary refs: https://github.com/nodejs/node/pull/23801 + 'defines!': ['ENABLE_HANDLE_ZAPPING',], }, # Debug 'conditions': [ [ 'OS=="win"', { From dfecf85ded89f5bd32fec7d312dc1efc11752131 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Tue, 16 Oct 2018 15:54:02 +0200 Subject: [PATCH 07/84] test: fix test-require-symlink on Windows Creating directory symlinks on Windows require 'dir' parameter to be provided. Fixes: https://github.com/nodejs/node/issues/23596 PR-URL: https://github.com/nodejs/node/pull/23691 Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: James M Snell --- test/parallel/test-require-symlink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-require-symlink.js b/test/parallel/test-require-symlink.js index 7aad3ee0a7e7e9..c73fdcd41e6efa 100644 --- a/test/parallel/test-require-symlink.js +++ b/test/parallel/test-require-symlink.js @@ -60,7 +60,7 @@ const linkScriptTarget = path.join(dirName, 'symlinked.js'); test(); function test() { - fs.symlinkSync(linkTarget, linkDir); + fs.symlinkSync(linkTarget, linkDir, 'dir'); fs.symlinkSync(linkScriptTarget, linkScript); // load symlinked-module From b07cb4810cee8b0c9c071364e23fed664069b01c Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Thu, 18 Oct 2018 17:40:57 +0200 Subject: [PATCH 08/84] zlib: do not leak on destroy PR-URL: https://github.com/nodejs/node/pull/23734 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Matteo Collina --- lib/zlib.js | 9 +++++++++ test/parallel/test-zlib-close-in-ondata.js | 10 ++++++++++ test/parallel/test-zlib-destroy.js | 13 +++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 test/parallel/test-zlib-close-in-ondata.js create mode 100644 test/parallel/test-zlib-destroy.js diff --git a/lib/zlib.js b/lib/zlib.js index 61f57429d63586..c833afff14f4b9 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -430,6 +430,11 @@ Zlib.prototype.close = function close(callback) { this.destroy(); }; +Zlib.prototype._destroy = function _destroy(err, callback) { + _close(this); + callback(err); +}; + Zlib.prototype._transform = function _transform(chunk, encoding, cb) { var flushFlag = this._defaultFlushFlag; // We use a 'fake' zero-length chunk to carry information about flushes from @@ -592,6 +597,10 @@ function processCallback() { assert(false, 'have should not go down'); } + if (self.destroyed) { + return; + } + // exhausted the output buffer, or used all the input create a new one. if (availOutAfter === 0 || self._outOffset >= self._chunkSize) { handle.availOutBefore = self._chunkSize; diff --git a/test/parallel/test-zlib-close-in-ondata.js b/test/parallel/test-zlib-close-in-ondata.js new file mode 100644 index 00000000000000..44d996311dca13 --- /dev/null +++ b/test/parallel/test-zlib-close-in-ondata.js @@ -0,0 +1,10 @@ +'use strict'; + +const common = require('../common'); +const zlib = require('zlib'); + +const ts = zlib.createGzip(); +const buf = Buffer.alloc(1024 * 1024 * 20); + +ts.on('data', common.mustCall(() => ts.close())); +ts.end(buf); diff --git a/test/parallel/test-zlib-destroy.js b/test/parallel/test-zlib-destroy.js new file mode 100644 index 00000000000000..d8eab42186a5fa --- /dev/null +++ b/test/parallel/test-zlib-destroy.js @@ -0,0 +1,13 @@ +'use strict'; + +require('../common'); + +const assert = require('assert'); +const zlib = require('zlib'); + +// verify that the zlib transform does clean up +// the handle when calling destroy. + +const ts = zlib.createGzip(); +ts.destroy(); +assert.strictEqual(ts._handle, null); From 22cd53791ad0643d29e3b698267486aeb0b2b4f8 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sat, 20 Oct 2018 22:08:41 -0500 Subject: [PATCH 09/84] lib: trigger uncaught exception handler for microtasks PR-URL: https://github.com/nodejs/node/pull/23794 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Matheus Marchini --- doc/api/globals.md | 4 +-- lib/internal/bootstrap/node.js | 6 ++-- lib/internal/queue_microtask.js | 46 ++++++++++++++++----------- src/node.cc | 19 ++++++++++- test/parallel/test-queue-microtask.js | 2 +- 5 files changed, 52 insertions(+), 25 deletions(-) diff --git a/doc/api/globals.md b/doc/api/globals.md index 78087060a5257f..e41d621883184b 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -119,8 +119,8 @@ added: v11.0.0 * `callback` {Function} Function to be queued. The `queueMicrotask()` method queues a microtask to invoke `callback`. If -`callback` throws an exception, the [`process` object][] `'error'` event will -be emitted. +`callback` throws an exception, the [`process` object][] `'uncaughtException'` +event will be emitted. In general, `queueMicrotask` is the idiomatic choice over `process.nextTick()`. `process.nextTick()` will always run before the microtask queue, and so diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 2d99885750fb37..bc87801be2769b 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -24,7 +24,8 @@ _umask, _initgroups, _setegid, _seteuid, _setgid, _setuid, _setgroups, _shouldAbortOnUncaughtToggle }, - { internalBinding, NativeModule }) { + { internalBinding, NativeModule }, + triggerFatalException) { const exceptionHandlerState = { captureFn: null }; const isMainThread = internalBinding('worker').threadId === 0; @@ -538,8 +539,9 @@ get: () => { process.emitWarning('queueMicrotask() is experimental.', 'ExperimentalWarning'); - const { queueMicrotask } = + const { setupQueueMicrotask } = NativeModule.require('internal/queue_microtask'); + const queueMicrotask = setupQueueMicrotask(triggerFatalException); Object.defineProperty(global, 'queueMicrotask', { value: queueMicrotask, writable: true, diff --git a/lib/internal/queue_microtask.js b/lib/internal/queue_microtask.js index e9cc414389ac13..6421e7f9400e55 100644 --- a/lib/internal/queue_microtask.js +++ b/lib/internal/queue_microtask.js @@ -5,27 +5,35 @@ const { AsyncResource } = require('async_hooks'); const { getDefaultTriggerAsyncId } = require('internal/async_hooks'); const { enqueueMicrotask } = internalBinding('util'); -// declared separately for name, arrow function to prevent construction -const queueMicrotask = (callback) => { - if (typeof callback !== 'function') { - throw new ERR_INVALID_ARG_TYPE('callback', 'function', callback); - } +const setupQueueMicrotask = (triggerFatalException) => { + const queueMicrotask = (callback) => { + if (typeof callback !== 'function') { + throw new ERR_INVALID_ARG_TYPE('callback', 'function', callback); + } - const asyncResource = new AsyncResource('Microtask', { - triggerAsyncId: getDefaultTriggerAsyncId(), - requireManualDestroy: true, - }); + const asyncResource = new AsyncResource('Microtask', { + triggerAsyncId: getDefaultTriggerAsyncId(), + requireManualDestroy: true, + }); - enqueueMicrotask(() => { - asyncResource.runInAsyncScope(() => { - try { - callback(); - } catch (e) { - process.emit('error', e); - } + enqueueMicrotask(() => { + asyncResource.runInAsyncScope(() => { + try { + callback(); + } catch (error) { + // TODO(devsnek) remove this if + // https://bugs.chromium.org/p/v8/issues/detail?id=8326 + // is resolved such that V8 triggers the fatal exception + // handler for microtasks + triggerFatalException(error); + } finally { + asyncResource.emitDestroy(); + } + }); }); - asyncResource.emitDestroy(); - }); + }; + + return queueMicrotask; }; -module.exports = { queueMicrotask }; +module.exports = { setupQueueMicrotask }; diff --git a/src/node.cc b/src/node.cc index c24dfce0abd0f4..02d9765301aebc 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1423,6 +1423,18 @@ void FatalException(Isolate* isolate, const TryCatch& try_catch) { } +static void FatalException(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Environment* env = Environment::GetCurrent(isolate); + if (env != nullptr && env->abort_on_uncaught_exception()) { + Abort(); + } + Local exception = args[0]; + Local message = Exception::CreateMessage(isolate, exception); + FatalException(isolate, exception, message); +} + + static void OnMessage(Local message, Local error) { // The current version of V8 sends messages for errors only // (thus `error` is always set). @@ -2161,6 +2173,10 @@ void LoadEnvironment(Environment* env) { return; } + Local trigger_fatal_exception = + env->NewFunctionTemplate(FatalException)->GetFunction(env->context()) + .ToLocalChecked(); + // Bootstrap Node.js Local bootstrapper = Object::New(env->isolate()); SetupBootstrapObject(env, bootstrapper); @@ -2168,7 +2184,8 @@ void LoadEnvironment(Environment* env) { Local node_bootstrapper_args[] = { env->process_object(), bootstrapper, - bootstrapped_loaders + bootstrapped_loaders, + trigger_fatal_exception, }; if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(), arraysize(node_bootstrapper_args), diff --git a/test/parallel/test-queue-microtask.js b/test/parallel/test-queue-microtask.js index ea9b88c71e2966..f0eb4364258cc1 100644 --- a/test/parallel/test-queue-microtask.js +++ b/test/parallel/test-queue-microtask.js @@ -42,7 +42,7 @@ queueMicrotask(common.mustCall(function() { } const eq = []; -process.on('error', (e) => { +process.on('uncaughtException', (e) => { eq.push(e); }); From 83b776c864ab50ce9f5622477b89f2aba829eded Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 18 Oct 2018 18:12:59 -0700 Subject: [PATCH 10/84] doc: document that addMembership must be called once in a cluster Fixes: https://github.com/nodejs/node/issues/12572 Refs: https://github.com/nodejs/node/pull/16240 PR-URL: https://github.com/nodejs/node/pull/23746 Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat --- doc/api/dgram.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 069ec40b4eff37..4e50d24d4cdd43 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -95,6 +95,24 @@ Tells the kernel to join a multicast group at the given `multicastAddress` and one interface and will add membership to it. To add membership to every available interface, call `addMembership` multiple times, once per interface. +When sharing a UDP socket across multiple `cluster` workers, the +`socket.addMembership()` function must be called only once or an +`EADDRINUSE` error will occur: + +```js +const cluster = require('cluster'); +const dgram = require('dgram'); +if (cluster.isMaster) { + cluster.fork(); // Works ok. + cluster.fork(); // Fails with EADDRINUSE. +} else { + const s = dgram.createSocket('udp4'); + s.bind(1234, () => { + s.addMembership('224.0.0.114'); + }); +} +``` + ### socket.address() ?i|v0we@>40j4Zjm{MGsS?EcyB zQMp?xX;kp#s8HJXTsfX&uHd1<{b25&mg@QNo8yERcfZR0-yLjs+*f#u+HGW~Joa&% zKHlvf^)Hogw~rT}zxMsX_loa5ytmOW{zu=dcza`bd}@4?`1bK%JH%Ub>+KuguHyFF z_r8~We}a0g1p3BT3RL-yvQ76<{QmgU@$2Ka#~+Tr5WhKoZTxYtHU6NufyX7N5^M=U z3GoRp%3P)K{~`~PTYWKb%Y>E*ogwvoVN}7~u!PA8^AlDlY)ROca5CXq!ovg&UJa*7 z{MYe9|F3v6EOEDQ^~A4z8zV?NF<7rkfd?nPmN*x0k^3NVZzcDNar~8hBJpbC1H5t0 zniQ5)J*jb0yCg@iq`^tA;VpA-Cw+i-%$-QOn)Dz^oor1GORk>WIJsSNujIkWuO-h- zejD$T+nanM`D*fCCGdCm&hXED9M3!a&2)g=5x`!qBA(*%~l|=?NvX=hWcUtWk*xAh(;C>+?XP`Pt81rqbyI7_oz`bftwF@z4AH-6r*#rxn_I2q+h*2^JFTjh zkZbI;Mv{Rqp-gn6@?UMYw$8E^(v1JbPAhVsM($==u~p>SZcUT+S94m>hI($}mF_!# z)WRxmW;Xo)y9IlzB?^FC`H|#S)_=MM8|ZA_+G-Z}GO_FUvh^5A%(l9=Uk_(n-P^DB z4%Q~lz8$RY?N_fHYdCp&DZ;h=+AYUAimbRC;o5#JzY^ivehui1PJukxoXtC12fDUj zw|22MV(oMUG$jMCMIh5%vDt^toKDiaqRqaqXYEez*0cJPZ}PAMpL9LKhpg?278Se1 zU+>ZOeN`F)G;k_e-yQk6&>ihNqKDPBM_ZC>b?wn+_q0~kknZ)Z z`oBMTkfOfU2{cyh0n>e3beIsDR~-q=Lmx)|QK5O(1oC>GwK^%QYc-SYdHCi8A?gxy zJ}&=uS6AGjfAOwvbU*7sayLG5AXzXA!$CacK=MA@{#^UB%7=t3w?wGnNQI~>XWP3s za?iH!kwInZa<+Y8h9C9NSj?U3s}|&rLmI>Nop<|L-J7}_i!eQHDYi~_HXLZhrf%)Q zR@bJkGiQjkoL%#Ds8vON8*Uv#TKB}>=!lWlY`UF`_i~NG_#8LNTJ8Bg-JYYdLpy3T z?uvW5=lf$&X~tl(d2VC(^cZ|+Q)y#2RNB+^8)tRz>5fAz%EoSLsWp;xD@8DD>_(G| zrPf$dJ|12!4ny5P9*-e>c!G5ZDSgdaPVT;jP2u$uQIjv)%3UxCjr`jrY$)UV3NMxE z8RY~4;aPeI4LI|cD3PsL&2RBNi{e8%Mr=h>-NZ0?qoS?f19Kw_oGbKZr!M*TT#0>6D?j7*1s_V}TDPe}@5$}WEzK)Wi zg?$DygZm6gP8N?T;<1`|tS%l?#bXWeSW`UK5|6dTV;y=-5yPg4VN=AgDPq_ZF>Hz$ zHbo4ZB8E+=&8%ba8pa~V(FgU@m+8X{$9V{j#W)XOa&c=Uq*1t2BDxjhZoYWMFoSU( zf)~c6!iQU~Q9(|rASYLlt5uL|N-}A7#M_4i9`W{?cZWArPiCrD@KdXTT)To?N0w8V zWK#8rci6nTycg+x#M{hvBC}6>TOEy=rg#fpOXg(;@3~`gm_)V<(+$Py&EzrtQMf@U zzzF>3?>J^WGm)9XOk>`_yFlkM^O=RrVrCh$f?36^W!_~rFq@byjFb6<`IOnk>}B>d zpEHMq<{tBq`GtAP{LU~Ab||A}Io5;qV!c@lE3kfS z6*hpY6X`Vls?_%@(NrAL8ggQKQtQYOfyBV z=qH9zGrr_A~ zeLg|ynjWQyE8n*;7SY{;a5Tg8N-B}$PF*XPTym%BNCkBJ*D_j0?SP}?poIhnAl|^y zodM~ZUP%eL6Oi01hNlVqIlMdJKgXkG9JDPw@S*3*5qh{XMDNo39F<~QP6wgu#J#a-!>Q0E>rT3{TJu6K{eb8&^z7ny!AeG})GAOyz z8bngFk(@}3Pt^p|_r7b0Y?wU|Wh2+oTs!@w8K4rAHGVE}9U|k;ERrarQEG4L9 zRO&Oz@cR1bX|AGxf|%|y6%f}KTzblF2Q*i7zG^kM=|(y zOW6c48B7DzZ6?lhz(6<{@32Rz_!1J0YlN8l5%1MC6&!69%2;Hz=wIL@cR zd2kVY3vRHCqwE$08qpn`?}JC+DR>6(sH`$PO|T44Co97P&G8T(hOyvm0|6iign~#A z3lc#!P!rSz4M7HI3bH_JfL{PHZE@}hI^%JOW!)h31bsn2Py|ZAFfa<35MUh66ToCJ z4a@{{zECnmTYOoG$0Gk2L@JBd*0(O8sU_Uqnj)3EM99-FHa2{L)-+~+97PtfM z10O{42;QW( z{>t`4I0TM>3!BU4u>;t_>`2zZPGYCCvsuC} zVY{lB(r%z9=nMLRB7mkW9S+8T@nAZb3zmQls#vBJZBzO=KogYS2CSMXRpBRPaqPNv zvl#qT5e5VON!eU4E<6Z7JGRsAtjB=F&yPip;+l?67$2}6cCoq6F~7l%cfS6+)la3W zQIjnB!}}=DnAeYQI`1IwrLMuGe)t8S$CBT0%c$tZHJF;tMk@Y8*0TuN zXaG`}c=A;+AMBF?5sA8-tHHTAkPo(|FjQl9J6C7onG}+)=l#hpHLp>pFx8#+)O_PS z<54D>iDMEGNh(u7();s5>~BnG=2e%z+YeFDS3r+s#xQo)0X1_nl+PK=ET*|its#Xku|ec))(q*FdN23 zv9W9-o5H4|G3%l^)7eb6IopD5&9+6O=CEDa?rcxC51Y>xvc+iJVQiRcBs+$UQaRWO zXy(`1H`p@vfI~HxozE^rdzZ5-*)?o6^}Fo*>}K{ub}PG$-O27@_p_g~huP!oHPtEh z9D9+y!d_>;XMbexvJdeuIlr>cSe1%XWw0J9qspwZs%)wNRgfxF6{(6zP5SA*$i3QL3@3 z@v4ccr>d!{>8e@yUEn;`Le*jw%Lt4a*28FWu8@!MD25S`h~FUgBAx?y|9WlEZ32KN zY=n1lWZ_qUtw6Pj0?3(6FGvBn!?`}5us%HTDAWS->Ht37yAy5;U@l;pSIK(=_>?5- z7%ay2DkP2>DjsPnGzAu+sVj%rS25vCG4U+ole}qGIPrE2jzh^yMSO^(2f7RGECp;D z)0k<^baM3*rH9bIp;pad<}nMHrOa|zLhm!1nGcz*_@(4dY_(SIEjPq|LVJlB{Xyyr zEnMwhvBf8#tq-W?c162xmD}{1ingZIjv1`fcC@uakD6b9E+$r7q1#qhh|QDv2dsi+R7s)tMHeM<3QxyiL8-5nXDC*L9dMR=R!w*L2yB z+gA&w1^J+uPjYNi)%8^|`&HXiU3E^k6uvA*a=V?lF;tR%N=@}si~hbY-PW>K3QCZ1Ztgk&8M8#VI;|WU@Nuu|{!e81|{YVeFU$#pQ#5O@0s6ZK^6R z+kBb?);8BMNZB8P?8A_7CHq8`koeGiA}YhyKf0pp*{Wfo4;|_!sGy3@5tfHu6AdlZ zM-5zsD85wzp@5PFAYwy6^F@LXEmJ^2xwB(-AcqqM2p z5%vjQ(MF|f>@B!Cs92;*^j9IVZK`v8CT>$H(@5X-MBhD~(koce#UXm?hGBDyE5*Z8 zX`l`MJE|z&J7S`{#Wh4bx?A=K>jGmfk00=uQFj$PBIcRrTCR9ktjBJcm0Pjn^()xt zT^aQ;o!eC`{}UDUd|5Rg&Xue7DQi}>Vi##k*_A3ObG5u{SCORK;l>b2dZ@k`BuQbq z#DI0{>Oh6stvaMSraG;<_?Jup1l#C%{GUJ&1mY16vnQ zk^r8-44}&}%TyaxrkeP@eJwn`0QwARzS1i>uoJZYWn(0uOu!)? zfdfm5M-&Xm9nz<8B$GR&WuM%^LvU_Y?93d-H&>gRG0jG{qGa}_$KK8vBl&x}xZ;w8 zqTG^_V(b}~Bn-|kE*ZiM9+F$sJGZ2_EVz6)CynPnQG4VS7v*6~G(V3toWuu{o|E`? z`iO}1mM^8ZW60h~{1l-*w(S@!Nm)30+v9M|XVOXc$$Xor_M$S>9`iKAv=_G?GcdbT znd(kmpzSaWev?nWn#?C8V&cYSKQ54C7?T)JAeSI|Zi{0X`wEVsTr}?f%%yUq_7r|H z**Aqxc0QfLr>UyGj9s!J@X{2UX+3dnjV;h&IJd$|Swdc(##bRF)1WnBrx%(P!!&_E zx?S2HXL{WVXSxwhH&$u*Vpn`Cv1y9O4=@>Mu6&$nxWPF0!)jiLb2^UHo%+jgooPYn zbt{~kGp{fmai;k|dfmj`*MV@LWi;7o1bO0aZ3o6`?*R9FT+xit0KHsinlY0-!R3D_ zLNM4v%*BVnhUtUxEpbjqwo6FybUsX*i@fELS=0GAvS&JPZ|w8(TzUibuA0gFB?Ka_I*2P+Q$rJoa}%8D zb0Biy-T>zmE?#Wh>RdXPLXu|k^|%(O(6$W8pUFoz>>WB9364d?u?9>KZr}V?1-bw&%=1gelb`;;;@QILU(aOa} z&qU)&%}l#TzSvRH;hTns?TYgNCXx8h;zM*a5PAx!g^Mb*a}+^gW1ybj!_$MiLCO-{ z3drnPJYEMV_Co5RACpUp;Y7C1;^VtF#VE1b=_Y+UB$q2j(H=E9RP5Wmk%?ZS8*Q01 zu`ORhXOXfag>`Sn4;1}LZgjMXFg<^l}!g$$@ zV$(<=T99|j_z)64o9FAK%Qce@|58Szu}!nonf5Bw0)xh*4M+z-fm8!z&}=@;L0e85 zhBPa5;D&KoVip)CihCa!iIp=o8B%k(U!`MYN_|2a9yGaTh&o9e##y*0wWw4KdRJ;u zDz!tF#0n>8X7e$`Fo(BmY5L7b(i}eBoPZk0L}JB^59`DBV@T;7-bS{};rS}f#hRtP z=_T3~TvHJ}4MDOOUyZDs%SY=5qXPP34oM?BZ!6M(@KppV z(r(ncLdXm6bVZ^qN2ix0wCDh`Y5^Y=l8$M-p{tf#BMmyo(4vYnKcqt9 zvyhL}#BjY(@Aw)Oy>t9qnDL_*@y$c=oh-Uop;!`k3p8y* zTZ0Y_3=W2jTEtf~xbNY5-6H-xS^O3sK=!39bbIQK9H` zHSdF>&s)rIssaIyQq}$_$}|H7$ZjrqX$e0z*be{ni%>@F1%q* z>NY7u?s-J&46PVqTgq1x($Rk#VdAAtm?4aPi$nW_ z+U1q%#;lfY=XJX=OOJ)S4jO?@iLo59EaM{`@nY3B7n_Avb0nVKOXsLIu8$pa5M82a zV_EG|lS!S5=8R75U6=^yP5qu}UF%*~%-acQMmk!0i|bo2Gz8Tpx?r23;F;!+aPb~h zWV(|j%Xp6{Dx&pJm$Ys&P=)!l($K+ZpP*N?j}9hZF5}00#<|L6heL~UzDh6pMQ=L% z(>5wV9N3HY+~K*>bA#uXo^^0VCrUaJ?U>|f-=l+tehE!`oZ^#iyD3pqoyy(PG@)(f zd_AXTIq%1^2_$X>U&WISI(%J^So)L3EBFNe!AOJ-C`qw%cPq3b`2e>)MXd-q8H}m* zbvQT_A9Q#qiBWBUe(g*Lq?Bb^5n?YA`&56(gT-{Hg6Zzgl?R-(3^qX=)VDMdXCk)d zn8ya-gA_>PxA}IBhcTZ9QO)vP5S_JY0g8~v0oy@<|=-C6kW9FxGi$2KZ)pMiAa}rZJJ@~K8`IQ z9;^92US?4xY^+H~-zQU7^UWLA*SriRQBp*dDOS>(TA%>5$qNt-txKtE+!4D*298(6 zNp1*nthNQ$pxv0x2IZ(qMwDq)R=jFe>8d@wA|Y$|KK^v2rdfsNi=a~dCL*-~WZ4=% zft+8%_as?s`M@?EQ1x_;ND#}~2^ph}g8u{&vqu*^v0sQ+_>U3!ifUX+0@C^-)yf-d z`ByyXqD-r<;Rn8@9;soWYkHDrZJiK4u73YU010oT9EhG@%^hx3ar&W8pC%i z(#*%e&PNV&!7x(mT|SKTdzZI6T0*&()O&iS>Ij_-?5>G{UiTK&lO(v(NrJ{48>}9TGLS z5=pc5FathW&)c!GQcI=;_c4~pne}{_u`gCR>O^OjAw>5cU!7#V$M-Nw%GFS~Vl+F~ zz@0TpI$trG7HbT-xq)x&touH1XRE@_MFfRnx^zyHx=*?2Rzx~&YDHYuYzj;Y{z-_NMb7omZ}Jfi`?@y8*C@Os^#$v=|*o-WER0xo8WY#+vG2QOV@&OcK`r z6pozzkPkId+k!?u3KLl_`Q<~}5+9+_>OwiA)?Y_Wb1Z9lAMt0%v{r)2gBFJluim7C zlh5;3rXq2|A|E^X@!s@)2FRDDI8tjXA4Mi?BF_1Hpu9*C`=1gtIw9K4PHgRI@oHz%r3`Ie-|r@Y;p&MS0*LMCWl zont@c!&q`{C!Jw;@P#C3Cm&AQ(?ck4wlt-srloh49Ldrij{j0a&!g%G9VXRKuXQke zCc_4&iUX}r$@HWKMiMeh7VYE%1Aa$HX*x^hvY`yyVYW2E8&={u@^B~LnsnU7_w|lq zwyQd8KMmd)>~Gio@hWldf~8QoU^STnFq)kvAabDfcx3elaplyR!Gf>G>G7 zzi%&ZtB@%vnHr?~UX8jOQ_=a@nVg7p+Id+t<9|7G8e(mV>?hOz+kR&%cReX;EFeG=U%}Pp-@jXcL7(qh< z_w(V-%g6Yx_=o-DJYEO|Pg2v^$?`+ImFzms>%FOkO(UXX5-LC0dz{~?YR)+ap5QmI zr0ExYee&&5bm!z#d_x~7iVTY3RF@jY+6!rDe6~2xd3K_Zg1XX&=2RWK?g*SxIwUn+wv{*`EsbXD- zBEi);{R-bmWv$q2?XG@%;40tDhi)SjVDYD83hO$O^0>xV@hO6qP$*98xv*6+_mbdi zd?qqY7lOg4F=@b+GyTZ$YkZPV9@_RMD8j9q@Ki#UBO0>B-)wf8uJcD!B>n=QO#%bV zdgq0k{ArcAE0Dlg?4#||?UvB_QN5lSF&8>+@xE*ZdH)sy)3uA-y~P`d+12dIr)3-qP5yJ)DEw|T!f+NoQiQ`7mY z1RuI&NlRjdB@YW9{x6u!x{X}~Nu!|0ByswnI#+Mf<_rerj@x`7xsO;$-5+7v=_KtZzOL}+84M*Rv!W4u*-w0y^Zrjf9y7A}0WvdxKcd`t z50%xHUY6X$;rKoD*{+WuO}vl8%13-82{5ATEWVHW4EzOdhwoz}zTX4BxlPh*S~2=O zw~j+)QuY{yJoJDs^KCA+J=L=4B2XZ%xQ5LR$jO7BcV|2H1|re4z9GWBwpZO8m@z3>sK2d^wXn`sAJb&2rZ#rzYC}Ou zhLuNmnw;OMg?_9c&2vkDsZ=pC6LToW3eO2aq?8jTkU$*{ z^X(Xam+$ZzlHCw@7wd#Ta$F|_kURYa8=3hNodI=1M-uJe{%rYr?dGHn^ibT7WPCK#2rAo%StCjJNAI6>J3fynZFQN_}rHg#YA;F1N(d8Qw^apbgqzOSthmK^oLRyHb zq>3Nacc`TY)ly1lX^=3GYzPqob*{yjun}19O~G(paT67_K3Iq(s!$Z=xh{Km3i|Dx zVAM&59e0O3LT{UC7ocy3V3cLI!rhj4pftA+5jy+Ru|hWx?ui|QHYx23_~MVW2p59s zoXV4>JyAooLxufx?D~skN1WP9be&K`Ed!EY_PSK|eoC2vEajkjm4e zF4FB7hVVtP$W1xDb#H z2e2+Z4MQ1c)DsNOA>qO(l?T2Emp-J80ZL~^6mGXoK~=?v!T0egh-qV#P&c3%wzsQe zPR!)q!I6GrWM@*jM6L!$@B4ieE!0<$PgFL82kq#R)?PhUXh3S-!4%iS*QOy$V})B} z<15JE)HpQAo&a+|jdrdok@i>V7rJyyjDCkozclJE_K$&xkQzR81c+OOonA+(VGSXB}dZc3ZY?vy1M+{L&^I53i=P?u+q}jzJHwx2J z!x|WYbCwAFEAR0LeszUd zGOn(0+*wpl$YROE`sh9Vx**`m`huNU8VFs;&o>2s=gI~`01E}MHwn3jiQq^9TK^ap zCbp354lq}7o@^*gWu2qa1pIXP^e>q6`(+3#N#ASGi@L2Aywq5|Nt*z(FaCSbwUiUo zcopK+Sg7x=|0<+8uAIL$79OccVl%;3?*6A3JYd-YZSPs6^0<)XWW#Ag`;R6e8jd!HO;w= zNvymz`tU~$1>5{=RQa@*g<(!RBo)bOEA$}8_aJ=YMd(QD+6txQP%B!yL39WOBbKao z!mc1i2kgyU?^96^q}N2>Ug+tZ)?P?s33nc?G-e^9_^yM{Q(FB4UqNrq>IgTCOiVHz z1+S{o&Vl&VC%TdJZH{DW&>89FTl9ZxJ3>ooLf#KF3uISk)Y`CE9L(ov(K=yy@7EFY zhlYpSxK3EQu};q$Z>vJ4=1>*oYt+t$i}0HE3MLrTot~8D3kEe^AFlicb$#&_3|siA#$iQre<>&A=F1Q z)#zeE#|+h^8vTmS*|m#MUqdz)2^@@)OzA_WbQjhT!(wEtX$~4Xwuf+;Y>pCaI+rm` za<8EyqjQ?Y$)U~fXi`J2V6Xao&iW&VgMRWpi$! ziTaKfwtLX8!bSaryBXn+W#m?q32PiF|>&Z6nU4A$BA4Ixb>?Ia|=A@I)CvxI$G zGWiVZB7Yu2KAk6gL{84f<+VFVeaC#1_Ut@d?)w=BKO(dw<}>Ji!-k;mmwkw8D8Gl& ztRr+_FM#^n`d4(lPiUr13()*c?$WRe(VIFh!rg#{LT~czTkt$?q0pS%T8JcTUqIK} zwFvreMhH^NuZ48YZwbe#hKOJ1FBVofBbNxx*{XEvru#y4e~Xr$c1hWd+|yyj9JLhj zceB{MOw#_iYw?3J{h<))JiS!tsg9&Qi7xh3m!!M~fE1JpcqVYvxX20cp8Q zxIvm9fUnCM8wY)O`3)fq|G<<;*n>h0$=?Z&sh^{UyY9iF@|cFhtQYAF+AG{;N%Sru zoNZ3pd?Q$$_RoZ96$mHXw%hqZerZyfSdMpt*HFQ_f?1bhza_Po#@Q)?mVeh{96F43vrJW4w55~}K<4RcD-=g39r9zo;0e@SSm zcFw#i+-FH&jm*&FYuA_-^Xt?A(NU1y*hwvLhj`P?JOtVD47&Ti;9ar2C z5=o>7>M1z_buup2W^&qY3E8Z(><8gD6-mWBMQ1kn`~lYTW|b|TWc$G9CwGJkq@&gr zP4@9No~-@}X&t+VXua+V+sVVb!Y*?7Yn12mU1WKjH~Q#z(rN|f5T^)g_(f?W;y3D!wkbVC?+B*ZmEG=Zm6iJn1~C*rkJRh zn2ap4FUocR6;J^U3)6~8DpV{?OiC(COD!!;D=jT6y|wpy7-@Ol?)!e9_xb!E_X+af} z_6}O{6DGn(H12uAenQ~RhX}0y2{)!cNs-x`pCR@7pS8LC{VJiZt{9`w-a}@=pQ8ZB zDiHeA3?%ISDT@4o&^h(@w3md%!NlLXhR}%PC^wdgINL|RXdOr%t)sJf{ieM~_7CZu zU>nfe!nP@4SDP@|gtw6XTt48jjc7ytsx{ zec|s>F`PnJk3Zj}HDDJR zo`h^0otSjWAiM*%?;E-SU;8^@p>vXi?Nj`k2e`%kLVT(rPM{jIvT#9isg);cI!V1AOp0#hbY_5;RfL!Lij_z%nUx&huO&oYSHkferN|YH|}3<^vF8h&#l<7=co z9|DKqH3lYyLOnq= z|7y8l{@ClI>h&4e>+@@`PZ=eIYJ|8W$*&v)2jA=E)|=eTUZ1tS(RTDkd%f4()GPC$ zNRaQu#c3a-vtHgc+he$!6i2hiqH0qVYg1rb6|#K!>V(UEkB<5D`FewLn2-flp!d>Ey$4zPIe#ke6m^N#I=@ce zreCAm=wtM|^au0>`YMjJ+@&AT43+H3Oqk(hbel6IIk^3-s^{wb`)6;-Vuo}Z-lMj@ zu|b{r_Q~vbv&rF0rJ3`lCw}H?)^ByNx(^9k_q+Qyrq2g{V|r0Kcd!ucfLW+taL;RI zN21Hss7qDO*F4hPlqblRXu>qHnrCHFd=0*O_O1aFo_Th0^M>aKjGk5D-+%myg!lXp z_@ACRVE7=@Z;QUxo1d97Ym9%Ze^&f)e5>S1Vv$mzovd4^d!Sh)JD^#l*{%D`s+p_Y zs@$RR^w^*rp&aIsrd+1{P*b9-QI=_D>DJ1wYS!uIXsUGn${ETsCF_x>TO}K;d_$wt z-PN4dWa~D{3N*`f(=?NmuV`rPv&zl7Z#9KVCy%|FSlKw`IFIF;c;yKVN$jQvIZ-h0 zC^v^}4zb%}r^imW3PE!)INRx0a89e8?&ln^FJPbG?tqx!jyoE6)NUKGejCp734U#v zZJ8v|&$+sWBHYk5pBOS7=w90$rFI=VgvF^o!T*kOMCSVG>!;hLyoXFfPOsA~l#t5n zba!UAHIwd5@OApm8R6d^u*7TAygvVPN6sDbIbrv&8}Sv6WD5m&o&G3ko>%bpK3B$3 z;olJ_vWqd6DlwXB={*=b&2$(YPDjv=M7TIn{Iu9#e8cIe(;?<1}bNV;Qy{rz$I%$u+ z+O5&)6Ngn!3Dg7iXXHa#|{@YX=t?ucU9ISO4G(;Mz%X+Cx)cQ|T zPMB);nI;XDhHgCe`dLACv75+>x@}UA#IZr4(I}!@^g2DRrvihi8!N%<^vYxJX1<## z>U9ad-gx%AGs1sgxJy>z5Fg8*;k8{Wj;=WB-ub7`udg*^o*p9E_ot7%`}w27zcBQz z|2!@JugwZ8CQ0A4sOX)5uhT+}`^L4sw)W94)U?mvUQ4_GOVdmLkhj;hPs(1;|1>MC z|2!>TR#Sur_3~d<{m6AMG^_UQjQ{^T5QQs=v{o=1EK=g=z=a?9{IE#;&yNP{>-1lT!~gZsAoTw~FOvM@(SSwrkKX<38o6qS z`H#_HIchm-?6i-DgVW3ZkZ;O7GsIzE-)Q)!HPZV3Ws!VYEy7*f0^CGJ;l`$K#NeL-y~BuCUA#gUq7$N8r>p97PI}Gfq9?@dqA@a? zTcevJ5iqpUEv$dk(Bh%W&`WNs@tLy~{rzIu*ndjVDqI9!R)0^di|xwUxSmY$iTlXH zE&9pgx9DvPv7zS8LvOaXX1-}@{XFugxTc))SW(>2ly4*NN3Mu%h^yZ4YV3g&P2BAi zRZ4qgLu`56#FT=a`CHe_kS#hB`P^354R6O5tb5h+Rc!F0gOM>iMLCn!t8$r~Gdp&y zADg{s$K99HtvlrVGjg)C_vH5MFVDG|8+0fyB_fZ=y_6D_^Tw_p*5AqY$$f68_pWDi zp4s(gN>ErQMVmousW!=h& zNO^JnGl#mf@9y|lu4L!F9jkY_=Q|vFIyWHyqu90`vunP|3f=nFdTa0tmtLN`)o`dL zWm)#vn*8-&?AVs8%p13}BQGs?%C6wt?)Ba&j$1#?T~QOb_0Z0g{MZyz-WS<%>wnFA zVrTLT_x8P>^HjcZtJ}`-oyPr7@2JYo*#G0Yb2V-IinHd%cJIrI_1dv>Ytz2BciyN; z+W$m$(EfkbyjgThD?MU0_yrVGh=FWB5 z^;vV{lrLDeifeYRtIhjrYw5n1)>ZCz$i7p3Z|kwG4|jgDb5?d--hdjeMwdM)>qvET z_803?*A2~b*|n>tXKVYqDKbKt=W)@gQuOb;*ZM!)zyGa!t^dRQ``^0P`aj&i|E+ti z{|EgmTroljk$;hbB*tS!s4zYlqSi!G9d0ieUlpAZeIl|@7N>Pi|1|II(;j*YCeL^= zI0D+h^2Igc1LDKtR_SqZr?^LaL3~yGqnMJYC0>&LI9fST5+V8CVYOtvBwJD>DV0=7 z+(mmOui+C$mn8QjVyQ~XN&8DjOGBjL(j@8g(oAWdbQ``@@RsxgX|CjR=?y92pmZ=e zm>t^0!T13B6o=#FY=;F_hb0bc95y>-;$icEw8G(lL%YK}4j(yu<1o^JkSQb*87K3W z`OBguBV?0gb7YHT%@UuU8_#@|;NhJ7d{tM+*%KpZ&A^^j(Vov~R&U$xs!(V;x4*r5 z<%#Etk2uU-_4V0Z(htx2O?g7o((-KGgl9ABPR?3BLU;0fz2(69v#&mDU3U88S<)Ad zo%&Yy_OqE?wWZ&VxqkMSF~^P^jCdBA?A*YsCh z9a+>hXxWTqrHc{R)_Z3@xRe|xcO#9X)C%go|+}`3&bP-zc>MX$&B?_j?bA7U;`A72@vmk3V zx(ehA^Nj2^v~t{+yy*DC48sf&F-+O+*x`7}G01;(u%nx!+n+vyOZcaWF-}i8jd#iv z7m1yr&0@Thz6V<9jK3S6bb3y7^6Z(jYekzyl_4~-q$e*#4c!*Y)ro51ozfs2u$c+f zIwAb3*O^!!yeJB+d7Fs7Wgwy{=oVE-nwxKm2-Amn%>?~DlJA7qP0_F8J)i#(=BcSA zGr(3aEOjP9LYPTlt5J$Cnih-01NYBS7l;%Q(V>Vl1qc@t(UG?F zHYT2Sk;Mh|oxla)2LLBiO~FWRIuI@41Ab*%Z9g1kI!T>9yC0F=C4`Yu07s5} zq=aU zVZRG3=P!0LvwNRtpB7F3<3*D28mXW2Op)*cX@Te&JYWhsQBKnz;=^>;@G_~nc`ilF znh!ve+N`C(3Lq9(39JUz0ULod;7bhAbZ|CM1e62Sz)oN{upduOvt9yT1&#p60N!+p zS;4>fHQvg0pJH^C@8X^9v+pwgYI}wEp`yotlW3%1-t!c*kaszbce}<@Oq`cp-K5lGJ84>s-@FlV)iEPnV;E}xNX=aH%UC1YS z+tXbNvFix7f@!3ihLj_b<`STWKXjUzJ^k+kOeA_h2?H!q6iDMlf8Y*a1BSpW;FG{s zjP9L43<|dzh0OpPkXRkiAhThReMIqNKft^9!1tLnXL~6GrGF`MBCyc**89w0@^Q1g z1)p=k_Xr)vuQ|)iw-^7}vy8=LkN69MA0QZSMgC}(J95JGgn|#a&di$p_p<+Wa-2qm zzW{y(lt{%37zxY(mIHf`%0BR51z{RyE9zkei~d7PEJFUPfoxzWa1eM0I1k(gM2uVAG!I>Nbk zCE~FXy~sCQWgc1WUA+gHy@K#lfCrIBe}L~v+TR;r5D71_{&%K)BMmJ=z##xS8D|{_ zpo($Uhrs8+W#B8|2JjvKFr%M-m@x05j%pSZP|eZ;P^vP^6Yv5012|$fYZ&k(5CS|6 z4C0T!kKZxUzGfO8x0u=mV*r@R55C4+^sv_~3?9#jh;51BzOI|%LYT7nf!CSY)BgP! zei}`&81P5atOw@-BT(d-Kt1f2oe9%dKpqk+LgN0|FU`#4xo?;R>tEi%|HErR`&+@^ z(5QW{;~$CaFXa2)4T{7IdSAx>eJ#BQ%~CRPb2Ec$ak3{7%}gMoXE+hjMmHjQ4zAUs z)kJhpKZIF>3G9O+q6fiK8cIa#vWV!Hx`=2|D=y|TB02{C-DvWQ5WYTxh<*@o@{Dk+f8_Z2s=%XN9e4Cs7T#3M^ zfW-hWbl?E~*bU*gM`5i_{+9W`|4-R;$kd@vYr(Gref^s1N|??9{1fgb}&{7XMD7cKUg^9wxI zBBn;1Y0ORg*M?X}{*btm)vTcxXz zUxtJ<<}U5lnCK{=*9Y39|kU z5Ftq&5CBXB76Pk*7NqhDcnm|BLKxdEj>T<26vevm%_Qc)(_i5-*yr?l+{~|{Br28& z?8ow#NcMxrcLlBRT?pS3;9#BmM*O)LN32fS+S>59bZGzwj5Uc|CRVal; z3$g#Ly<^b?&jaN^Gtdrv4BP;I2gV|m@kq55+-93CVo%Zk;cnv#Nd5#UI3my!7z#`U zqJVWkHc$z?2pqL7b@>0i8&R%#tD}IBw%18vh!S6P(7atFzq40PYab|=22GJlRVM;Lmw^<=Y za_+!TU@8y=tOxRdI^dFlFkJ<&Mrvz~k8cUT@?`fso&g^t*9jh2Gd=!n66?ReAE-tF zTYygBbKnO+is*V^FtE~tFs%XS06PFRkxz}J^YO#me3BQ{i(VC77CDO5Vx8Da94HUV*Qqt;K_)4fpR)<6hW;XKYiMFA@C^w}ZoQb5W1AGZ<^-+gNz!Vs@XwggDC) zrjOkS(|H|Xx~L~iKcO$OQO6b(fFf?levmacS2#eUBS7QD!w0g@Wo>7P=wi4p*;e_m z?~r=C)B*Uk02Cp}G&eWEKA)dqX5+o>0dw>4W0M?gp>(5SjoaTM_J_PzQE^r~De}Q`{($w>3`=eG{{86hg zfA*=z2}@T{KYs22HuSL+9ye$C{6$I! z`^$n<{9}OtcntoFfFJB0RvjOZGE9>at7~uG`?01=q+$8sxkCso9 z&y+{XSIFb!Yw=0>40*AzHys3sVnWgMCneu0Sp9P?HrH2<(P^EOcopzG?CIbV zpceMM;KM)%?496`fUB^71O5e&qM;l;vGM@cfp83lWgHL&`yB8xAQ|=)a28MoI}dII zUWNU2a3}CF?B~JPfqSq&1S`CVzz{Sq1MUY*fPFZ4vH;lUf@6VAUW93j7oiF)hGRYg zs=@mJBfn-aI{>FblKHwI7CI>gvrjk+8`%e9r?CBi?mGU!V0PsH%k%DFcFdUnMG|ik zh4aP226#c0Rx|E;``%mPDa4xy^aDl$(*dqGYpIaLAm}hzJ&<+dpBl_^u67?`SLBM` zL=3%xTD!M!_Cwf~Cv3Zi=Dpsa!S*RK9ceNmj= z%=zEnV|t6!&+zxqzn7t3ZvrF#F7ofo(v1Aufe(QjKyMF>;S&b4-{}8rEQt>;+CYEc zNx;O<9>Rw3EkW#0f02qnNF1;UDEYTi%?NoDcptb5{3S>0pE*84h_f$lh=8GhjPQ`W z?|9zvisQGA4;D1i374|#;Ps2`&onoAxfozl&Ml>L7dt{*NcRX~nZ6XSYjZkC%tay#AQ`YEs*wO4X zRY(9k9Xs*rSztF@o<9D7h+gwPo@m8*L)$|{AIGHrREls++`|~}cyTr>3~8?cuK)`l zPZ0i0#05WWx5OVsl(|bZ#-hviy_dOAJon;dJMiX*z}8A)H*X6Y&R(KqK|_Lxq@}B3 zR@erNVim6Z)M;!he`q?JVF(NyLQI@TOpGMvg%Rswl9S`ttxn!JCCRdy2pNy9-0W1} zkSWBea;LS;XWy#N>Iz(>QxHo|rNN-*j6tAtq%hF=ZycEoV=A>O|f> zjD5m7V-m4!l|9~!S;UOl#Edya81(H=BGxA*+hc{z!$T!L7-x^TF4oSoW}u;o@QK8n zsl=QG#M}^K?s#JEBx3F~B5|X=&=Da-#AG633b9}sv2ZRC8A+^*UllW9={l(KUAc1g zhL{zEEjNt)j&Vf%zuNuoxWF&+N*@X5MYkaT&WGHE<4rjf`2-|JLkdqKW5DG!Mf~cUw zEVQ?bp@bka5g|hTgwV;op)-it{E2YZkDf?G+OCJQuB3GaswosuXaFJKDJZI-wQ~V7 z5SnKJu3bXYgn@+&7C=%c{WM4m4L1idgz!jYCNx7T8aEyshAhLt3s4}T7(!DCax>s7 z#GeB<3TZ?l^Lr!CL9h@(XmKIoNf4OE7tLk$VtkDdTh?Ei%X$wKk`Y>1NM=?qFYHZr z4id9xH>)?br%}Mk{Hl4ZULoXTFTr@eY#!^U7Is++1q<&jNF-d-c&B;n0BZ;m7bGVm zNkIfH-pfLp2m=5UrZ*F){_f2r4AO$!OqfFEbI@kOaG3+QP=$GL3F*y)kHGVLLxij+ z^|rb2xjCVYg|GBZv|F#f9t!awtD9k{w5m;CDr`gLu&bR>S`g$v#g8 z@-d6pLA_~?K$d}sg*Zs_wMDE4|HJ||m<}dJ@{1R+EQyR3AR{6Fk=TkolK&b}Z9|`7 zZ&5TpRA@6SVRw-juXAj#MYA7M(7!a;wskrC3Ca5`WM}ar3u_{S`56}0pdQ{^dO^jO zkfXpu`R^_4WSQU`2G0?EOf0+Mu~XPAE{hH=>_bw&U|MLJ4*^B#X?rRVF&wAx*WGQ8xfn`$xh)DcC!6k*WwJ906`sV zDneszr+2dJ$;Z)#*~Zkeo|G-Qo^_6eA)utLFf0d2EKJC%kiSU>|B1?UN)3( z*~=Q8SK`;E}b#}Uq zJIK1=X!12zjji9yY_lVJ|J0kT!S=(OYy)MhJ<3Ll#OPom(DvI2)vKU&?|z{J!nk(!zT2M;0G;b{EvHC zz0(L3TTn+XwAN5wf1cIz+s?D@;$(E(V1D0u)(_+N{qrn~!&j`o&F2F9G^L0|l-aoJ z#Q7$E`R8l_USSJUY`pE;&)Gy7zyB*&N8ameR~6syI;*nfUuT;|iouU_#wS+z0pGE{ zG`^w2AODm!pw=IM%6dxe#Tss#^Bp@=j6q!eBkSpEFPIS5ZX05={m9NTQLuP#M1;#EfXdK#&M5c}Jy)fD%PUyYz*zLl{O8XL- z+#AvEKcjcKx7&sFm%x3xpbQO91pLn)+(3E?4iLGSxY15R;p}p_LE)F0xFP(DCXVCZ z_2B&J@lZ!S+mjo_7ka|$Wlt`Ezv;=1;;T%Y#uFdI#axLcmiMNff>9pyxNU`Fr9w_$ zo4DC@C^4Vk<;}7DF>j86Y7CBZ4(nZW`*NMbd-@=Ff)D496Fl7WJmt%&c#{|R9B=aF zjPzV$I$z<%9ncO&gAYZ63%#@)gB3FXWAki3jwPq?7yEJEykmdPk>Baf$@xkBIVF70 zd&75Se|Ti{=QwDa6-H!V#=uYmF~=oT8!Dlpo{G>G@gxxO_Cv z4Bn|fH=3V|0+I{)?fuc*@Ac59r5v*-X>92_pXaSzIpfKAW2$6ZDL)M8m}J zi)V97$RYfp+32V5W^;^97tSS+nC9E(a0mG5PjJEfp1GV3>(QV2CfZKTmIR#(4g77@vafn7-^b63cAW&vANE9E6lc+Kz1G=Fm27GuJ?qD{XIW z;YQQ^mN_WEPnq1yj&8z|BD75qx?EUj`|Lw(joY|EG?{AqxQwH5m70q&d9DgQ95)x) z{;LYTI)r~%g^5r&7lT++&6)V}xtxn_L^aos8vdCYu8MyX!M2}jxDRA*%W)T( ziW!&&7QT-lEY5*&4dyR4a09U%3+KIs?peu88@Va?ew^?TW2g>B!_R2smXa3R!A8!5 zlnUn^G0^#wP24!CT{TLQ?e`{bFAdH9g6foK`5n#NZg1gaWLobS5H6i@NGz?lsRWmB zzB~2PTlUS6!Qeg7u6LC%+-#EM`!iRGu^B=v+n9%w` zeEJ96AXnisBYZnTP?*`_LVB?%v7nA;InVZRpE(O! z4DH$rdYj&MyN5fW@DOxiuI@cFY}X4c93L0-(F*MZjfb{_m$;1zYuYg}k#_9%+c%C_ zI=YUFiL-5K$NKDl`csf`ZL^yq*zFR3+JrQeFaEE-e})S&cj5SxkcuGt^g+8UWrbtV z%YO>~wE%zm3K2iVudjU>3+~^t|61@r!~V%;&-kB0tbcm`J-OR&3z?1U_%r<9CqfY$ zkER{_Q<6sU%m&xCzxqt3lSEMpnm9myot6QP!pYSd1-{=LOZp`w!6P{C$F#%XC*#88 zDd1_;nY2`}ALVD=1CFKc$+E#CEZ?RjgA0g(2`%8KVjrf}f|nAP)0)9qF3C2%)*!^Mvdp%c z!3o5D*%gG>TH>uLgonlHt@q$wMNG4*tTauO6NBRX5x^76tpVUWmc`Z}@cZPvGzvT^ zcC}Rkel_N$#8B|uxR0%qz%$8D5|@ELBkQbV!GowTtrqb97=ICibOVSESvcJF3D>O& z;OVjNBu)iKSQe#4f`^b-d%$i)B;5o)7Beid8T_kd zV!~Lo$&hZDl-Vub$?qm$o+dpsrHat$mcGGv#) zyNEQ|E%0#4S}MB(OMXna=pHyS&UH%%G8jr!${xY(O=Zi1u?hF}gcdmkelMm;CILss zEu)p-dP1=!2>i$rMeD$;$9Ks;yq&0oHk}W)#I?$kz)#1d(8=KTg!R@Gum_PrXMnB4$uv3*mJ}kH z&IT_h+htKG(8{>O@=CauS@P*p@Du{4A;BAoV!9T*GDf;`5BMbMv9byLJmHhvXj0i_!F08_ra5?4*HQ3=6?opMV1PI2V{gi7=tO!(k+vq zq~U~7t^)r;P8I1eoqUNN*4g0Dq96lt+S-V=mB9;Dp$7bU5VFV(!Q+a1SRg(Mez%IVUj! z8LzY4lKF#a>X9rN{!FY~Ze0dTs-=fc0beI)B>E$PXJh^47H~@JEjk1KC&+wRD|n0L z8eIvV8*_)w2S>+Tp;N*0$sl_yr(M|AqqE>VZe3!I_;@lh- z2y$!MBk*W4K^~0xIe?5wlz<&9iHUOXXo?ak!C7&etXEL8LW@Kc0k_hUCTGAJi&+!~ z)>)LI1hl~C3HNC;+&g2ENbZa*_tgB5Pj0BI8Dp3#IW=l7H0h~#8$}fRSEf&#OWb`?)M>Giqzf3fV zf~9B?qFHne;a?LiqMP7vh{K{t67&CCqE&PY9=C`#(LL~wM7!ud_$Q)6^a%V55v-tG za7cj|rI3K{6P+SC*jd&kx`l!ar@KW;xE~T@6)Lbo7OG&t1UX5eLf1%T9s6}~)8tfz z5iB9Y6kcE%8Llu}VHr)k`uT$$$p}RNcqa8@NEmA1O!kO^;8u~5ieT{XWU71;{GTGa z<)h$!gZ#|eh5|@&xekRpGDat|!2N`!M?Mwq!^9_vPzOf@SyJSYa8IMpiKfyNaRK@Y zDdLi-2B!6j==^?)xF!noqllZLjo6!hOSA_8qsZJ)int>xg?Uf3FcC*OL=--}`bcyb zp_F(I)}z$EcYNMfqE1wITdN0wn?f7rvtO4uVDJ5byR@jH--6km;_h^St3 znfNq(EaFN?CWtS>o+Q48@82eiZ@``+eg$Tlco57CaU|LxTRaT*e6iIVNfe8_k#VUw z43R6vw-Hb)zKbu*?-94cr%4=v2z$tIn9bsF__T;SU>+9VLI$nkW$ zOon+!oDcJ!xDw`laWTwCVkwfKptlyaC%uvAeOzqO9TF$_$R%o+N{JgxmE;Kg8A&N( z=_J1JF-k(<<0Ux?(<~Xh61DV~Ook&sQY$1)*1!ysbiy1Z>3}&_Qi{6j=&3M6C4^kWMm`14zK3>vp6v!;K!0s<)kWGLz74{%$GR#WS44+`BKg=u60WfQz zL{&C1g+Q z1RtrA&Lb>}1Vx%6Us0?mRa7dbZD~@pDmoQiif+X@#RY|2JbTM6g;}h0^cTkP%=On zq#Uc1%SO>tm0`+oDnXg1%vP2v4=e8}?<*;1m9x%y8EFl09_8F4IVYLqoa~(Dob8si6vsCSS4n#HO`35aRK6B zt5`*k5|45W6;HxGxiE2rI7+-soFGmTCyP_WY2plVHqMk5i%Z3o;#%<@ag%rt*(`1m zPMC_@#O*j^+9mGBIn#6ECh~&#lK6`Fn)s&pmUt?8M|@9wU;GGXPosqMYZAFcDN#un ziB4j~SyVH=R`-Yul2}Jc#!7T_sDz>>;gg$Tl5iYQ4W=U{QIcjdiCiYJND?GTl4MDW zBvq0o$&h4A@+HMMxLPBrmF$sZkWG?iNsHvLq*c-;X_s_JIwf6_Zb>$I0S8*INUlk4 zN^VK+NbX5m$orB<5=ttO%B2!YCDlodQZK35D)pC!kz=JD|NMHNv$guGF>CbxQoq_yARuYN2nbszz0-+Th!+9v-UFRBF04qs(Kqwc2*=HSHZO zG&-^m_Q%Rz@-zG8bH!XKSIGs?`^|f}9-n--R=2d!4mV$KweKxmu)b2?s=uYT-q9P~ zQ{5xHhkExI8h!2=?i=RFB8>B89Y(o_#MA7V;VF&p=hNk-A!Jp~RoW_jm1mV-)xfGD zRU@m$RZXm#RyDh7e%0ct)9iTRCN#ByQ#o}@4#nN(pz2HT-seaT*?zF(s!iqOIIbnl71xpo%GY`XVX7P_t|1K zyZXDn<$E#xYWj`z+vx$WKc_!P4|47B4R$3nM!6oPq!~^b>I}CGj||_87h?xxgt`vS znCcql>h3os!zq4d#-fa+8L=6wGS+5n%-EXo3ssQunq_+ipYcY<3F>&p$&51@9)#`R@XMycGnKqPS-BiuYE7LUUI$S zx?E=MpEW3JSl03Q(ODr`*IaM9PR_dJddKyi>wVWpt~Y&WWKpU)SqrnWDT!)H79Iyx zFLzYgpIm@W>QvKxno3B~*$k$($nMIrPvP!ZlvUX(6OxvBcFYA5p zm$F{TI-2!P*6FMu)!D3I)hN{`Sz}e9sv)wA)~u^px3g0Ge$IN3MQ#mKNw+#}Rd03M z8m?OD=dsmy>wvB0ei5oj)!?nmR2Ef&YM1x$tx2k6Rf_8S>{L}9nWnm%{d=}Jr+dF5 z$2Et|G33mP&rmH1%~pBmSFcA z++WS5>K{&3svnwv_o-1Q`_`)WsI9qMbDPx9`;M12s|#||eY1VH=MHOYQS-Tn)z(&Z zn|fDnhq_a}H`kjynfqE=m-o-4^rLg9yR56Irljq=g_Znm&QxIwQWD<{*rr6 zeb6HHdzf1jOXpqlk>xq(T~J?Azd~*HxuU+NzNx;YzN5aUzOR0yrZoHgw0RPZK2NSu zLdBGzpp^c_Z_ZG|8G2&0VjFd1;yq&EmWxKKYtrO{r#m-ln|tyqvtE zyc$idW{;*xQ$l5VSLeNzw=lmXzaqa!b51kPd_i-P+L6CI|B_~3zV)U2E1EI!ujF6T z+|=CC9LYbLe@F99{^|UCnzQ-$H4ow*X(+8k`$_)A{Hysl@^9z=oc|zyf?2L53zS-w zmeF3_FD=k%b7P$f)CESZm)5NH*9K_a3OovY3rg0H(hewSj~!evykJbh_ySF6sCG)h z%z{bUsoF4YxYkTZShbPbDDAw0r3IIyU&qH5f*7qpkOSF|^^x3ru5?rF~#+}A$RQjCO=Gx?M?k-S{+ZT!~-Du!Wn%(n$b z#)~mC{!9RKFXYF9UkV-;(1o(XAjY{+Tc|Hw8z0OB`gs=m6%H&MQaG}3T;V8YEHl$!7AI zVk=Y1R5CS80aeQ^FXYIp)E<2Qrip20;tN+7t}onFnB&vJ9A@U2TbVYdof+hvUf99p z6h3vdsIaWClj&mUgktKNrJLzt&N0=67nn=T73LaqlextVm)&9RG548A48_(JN?7BT zLZ8OM1BHhQZG}qqt-=#NvIOgi!c&FL3GWwf_ffIxc!vGB@Uy~7pDznf#$PYgvELWo zEi|&M%!@U%8{_@i05*sXW*>x%Vt*@KobY?$ST>Xu7wx6A39dzK5q8TIC9vK_S7Q4Y zC9#8wlG$NJql+YoDeSvGscagX!Dh4hY%yEPRn;3BywZW;Hf&+Ve+2|pJ- zC?boc#qkMF#p+_WVvpkMlyC8vVr%^P;>ofp#WRcN6)!5*lS_+Ziyu&{iUWK$79aAq z7H=(n(Yv5{dof?UtC&cv;r154P<*iXHEZ!3#m9>e`<*O4Q~Y7^(a`h7Ul)gae_Q-x z@fN>diih|-ET&6jCErrcCEAiaZ+(epNiFAB@{aewk|8A{OU9K=BEKPG8S30qDTIuZ4`K60XmzTzudYM<3z8#uVT2xwATI^k2T36awdZ6@B z>ET#g>06~cs8glymwsG&*zL2@FH67o7MCf?+T2{r+TGYPLz#D3|FS`4=C)yFqs#7i zTPK$_`_3qvQ?{^dNm)!;V%eIq4P~3lGRyMH=6hF^?JnC_=Hqju>}Z+4_d8{$%g&Zv zaJ%F-TJ}lV#j>kq$GmTsJt!l~MZT0yqLcZ`bz^*_W-I(>L%$Dy-${(DW9tQuslo`t~*~Ip^MZFj=x;~b@{jD+kAg4kJ9~8 z{;+(94_zUv@bp`zv*;3Z+KMDyvMxopJw8>Jrqfqs=sYX3b@@8Kih&iyx>B8u8d6~$ zSy8F0(bekq=vo{~sc{v}x)$9g^I=`9Zem57?yz}U#qU(Ru0z+U>(X`WdUUfZ&gm}b zF6ri1*vwaSZlP}Riz}|_Zt7USn9Xs5n)j(;M}^C*QB|(wp`E`XxRqd;;|4 zu}MBb`t=DPSA16SWyL7{t%NttWA&l>>lNQuOw!-2_^o29{`U%TrJ~ZcGE5(?XDcK0 zk@_h8GQCBgpij~#>o59vSN5+QR5`42bY)283;Ij?9hFz~*YxjHp02!Dd9~78cBArk z<&2zhCwJ z@lN-Tt3IpxvZ~9y+r7vAr0+TR>s1%rFS%cFzvljZ)o)cd-G8sT<$lNgp1ZhOQGMT? z2z})KhPP`qTTK~$GD{3{gVLZfFb18$Xz(&z2{lxESNE^>Hv|}h48ev`hWC8EL&q9I z4ad#HswY_uQw?E;a6^RQSFh34A=QzF8P#*D7gpb;I?YjrWd@5O!H{G~Hl!F*4QYl9 z!&2`h)iKqH)oZFp`E97)T%B2+S6x!Q$Gf6>NA>RNebw0poos;LOVy{VTMUN{t%f#3 zyJ4E_Z1pGA7pt#U->AM_eaU-v?flxswaaVcYdlAgab+vwMouTfEk9S@Fx?S-W??H8!3|9=p>PFXv)Q#|&T(>FVn&GBl zM%^u}MR%-*Idu!`mef5mP{x?L#5##lZd_BRG;XNdT$fpwSEn*EMxD`U^fH#zJ>y+b zx1(-%-M+e)>RzckQg^iOox0O?XX`$xlhPOK%*LyAb-p+18hrhY3i@{4&vhk!59-Kz zX}weZ>#+ewb-i0X=Nn`UHhR>LG8%lx8n1f$)>{YE53V0xA8H&^KfZou{i6C;eV5k9 z)_>!@s(x+##(Hagi|@S9t@Q=<+v~%OeEqKaaN|B|Z~YX%7wQkzpZ9*P{$%}!_2=s^ z*MD6f8TxJgkM+OQM;fDy59?*SJ$L)<9=Lm%amenGyT|RGxOKnR^3En-%bH)qCOGYo*6{Gci%Co_*fi(|oC@~LdnCg4Yc+*&J z_J8}9v5C549NBQsc;7hJ_mPqE$ncSP)W<44nyGOO6C0*A%x+M5FdjOOak9k?%Nybw z#Bs?UDIUZ8);DZwc(#LhH@zX%Bh4eHp{Sv(A;Tlvqq?E4p|K&~qu8U=quMV$q0*zq zqt@zipka?kQ0Q=Jt#`-Zy>ogQ5tzcqAw^mv@}xZrWgY)Ubun$k=erfgHbsn}F%`nj>v^q{fEL^gF&(xzII zQ_~((ld0LnQ!OTS(_xcalSfmqtku+JYB%{db>KK#m#Nz{plNW^@c)Oj?+$1p>-wIA zU;k2o|hs@4D)$tFF5CwSP02 zOhDJCywCR!9`D?H?rHa&J0-tcd2aEg#a5Nq7T;QYcd5tV{U zFt+mX;%AFrE>5m|yZFQ6FN?86WnyL}SUHV2lQ@T%U%9bzK5-GTxU!_OqLM^BP+3#i zRM}CfP3)~4t~^?Ks`7lL9`QKVka)H7H1>9-wUR0Eex*6ln)syBp7^5j9M*~GMqEnt zA^H=8h+)JP#CMgSEBQn*@e($Um_$?ntCXsySIw?cuSz36)662~5qD$elM9F&h?|L9 zi93ncu*52RrBWiTYBzB|v684;RZBFgx`k~dUejzPitIayz1X{0c9l&Pr>cke0PCdW zUNu1Uu6m5+RvjWf!yX}qRvjmvCY~ckR*9MgOZ>I1Q*>I)G|>Z+PVdWlsg^;fwmEmaz+8mpQ{3MTs~ z%_R9N1u31Wx>$9+>Q2?esyU?jq~EBENF1oxgDs7S;$&mEE%9LbIvL@M+oJek@ zrKEVJuT_fGldFA5Z?XQQAdnPB3R7C4w1UJZsZ^6NbF0Oqh1GGS%h*MjB$61DMj}_! ztC`gd5nm~bWKx|+vZ(%mwX1HSIajYH6_7TNmQ-&hZ6)m_`BsxDfz_6jQqpeH7wmo# zR-uvXe{KKX{sczBf#5LJVWz`ehXoGpJWU6NgT8~0z{FuGuU>rL{%?MO zU@C<7^$R~3bC+b};OOud&jE`ETpgA=_&NkQ92ejO?}lO=!ZC>s8yvPcYk8lnnSk3EG;!H#hR543wl1-PbTkn zAZux9aVTz-R)?Q@X467?bhWx147EUyo>2))%TjAfjh&X0mb;dh)-?w|tspHW``ZrT zT2Wfl?6>!bwAy>(w34-A?I}GOTDe-!98!8-Ijq)Nr}dLoRL|cI#acVHrZ|>qc~bUj z9n`ATYSL=g5>l9sBJwiI8?r=8)jp?ZKx;(nnAWl$7sq+_v6LjrDXm;Gi+m2$x~z3W z>yB1TPlV$GE#sa=6;2(E6%{qbtz^Dbwg#j-cbuj?fPV9oIS*I&OB{ z=2#EVIeHu;jv2>_lVoqtaprh%ygB}yU`}eyat@Cp=EQSSIGLP0&Kk~o&L+-QPEJh; zXQ6#LXCJ4MQ^#rMba4Kx0ed(zT~4@MbGhyE%%!NVq;9zGSlyYrOLaHvey>~X`lN1O zFQ!kaugbOF^%A9-mTsS8-{N|mvdX^G^*2hd>yYbV*8t{XeVan6e%35)efL79zOlY{ zAzR;CzhIVwKDW?Ce~Er%p^v_(kgFeG7@{Ac-%{9BSe7?dc&6}T;X|0KQ>~Ul$vHV zytWi*b%w67yc@8xt549`jYmi;0d&j7g8ljad^@7_%j2M@(7F zzL=_*hM2Y(Nz7o(;h3BJ6ESCFF2}gn_|yn$;%ap0NB9PGQ@RD+md*j`ZgfxjGI}8W zX3V{qM={T1-o&tbKgM8U@v&25Rb!X%)nYYbsj>I?ilQy6_N{7IHMoiqYY-boXT?U+ ztzsQwS5aJJJ!Ac1gJUCN1+lTQ^J&SklSP@aU~GQu#@OQ6lGuva1F@^gHL*>x9kIQ! z!?7x&qp_!A&&OVkT}K9Q$KH>968j?dCo+lhE>;6dSaU_6V-@0*;-<&Vj#G~##?j(p z>AG=7aqPH=UYj^hoO_&i95;?e35|=4b0>@9;^R`|vg4BItK!zhZHn6#w<|84z9(*@ zSk!wkt}d=6?n4cxc6#lc+J&{0T1Ks5ExQ(6-4)j#Hxf4%cLt2R7VhKRI3{es282cyc^Fo*8cvZxL@7?;O7*epRn;d|-TdJTE>v zJ~2K$J~w_%d|~{S_#N?NQCa-H_^SAZ__laS{9ydy_!IGT(b@RR@sYLS+QeG0Hiy27 zzNxl=Qb6BGFQS7RDLd$;^dib0`Y-eylp1;?y^Y>YFRSgRAEFWhdI^C4XIx}=q>U{A2c=Fok z@w0X2>uBgubm%&IIz~EXI#xRNI?g&CI^Lj;zfQ2u>bm7RJRPx4KP6r#MJH2dM|Gag z8lCkzn{>A7l;|9ylCqX~8PyrnIjwVE=Zelvox3^@b^g?O zq4QSfEajsPpsT2>tUFzImadxaB3-hsmaeX@p)O0;ie{;6r|YEauKTjiOV>~LeO-_) z7_J+oE7FbAP1eoO&DCA43)HXE{Ykf2cc*Td?q1!4x*y23x^Ln?#$yuj2~Px56I2t_ z5;PL135*1T1XhAoLX)mTf@^|jf?q;#LPUZffhmejNKVL102A^PHYOA&lq6In97tG! z=i?u(6+@7|?Ya_OgL<=ids-TPKzF1>b*|c6Fbltz{8iVf9;c_IH%(7f&zZKOexBa0 z-kRQ)-i3OS-r-)7-dHb9?`*G*-ql_My*s@gv`4+(v=_amdhdHJ^i=x%X=;78dc?k9 z8oh5h&7hB?=cebWw@fckFHA2|PpB8Gm!y}jm!tQUyh;y8xlj42ep~%xN`c%G_eqIW7mfk|LK zr<_li%DkFzJK=u9lY|!u?-FJ*=Q0;CiA+r<$Y82b^qD41b0)XJhFO4jWV$k!GB@DE z8hn|&hEQfq!)wY4rhpm4Ok}1p7g4gAE17&6K*?urU~XZ)7i?!HH|%2WW*%TxGpAD; zn49sf%r0ghbC}u0Kf*l0{FQl;d5x(^$!fUG+=~C5`H1<9sZ4pr{F`}@{F#Xb_3`>s z^i}ld=&x^3*WcMt(NNdW+OQK}irYVp4iiZqk~h z!lW%pJCe$h68pkM`;r>?RY?s=ZAmb%Sktr?tw{I9!@@*d@A{T^3~+q$@i0=B)>?0m;5=gABVhSxqH^nH0odVjVa8le;yi>R-p(&9mqLdw?_>|O??37h0>rytQY)jdd zvM1$WN?nSC-;&am(w{PtvZ`+^MIjHO?j2_KILnQV(R2n zmDIVZ3scFd^wfL-Gu0$@pU5KBF4Z}8Nvdz^MnPceeQ|gyFSSY(otg-yrl;nnu1PIS zEf$mrJR14>(fSGcsrp&^UnrpdTKz)(phhLiX8mpYKkHZM@7J%=uh(zU@6_+rAJRXp ze_a2J{ssL;{Fc;Kd?&sKzqRqI{s8`#{vrH5{Xg`d>c7-Kf>)rv(0=Cz<99Xg zZLDgXWN;ckl{(pAhQT>J*x1<7cnLq-U?z3GfrbIafNr2?U}Rusa1C!|ps7$xwl{D# z@GuD8=xyL{5NxpAfM*~!h&MV3WaCgA#*sgM9{-26YBRYO{e+ zlO0);+F@`P|4P81_82_C4;qXbh-qr%F#|>NX@m0y@w6)jHx2HB1`iFQn*KC+Ver=A zBlI&YMMGu7>4vim)eILIk`1*Cbq$l6GMiR5o#Y!DvJ5vjSsL0IIvMV0ayRrc^fL@H z3^$B2OrhyhO{gNnIKyPa3`28ju3;u^wc$F$pA4JGc{CfUBemFYr(v04J9)3+LBm=@ zSL%VL+NLJMc0-9FIAG{Y9Wgv+c*^jc;i>A&hBpiYsDn*+3?CRiF$|?1Y5L3XRMQ*7 z4~Ab2aYjl;7n-g&t)Naby4$2`^r-2trg=t>@dE0XrWooo{6eFb_(W``;lF@aeE!5wP z?i)QedT#XE=)KVwBgbY1V}kKiAdb{y1HV*GRS3FAG@mCe5zUo^gEeB1bUj85(7My6(_R;GPadsAoAVXB9zx2eBru<3Hs#b7JXRBRe=s@H1LYT4@6 z>fLHh2ye9~@LQb-v8`@|l-8w$>{cJb>Q;Y3VQUbfs5OjG(wbtLX_{xc#&o^u5$Yz> zt)?ZW<)(h*eWsPBC#ZF%Dn;a?w$`53;nriVXId|{Hk)>s_LvTuj+%~{o;E#idd2jn z>0Q%@rhl5gFa_V5{!0C5dXWmS6j>6oGHW{PPT!-x7k%&hF#SsXD*bBx#D03eLI1tf z7ve{$&r{!|wuwGMr;JEM__SFpHP#{)nYEs##nNRNvREuj*2`8qmJ|6J)rsZK@?zbl z`muso;VhsH-!?T(HBBu|Bdv|k?x&_P(hSmAX;xsGL)xIoHO({4FYTQmI4vSgkQSR} z*Poo0nFgliryUk;Oe;<+NvlXZkmlN7lh%}WnBS4sn>L(wH0@N{`LwHPx6|&YJxP0! z_Ac#nnnJo#`tFVj;{ls)yx^B8rIy>Day+*)EcTe|D=cb3IN2ZI?qgWzV z91HxN`iT0B`ilBD^)nT#nas*y<+2vEt!Axb{lqF}?PO`Um9Y%k%-Z&{4zg-lO{{j7 zgf+k#Vc|88u}-nhu`aW2uDw*mgbrPWr?2 zr|GZKMg8y7zosi@OwLfrn47UMBe9>HLC;`jm}G1qsI<>(*KId$w`jL-cWw7-=eC17 zW>Yj(G!4v5%`D7p%{XRmW}art%mU5A%p%R^XbR0@&0^Y<+q2q}%+k$Pwda^wWUMkH zlMBo?niZMtFe^3NW44*_i&>3Xqgk6-x7n6_^*(Y)v+Ut|yp1_6hc{?2GJc?Az?G?Z2}hv7fOE`#-a>=6Lfd<|^iM%+<{on^Vo1=Emk+%~>7l z9i$F=$ARr^b8B-4^AJrJ^Ch6Uk2%*o#5}@0LX&UK*Nir|?%;Gh%6KDsp7AE*V+JM@ zpE)&CHB&89Ba@oR$TZ086?_)6G84>G&9lrw^R?!M=9|s8ng47atyy8-O4x6{aA%cy zy?KkdL#At{XQp3faAriNATu^IIWsd8%*@Z+)xR;bII|?PBJ)6IO(v)i-IUpp*_){( z9L_wNc`Eax=zQkY%-fmwGoNI>$b6T%um5wVLY7k2^sL!g>RH4rT9$5>QP#$etsT2M z_I9wdY_d36?pfYh+^o>7$ShG-d{$~!cGh&^s;qTcHT|2iTKczTN&0tX%@*#-I+#_L z)soef)t@zzHI{`DMbn%^=XA>T7k)%?T!srgIucjlkWF&1D)$0Uo%7Bei` zvL)GS;=$~z{fDzpWS`BxoP9IjbHMX<$k z3!a78BHkj!BGV$zVlLRZmA1xWy~QSrtrjH~bE*% zb=2yl)mf`cR@be51Fh~`mD5ZqkFB0ty|#L9^~LI{rh>IqmoAxLeT+QSdZzVU>jlwPp$YeO=_THo5l+T7a4+R@t8da3m-O<(H(>rm?z)&lDo>qP4`>ul?l*7?>OthZQi zx4uTWMYv0NKzK~Z=~~mZp{uy-=dL|nm0b;8?Oo3ZyR7eN?zRRGSXWy&ShretS@&5F zTOYALVg0N1MeA$Ux2=D-eq`;s_btJ1?^@ceuKQhocD?HQ(Dlq3(@p4}(@p7SbQ^ZF zyKTFjyO(zRb(dGOb8T`tx$e2%x!l~)+{j!}?o~m2Zfb6J?yB5%xtnrt3%2F%%H5ND zFt;wZCATZLKX)YeJ}4N=J(GJe_j>M~+=sbOb6@4Y&;6RKm^V33CC`pOH*aAcIgg%~ z(G7MNbicCx+xoLL)&_4g#YV+uj*Ys_VjHTBwhhz9*oJLmZR23$Vzb1?$A)VYViRG* zw~4k%ut~MavS}HR3=9v94V)dgI&f#;(ZGv=_XC(gr9qWJwLy?L_<>-k@P&X?0&UjX z6xwXI*=F;zO@+;Vn<|@u?sNPWn@*cvn<1OSHpgww*j%u=WpmHw51XepFKyo0e6smN z6JvY0dy?(R?(^N(x@XwVww-UQVN0>4+v?dG*_zqf+urGRw)L>}w+*)C*@|uBZBuMB zZLje2Y@ceLBCoMs587_B-D+E6TW-70_IY=uZJlki?KyG~`7*h~w#T-TR!6g-4BC#` zj@gEjZ;+$NcgPROr)?)oxWB~zq9-|TYa+Q~YbkM%+_ZI*cuVfu21p*-{%IR7;Y(iF zzP0^m3)m^zG4o9FEb{Wjv!m_ulVxY=^$GQP_4)Os z_0{$L^$+V+8s;@vt$*pRwv{r}KfY#lu2V3h~ zZ?^v4`lR)J>uj)%+-B1j+_s`k)Rxe8uI*~uv$i*FpV}1KmD@GiHQU45dF|`lE82f) zm$VPHpKia{exvJ6Iha9ljkw9T6Sz9cdl89cw$PIvP9rIz~E`U$zlmj5-UlOWJ^{{3MEC763K2!y`)F70l<&_aYE%V>G1EvUxtki zmk(VYem&-R*bh8hIz~UrKb(FzeCl0Z6GsgX z-8y>naQ@h)W1C0!9qTw&cD(<{v%|k1T0NXL5;pwxu*Ff2LuZau4uh+Y-#Iel$jxIf z4-t=S9&R2|AMP32eQ5WnV5D_KbGUI-ad^h?yTRcR!y~_r+#VSiH5h(*3^-hOWbp}` z6Qbjm!$-!fj(H!uIW~6e#nEL)fRQCfy^n_TIx-po%*?jQ!=CgfQ`|c0cZFx2r*q_<|SM{51z!3O%J8S#& z9UDQVq0u2>$IPL3)nol<`%jg;`kA@Qd6)W7dFO@BGrNf^b%#uc_6^hw_;f|?E9c%8Hbp5_WK=)3+L9E%M7MvMYa^X+7T6to3tN3U8*g#%AQ>^L|s zZb}a#`8Wf#`wbb(`4Di30MZaTRT)Bu_?;KR*MOi2wn6WzA z?GeLT_l&bfjE~q4;RdU~#koKSe!;4aN`B@m02d@DC8HAPN5~qGgh=O!120G**bxj1 zvs^Y6GW0Y}>NOl{6D)*zvUGwl=cVp~T?9{bMb>-Vrd*sJWD)q33xjZ8PrfP;&XY6{zggPTQ$|K5;IcTzG(Y9mxz_!?q6M2YFL-iR%bk>L1$5JN7L zYI6h9-i7yx*M&h%ra3_pgi4DJZ)$;BB-nZXf&>c#p8d&DspWEL5fAey5V!2+<)Ckh7Xk4lCN zg<}9+BE2&9h)8kdac6LG{&IV8ptXaJL3yDOFe<5&sxdJ<5j)8Kf{>)IC3mGpnHYYE zloJijmq%~1%u=u(e@X2#F7&tnut*h{4TWL;!|AL4qk)#9D(5cbTdVq(a zOyQ*xNkM`K*6Sk)ksY~?Oo6l@^gmk=Wq#tLu{1*(8}4vyfztKJl}5s5667t;GLt$f&xaQ;UcE=a}~ z3m2y)OB1umv2t(2?4StdRY^ra#6gxH!usO`KXWM1FROVQF@X@clcg{Mf@E?LG9a9! zrNWndCqX-JnQ*VzpI<2k>&1Wbf9E~swTl1ZZQun7yTvDY%Y|R~$q*jSyP>x{zR-m? zAcntZis2~>l7yq;3}K#dhCs;ofnZmTi_bw>B94EB_p3OGhkV4elD~|%oOemwC@kO; z_-lnf@u%_U^KXb3^A`v<2uXsw;v%7zKu=&S*w5pG(r=f{rC%*+^0)GlZUr$bt zK47C@D_F}b!IWW&cyl1%Rr5RqJ-itZ%Fz&SDg;?%0KpO|Ll8uG2<0anvjBqL(ST5N zTp`cigFdxNhdd5qY%oy*EI*IO#rQ&BQ_bST?heN~V^pDUqonbV`eiPJXZ17RLr^aC z5$qQR2;lF%tb45aVS;L*FE&ab79?`OqwV(J*Y2~kiYCrr5 zS}%qGIcozi5|byj5EuGT4V_xLI>7Ii-MF!k#lyv|nGo&B;v4V7#f`^57dNqn=E-$^ zE6o!dqAj=I1rzDsIQUlPHjz)m8 z0KSHdoH$+{2eAG~u0m@WI<$5|fkDN<0yiYa(rP)LYGfNpS@KepZLuIM720(22?u!k z*HG4|hVmb*3X(6UL%k5Sp!`2k-*K9Yi;jr%{2(iq@j2r)-7Ubd(Pb10+ z;9L)-`UO29vMO*x0&mA2gV0VE)@tI!NYz93txXfQjEkf+Vn);=uwWh&%CDNd54@UC zTdtJa65S`^=!o@T9#H(Fro=+Hbm0(&%UYfVR1;vvh)|zov4Jvkk}tpo(CGtfdGIHi zNN=Ra+8!Dd9TUqI%4wpKNr-Up`bV}Ep}N0}hgXlZ523l0~zVnPri(j!r@Kx%U2 zFRB$Xo~(tF*~hWxpZ7l#xA@X=u>P>IV&s~9d;c>bRZa+0E^fcHzp`{ki*Oi~E;U3L zL`eAWxO-vRQ=Usumw;&beGSDU?8Q6M0Q!C?2S<@=Jnp1#MMgxpBIPhK91(ZGN}$_U zbiPr^UdYZ|5C`vLP>-Wa?x&ud2~IGRIw3^9?%{1U7D9D%t;g9c>afd z$;CNKJp|u;AxvQw@LmRq=F8HnN2FP8V(=kJW@7b3@2Am`jZ!QBQ!o$-A(qtZsFZ^= z24rC5RsnU*IKvwfOKES!sCE-*BntkyoWD=mC{IrebpHcu=Fu};)rIR3*`2=~+5&BRY9r|s#nHUvt zdUb*B7?GZc;o*BGcpH-fZDYRh4HSQ{*h_F-SMDZ5xFTn&!zf)zlgXv zWNr9KSHkzPlp?j?C#jpiEnv`-AwV6J#XT~`sKiiiZq!4t-XBIC@iw3dNEqV-C&`(h^Nm z6U~aaL^L5_Q>0!;1VSFyO}xRCwS!Xspoac72;(4IeET#Asd~szG$DPfBNvC43j6I; zh$84CzNiTSE8YL1Pby*ap!X|3NyDlfiewk)ZVsIUUY=M0{;9>cEm4sDU}44bbyFaB zBpT2YcZ-O^N_6N(0`*O;76cq9S=NKrbkz88#)B4(H1yzNb5b(>n_DX62?!i^C@0j* z7bF7d*yTKB2)cMTe^g-2KQ6c;+zH)^+!FpOjR0uBh1l@k3Vxc_HETIU&86U-v00t%*qXc0pFXaV8_r@TGi&4iyAe6yUrfBDHCnQYp zq8mjKa*(nX{BxRR^4Oj@8Jx(W<28GhefP+Dyk_8_hg~-$>!6?Rz)odir2d!4g9%~A z#YIZZI&pc8uMqTx3pOvjEx`h_X~&>oofxJ+zNb1VnYfUVRRrqEObW|`lmuid)E=nm zuS1%RN>rDk7Xa(OQUTH~y^PJT&nINik$6^c4lN-vXVX3+`AeNWyo} zeGIbe!9jOIt05_oR|Lppv2vesaknSv2Kf-u1uavf5)!m_xH$Cn1S;B$Z(1kB7>GLs z-7ui~q5Jyr6&w%UkZp#Z@XUgq*vIgo2S!pGdCClkvhS4(^sg5zT7GlMWzya(X{wg) z|F>Y^vI*^TrG`d4kE~VX0Xt%Wb5h@rZ^NOfq%9MBBDC>@1dBLg;+6$X+*0A;`=4K- z*CXf_8r~o%laW0P!VLY3=sKn6cc}%Gr8a{fI&g7t3%YWWc;md_r%I@WiiG1ET7)CA zafk9hq8%b!ed|!~Dl@k^SF)+#Ja6 z0SS%dKjhvO>57;fcEZGcAqTPw+yaLyD)M;F=i=gIj}=BG#@~rJBK0=P4^7F)O^WpS z52_2CyI?n<|3`K!AD|@zJLRMVEIWxE)YsI5>D0fc)j+Y#{r7l>&6)+#ZzrlMe|9O3k`aZje=SBi)m;ejvBe z0eRaxEK_D+yB^d=SLDulh(&e(DCgWF7r#(GqMi(*(geyI%?W6m54lQanJ02Kh2*;e z#9Ghg!fY0x(}D6yT;=>$$oYA~8cP)xqirBS(nK3K%Llg#Mr0G0$tNk6Gki)$!$-3R zHSkL^YL8lZ^l;_;i1M*R^0uqe*aG3GcI0bA#)OxSBcCcWYb`1v&?Oh)qkQmJxq%fF zP-|_M`#3^A9fW`+i=$ogwoWA-+ z>xG=lEqR-_yv<8)nG5o(;2(0SA=n(5Fc5H#Y~pS5jv;bNBxi_MKt~wJ+a@cZ&gqtO zR+3-6CwCq6Y6#8-AY}fRa)Y$XCHzA^-BtOJ$wG9x6WGhL_&6hXj#4kW4))4Z&aebc zIp^heE0K@rg(wg)u$o-L6uA|)$vf8cyzlu)f#c)7gx*tW5629>=e=Z1NFzXAh6q2lmv;8aEE2RBd%_H8LH$r$xqQ z`(TT#UrTk1>}umsON@|aOOMnkx87Uc~0}27Bp>3v}h&!_^Tt605Ya# zJ)Z2|(xHuprTpSPzE)EC<*9L@wYXd^TwE>~v+JI1SZ9piv zHXsyS8xRVv4G0C-284oZ14O~`4;Kfd5iSl01s4Z|f@=dp!4(0a;EI4ya792UxFR4F zTn7*et^)`K*8zlr>i|O4LllURaLz|4IOii2obwS1&iM!h=X`{Mb3Q`BIUk|mOpj1- zrbj3^(<2m|=n)D|^a#}oLYW>R;Y^QEaDGQ9IKLwloZk@&&hH2X=XZpHvpPb-sr;Ed zmCHuRMSxQ|(gvq;n1bp*oXe3$IF}<7oXZgk&fo|I=WQ7!pAJseNE@825eiP$2n8o= zgo2YbLcz%zq2Lt#45|NcW=0y}%#2WQVn!%9F(VY5m=Ow2%m@W1W`u&%F+#yf7@^=K zj8JguMJPDmB2+sSs{aTHCtQSr6D~r*2^XQ@go{vc!bK=J%_0<>ToDRRt_TGuSA>Ey zDnh{-6`|nNwE|99AOLR*kw$p8hfwe?2%+HJ4MM@Y7KDPgDhLH{G7t*h9Uv53>k$gB z@CXGLWQ2mtuWdV%yaA2FAWeKzt;M#1$0x#~LNDr@^P@7+ZsL`Q-G$HjP3v2D-ogs8FaLnJi&rCl!@t9O$ZHZm z<*nm!g&pECUa0URA0y~p|B4sLj}&rvy<(9toG;?xK|#E5Sez=%7ETrL_`~auiqG)g z^P>4*c^7%7#PPgDzN#RdpUd~=h4Rje*YFkjtAvI8$^5zetKx-xHNiTehTyh%laMN4 z2n+;!c#%AoV4IN4-@@ne=zJ!h0IcG5tas=2^G0~tJQe;f=sO}S!47^I-$CFi*d+u# z1$%^kf_?m8!9ih!Kp=<}Bn#?QSx6H#zLjvNJNCNPeJlelV0-j9)R<^e3xTe7nK&f(vNkIXne*LRXMC9PWrh-fRhgustTIhyrpg?Z`6`Q4 zNGb$ChNJ_^p>&*p@4<8?Lh1Y%NC$?|`4&Y7#?bjEf(~o7)#@Lk=YT(g&v95?ELH#z z2%X8mAZL^_#yQP7&$+_6$+^pU$oZ4=f6;XQ6YfbCUA{Al*5~d6jd4^G4?)=N-=!oKIwec`I7T>=ii*~J3n@Q?)=*Mz4I4m9H8JraGC0oL!Sw(qR(|% z;DQ3_{1``P3P5zxbomjM4h}%kbd&%vO(jbOhSbSZS*`L;RG_i}(gT6kQ3s}KGhFmt zzK7Q_aWQwXadC7(A$D9{NcKxzd|gnO9Sz_+pq+n*vjhGBXlE7>;1cSx!bRW`yUQb&@1c2Afd356GX;Rbc}}aGQ@I4HymI;5 z<+BUc74JI5^?Ce!;9uhPNa1=^Txs^-0`|;tRd<~R{5#N|>A=5+?Ezuj9%bN1$UP+B zd+Z*ntF|kQ-lJpBbPdw|9=^xemF@aZ03RaoZy|iZ{|dtg55OosPBYzRA~-%X0Ew=( ztAneH>k?NVSFUS_YlJJ`HQF`7HPtoC6?CbN|V`*uB7hr~5|x zGWR0;z3vCyYu%gN+ubGZ1MWNQN8FFOpK>p?p9dJKnyQ+sTB{1F_Nq>*ZmLUFeN_Eb zo$TH1gH*#*SE!zIzwFLe6|2Tl<5ctTNvhLp(S%kqRXyf;?1B)3V4R>wOmH$Fg9DPI0nt2kJk<47fyMd; z9;O}^9=0AF4>u1_k7XW#9$_Al9zu^;k0g(Dj~tIx9t9qXz&K(M4nQ%3<^wQ35LI6t zLI~23{Mq8! zakFDZNwd>tXU%ri%$vP>cERjh_&LD;1)c^6*pXping@7gKnh9&euqjk6Sxb((tKKq z@%(qdG_!$8o|8Ric+U2m@2TNQ@uYj|c^Y||d0Khedpdi1czS#Kdj@+h_vCqsJ(U3j zz$V@^#S?+B$@I+gWB>?^4fwy}*es>4@m%k@$rHh{8HcjL1EJJP&##7Ko-3%f_BTCo zz+?Pd{0ICOC?m+BXCUMm3IJozOb5MYdHw&w&&&j102(!~MPC07f<^-%due&;dKr4L zyez%!yqvt;y}Z0YKd&IKaIYvYkyo5ovR8&zuGea>bzVPt6?^UUD)ZXwbl5G;>a)T};1lDM=#%D??X%J+ z-)Do*7N6}tyL@*09Pp|3Y4BGJ9G8TL8ibHe9WpNl?B;F`~EpWl5R`8@M^<@2}C zXCJID-gkb>GFlR9|ghrmwLt+t=FH!PmuiiLZ|@*EhsB!k6zG?VI46>YL>Y z`mQZWj8aq6QUVe+`STDgn|QH!9*kzA2FxccBE-#0nwK^&YhK>G)$F!^X989QY*gp3NH(W=CJnyP3BtdR_FU=zDo%!rY=YMUV0di?$T)D0-eZ$ln(IChucjSrG=r zgHyqMMO8(+qE*3$qP8MQks3Hybhzk5kp_6S=yDMiWPk=B3%prm1@4KySM;dJ0X!J} zyy#7lEBLVpQ;aY61g94JfvUw|FsN1>0csQrKx#3g*r1qIY*p+~>{=WPdKM>xe#ODX z5yhFHpcn*Wi<65pi}OLSIKOyfadB};aYgZg;+o>7;*R3p;^E?>#XkZOngjd@M(B&b z0#^zo1b&AkGzB1Vr*da<=W-WtiCj%CgR9Rq;hJ-8xGDew>GLB*A4je$7sm9V0tl+l zQm!wzj1|BQ<%Zd>;0m}g+<%4dvtS~?Pa-#sI}Y(P7bxlEtLcH002JnDwOWB17RV#4 zCO8AHxPNm$bFl&VfGGhg0qOyZ1E>Mo0nC7DX4U}?0WJYc0(=6v0U-eq0sMgI09CWp zfUE#8U~NEQz~+E$0Y3*+1ndu}3aAfg3Fr*y4HybI9B@3~Ou&VJs{ywH?gcyzcp306 z;8Or5a1t0eIdDec?7;bf^UNrL^gz8pqd>Djt3dm}g=XG?{(-@P%L7SflYs)lR<)gK zrE0s?_N!H@)v7hB(abKUPY1+-@qsCUnSptMYXa8?ZVKEQSQ1zsxG%6Wur9DUa1OA6 zFb*#CaO=~p-@*&M+G_fK>({L)#t^jE4(tgW3>*y{3p^coKJZH5&A_{X4+H-Ud=dCI z@MEAO00b!pDF;mtD#;K*wp$nUQ&4fx&Y-fOy+H?qYJ-}B+JhuP13@D}$AV4;oeR1g zbR+0a(1V~SL4O5x(B1@n2>Kd?3swrA7OWaPFL+^a4~-N|3)TrX2sRD22(}IGwpRiE zGo%p#kO3JjlOq{HpV<($5_S?619k{9(ftLbil#57`y6JLEt}bx1=%`hIf==m><6j^+dZ3hO9wXZp^GXh##lj^+SAf;-x>bH~mf0UoIU z7elUv+z$CY>}J^Au!muPhJi1_-iCb) z1Hu))V0*J)UPzSG@?{c8e5uNnpp~#=9g|PEiNr7 zttdTET2tCo+ELnDI$V0R^i=8j(yOJnOYfIHDSc7;uJm)MLYY$8^s?Dy>Se?-TA6N{ zQ5n0;ri@eOUIu!Xamzx>BFi8k?XuLe?6Os5>&iBjZ7bVVwx{f1SzTF6Syx$q*+|(~ z*_pD7W!KB@lsznaTK1~!ec9JC#q!DJD&=#_7nYOD>E+CFlX8o4yK?99CFQ>5f#u=l zyz=Ps#Pam=-10T$h2>kyca)cv?<=n=Zzyjomy{2dA1*%umY*%Ji@scbv;1E9qw?qF zZ^}QGw?tzq@D)=lx}sGp)G9P8DnM$*0k8(_k7iUDR5XFC3ag3^a3tEHq8A(n?+9Hh zj)I;QeigwLr@)8`K}BrEc`&&mvjVIbi_WjuSW#SYCi*H^Qc+QH8$3{PF}kLrsiLFe zKG<6^Tmc@fxE_6~;(W!O=!el)D{fcZuXqAJsd!QGuHtir!fvJA(|6C_t-hPMo3>kb zx6y9)Zkyel-R`>y!1vHrH~;~+I!#alMB#Da$>AB{x#6qB*MhABk~---lpUOaf7@eypaxij|?P%mP;bhyf z$kUPMBdj4WBHr8Wn=8~HHO8A9jsmf~|QpMcP%3QWN0ngG%DQu8QOrm<9`SJa60(NGln zYXoVuV#736Xz(?}8gUvnfO6FIs98~JQH!F;QCd;wZFQpzqpsMNoJ>)pfH!T6qjpA> zMeU6`7*!k96m{3OJxUTa5H%8YEb3I$xv0xgH=^!D!H8fFqMk(k74;_SL)6zO98ZZi zjt({nn1~Oi03ZlqlYw!Ju!#_1bASmTVc>s62~z_8i4&#_OyjBY=J6KtNIV)(hiAYu z<(;xq2ENA*v*6kC2tYD)io|*7aEQ;b@G%fJag%_Loas)poZ_6GIDvmTO$Od_6rI$Z z7CDifw4CgmRy+OVbi+x>c`9J&Wa;GOdtCz`X4vofIUr0W#! z6y=oRw9cv4som+Ald3ZT0Gvclr<~3?-En&0^wnt|)WUM|a>{iocDn5J#tG+a0KJ3q zb82#0=uCpBAg40WX~1ckvmyW=C~-!5nuH=SewxH2pkj5+>Za8^=#+@Icr2g-og1M5 zC_-mQbgWhY4y=xbPK&?+ljF;vGb89C1>k*LB6L=SA^@K`0iQJ?fqK)Sb0-F&Ug6LQ z6DQ)&LM?OSeW4R4a6ln+-UQeH9WnuZz!ArUj-l8QPXI=A@8~|z{Y&?au7UkD2+DsN zFra%(_mu8A-OIW+bf4&c(1pSN*Sf-B|EhY>o8WwheAj$kp=Z8desI2ebVR-&KQ`Yt zFF8LmAIv94=jU(CFU}9lE6K0Op8^c$AI(3Ne;}V0ts5PlSCiia=6B>9Mfc|8f%Eyi zysP=Q^Y7HR3Fdw*wLdO9t0x5jjb_nBN;r~%~9`H?7Z`{90ZbmbjbOB|^-Xa@W z1q6$LO`!+^vWiezmTW3R0s=BshJb9^G7HKU6%dfU_Y!0YGGtFdkoS9T&ZQUrzVGMr z{{MdSJm+`zbIwgdlbovzES)FLStvxQ$-M(ca1Vg(+PVLiO5ZPSRmzlp@qTDrztZPQ zo0a6!1>#iY3wzhnN+Byh>wUNMo%dB`jQ#7<-*MLfi&CF^1>C|$7gFOU+O5i}xF6$w zjoT5oH_oC=kDC)W4?8|?a@=C<*to#=aU0^?%AvT^akt~L`|JC^_GkDP`Q7m);%mg$ ziFYVv{O|g|@!$8Cj;|0uJpM`nRjKH2?jPd6<~J*?{U7^nN)i7D{t^B${@MPOey8#v z?%%kB{$u`g{!9K_{(SL;;{)+l<#^oR{^x#sd^=jK7vDI(S^VhuPYZq(zc^6)Ng=nA z+n?WG(qGkI)8EfO&A;9s7T+qqZ~Oo%hWq3Fd;I2jf4oO|5@+!{{K@{V{+|AU{kA5p2|ML6B!m!7V;U+z5+;MN0+4YwQkOS{oP@HPYDCIhAV1n({oytjb3v%o-kUx8Qe zDA0CH(wGB%x{T>LCU{SQVPmfJ>E31Zm>Hdn_Y@F!6cBe4$hwz6z;Gi0?jsPqi-1d+ zGg{p5VH!7ZNb2=duln2}VRWavz4IyaM=u%Op8G&#@71E0YfRRS8rpUeH)zeAd^h{1AUiyY;{U_QF|iM)0`Iw)nhdRYlyKz*5*&)~c+F z-yMH6{%m|s{7v!VrUZY)7bKCh+{}i{8$K)-TE1HC8x0>d zv?}-PBMK{x#3BA}MI81o4*D+;;FSM2%a<)*i8KAJjhu~aN^;=_wFed+Qn*(6Sh|U= zou~Xi4f#lGQ3j{ys|lqm4oVoGFquypR#y14QAk2)f}7Lv8`dsd@y&!L2`LFJYMYhK z6;>9uE9)y%N@$<(RYh^w{qzJ?xnH4H!q|jK6;R@7fHHlabnfQtOItKt_4R%K_S!;P+0D4Ng^KcjG- zgdP=JB+R4n6OEoWs+KUCat|AsD_WIB6{Z#5UZF(AzI+1kU4;vc{%UloLKvs;bBapg zX5>dC9IRmHr2cd0z`_nts-FLQ{S_+H@z6y_^2hl=WZTbRUT+O*5N1l$d@kIWvA)zcri% zAImxK4(0NM`kW{Ke8L3IiND*gRBDJ)k`v~8bFTbm&W_*HsXV8`+m)%DEq{*FQ;>dZvaLfVsi~AK#H7gMuSRbkkooGA_ zp0nWP0q|Q=ccnU&ffL1f@mYt%uSq_TYEiniOl{e#GOwF08@6oGGBCEKsx)cYt7U5C zFIt+F@hvCw*r4U~mKLRb%Rw!Nl4{d3r6pU1quDpq&Q;{s%Hk;Y(nTs1;bYgzb6RfT zi1uOy9~I!{ejMa3j&aXd7k$Ch_2VpdvJ?NU`$4sewB{Q)PYSe20jz8nzI`8^KmwkzUH@P$*}8F*;Qo{kF# z+LVL=tET)kW#bep$9CJ4_c=Fw5@&(iJC`1)D&CZ+l!_ecZBqtvLio)A)i~aJ2731a z;!yAJ@Y1GyH$@x@Zdb%<;sJ4-_=W-EByfvzVL)-t0kqHCGBR~{j?`(FVd{(1r%3$SbFyKJn03~i>H@Pub5sf{hjpp(*5Zlq_;?Ko1T>3 zCB0{QYWipC!_r5mf1N%#eMWj(`oi?@(pRP54LlCq?D9Nd8In)=DSc!5w)Bu8d(sc3 zpGfx(`91xQ^lRz2(*qCF|4BDx*fTsC5gE}L_q*iHD4bC;qin|888I1kGM;p)pV2U* zX~v5#d6kwK?J|-xtX;ch^v>v?;p!U52)CZypAh77c>tvtDF;-+3}o7oD#;byaH7MY221_u@a^f#vAIYD$_^y*y}LijU>@sQekI>h3Fn~GqUJrO zWPaLOK|52fz9J4e)sHt7$K2H7w|5%?fh~cxff-$#{HXqb$*1JzXZg)cbvRA*eST{1 zQ-18+F{NwDR~$Il(zKmBhK@;kl+;fVKfQljiR_q*Wzi2Ov@7Cx!T@Jbh~JXdw5(B< zc5Z97DB|{|bu4CO$KaA(&B`}QZ+>6e(ro9^!mUtw{@3n}DpyZc76=&s*NeZ5p_b92oJR|Qg=WB@b@q(x0WmD>KI-VHX&zzg6*BWbjwLD7^;3&P# ztQF_NnkuEdZ!T)C+)*6ZS36~oX{xDSia55f7_mv#&X&t-{+2@+;#0b@@eXiup7Er) zxa1EzmNx}Y-rFjV_=_fP!8@;t`>vMd3J4zdcRlG2lX#nG20luuz7qDnuPG6+ktd2zUCUT9<8%qU;Xw1#3t1^61H#j+cK*2r(dXrhjgJaE#gVEDR zo~4=j6@75vVt~N`=mQI;vdRiC*u5wr%Jbue;K+kP71<(KdOWf!WO@JFs0e&;!Ss5s zm(jzo=Vwh;{CHJcx4irwz_`-EasF?&S!HxDD_(jXF$vMCaU%a4Ic*RDZ5sv0`}(M} zM)`jWXja#v`QT;^Zp_zP)Q6_WN}pIDIB#R6tZv1r5+di-jUyIGum1XC1&8taME+}- z!IoKn{i4bW*6Y=c1JZ*Y+(1`r2ZtzTC59Bt6OeWvz79(@54J^b1zltOd*()T>@_69#L`7zDJfBxV!bRJxZnKVzu% zB@$MY&;zM&Fum-n&z8nPyuQpYpZ{KO;=hA$d;&48t z9kZe!z2N$1t)}qwy)FV79G>ukLwQxx=bsgo;P8ws1m~~EOb@=^j<)~x3r?T?>(R)X zfki&G=r$|oRWCU3tWtU$b1C0uUy}Wo?1!>n&2Gw(Ek}t!jv6@{+ zfzd-4Oy@mkw{G3Odb>&aAo|*_tR_Txp{R5=F?wM1>S*_#1A9hoO4@8JV7@KhB!DF5!F{? znzl*&KRC!h(&n2xCvP6L>E_PSn^$h`w|VvUIy?1l4`ml!i81$kWiG~uiQ$N$iMWVh z^M`yQ5Ed=wAF?f|nTcVW93p;MgEygd-oy2uwL+p;MZ%mlpZ^VXR_S2V|G$sH<@`l1 z=h>}+;*41A#x~4TjL_JizM}hN-s$b4>_9f9h)LEkvj!zrwIb0FdBMRCB&GYJoM>|( z@d>t3Jiu(Tf+8~8u^X`wMf_fko<%veDfgDfoB12@rmRPy zh@8fob8j&#rvip7V=>`p6$|EwN_u0BH=o*MRzxEfntwGXs0BL+mU!8n)wumZxY+)Dwda=IiD4LFz*YMkM%1 zI{||5de^}*XEl?1i#|ZnXjUq#^Vd6hwS{2U#yE)xDays?FJAEcukf5MsHUV%RnD7~ zy5{*)m3(~5U3o{z%v^{+Ws{O9Dy)9^;)SvNce4BnL-|$s6J`0_6y`Hw{v|EiZ>Ic2 zdC`up=TQ{#@1JVQMl#HFTrV;+a{~=*F*LXhKc;_h0GA%UI)Ht00EZ0akKpSA5S<$b za7qq9*YnW7Hh^=60sKw_e;69PjIR%1-1QePL}f;<&FH2az+K9ih}eCsn4$Qe8}fpf z`D58}R`i1XJ`Wf={zo+OZC2`c!D@=@+u%}p4duh|^_e%+%85>b z9c7p0b5TYNG!Iq`H1LTz*r-<)%r6TTHZ)um|8!Dt3H0(lS-zAkU)E5*{C||!+pi+a z#{|mNDXpm>LNSI6{!{dk zwwL-TM6u>ptwJ@Wlhh}u3hxkud14cHm--~BN6GSirOtsV+VTajhHA<{p|k&#X=I2F zL}Q|%p|Zj(Ss_&FBc(nYT?{6d)W4MaTy)WfzBH4ho`xve*V~yU^#$ns`(II9vY|OL zV;Q2*^$zAs{U(tRy57(dsjom3k@LuQR!Dud)FY+7R_Z^Xi*{%~c>QmX8Ea9+E{~QK zwn%*)x>%wRsqd2d26ShKPbb(hITz zZ|by$bp49dMI^+fC}u4>xG8mB-nCA}B!qrn>if{e1oS=hMCu1c{Q2)?LoZ~;A*t(| z(K;YkIVAe$rA(0F7*@WV(=VZ9L&fgGft8rG<_2l zl=^8|A*U=~Ted0bN8wmJcY^WX4r8MA-D1y(9H&vVy+p z-jn)YQr8FMm--EK{(HF@Kal!OL@{H1DO+ed*WVqPp^vn!tniO)NZ*V}QvX+$555Le zQ@Tj~IjxJQTRoyZrOsCxwE^kvr%K&}?hx0%KI6}1Mue=OcRWn$+0ez>>rX7BrJh|h zWN7DWspmu&SBDK3FBwcuzFzZwK#hU4%TPXFy=pv*d zPqg!$)L+Owq3@wpQZM>i`#()n0_R2L;<6!qmu{35-b5EO(69S#Qs;-$+CcTS-y?Ot z0-;4hUz$Tw=Nk-~uD5eS>Xod-U#yv4;dhx)nF?ZNy8egMtILk{wY(;EzH_4uR4jvt z#BHhb`HL26{bl%})IXxU*e5x}`ilzx$c$F91HA&Dy=f6@i_U*9pOWoTZ;vPq|WiK`dFAY^R~r=Sf{J z-&E?05$xjqpT3qYWyVr1BkM(|oz$1TrgL{EZE04Zivj8Fbd&mObg_B$%eA-ELy3gg zC)!gr&womPnZa?M+6?rD0#aXxEwH=r9Y*RfJRfG#4cZ{7(~KZGti)(12d zotqab%28QCfAN?lEBuabyb3a;eqQQt$N?>u`d!(9zE_q>{cox3&mU`~&KDvA+B)hl z9_wVrGb$KouvzL6ywHmst#`0P>eRdPKcaPem7z&<7eN^}ql!M5y%;<&qhn$qM?5 zP=2Y8mL2GusHoH@NL}A_rKJ81x`>2czP!}G4VDkQ3{e%Cv4{+@DfN-olsey{(IUjw z(5`}5sV}3vn3+D%_ocoXo&R1wGbTuVrz{`bE4=@2CNuVtAx5gNacij`l)65H_EJBJ zE+QxPi?}R1N&N)6aj$fj`XzM!)A|tQ`wCq=|KC6ruj~4z7$_?|L>Ds?gAx^nO1-v> zgou*RM@s!U<;5P-Bk`rwLl~uKLyz1fsk_nn{6E;aXlR&f!^6V3st*GCr!+F zztCxs3r2$Lzp2dFN`@GzzPnrM4G{^lUWU4z)OR9^b=Eguveb8@i}L#3=qB}jh~nze zBidW&;`%>GhUi#tsK2am7+tKr{*)S!`U!NgSM-pMkoqa9>q|3M>ZhfyU;h)N{yTa= z%s}6*Q)R|kGDOE>P-1CjNqrNM5RK>&%8>dWloy*(UxLL_zk)8V27O}7q<#Zkv`r*} z|NdViGais3LZpXooz$P8iy7-LQk$jz99?uQ5Ch#Iby3(D(S1_q#!H&6w|``&y#768 zhz|72>6EPCLllwFXM9fTe2}5dOyr4N=iCRm& z#cO(dsqdp#F;IO1ouuA|^8BYgCy0)_OFdEO;`-M^-B)IGc&)-fsdq#ddquy@hDyDQ z)b+hGQtDmN#igz9tuLj{@13*(iRTIJ-~W?jMqe_-jP(IclX^c{K@asDseg(tLalGE z`BFcMD0H&5h%S+Of7!l1ffcjlzyI~CK!5RAD=U0X1u+=C;|)?DjxHM4pXs(peWcX& zr`TOmAB8R=r%&vF)JLoBf*V3KCf4Sd%ovLx_JbbM(^CHuUA*DYpGq%C{VQ}4YJEUg z&~IuVXnZ-f;j-wcQlldsCb!9FiZtagIr6*3hwy=nR?vW%&Msj{iMsg~(oQ$16h zsgbFPY0}gQRC(*$$RVcTrctJGrtzk4Oy8Pjn&z73nPx>6@h&ngH7z%-HvMQ?Z`x$q zYT9Y~&OG(#vglgox4cs}dn2RcA}5A*HTN+0F@I_vWFBH3ZXRVGXC7~komyvkbjd)2 zh)d?H<{Rca<_G4#&CksH%nc)snNOL2H(xL}io9%|8a6ZRNLY)A-^1EOTnW1ob~mg^ zL`Xb_{>8@#4#6#28uw7v$vo&BIAK@`ij+h=1ZQd8LKP5On|8{3o>9a zEQ2+$4mQIM2<+qG2%Lg*a2fuByYLvEgJqhMF9f_01-T$U6opby9;!f1h=und0h&Q; zXb+vBJM@KtFce1eH?MqO;!J{RFbC$t5?BFiVFPS|U2p)7!D+YvSKubxhbQm?tkacz zE(n9{kOvAvaVQNHp&Gmc92lzP^W%H~EubwVK^N!=sqh&LgVFFcOokbd1`FXkSOq`9 zM%V^>;1HaE-{B9q2DjlM`~#*LNKJ z8}x?$Ale%NV_^bJg;|gRi(wh8fpxGM0y}uv2S?x(oP*2o7u_WTQ*aJ0!(X6(ntT&~N?=pgM~UKDIS6mW=LA2~Y%wRR zLQDK9vV1D9P2#OXUad|ur5)wPleG9pnz5Z^bp6xhBYwFC<_dF!W5DWFe4++o|T0m=P2T9Ng zxy6F>-fAPk})8uCDXC=A7+6qJREPz7S(9f*bc;D-cg z3N4^Dw1Xt*1l^z~^o9QL83cy%Fak!ymoNb)!!(!$X)qra!*{R(*1%7&0XD-n*aiFG z5FCS3@HPvH3h*57oH2tWvUAPk})8uCDXC=A7+6qJREPz7S(9f*bc z;D-cg3N4^Dw1Xt*1l^z~^o9QL*+JHSD9#8N4PU|pm<-ck7No&^SPb963RnX_!3Nk2 z+h7;$gF|o(PQmYR0WQNexCwXRAv}TS0Uk_;hya9u2f`on69m3#j*`8?3gmX2s}KijCXHV5^dzWRlP)J<`Z<=Ic0oaC<0yHRTAH~yxL9) zv^nI>gP8NIFKPM?Xr0$VxC0GtDC4<-AzEf;o$WMolQmM#S&n1v${x#YOPHEN&8wDF z|A}6frsP`<>tQ?Wha+$T#BB+y-x6)bsD3pwv&t={(Is>}U6XWeFe!l;H5NzDsE7Z) zAsvsOU`RK?Zw4kB{>Y%W#!u9AzuMlQcf{|c>CM#ch5>a&bEGrS01fprROpNUsa7FY z9Y_U};#VUns1I;3c|)~)zdBsAG3rQZ$6)nxU*eCK`Xp(mNIOH?+1P;SAWaJMq+N&& z-T^Q(^XN}XVx~57ai74<%(n|FiQ5b_slebWivS$K-$AvyTK(n zhJW&w5+Ia*^|T@5EdB*U`V#&XL;5=YO%O|P$DrTGebh+_tN15GK^9Q1Tc{5FPkJNynH z>LnZWuK3-h-b=H7wXaNniq+d2h(Gv_y#9yE0>cdjM&ge#q`$-;52C|Knr)^|W8iv& zQ_u!zOAw>Zl;!4VHdam7CdgB^%wHh&#Q{0TgS1RoWQMa{bqmLLJTe)w(iWAFIzO9zVg5{t&+fh=H||ww-3VA98SJ z+Qd4b{maDkb~=;pCd>B_Ho)5SmO?*i`(yP`c?s1Z8WbJ*=81-~LK-lH^c4OXL&w=D zn-j#^d+r4X>cblAN8ICGsCcR^iKCCO2$f1`6=T$jvSMY;#;P%t6Ae}%UoT&aygIU6 zU1{q}8;8|96z?M%8v3bC8;$RA{p$@irEqhtVyxOy>!_L9#!w-i3XKdMx1($at$Z`J ztD#&n+DDWV5$lexx8DmtRVyE(4w5!-PhS7S4FyNzkJHjwq5fLyAeeqsR7u=m=&%Q! z^^qNJ*BbV#yQJN#*%6^jZ81AZBpMpkKkiZb;w6zhg+> z$A4rv$1L_4TzcCk!w5nQgG4gGZDZs^tgY z9dPa8-xb)lid@cBx$Y zgA+JFxx*kLbxgA{>Pf6VpwswgrG6nx4`f~(e0`>6@GENNW7Nu;^{drnx&~G+_YVHM0fX=!ejJFAH#F#t@tYdb&GB1;D3@r^ z+v9gMq&wkv)zZNT^kVQOd9SDspgVbixpD@54F$!n9w0--0A;8$Gczgsy;eR}9bwQ{ zqm81z7|>X0ztY;1n;U1GiU?q94VwrJ72SYbrDt{=@R_!W&SE@e>CK;!~aF< zo2A`q$lrm#Tk87^`oRZW|3_rTacNIUd&W@k9R5YAUpDAh@&A(gEotu>@*m(oHl&~8 zKL-&hh<&C7nFJtgI*l}O+&ggemT&t z|B6~haFbMi$RGTbtW8pE0Ut4uF9uXYD;HeTckt^P()ID0F;lT{`Y)sMra=t0CPTzZZxO`%3$%v;(CbjMdv4ia*?t9*IBZ zp?v-Sl7whzyrIA({3)6qt4=cv>=OnyQK!z~|G<#`5Wgje$h0x&?eIGo(#iOpLG1c&nvGF=htu1Y=wDqw1K;FlXH>4Brn}CR93u#-){D9b8ZApBr z3Bi#iF|rg8&tP4#dczACV5VHt?y><ks^^5qI4e6@^5`TdR-7RVF zO8Y?C$I?EP_61hIOvS*>e`hU`Z;_JE`FF5AkF-8%qphWsS_6hpcT{wIcXPy9ZHbbtIoFVnpL50LmAL@~Yq+)Y*B%H#ImHJnj z-b|ff2zgh^d;)r8zMNxs^3KU}7d6XMuC!ONdIbK$zoVtIuCDvCy&vTO{te~_v=5a;1WZpv$Yaz^h7PSy z_>2aG?!xLFgyM%uJyP22hWwoPc?{`%_ys|Y#<^qRMs1g)!zS)l)@Nkzm|3)R)3!&MZhrB(E+ z>$C=A)L*3CjMd9+#ou8_@5bK;Vx|WT`Vsu&Qa`2HSoO@4fLQxr=*}^Ki=a2$hRze^ z$S)fjx{CjoA$<$~E{F~v8T2Rk&kX4o!haepXVt7Y%4<;=c=GX75Sc zK+DhCw0>=%G3rt|&_=S{2hx71S-;vsrdvtdHmC>G4mf&;$@rbMbg+Y7G~U-R;%?+^ zH4OMu(gO|U#q-Eut$eUPXB8(7HPk;y-J@FlVE*u@tp7*~h#8(SG(3(*zt$QK?&^v7 zlMU%_@n?XjH`}16;V+Q-VuQXEe}&Xn8}zke{eLzH8}WZNq_^Sk)Y4fY-zNv`$P`PL zr5`fPG?ct!hIUTkp9V4D^9DWe2Z=vr#x-eg7z*6Rzo+Sb^|8!gN2#LlkHwM_gMLd{5d2()zWE!9CFkzo{YJ9KWR@ z-3Gs%mJUX$1N}tsc3-@!PSGPJUjO^i=>XYr7b=K0$VzwDP=x(QJ(Rm9&$j4NSo?ZlW3b$Qamc8lSD@2WOmtzd%-8tl4Jj zGDG>LXiMdQSITm0u=;?0#9t@%UxGHEZZ;IyioZh^*lp1F;UCoWSoMgZ!<}??+)(Zm z{u!+tZ@ZFoRKqlXsGZv{y!j=MtPRC%db+_@=WMF zmt*w~T=+gs=aUqJo((@*)0?TeX-E6~@2S>dtXja(@V{tyqS^ z0e$JpQ>LZi&vtIgzAfulmGvVH^<&7Z1={O>9j#!DS{JL&pgw-Q)ITujAL6$#q+8*) zHKaerPXZB<6luF?mQPru?I~@aXT1K4nWZA=9S^|&%#a>}KMX{sc)BdmuC5+ zl}sOy_OP_auv&fX^FI=&b%D$7EdB)$A-p8*70t$|*EJif-qhCAua06(#Q^Wf{QJ^A zlJ<$T&!l}Jt@=DTv4CAVPR+)up66n-HB)_9eTK8?WUgWJL{K)Htd~pLH>AxkZ4u4- z)#6yaoj37IYw6%KV!7vh3$>!wQBbIcU&GMxk94|T&hTABL+{}?05NmFL2rcr0fbnJ zI{LZWtI28?wY%C|O;wXT1Jy;YfI3VasV)f_tA4FcQm3jj)WCAr9Mu}0p)ORHsGU5^ z)K%(Qb)C9V-J-su?ohjV_NWKcBkDoV3H7wPFnp8ihW(uShk8Z*OTDe$S0AhYs4vt! zAr`CM>au#R5!US1T-LnSg4QC|64tk@<*b#gRjoCwwXLz%`c}U+!P?Z?!rI#UtJ2Pz z-=1Xc6lLvd?QZRDO||y-473KU!>l8%W2{s2g@)w_)N%Y`{nfhNy4$+n8XbAqdfb}i z{LOmSdeQo)^}6+z^`7;S^{Mq=tJ!9=?R7bAp|%O0a9cK8PTL!{0=6QygRT;`w`}EX zm26dPpS!b%Rkzi$y=$vy%jJo)HL^9aHMh00CE7aJQfysqJ#2k!pV|i5hS-MNM%u>O zzP3#a*v`17*rwZN+tO_dY~`XKcrtC1-FIBy+h(~}+G<7oVEftji|s_nueR;BUAC#V zeYQikW42Sa#Hcg2wvO|*OSY@F8@4;P2e!X$&uofawL9$X9R)pZyU!kJ&tcDP&u1@W zFJ^z!UfN#X{8{O+2n;csmI~{u+2OUQo zCmg38ZLH@UNq;!5IIcTxIqo?gI-WQd+MYYMD5el=NJxk$BrGHLIm4-VLc25*N}aq)Eth$1{8LkX9jyA&ati2uTU)64E`ScSvf; zz>q-5u#k}o)l+S=P&ji&Oxp|&QG0#oI{+$oui!NoOi>=JC{a$9riTk8-UF&*nVt{LOjRdC_^S`Na9$ zX>wUzAuf+A%yrrw<%)LYcI9&wausvE=_=#$+H$KET$NqbTs2*FT<^KwcQtf<;A-Y- z>1yk0?@D%EwgtMly1RP2QeAJm2fEsM0bMCKQlU!3>Th$q^Ij;4d4A(-} z64x@;ORyZy0k`Z>d%UveI>yB_|cjt2Fb)U5t47iKB*EmbMOS?CD%DF4KtGa8r zzqZzPmsje#OGP$t$GaQ5``DYhTew@h+qsk6o!s5rJ>8Q+`?~wPKXVUtk8qE6f9am! zepmU%{jGbZJ1JzYJHx%uy~MrDz0&=I`<(M<_b={W-P_%}-TU31?1$ZxtjFEIxr;c@ zx-Yt4xC4K>ue)!#@3|kjEuN?Df8Az}&ExchdVb3h?#brK>3PHRjjMp?eRmO03C~-e za-K?_VfIlWRXsI4?|5Q8^*wQ(MxG{~=AIRitvrdIvXN)h4xSoeDW0yL9-cm)Pd#VC z2YJ@nhIod1MtR10#(Tc;O!dt0%<*J+7J8O=mIXYkJZnAcJR3b*JUcvlJO?~SJRRK! zoF_bGvYqyv^VmcG@Lciy<+<&-?|JN*6!MSfg~uFf3;mPtbYF*Ca0ed1-|!6n1v6jM zRKW?M;DcXar55IkbW{@G*3N z6zB|}KtC7&pTie02EKxc>HHw?8=NUH9cIE@NQVWG3E#tVSP84)NB9}m!zS1Y+hI5C zhof*3euJ}c5&neha070^J$L|rrw0fb&c9&h+iEs&fEz-=2jP$n-hg~i01817CQDn}!Mjiw>OljDhepsOz(aFr1#RGC=l~rd1-il~&;$Cwr!WYHz~}G< zjDm6S6^w^(UQ8*4K;S8LG^Kc3N zgsX5JZonBYP zBdmu_@GESGov<7B!a+C;$KfRW24~Gm7zM+fLib_)P)8R2aTW!dxu@GESE?XVMe!(P}Ahv&2YM{$nBZ*T_A!bP|Q zSK&I`fLm}69>Cx56rO>?r{gNvzyWRug>Z<3Y>)$T!y8ZliolytW&!J84yO`Sh3ZfX z-h~Db4~^kNXbvAiD`*2BLq|w~&d>w;KtK2t2E*s@1&o4m@D+@Qi7*9b26&hab0Hn( z!2(zWOJO;zgw^mP{0!^i7uX8hVK?lDgK!v*!g2Tw&cIo?2$$e0T!$NQ3j+6ecm#jL zGf>25d7y#=oZto@L_#*m0lDD~C;)}vO(+AEp*qxnTJSE^gE)wX#_%CDhgJ(&|3sXR zp#!8qXXpx_Ko95zec)3V0E1yTjDj)n6^w_8@C{6X=`b7SLOLvk<**WdfFI#!Sig|< z{{?3gY=!Nx6L!OXI1ESOB>VcbFb>AUMEC}#z_&0HX2V>V2a6yRzK7+o5>~@{_yxAYcGwMj;UFA_qi_<=z*)Em zf5P=etp6>Xd+-1r!Bcn!|ANXNrXAn}H~1h2Pz2tDx1bD^gUV19s>8cb z4;nxm#6#o7tpA5N&7l=^fE4HqpFl6@1E0bm7z{(;bNB*A!8jNX-@p`@33Fi{EP_l} z4l7|b`~W|~&#*qg!!NK2cEVmb3FqM={0Z0L7Tkdc@Ccs5Gf?j}87zN|t zE0_pV;9HmuGa(%oKxQWE|2@u1SPehG&#)eTfnQ-O?1uet7>>emI0@(BB3y#&a0~9h z19$|_K;f?_HgJFsvOx~W4R0)A{qx}zf+A1?-hy&a0V+Xds0!7g2GoYSP!AeFJT!(6 zp*ggIMCbq=Aq6_aC(r|WK_BP`p9Xjs0E6Lk7!F^+7#Ig%!FZSm-@p|37N)~YNQVWG z2}|L7SPm;;HEe>dupM^8UYNnpZ$IR3O)Vji$U_ozhVIY@`omxt2BY9hmyNDPzz$A0W^dr&;r^( zdq{z9&$uJ$}z&uzC-@_{S5jMcDumkqOAvg|!(>$Dq%WxfT!vlB% z|AIv^jdy?t!XZ24hWtrUiJI4H>WqzJryp7S_XN*baN(ARL3=;2d0nYj6wh!{6{6%x2Sg zJGdbXvOzA$2Zf;ol!girsKP@Hr~~!D4~?N2w1Rff5xPJR=nDfN0K;K4dTbKpu zun?BQ3itum!6w)SyWs#FHM9PwaL&RXa20OCJ$MYyz+^Fvw}A_M5Cu6QFBF2}@D`MZ z$`Av!;XR0h1o#kILLwwVXXp-nEUbTjoWUSAqIrebp`40tQk273Zq6OLh~0|YBV&a) zBj-RUSv^e3n$XM@;sc0aTGYu-#!0Qt8m-Rvn{a)2~P*(sq6Ia3V&xIqsXGtQ9ldZQQrV-Q#VL%Z=G+Fiqd zjP06QqoT-g=j8Qvp z2XC^sv$vbKhqt%4pSQnvkT>A{+&jWM%3Inp*87!rg7+KmRPS`=HOo8Ko8c9+Ti{*n zUFu!tUFkg=y2e}1BIf#|cb)ea?`H2-Z)M94?{4otZ#Bz7?-6ee4o7O7{XNTZ?X;9Z{SMkW$#t*U*22ZyWR)h$KI#j>!HuRiqGP+`9gedpVt@e)6Y_h^5yX5@`)3b z-tgu374jAJwXl@%mGX(xmCE?a`#!c*@>TIw_uUDt>8tIF_0{u<6PMoi#rqO`O?=IK zANgAQ?uRD&KC!g-b@X-eb@e?8gm(A!^7Zw7>Ko{L5<1v7)HmEW(l^G})AB6zOW%0k zi_l5FDZW0I3ar&MU#exMZ;mhBH{UnFvdFi@_nGB;-w?|R-)i4l-_O1czD>R@zU{tU zzP&z&cbMgX?+eRe-)PG*-$~zT-#E)z-v!?#-xXiZoY#FfeRq8Kea%AOf8=}Od**X_ zU--;n)-Xrd*Ot$-yTU@l!osqJm1fStWQ|~u)$%&!bVOlY|fd`_Ji=|;jO|G!#jkhgnts=CwxHoknk_U$AwP} z|2BMf_`LAU@a5q@gs%_(HGF6I{_vyWzlEO+gge3) z5fza$B5y>Yh~g1%MU;moKrY>C(ru_xj{ z#F2=T5x+-VjJOhUBjRqvqlkYZlt^o&GtwIw5t%(QcVzy^B9SE{%S2X;tQuJ(vUX(M z$Oe(|k&PoijQl9F?bHNI&Vqp-BiBc6;$~3MY|s2q9O9rUd<>t!P?!$$;5&E#e}ih} zB^1ISFI0zjpb4~tj?e@8z<5{=+u%5yh09i65booI+IYEwQcw??K{E7$$*>kS!a+C! zzri(l3MM-*e-I9NARdw-6(+%S_#S?S{csdc!2|f$&I^Lg!2lo^6oHaZ4yr*7@Iwda z1btv6%z{O56wbf}xC)*SCIYpfKD2>uFaR>)H@F1|-xDVl z20|mBX?zQ411XRSV_-7Og$!5;n_)Ygg-cLAjLzXbh=*k81{>i3oP^sD8qV7xC=FGh zcR1@m5@!m`g0=7%{snUc6`(MbhN=(?@z507L3bDc!(bdtfGIE&(qS=F?5-p(#V&`{ z@Dpr+EwCfN!(KQD$KW^k1MWdcB>Mv1fFe)=%E8+Z1GS+ZG=dMIC43CY&=q<>A4r8k zFa(CdC>RHmA>b{fBrfZyBu*od0gGWNtbo<9vb2&o8=fTd-EHhoXk)M&u$y5A?12Mt z1kS@XxCM9NZ>Ug)Baot)5H!Yb2jTd6qgemKIOU-#)PhrR8Eo0Oo}nNVhqs^tRD~K4 z3k@J15}+xxfJEpBouC`^fK>P#M!{s533FjzqkxjQ80QE02{yxa*aOGlJp2LI;5Iyf z$M77~>^$*+2eLyxC;?@l0#t_TP#fw(eTajG&=^`mhX4-gL795?`XycI&g13rj?Tu=~7K%guSl^_Oc!+X#WK7ba` z29lr)^n_Fhz%*D7zk`MMUZ*0TM^?(oQgu-ht708!4nY;@?ScsQgidqr|bk-NjOa2QU*pKt^2ft7(eAqt8>8JMt| zzv(~*n3RrDJp#L)_7W#+R;bX`(qq?C^ZC6+EoS9`CzTPNrO^4+;;r!KQ5{K-=b*42 z{qFY?74O8{(`=dfe`@txH6Lxsm-@_H-4kn3l{$_)uC@-*##P$50k`1JYi;G5{J2*@ z8^x`2!NwW~ZDP(VTKeG0^IGG+cfYfo@ASm%`?ambrgZY0Q%~@v39n6b@DB~Y0Mi=2 zAP82lugMzpGzNX=;}gBi40;0Pmv2AbE1%~QX>C#gZB~g5gR@%R^>T1_^Ve#2Q?0Xl zL9LvawTRZ@~L>NLxc-cQYQ3bkb2%SAs5DeV@^l0+NH&j!AIQVvO$+R`jYP`pl zhgzF6m(RD<>iWoBx(fdaXF|SQceoGLEXQ<*h);=tXDp3=4HIB8jZedha6U*)30@J7 zH?)dk#%3io>Mc)ZW(MUJQcg5D{_qZM0AkY`mq(P>Hh07}Z6G_3EVq0*`>DC_=UpvU z<#YD~&mGr>$Uth;cQmvNR=^rqtIaStlaYj)FW$e>Fqf&;;6Zo5LY_JCSWRuc%S5C` zZK3`S*h3rI^0CgwL5a46e(=zvVAKLFZ@w%bcB*m5i*%2AhqQuoi(Y@FobSM4Z4f;M zFSf9b<`t*fTSAn-)Lfnip0 zlb$s9{#VYpj?1=i8#>_wP>BJApc?Z@BVy1K3 zpMN=Uv2kCE=G2XOa%K-a@Z1f*>l9lpl4{u?C%i#Z#^C9JA60Ic_FQ-8?`m8#jkWz= zobsh!D}S)|lUKSfGx9HO=(Ua<)TY)vWxi$k)u-k+11tC|5o6sn{eV^=Ut+Lez7Yp| z*|`pmMTzU+7rs+u_Ee;!Di8xT>97tq7T$yZ9jw?z6Qabt#o)#Bp6JIn?%pc{3n;^~ zc7Z4?E-Z`oycVo1(xS3hkiVNw*H*l7Vk?VX8EO4J>Van|U#Gepl^WHAK{SWf&=%T5 zGIV_{GWxSenb>ibotK^l%*$82|MKZ)AQd>X^OewxrwTE05fNb%yWI-T#I;Ma`mUI} zU{g?UbC4MZpCyK@yVc9r?9Z3!9@e`rCsRH4J4>-afd^(wmsE>W>BJX6A9%XkO?>mN zzBAd?Nn6{I3}`HT317nmm;{qyD$Ia6uMK!^h~E9vFo4|-X|U*%Sx z%GCCG{-Md*UJxPIU$f@MUe-ozSAv(<-SE_?MxHb3Dmq>ZKfwmr%pkU5cYuget?_rX zXwW==LhLB+tHEF9vYsRLK?XMMysNG4qG#V)ntShg?238H@z9v))A#$8OLe# zB>VZPxm8o|1M|>sWtsUS8(5)_z>x`4(m6Q?tEEJ8hD8c=oX=1p`(wuX6;u z$p4}3z2mDW+Q;q9IY~%AhmwRELPr4!MWq`B3l@xsh=3#r(o3WTP&`4pjflztq(lY5 z*ib}NM53Ueh@c{hh(xhBf^@`(_qu0x_H0&tp6~CE7d}^ZXLjbE-pffSDJe(rF*pII z;0%uZho{@;YmeD&pWSj4U9sF>ROgJZ@v1)5g~OAp(fLT&zyde~H&o0^Wewl0kObw= zhbpE~)-}hK@5`@wSNZz$iADbG!^eHi3x`s3OZ|2+n*<9|YaqN1)PqLQ1cxM=CDd-u zN`{k?GhuMpU)cB$--NL`iKXupZLx5Oll)x$|A zen9hBa%R$>6!UGV0}z@AgJBrLNAZ-Pmo-~k!2v0IPAI5Yf`1)TQCn20Vs}DvszlMV zR}}k87oGO?9zT=}xFLFV6=@{fB}&yCnuH^h;VvkIdtkOVChVM-lW87@zpN&|T^W;7d=r5|!X`!DHM;Hg!x z8lHw{;5m2!UfjUi@j6~M;OmV%H-S59O`V!~?W6wUZfAU3yIt$#fsZk}*Ar7&U+5mZ zltBqpe(pEwnRCVOD&{`_&x8KbH;(#t@9e1pkrg^6g>`=HvE-)lZ<75_Br!xl@Hg-+ zd=Ee3$geylEq~qHMb&6{%%@__)qy&NxwDv44%5YO2gD@ZsR@hylS@wdE;x7#0l6nN zWX2$w4Ubc9)+EX(B{{vM#P=%AKE%Chl_l|X3zJxJtEHtA&sCebN_91JnKSlVb>gM+ zNylz2sEZu89lKTwrCP^yHI~$Dp1e}?4w(vV(TRx zy`O!ko|0!&sBLwAD{U_4kj_(i30iGB-Z@3DD)VKBL$6f`iFE(nzBHA2cG`=C@TF9# z<})uVA1A#y(>!KRkxo^`Z<#q;|4~moSycYEay)PGrg5C08j_mx{5qu}T^JRLv+GoJ z&V2J_mDW33j#QZ?=bf$NYFM8{{~YsBvNhIY51CDv@nsJD<3vLe; zeIu2S?!BsHT6}z5$Te(Nqw%$WO7!btebIB@INjUKrC&S3B$~_K-=mXZ;YTWzMbGK3 zR*%3Sm01h_^C6>i-L)D|w(J#OJNmoWv1G`>$$#PLsMn~_UL*Z0@sb2Vs0L|J6KcO^ zm1XiYJx=MnNww-$?|y5Sqb~mAz_`NMk-TG)Kr&+1vywFSTm=C%O>%io=n4Oi{rMTE z{NePw&qWu+4CeGt-?)SLvki`43?1PT=n9uZcRc2fRx|8B`{)!k>Tmk(MNS*h2lM?g zFPOQ*1BjJ%t{+Q7$HMo7>rVmNBZE! z*Xq$tR-I3rn2@fL3^~OyJ@nM(MZfGpDNR}}6lypMbcD4Ecw9LmpoH?`xZwnU1*5`iS6oXkNbzs51sHWE7F5t>jjx# z(ms|t-8%5qIDX-nb9Hi7?$79|oPB#R=Bb#MV(y~4eckTIS4&Hbdz4d8%Q=B`UP4jA zBlPR#07ywm0m*eIOoQn#1LnYeFdrUPS%I?;)dD19JwA<;al2gp*)zfnvrpdJ)(oM82oA|UHQo$(5%tAJ)@}+5MdPMrD5Ow-tLl%x#XVX^mp& zS&dV62P(~so*1_xm7ZZ*Lr$43h;NwIpEFvagB(99NPQ%+d0KbQ_q0u`l=5(VNy%BF z(|VmKg=mO{I7osN2tqYTgX&NdYC|T}hlbD?n!aw8HRqWHt)VSk1nr;`aDz%@@<_GjPW8O$b^8Br*&)cM^Jp9uPe@cr$V_u; zCeUTNLGQ#nUj$!Q$_0sddg$>le)RhuB!(UduFatq3JkK#&o+ArJ=3C5j|-yenjT4@H>>l zA8<^?if#dAFk))UkkoW;59oBXo627{ItDZ8PKk%I#~oKsQw+_dQT7}5@NMEt$kXbc))i!6VFbuzsd#{xSMx4KbUZ|DJYr3iQL=Ve z+5oX9$@IanS5-_+NE)X)CPkgf9D6mb&@a*Hm1`xBQYVCEeML_Ej#me6TSUuA)=`}E zOy)@D!K5oVz$j_ii@M#nkvak5APIs{1*$dJ~W3cXdU8DTet|? zK?mrv(JH%)XE!iOBc;Ghl{RfTTz99_>Nz=i3}(k+PhzAjt>R2%(fo>&=rYSI=5`-G zGA<-hRJd!Ne^J5--@38An2Tu=H=KOCo~$$#p?5(c%!JuEU_2x_-96Kxs%(4oYZg&V zo{=Oo_Qag@4aEb&lHWoqjf&1&twQukVy-{Vk_0)HoR?acL&tg|cma+tge9;PmP0YD zgr_{7%8b>$sUOc4`g!-&%E`u zlBOcqR6aQu>E$6a3AnOso&VIa6TV*_oInO1p1dtuD&K7t)d^p<*||=` zAmvxOSz=DA%s5rdo~L(mSyDkLRSr6rlw5}gu7_UG8~Q?jJe0?CFc?Rr47oiaYLlR) zH+$wuS)y>;llopfAq|Sr4~YQDx{_#iKq~DT}+JyT(Zo$gcWk>_pYNjK?Dd za3@TI=`aiCz)9`2 za#+^;J9PBS($kkRdJv0dvPYgK+9Y3Cx9i30ynCKf%U8>O8sOK%UdiMmX*Qyw(>W$D z^;jvMc^kIEyYN1I03U|4Uy1dc=AN&fr^e|a31T0@ehwCQA3KR3^6;nbyxoA`C# zO}avmkz@sr|EKn@=tV1?hdKR0^LE7xf;{4 zFi#V!v`Wg8{C;AEKuPl}p3l4F1N7}4PSSoyPImqi>bn_gY5UroctlOLhyWQn%TtQ5 z#BNURD=Kyu{x#NL*_x8vHSPn|pOaFT8}}>Sk^YG-qK{Mw_)jOuymmIB>;_lB)o?BJ zfE?%vy`c~EhXIfWw{2poWe6|BV1$aINbxjlGt$Kp4{fct*v~qv@9NgK&;sVhwIzw> zV()%<&`xr_{X@%;>Z9nV&sCsIiIriyJK6Hz3+d>~e#2%AV5|HiFbj)7=1SbV#sIy#M^_T5+IgFP=2gIZ$NPE13o^3gfAA=Kc2F`-@CPnZ~ zt1MQYu0RCGoK&${wn|UoFMVRRpPrB}^~$T28`9O58PBE+T(_liSzRguYCtW7)%6H7 z1I=y^+MAy0MwZ)}VzxPUq|}(=Dn-h8M&%nSMYmed6-HvbC}j6e$QOTGxD^4VFY3z4 zZj@59^1o1_lfi^IEQ<<~sb+q%(%&w8!dLLeaDTEjlna`kiT{#zN!E3fxZY=6+{X#4 zDKTyF^hMAPIzcF#Ki%L8xC*X?9*_e)p%)=EA&|Bu`;d-aGjp9aXpSE}-}Z@}oQ~-z z?B&Ba6FVPO+;kxG$l~cwEs2o}I2wx=Y2L|N4TBG4T|5h#LX{4Y-#I?L0f zv816mc(y3)r*ZQ&TQ!tEiC#c|Ij&FIvk5&2MoCFAjy(Y@VGWePv+z8uHGvCZP@+{P zhD2!e?+FDpBlShOdWSs&DEgnDOJ+GeY)=4Pf^ z+@bLf9!>vq?xB_b>RnIzTGk#$MlI*wqk`1>IMx`>N03{FEYBIW^svoZ@yc2cC{Nw} zUUy{No*-j^HX#ID3>^_7(Ix3r;py4bWGbYFDf9fpGLHG`caYpJnQx^^#BRvC06(+Qj zA*ClITPN7`$gM)#QimXO1Tx3)%!hFx@gS@R9G|(&%n1-h%~ksIW{H6Czco zGcta7iCR2<`>MfC1#~ZV?uR1mi(Od_bK8|ntJT#1Qq9V=y7=l?ua*9}@0{^1Nw}2( zr)+nUU1yj<*kiB)o>hs80 z2OGq5(*B#-DjAoHZ>15Drz|SCg-Y6qetEYq)l=pMMZNX~z3;GTYdvA{*R0!FMAWNX zvOjNN@{0+wL$4G^--fO5E^LR;2mJXEcEiW`$nBsR&*#)zp+;X@UX=BDJ)Zv-^FP|r zD|o21ue`*k-?a${dgTJBv@D3L26O%7Q%?lQXhnn#)kzEgq})P1*fQ!p8B2C zV1Oz(x!g*~j@Ocs5eOOs`7i;&A|(I(y%mI*j9>Ir#f=Uo!<){Ij7`LT;R7G2r&+u- zZH#G|A6d5A-!4SmQnhJh-B&D1$x61?CJtvRZ%V?~m15XjUW41|q@Vdh(vT#HvFR`i z=D>aM0L+Jn;9+|gJBI7UDt4}@(C=pRlF7TWxzIGEW+F2?bR?3wWiTu=-^PMW`(&?| zRaRZ2io?O}dSGm(6$)cs(+++AvU-}*RkrjcrOs}l_l%h2vFznNvp5!#!KZORYDpPo zsr09wkf$lOGVm4k?!Vq~%&VB_Ua?j+Qwe6QnzvS0fW;%;SN3K0ROINzke5PgXN+{` zL|9>MZOE({=2b4K;Fx40<5?9Oc9EB1o?Bn)B;{Gw6y%xD#u#~;Scz1Ev@H_tdbK+e z&0e+DLoYtNmwLnl()SR-#rt(`_u7->lkeqrzHm#X^sL{g zsipqBuE%}%w4bepZZgRs@(Mdt%qOOVh=-JWN*?Ji%eJx)z*O6^?Yf6GI(dJzzEifb zx=pqVx5y4xm&V@7Ww8s{8GIENxX$FlR<=P_k}Ffka!u-~#7&jt;?n_fw{aus6mBDZ zocl)Qe$iyE3vJ8QpijgCTz4OgVq5HXmb6u5h61s9P=1?xX+`#pg+ql$n zd|DT7oqRZDI`>N!r0T05Omto51K(sXa#NHLbw<@ z!X?lZE{Eg+zHcQI?RAMZ&_vc@q7U0 z!^7|>gyAvp^vXic*_Ahj7pUqtKji|avs?9TLiu*2>XiygwtKiUqI(yu~*n_lIV3Mfs*h8&O@ z&n?TJ#W&<~Vwvt)k$M%eGbg@Jf*hF|&$X{|Y^tQ>a$@94=nmJw^>72+2sgtm&<}2f zTo?$0VCdV-Ee_{pB#ef!Fdilny;FFq7*Wf*t}zAexA^?3ix;Z=a%hBX`%JIgnR$d| z*jWKj+R0-oHPdG;o~vi^jDFr%p~(ERWFF~!I_VeK=A>U~)`kk{W|sIfyX&c*ygT1^ z>`8yqBtw3wPFDP@rjBHa*T^q>cHg+nkiGdxHl#^t~bFFXFYW1spk|<+{OR1oqB^I8CweS+W46nfJ@FtYP zRtUYzpY8Agd^aQ(w^S^$&fWz3oZG2F z_9PxV<;zOx7gAlVN-SR{ZedvfDtj!O4yGKFk(ilW_i=xpoHM?Ma%8wBy~Kjln%K*L zOpjfYOjeD^UNxC-mgEsxZF_}YS0NZ*K8Y^z$(S@QJeIP59>Q8cOK5{oNrJpzw^mF$ zHOr!lq7*IZ>AGXd^rTEzEyzls$SIB1T{yMyCSyyZVGbJU2}mtirtnPel}(BwKsK$Z zJfSwcM?8@Ed1NFd9x^Se?yN>iP+qCti6I-|)G~hmD^~e)qEGueN00WW5~bZ@7f=%x zaNqbvT;{zvu7EqUUyA=Qes1D738`EIy*^<=rAMeEyAV6s&<(DFYoQ0^Ku_oey`c~E zg#nNUx4~c-wuSOPikC4k4kmcgFFUH@oIqi7eRiW;T-cxe(HURfjk)B3)oM+65%!lt zv7KBd*4$k-sdD8Un56yIUdveeWgB1T_Oft&BBm$TluOz_jgV*HIe5|Ip^AeCORda` zu$+mL)s$eXZ>~}q`eMcoZ(zR^wt8ep^gH=PwsD$O@0FL&_D^ne(w9?oBgM&;UW}mK z>Y^KuFnuF?EecZa;(F+vIPwvEibMN&9ssv_GeuCmc(%W2$r<1C(b-OM4gG}S-#k7n zt)-)=@bSfJ>Ua8*;aEshCF3~ePkYQutVk?WYq(w=s+=`{v|~PME2n_BR;&+<`CmJ( z4*A>pnCbkwFBbG-dNLL&dn}j`BvqfQrhfW<8wo)T%-6xZln5(J&mG7nD0d9#If+P& zmX@4Q9xkgADp89Ybsrt(7Xi|q$EsoVQ_Pp{(sK)P zCd}<%(S_Q9Zt;)#tG|1~cktGM9pWXMgZ^pS?=82^ylwD&FrHKQ*klP3PLVp+lc^-FUda%8uTV8{?YU9df zrLq@9D%6saF<2Pqv7pmUqVb{BIpIycYt~_EUiNoK6J`8N0XwuyN~U7*ZkU1PIXuP3 zGSTFY9(Ny3%A};1c;wnMPpJb(%bN`+x{f6ur2{UWDMHQySO`npo|58Yw$NbTS)LI` zGg;A4X~YI&5#Ida2mIN`kNKWjb*oD2Vy127yV#4vF`1x!IqrSB5gn2jlkTf<>}hxg zo`Vu754ctZ8**R z2p7DUl)Q`Z_u&KBje~o5?ge+C?30U;UC<`en6)1Xm4rGt{&AJVtL*GcCXorpHR%VF zj;gZ!4MM+#@8M_o6@GU|uOy9q{7xz@Ni*+*JA;%&M;X0zeo8p~7#vf$br z+wt5ue!f9X*Pg{O>m8yIVj&Td-_hkbbKM^*X^Je@j(0p`4y;M&C2(JcN*_}jg^DNY z1*O69_o>4}wGdVZ>Ouo(gkZPtW&4!~DDJz=->3I!-%l&^oC>HF<}dV^mqShx{bni0 zDtC$304nfMF^K8@c8C@JZT&o70pa5-EF*TD5~BisZx6S96h z^T2q#C_JsNbE0t~AEwypP_{*HoeXlY(=qJI6f##QzRwHmzIe4AT(oBwJx-Fw1ew>C zYV;cRC{0K1444J;;6B`#&r{6HidodPVo^m`q@p%0#mb8w_5Zm3jPI5B8>kps+6SCV zN*+VNGFSmmy3;H?u%8p6=lS@O`y(Nc`FwYXq{4Qq&062Fg^T^$XC3$bzChPV9F|g> znO;ZcoA5Tg>yhm&P(@4C75+%QsIjOGBYHeEZV-{dB)rM zHXHt=M}Q|oR;Qg5uuo3=W}i2Ps^|iyhT=I?{->%3vk=-E+QLQ90XpHBI3)92?$|MV z?PVrULeKsPl|*x!>#T1M>B)LathFL_r78fSd1-Pw;A#Y43pvme2YU1D1LBaL`E_M| zih?-s2OQ^F8KewLk)=c8kgj z0aA^$41UD%Jxv$-b5r7xqG>I+gg#Z*SOJgY$SR%{JVvKl zS-8kgw#?5pa7^72k$Lvr2Wd>s_}&S%mvow`?&vv& z;ZvU2kXGI;z?^;9Q@+rjS^cE1=JUF2m(|hBn%SLo^R>J6$0XOWn&Y!9o+8+s49-8U*Cou1z1fm1 z$s^{>1e<#vTuMZ_J%LxeM^C6_{k7JA>YLNP+V|=kZuItA`iUYS$&$sz2@I}(snme| zVwtLcyDjxk8t-g8bQyGmE8r@)8m@&N&=Y#$@jg8Jf_Q2-i!btY?lSp6kAI|VYhqb> zGGup8P2Fv#8D%0&qE$BTt?7Ks*Zo6%q)j!*2sT?9rCY0Fi{++d>znvt2^090s@l<;^z~d)AAZ5;T=G~vb_a}yiBJG{LTH-&f$4-`7SA~_5AFjIY@#vmyU2DlRpHnR zENgq{o`{*%HN{pRO|`817wFQn{HngH9+6~>=Ty3Mcz>+4FckM}mAl9o$?1>d;FGWl zo`z@OId}nH#B=L;x}(nQw>#VJQGc-i8Q)jab8%VwYsR8{g84ZoV!qx``hOR&&G~p-2Y)x3VG%uJn#v8 z3ZKC~H~Y9!RZ&RpTo&p+m? z+DSJgW~s@P8q*+|faJfX<(YH1GUr{_+Rtxx){W^BQj4dPDGF`)1<6y1RpVqi^eKM& zu!j1H!a<2s)Nkn(r0U<#dz&A|`!H>D@{2_6I#>@I;5FC?n_x4%1zX@9*aq*x4%i91 z;3N11uKSEX```c^gs}Q0i81=cjZuZ*nU{+X7qMB6hb|4A@{f2JWP^d4QR8NAH#gjQx~B#N$Db-%j%sC%(AmyuCT z)^NQWOwO~(4)220FRF`27a(gPvX<~%4sJVo8?(sJGfgtU%uEjH;nCJ6i~OZ+j{9oH z4apMkYF^fFJ04RfyD6hkwhlzkA6JQ@_KkjyHt zI%(>zQq5>nLg)6m?BFp%HjuSxE0=o?XVMe!6)!3?1QhM48DUO;1@Uy zN8mWgaGK{|5cR%J4zo>6?_1HWn%p#DT02uquH6|bbwVO(Ety1OMAAmZjJ@&FYJ%9><#ZXd11FC~ZA$s$`0}H;~ zfP_BJzt{1s>YEIO+C;EU0+T zC78+bcH^h`iAvv7UF7z*W68&9I%9Uwb%x{}+Ozt4kcg+G+vJW`S)Pz+ZFp>%TKOB2 zCJSS=@Z=`7_!>$>SaqlknFw`TmZe)2Blet)uA?pM)jwCOJ1Hu~_Ek-(+(#@;X)|QB zgjUezUu2mh$abs8MByX%`I#K@WoO@ru-v%o6ZINY7ld2}-QWs4v?f=Z5sT@2Ijx+X zWM)v9dAA+`>0N!1STcS7!vBPH=dX7C61AJVTf82ROF2wpLR}xckQDv8l5C2VYd&Qn z_y#<6BisZx!!6JcZiQSJ2)DyfJU)`AiB(m``|fv=XtAWfwK=k-Qw-=W;gPa#CX(F; z@}$Vfj(u|=�x|mh|p_`%2Xxc=P6g6&fTy<;PoQ2YgF*_o^^mlT?T=XTn^#ABtcB zEQH4h#R{J8P*^wV^S5$in_J)8l;$v~bbmJuitI;4UoWUhs7*s+R$s-ZlKG50md;*`remDSM!*}o#`~rvJD4c{p;T%ML!0H85f_O-V%24$KRxNneg1XQE z8i9!sDJfF=n|jG@KR^6sYgyWw?@oWXPUBmTtNUD)6LXVX%8XmVF-o!^O)O5c*rdK<~?2U zT$|B1C$;4yuXx6sX^}%X5`b5qT;>1#sT01c<8^1F{Ky_A2Zty7>3r>sjjL2G?KG?Y zhmxQAfb=iH1JA-*cnMyHSKw7V^#)IIKo;9g6iZ1kvkqqWwPav1mp??$VCg=f9{bBo zXJ-3#%A;~J)W}i!pao~0#mCWa=u7cFTC4A(mi>i^q<1*>)7bur1&LA7fuySHZh#?4 zAK%J0u*T8kQht18d=0;F` zrZuwgROD)Yi{1^<@Yu&p<7VqiQLo&o4_?dG-8lQkCTacU&L&w{?~P-9pfB`?0gwlS z@xU;i?f{tSbCW^M(`=M1mxTh;n#l~bIicO|sz?26y8q!T{4SU1)0<^V*(}qIT`L7R zawklK5KM;|FvpGo_YreR60-v@XUH6Ng#F(1&cxoM>KI>WAr=?GQY@R{u~bM>%w!9< z(KAElqL<~&svh?ny<*q$hqC87z-`QmOqD-4{cZHHA5soU6Y0{_j&lRR-}Kl^YNA&h z(lus9&&d2-1vB>1F$!XU)}& zm#n9k z(tDS(vCz#EB9p6|w_oayd-#;^$d8fv{%bLx<1ufpt*m(4fB2Q!pYE@sZ zsw+snHn|TH`ojRY4M{_Iy3<9*Rc^I8wqu$?eKDS%Pbq!%eKnsV@f~dQm}=Xn70Mm+ zvZs`v`DhoTPeA13$OM=SQ{gTs^aP`V!{O<7GlZpnw10U;Cf#Mxd_EI!=aSAPKZt+@ zun-|jcrFD=Ks|EcPWC5A!M(jB zj8Zl=ienPfMqk!XxC}j{KA2n4oryEoB{nk6X!PZrrdfuPOkxIXbAMZ>7TTZ7%6FxpQ-L)1hcDV6R*ieyh(Uf|JJ)oxq?uGp zpQ&Aex5u|cP%CHy7veyBo=(09UpJlHEBzfk&#V$%jb9~ay`FSAhPz|wI-aJ&6f+Vf z(jAe^v2wwK{zVTT^W{&fc(Slffx46US{yYBG{+ZmY>Q?R#Tx&vPJH`mE)X(z{m51k5h#nH^32?>$GPSx ztRC;`+$(w}$M@>LUah5cOJi-t9V*jNHfOL(d+1Z8G7Ddwn{Wz_cJPpslbMOMZ2U?)-h5zkNIGuQ`i&zpTtvcX0&Xtneu{^GaJ_zv76zs;dnimcrf zJBZzFC%3urB-s8JWvQ&`D79$T?&@~z*V~`{ZnOS;Wy+tyZ3=>q^KBhB`*_UD(969V~sza$J z%`&jF#ej{hZu@%HN7wN(iEpnKgw+0AcQopdGWNNQd*)(K_}2e9TJ1B*$0L=k9nk@X zl7YA$ai7G+b5!Q{_;(X#BtDk7CGl$Y+a#^3wIpP%pbcCM?V%%dhD)F;Tn<-4_uZub zHN0F8H^5Cq&n-N~=Vq+y-0NzeFgE*`%ygBB8GZCg$Ds5i&DLs(VM(U4;cHaYdE?|! zDnP2k=U&^&;j(veSX!-QX6PHlRN(}go_;)-G@rSE#tGMOE`K5(EPyF+CrpD7OotgT z2j&rw2YAkhhe70;6(9HDJ|tDD`3Vd;dnX3XT|Z`P|AVrAXvRNS{r4 z++V!!gzxx!_L77BV`@3~d`qh}HhM2fcq*}SeEZ5dp@jDnwsNPx9CA97w2qxNPvhHX z;5m2^*1>w%0I$JD*aUCE7DBm==X+p0q@v#LKm?cR-!jX)GK12jdo5pM_B-sU7)q27MMQ~uz-Grk+H);l)zSzTA<<+(aT`hu}m<2VUo zW195l96ITZ{5~I1{`=y{02FyJ7>o}kz4Kb>Ed}xvhtG~0siq;yI-gIS-XeMn)#^Cx zOoGYCF?Lno&AyrOsy4IL;CtTtk^AGOV}6#HcXy$TBmEbx@xPjV#uuC;(}y}X9>Bsw zZU@54?o~T8WOTKdkIP&i#phBc#mCt#?o}CN>sJxiS7H8XWnS0EGG!RNYlkx5wB%X; z+TTz6?in=!$0Jc{PQA#wcC>YdVMh1lZPI$Zh_LktdyVHNa9i?riDVC|`@1w8;>n!1 z3;o%7r+jzce+^xv%cvf77wKK(y$>J4$F2aX=;g$s>b=MkkO;AU9OFlzuUBpdRTLyt zvaEE9y|`aiDJeOCkgwqof_~sx!6R&Da;wb<A}S1lg?VAeu^^_NfkZn{m5)P$qWVT-7bDPm9w5+U$$#f&BHNvSAq z64DFdyGJbc$E`Z<%daFyTJ%BPT3Dh!2sxF+Ws3#|4j4WeLrk&k->Q-ER37mF74CW1fQH7+e;CVkCN?&2d7-FTO@XW(< z$#X@$()x$~rYCz=yyoOUi>=4i=ynKX!%B+!ZKhL+Ym;A2kW*%|T{k)XTvC^0ecCLW zXuBM)h8}Pu^nqL9HW)&bj^H^KCcqT98zlL>`(5PRSCnjaGn-fKRaGlGVYz>85?eR3 zhLL`iC`$d~WzYCx1U&{T;Bk1;o2l&CUTLGnLH)~tk@7D?Ceh#hy8dkknIo;R+0|U~ zRkVJQzijL&-;DkG*WRS#Cl*V8+sp3SW64*?U7pY~c^I3Tzf$qjg*N{MJhTqh!v@$0 zn_x3+!K2%Fz6Yw9OHsG~QU2M2j)ADCL8$`*=lPra2L@h99UK@M7!i0Yb#!2BYJOmR zU{~tLsgnXz0(S*MfqMe80&@c`{r3eP3>;5AmHJTNkw7@GB=AzovVcFWIPhd(f6BG# zDQQmyo(?=4cp>mopmN$*DeD8R{a>eaPWv|H)xgF;cG`vhHv?}4wuS;-)7tsB1>O(r z40QBgk+wVVNuZ1WQhzsp&-5$(djtCd-P67dT$^?<@J--{l=qc2<`2dO{IovlccxwE&+(@Q zs|RPN)e7F|@9obB)(bWahMEL#@t+@T5$x~J_5YTV6>Jl{&3{p_eXvuoJmr$$Wx>mX zSMft%!~E9-djxL?zMR%8cyq9C@Ydkbl)T_b|K_x})5iGUNgEU#5*!{J6+DqLHaIRg zF}OW#a&Sl5ox#&7cL%2jX9nj4KTEqec!&RN$^*eK(u#uTQXUR24E~l@9!m2CCivS1 zVgieU1^%OHOM@$dPXt#5r~20fp9xO$KOZdgzZiTucp_~>@b%!PU})^M+AA&V&{v7-*SROnYygB7W z@N_Vkem0mGsG6RZelF;%98)I^8@LPxn!zQ|1Nv@Y4Py*1_rh}63}3+S z@E-{B8%hnJHB5#zumgU8Q&68@Fu4x$ARj)0Y<>u09880G@F+Y9ufRKS08YUb-1$Cf zBfXbLdsJ{*8@sKH5|Z0HLUU^YA~hn-gQ@*3=fpWrN1VQYVD=noIT2G|Kd zK@_`fFND4@8%p3fWU({vQs@bTU=rL1#qb*V**M{0KoN3L8UvxC(l~FqjF;;aQmg zeigREr|<*RU|OUz^n}4s01rSh?1uyf5w+la=m(F&4)_V0(5>nT!{9EM2am$z@EmN0 zz3>y9g-}%*g+|a0X25FL0SCcnHA`>9&m?xQ6;+^<-j11fngB?>ia0q_pu)JIFGu(V}GjW`!wf!NQdwqkAZtV>IXgQ1&#o1KkQLI z<}ttAqki0|Lv|Fe@(3s~2JG+8dDLq?=GS}FuY1gI^{BVm=DDw1hu{N`fL$I7dpzoW z9`j#$z8~_azxSwr*6NUxsebbqIO0(s^QcdI)c^6QeYGoQ!b%=>Wz^r*XARrLK$_Bs zsB3xD86I^5)b3o~!t*`LqrT8%zO$%9u3~bT$H0{y^|h$o#qb7?y0=Gti^u)|k9rX5 zkUIoJJOV~~EKKyMr+UnXJl|(}zR&Tf@2wpbst}_29s!SdEG+Vb-J@%jUd|%`F z{#@-)#VB3tv9Qjge$^vjljr-}p6}Z{-{1Fq-{p<6Jsu1DJnAn!>hC@3Up(sHJ?f*V z-ANug;W6;1$ADF*VhkmC)X5%o71VAA(mm?h70riAGAnA7H1ep=_Xud|QMdJ&Z}0iu z#iQ<8LCqevt14*l12rCXPt@*Wcaulm*JD1{qaN%rKg_KT(Y%iKSQzI~Pjp+r{8W$n zZjX9~$NpT;_Xk|+khJebE)7vX>`{k3>LsY%X}rSo{b`T-d5?Ns#J+C-UyW#}_I{Jc zLaFEbJD%_Fd%o}TeBa~wzR&q?xBp*y41Dbv(5>T79`)}Y^-+)dlt=xiM}5wyP5U36 zQ8AOnqjpDeibq}5qpt3;U&o`a=P}>VRy*zgc^(5TJOZ*j>I*&QJ9yNWc+6ks`F^=p zN810ZJr=I>sB=8(TeJYD`5xd=5Av8F>iK?$QoGv!NgfM#den100v_;uFY>4#@t6;L zzAusQ?)HC$$G{UF^=gm$SrOpsKfLHszv3~!(eu3&b%pkStH;82k9vnky&JXL1D|@- zpL@*j_k1tQp#66X_|9YDXOH@KkNT)b;3<##FOPX&-HN3wwyvlBPr!iNLjjMvnnzv3 zqt5WC>!EhH9SuF-n}j?Dnt2RldA_&tsM~qWclLb0%%i@-V?K1X$3PE{fg3&Qn?34& z9(A5aeY;0JqM|xfG6oHaqN7&bz~84J|JwxQ-=`mo{|{4-_Qaz-?-=^;6OVtNc8p9q zMy4EP!twty+4v80jiLWK+4xUWjsHB!_|H>}OfWk0i;>wy_uOLW|2nz&xihKw?^B90 zq3E7Z?3~^;y?grg={KeKOCOj%G<|gX`1C31q4Ys}*!>S9_b~r6mY4BR0Cz$NX22Y{ z59Y(e5QfKKR;{R<6+EAW)$k0w0PA1_Y=q6Q1-8Ks*ae%h_X*F>U_Ts$LwjWYhnHXA zFdT)G@F$!D|EEl$K_Ud8DkRm8%1P&03+h4xXaY^qZ^pAFw1IZ0FXq`1E`hFaC0qm7 z!;Nrrh(G-x7xJ+%i04ok31eYA6u_MzW@o@0xDV#T!w`nYU6$pKuO( zWklupKO;6E5dts@y{bIZp%&bYdIr?xy#X|VX3#RkpEhtYbc9QwD_jZJ!1Zt=+zkC7 z7Y4yl7ztxxJQTp4Ao6Cw9JmkW!^04U$6y6K39I25Sol=Utk6MT4#5xb3mk@{kVlm) zt3e|IvIaDTl^sh z1XJKHknb~L4%`b5KoL9)3t=%Vg%$7wtb#T03_K4n!t3xBY=v#G8$N?CAnyQw%HTWr z5q^Q+;Ru|8a}ZZADkl+ApfXg08c-YRK|^Q)z2Ii(3%PI`gm=GKv(xJAXKPjp=e<<3 zVR+5jn$^SE&(+M_uykF`yL{oi*J}0(=f6>N@+%u^Ci%kI>uNUKkoB6pmOWpy&xW-d zYZgX@9wReWT%bH$!}JdH;-oB1x-;mqKqQNr1;}qx)UsnBvgW8)9L;K@tTg_RqE{Jj zN*kDVCLqmxw}3xH8}H7=|GbY-jcl*U}I8oteX;c$Dc(5w)e)j_>7 zC|TUSAUM?@(rbZwC2$j~e>42D-nU<^^VO{Rn`?zHF(9jZx*@(NJ*D#TeOB37@PA>I zB|v4U4t1e1w1BqI5iW!7kOMcv0Jt4Sh4?cbrowcX3-e(iEQ6Ks47>!dK`Cs558+ez z5)Q%7a0E`lIf&hFl_f(ps0H=mJjjBJp$l9Np=;XYUZi=h}+ z!}G8n-heIeK70h9!$J5SeuHE1C-}a!%Hkmi>5u`9zGS0Hb6(m&2e=fjg6p9-+zNwX zB#eV8PzZD2L3k9F!jn(}FT$&^8Qz7Rum|?TH}Dgb!%6rL#2g55LEQnXtSZ!mde9VF z!bQ*-y1_Nj6K;V#7z$%xBHRTt;9htL7QqU53Z8?PVI#Z^@4;^P48DTzLj3s^j=~v; z`pPPcg8-yK9cT#6Ad1ZenjcbX9VA1stwVk!sWefxWDbv+6Vo+rcj7%s@*C)~3AsFR zSyFb@&*H;sV;#T1%&k9i;_YaRmDD-DMRc{ACu2fS#@-+OY_-SZ(h^t4o~^Vd{l54U z9Gzd8ye2s_=}46Z)xJrnkytxg?r=StB)?B4dx3hgqxIpGhmwkuWZ&ln$ula=jqlFS z$fegjmwbD@sG{M}^DQfH6wk3R4kp1A*jH-h-NiEm_taycI*XTia6ib$`8*fEqp%1> zkmw8Yz7)L`w!Wx^Cs02HPs4Mt7DRs?&sXgC*LiM&x8WVw4m;|FqKbC$@(JvP{csQt z!4L2={0>Lp7@UOKTdce@JkNozepFE`BtSA$hH6j)_)(a=+B`F%0W^VT&=RV#a$m*2 zz`s1?f5uGmC+Tkt-p8`pj49_3fVnU0FLoJjOhvr^!eUI)rms$hIg}s zm)2TRrSfQNiq*pEYYnsttf9OQ-!QUQtvmhk6H&FW_`BiLn`@2S5PI%FS%pxzo%sO<4e=n6v89sZsXhC_P2cA&$r(v@ZQ{hA8ZZuFTmDp=i5O4 z4Ad9c>dBaGDeoZ!4o1<+{xFXB*7o~U-WS>LBCL)5J|6wH_PYq}V82i2{ZjjV2xcy` z-|yhPtNlKb_ZRHS%Sd-$!BSa{GNW?^oFGV|ahlejmpBRrdQ>-nZHB z6M28vem}+gcKdw_?>p@G0^WD)_nOx2D7xDphVy>4{XQbRzH;q);oenh2SXFA3FN+M z(9aq`)ZWUQB*g@4H(}6`t^aC${Vv}oV0wm6|21|*N4`zwzt)><%NhKSt_%(jtWrC5 z!qg;>KI!?eF8&_Zhw!_IK^vbl-GaJzbd}Vhyp)4^igtu`=T$R`=sC-=8n zQB2xc7g-kvJA^OYlW|>gL#&Lq@+nh;tlPuq4%SI+Lk*F}PZe1GG27b8;{Rah{UTH? zGjlVoEcrSF*Cfcdh6nD=sJG$SJsDp_g(m&a;}?;p(KcI|a|T!XrM<$V}*Gb;jBptc9QbJR>Xo^XD10+qTD$ zS*iCew z!bc8dq(|KzzVtxG<>77zGJ@f~2QoT^DvEB32v?F>=OISI-o<{3VB*(fs+ls^l(N>0 z?2r{~&EJl}&cQB(NhCBFiMn#X;(@V6$+IgBdM+U951IPcy0~x6+!*v1Z{r z4rbJ;B`)jWw89@c9k7RPr*P%6j5?_i1Cq+N1hHH9l75aav=1Xj#W#*&-XuhS&*AlU z)=q6D0f<->`4yu~vYccYF{83hxWQK$yTY-P>!yTfew|Sz+~ezv`myr0eQ?8>gBj&f zl{ykX#7(&BHyIz*iovePkVuL{x{1ct7-)GYV-|%d;(ZY$( z7FfLioeLbD3(#qaPD@9pB|2H?WH~xn=(I+swWHG-or}=9$kDk79f|jfY1cl4R(r=# zdkjhFJ2*NW&{4(F(dmeeq){hFrxQAz(dq2ybVjEOI$a!{F6c-w`r+*kWGEd|Era3S z-)2;)>dlIj`S6NwGwOyUw++B>q@KCWsSY~+P1h8hj-H%-zDI)OMR)m-?~-tCS2|jj zb$G++Z!>OR?+XT`_RL8fLlroV|J0%3JCSpst>R z>qIj2vl4xNOsj`Ns^4~_`G_en;}aLqj#jiWkAOiGi_%^sfJ@bCWqos#8k^*R*;5*QFCW@%eJuYwapJx zCWp~(xNL-!-&+JPpl*?wqt0095*%z>8Bf)C8x{uPk>NBq6Zks;?~Qi6l!y62m~UYX zW7F>FU_Nhm1!qy~F0^Gt%9!20SzYn?7^KSIaLSR|!Fbi!iTQA?gBi`zC3i<^2Fd+{ z!TzXf?+ON_Ue_P1%EyS!`ywBt1V=vHANe3fGV;GijfbZig==d_)y%E@)I#6 zK5YXLck38~6%C02<7XvHy!Urm;!TmK16NCARSbtX7zv9qP%%7WAQGmKR1y)Nh`hln z%T2UKlCopyRt?8rCK6RJ$dDDkiVw6DaT(A3&4lrSI9%a-xY5CkdX*y{P!Vc13V-xj zM!k@hIRZPnRcgmuM@xDJ5-}oEn-CpQsfba2HSRsA%;<_wRdv|77d>6^ndqJC=tzw% zo|z{)AyvzYQaU2Kh82~>psrm-B~fNOfJ*m%#3?OEYTS<2CHxh$vz1C(of>3q)!LzB z9Mypo8*NE~WM&d<$KF-mpZ0k&LbgI}o6CItZw$3C+r<$!(5X=nOqEl_H$&R5kTW5-+ zlWyxwb#$uRIuAQKHEf-`9G%*>&Mc*qOl9kilaU>*fJ^HkWhfCH6O{`b9TVMQr6Vn5 zEBg0st;=ajIs~QMNZh#fCEi?}tMHLU8Fgw%UN)7SJVmW?rTSc1lp?31c3sJiVp=*b z@>$+>UVenP&fz0_GwRlDO1YB^?-s8Oss5pI;5;cA9qi7m?neGM$#Arzz zyj08TMB~%hE^GfHi-`F5E@|kW{oK)#d?MEVy**ULn-I@;q9bC<+fa*Hk@mL+IaFa- z5D}$2)sIk57?1qTsy$F>NS{H5laV%F95ZS4za)l+;-`PMDh``u)*VvQmQ3S|bT`F> z^mvV9Ms2+9);D@$USh)bbcp6h_htUs*J9jQ{l^IWudyJxwPFlJ;!}GdR59%T?!^BV zRZ)@&d&GHnFq|YC>YSdaJ@)Xayv%EXWCddl3mJKcKE&n8Fj9b52DnzWjw3L^4f~D+cI>Kr}QDjbYs*K zH>Ty2=f%PBg0C_fHqy?>Xi^;0QSi5}ad<4l(F6fKKKW!u<^P{NG1KD-?Yt`n zv=^-L;nPoM1aA4?G4b!=o&Jwb*&z-8A0ztT#ozNc@lyFb0utHs{wVz0*hvC5Cc!mM z6#sN@femTPOx}@Ew@xzoG6y6P|C>yA@UHWUEBt>J=SmnAV`IhN|MxO48S=kny?>5f zSB8uv)Bn4p-mGTw`@cKt3a!b8syzJlWJcl*;;Vmd;Ut8Sl+x|u|22(n`tM>RDfYj` zx_qyqt-a~hM>-~L{~vNsXJh?tC)fNh>s}vpZc0uzc_88oJxKcZWN_zUI#Cf35uf}o z5ni8M|8MzL((dmS#sAH3s*3!ld?`ZzUOoIzp^SB9?#4t|M8dyhrfXHz?VZ>$)+N4W z;QB9?m0fQ%wGy9466(KMbth6ttVI$>H?jXM#?64bBNJ2=I$N&3mdG6GWIYLo)QnQ4 z$roL<=}uqM(7zTS^hW!!_(UU22372#>q}$Vik%CO8U-Y-G z&&Adl`XcG(< z&8}UoXJnq=^tJz6&}7^vo`}r1xxJ&aYIyIVj7*hA(jzfsE^znC|DSM%M} z-SWK|-cs>xRB@c4F+pNT)bf^cG{Y8B{<4E|mjge50ZQc&I zH*Yt0FmE{*@zzc`+M%1#w7QtLty$*nyjJF|XIt~OBfPO!qk2(i!v}gbY8i@86p!4& zMM*jk*>%iYne%o}hSA&OytQ)PZmey-Hm+;lo^bSzIB!LcJWc}R=AC~2R<~x!!UGM_a@5!zlM+B)To{>rf;}7SDmOh>U_Pinfdzb#pdl5N3TY6qqp0UygmGMZ=$hdct`I>Ekc`}v>EOs z!|}_Et*@Qb{Mh-rLDEnqVO_^uhU4}u=dFq3@3;#j3f_q}_WXOy+X*?vrG;HuPYi8z z47J}Z>O;};_i{V?os1fA$e5pYwS4(aeLt!GHcm0$mcC%#X5VYxs=a64ZYwlzUoPlv zUZ>7AZzE@#x7@qU+a0sb+mL(ATdxxFKvaxT-&RwjvMuAl1^nfgwFn&Z4()zsMd`9kwH|9tay#CcogNdBcEF8i!;;Rd%f zx-jam@GZAAx+M9HBJoa(So!-wc-1Y9nuNM6H&SjGW8Mx;(r@RYZoSUvZMws}O&D+9 zUc20wYromNO}pBB9oE>qRpJLibxJpzXx`cmS8q+Nb5U>hG@3t-FmFponYVCf@oiCf zeBVY*e91S3m-cN`KUCd`%jNZq!QBna+lceb+trQC+tbe51r3c}i%j!2&w2aKdHd6m zJf*I9VTJAHxu`c1inPUZQDeea_G{E6YFv0Mk5Jo|Mqr=T<}J6AdCPE;Zl?3L$uW1* zDKj^=GdAvW%J3pba?>W_ndeoOy2y!!F;W1UQ#8*->56=lGO%C$-DQ`ob5SSqjOaJR zm-cVeB5H7WY=1ny&GBT%ON@zuUCrAymzuZr&f7}I-0O~a?{zALdQNU`+1c1V>jdF` zCk5s8Hy2i=u@lHbis10K7mHI|t3n$xGbCQ0X^Y(Fg_^qVO#_&V8Hfj^v z=>%r!4aWXrr_>s~b5VC=n2(iToNV5Z-_FI->7BYnq6hyS}FhPmN{3o+QZb}JAB5(2cL~%Obr=(5(u4#?cTU|6KIY<1qGtAo=mhW`=2rGE9 zCS2Z46*lLZVwlzdUb7fuF^_j5v4xK*M#qzbD8-X4w#Rt#J5GGRYc4q3HAr;*HD{-P zb$0M|5!2b(ttrKhcCQI_xIC&kT#uZttZMijJGFyrwmG67I4j)f9EreSN9^aKs@~43 z-keFzRrlDMVpd%dM%YWZ>kD^^7%eVBu8Zq_5%M?OwtVHB@VE-AttGCHoy8a2bX0tI z5mlrf;noN(@Aq`Xb!zEwb?8Q^dOJ<7nx7-)Cue7BJ3C_t(Abc?+*#ek0?J+??6!_* z>0Qx-e&YJ%^pNQ+HaWmiL1$;Ntpli(3C>bauO|Ntr@xpx@^oosb2wMO?QnI8qvWf_ z>aj&!-xt@}&R#9PKq;1rW)5|(A+J4jl(1l#!}Wr*p@WuUeG7=R9`p;XjfVU81>n!D$$Dml+%0Vloz9P(uH_+={0*mJ zmA7>?@VOfwZ&zvx@vr8r?W+>X{wMEWYWfVP-rD_4-)dgv0sV0XzQddM$M3}KwU_oc z)zQ>dcX6}W%O?pX&J)+=Vo+Wc*D?{(MO;I~wlZIYoB4$SrX1Tv5p-N!J)A8b@}1h^ z$C@GEQDZhbW7;~Ew$Z8Ly3U?|E>vuGcBNu0<-XzE-Hulyf2mj*no~3IDn~JS^v<(E zi<1sz4R%)ble4NqXH^EV?$>fwRo>GD|KU(k)ZFXVJ=Q2i7v{SZX_T2t)KZril54BE zVS$>dY?X3XHJe+3Bg5~=V93*m3<)yBCob0WHvgs^Qv=)RQRJf-2$E;F_b<26vVXt}P0lsbou8U&_W( zHkY!El(r7i(M8H0QWi^DDrA)FXh=tcsNx=OYQ@84#dDvD4=YnuKmM5pdw-?on z*<82DijGQoLdvhCJSXM1QeKtvrj&Q2{6)(9QvM}ml&g2RI_A}-v`CpOq-~~>CIjk7 znJZ-jDf6XlDP@6_ogf_=p`mkVWVh5v50Ng)wOFPvt&*NJxHw2#gza;ta`+h))%a6Y z-LWd+RDmP>q^w|wEO@MxHX);2Uzc*Olw8WiQZAQr6{Org)~%x!m3^!l*)35)lD1<#0vyw+qs+ft z=3gb{dMUR^xl_tLkfbr&97WZDW32khf%C%7XE2JDH<#;J4 z3yJwZT?V`+gp6`MB>kUA|0U_aC*|)_K9o`u1x?WW*O3F# zOG-Z}gQN_TGFr-bDQie+m9mzUnNrr3vZ0hsrEDc-J4hQ<+*t;66Eezm2&7|7$@m;& zdPk1wt1{gzDc`J;o~+$5TmBH~qg>yT>E3xJ-Lj(^o7nAKmOnjD``c6_@^~iv=sk7w z@Ig2=+%5{9sqB^VV3i7};f`{`o+;-@s#;FWa+_LEhiG*Ox=7hW%E6EhO;FD+hNu~> z&lGq@uZE{T6JDc84bMh6HF&%%ce0ezZPM|Yl(VILOUkQK-jwo=l)p%MU&=>Py2d=+ z;J#dKK-Xs)wzI7oZYz2w;@g92L|@rrFBC{E4|t~Fi?!8s>_0kDT}2nm9k9A;Zlx~a-x(|rF=!o*QJ~*B<4Sdqv{yr zr!R$3u97WX{7n2nA2ogx;;ZJ{dr39g9Wvj_XYwsGtNHfI_+O|2H2?o32c#xel{zVX zqzsTU9I|SKH&&_zo|FZ~$aE$t6QoR$GF{3nDeFOs`QJzeG?TIbvT8*?tye3${Y;NP zoT`RbJ`;ZYh8lifHq0i=ohId6DS52i|Ch>ul~S&ia+8$1Agea0;ZU^#pA}CJ!6=P7 z1c3-AjUJQvzmW2@l;@?q5^H<9;NSqY;CNZU4>I9hDSwsn4=MF=>W~FWSq-vkL-!}E z4a$_|Magv4rL@?jBl($(Nq%a^e3>yvrpuSIrIZCyc9OEIl*Lk(LRM|i*ga|oyQ5qR zckch42dWXpvcd{kz$hulOF3D}=~BKXGRVP#bbc78oKEMpHuZ zm{CplL5Z5~xJ<`nx+E!UN|_;LJt-SW*-XmTkYfH9!cnz?t%+&{*HA&#@TN1=@Y~OX zo42dsmCuCN=%j|Y5>I-VZ018InO?BHl3+>5NNAGKF`;Wh|AdhVa})L^Y)bez;dH_e z3BM=k5`z+JBvwz%OzfC=IQ(4rg~XwWZzOI?{5VxqI?}FtjTc=;!3Tftgl$#wl1@7wVtqEw?4EUuzqd5YjsNrOtF_u zHYI3mHB$;whNMLJzUZ5wJ+D)|9(lJkwypL~cy@Gr?9!A8DLig{+#4xdQx2w_O8Ft> z_Y_@fP-=K;LTa7VhN*v;Mw;)N-%IM5Iwtky)CH;UrLIrilNyIR&3Ld0&sofn7GMP* zz`q|H1cyN?!j9YE_yVNClMXUKCddZ4pdQEr4MAg&5A=Ad;0=6%5i~Ma>*%h)oCRr13(!V49dxkOhZ5g7(o(Y6CfvnsbD&I z70d*0fYFE_3pm^h!8>3Xco$4U_;j!e?zLgqdpE$b8N7l(JLDd)4;%m=fg@lB;%0(b zU^bWw=79y^EwB(Q21|f~8+=!w1A4FwVg8VTAOwVgNDu>7EVa4BtVDuUU=3IYHh@iF z3)lvBfL&lO=!#7HArF8gxgLSD*DW}H1b4wNU=kw#gnS4d0~g#Yy8#a{ z1##2Bbnpt80cL_(U^bWw<^gI0dNQ$21mfB;21a#PJol(6gUmef^*;-a1mSrm%&wV4cq{?KoM?@ zdxO59KPZdB_}@mvaCk<6v0wt21S%0e6>>Vb2lsE_K6nTo0R;#96^MHetO4u6Ca@Lg z5Vr%;8`1~@K`;mfM-YA#90y-SVf;_QaR!_N7r-TO1zZC+!ENvps06=)``}OT5IhDh zxb1ZV9>5Dkp%Nd+cu0T9KoA1LKqQC()qxq*pnLBmkOI;`ZIB6aKt0d^GzLvU3(y)A z05b}=fCNwse+lRZ27)An4TDUB90{2TSr3eXI}frUXbkd!tr;%!5zzwj9mr+iU9bwQ z1slL-unp`4yTJ!wKR5^ugHOOQ@HsdMz5-{#d2kVY2U?;0HlP5s2OYs*(HQ^EaC8BM zpbr=TJa9K!2I&Vm7%~(x91Mp$3UVamXfPH`0;veA1v0=C_@{yC;1w_fv`2U+Fca=s zU^bWw<}J6m#0*8m0(jm63&CQr1S|t9z)G+VYyjK9Zm=AA_COv0YvJAiHiK z0Qp_aS%$UWI=qcmpVO-Uf@|)j5#|kPq_g)2@Pxv%AMzkL3_by2 z2#WwwAO>7QSRAAU+<-d)G6`5gD)<{=3T|^;fexf0%m>mRq{E#7azQ(>1eni+d z$Q@u8*bVl8y}%u}So$NYa8jv3%}FdMuH7J#?GVz3mf z0Ple{U_ICbwt^kN4)%b3-~jjt905ncaqtB=1+mEc!! zAN&a(g2%um9&0@C0A9cc_=7+Y0>VHfhym4s8PottAO)m>+8`6;fO?<-Xl%o!DQE#& zg96Y2bOtYi?w}_q1|^^$7zhS~pduhxNRgvS9Buz*Bh1vNoBr~|S= zU62R7k;e!4f!6Q`Lx#SK`5y*H1c(BC5D^1e1{nuA9C8#G3nqYggqeW_B!DFFHo~ot zI^{~LTg{(SaR*ZKlhk$V@;vbikOsU})(3BqMf`G;+w70wURUK`48JnlG(@B2lN%WW z!uq_SD4|!u_s_y7&M~FgYW1(^s3^xgcjr!W?H;6YSCl+ul5zmQ_gP&?NaS|t*2Wfx2bOX-2UZe)eY7y(|xD=Ntf(C(0#r8S@%GX zjvjM7KKJm}x75F?|5Weh*~D|2=OMgOyMfn4uU%gEy)wKb^^%YV1ORrk-&@BSgi7mVEa zwb2mJIv~V2DBzudZv!F&dj!52xHs_Iz{sHPL5qVf21Nun3!WD2X*?XP4QU)QEo5Ja z?eCDfp%X&)h5j8{x7vhi`>Oq2t!~)(u)Sdq!*avNhwlylIXo$1V8r@}D-phtYQ@=+ zV=TW@Fg~cALdp z3N1@4R^26wUyXV-Cf3+r<57)zc#63&;e3KVv3cUFiANK^OgwK(yn@G-XA-|vz5k#4 zZ2xbozhe7e>wQpCo1|GuCz85j?f>V;Cz-@6+SISycW$t}A6VOWkJ5iqLa} z5Am|<(!3nis@1GQ&tgUIPN$zj|E{G6y9dksRvo3Kbibuj#q>D>4ZaDoP?pW5_MR#| zQ4?5o!D{P*jJ4?#U0V%L_avE8J4nVln(;(hbxW(1riN1<(pvr6ZE8PBDP7cmN2P_e zsTXCaY<%rkYtOGe5x>lLa&cmvExAykhYWok!##nVH;fiw`hg54&{AFk1w`wm& zF16I((b&&DzV%q{?w%2xVa}+Pk&{ui5jOHT8qhMMy@*u(#Ti30p5If7pPVr#V|hkZ zLoN0mrv$k#NB`CQ>z%o+x>?@&HPoS~S~=Y6_^TN{c&cTeWqg*QhOaR`lL<|J`lF^R zva~=Y^hweO2TZ`sP<@WUd^(Tn6aDWVv|Om`LdG@>fI4Yn-B!4VI>-4Q%*v|!G2;RH zpbyi48eI{wYzWO|(~S=YMj2y3(pSmI_O#8uG+FUaS(&YXIi|KP~p3 z3IAP)qlzb*`gbXxA1?b(vvsN4%BQA|RkzH|0#(yTAH28_Xj=YPA2PiE`cozMzZ?ImgHk2=b1Gi(l-8bCan<~R zn4rP#nRS}gQBz9$e_pmHVO0zGr<>-CRX0~`OI_;pt246BR1Di2b>6A75t1gKBhLr2 z(kCTj{$sVPqEK4n{yASOBbBK8k-Dgdk)PFZiTWebBkJoqH|zXf$30Vx3COITc`wp8 zvsPxK%tw*GMQWoSL_W!LFH+6(bWDfL-kHNPZBsMf%df<>N+;+Rg{kMvL($AxrUuJ%n`NZ#ZJ-z=qga2Vbj*6d^ z?|S|$ihZ23$16*rHTuvA;B3~}$Q!n-%EDa2aMs|k&JK7i`H%;2B)qPE^PK{qG6*yfq zbOLs|3DRtk_us8|&nxyx z7#&a-WUtEJm3<`pZ1#=p``Nmj;2d*KMoxZC=bXN_oRK-xa~9;R%Gs53BA zy4>Jgb8bd%es1U7zPTfFr{^xnU6uQ9RrueSA?0g2OyHk5c z`!B7pTZ&s-w;^tCxNUa(!tG}_Pu)qp)TD)OlB?r$QaPy%c*;MciqDbiX?apvhct&# zR+Wzpo@)rwx<8%x`M!Af9A~<2PM0I?IQK>FAGlv|KdJmB;=(=Dm>kHC9>YE6dF=2w zseIyb)5Bd)G1LrOm9|uE*MH<@`loZ((RY3(r0f}g)%2sN5pA6+<$Aklm7_QRH}Vrb zpIs-Q5BKY34CF;yO|S3)0cJCww9OR8C*3k>?Hjh4ay6@OZ#QXprZN$8?&%^?@mspZLJko}2fY?kzZI3goH#Oec9kW`Kn+ zs}s;-!G6;uo_Exw<1_Y~iui9OMk9Z;-!x#sB~t|V3p8i&${9v0zw@D~F^^ef^yKvp zm^^vj0n-6$R4_^`=6w&E22f#nJf>klW4`P)qX&;WWHNKlW&wUYub&ZB1)GgjjR)8M zW{SsuY&QGwlh;i~UUVH*FFu6I_8c;ec3qpt@PdJ&%~i^65uR_4uR@ zO=-OHWAyCgk0y@=pE&B7bifqD%iYX=yy6qnXc`p{o|+!u!IycOQ>jzI3qCd7r|?j| zY9LhSdDN7lCPQcEsV*dg*3$#D)LAXBJZf4++N#GF95Y$?fn!v45Q>`=4ISM-X4=EA z1(=gay@BXt(eSdtMjw91*BpU?is7kN%6}VUEeyw{c|bm; zFpEeO6vOX+ZfZe85##7@QEFq*do7=G0_sQGvU$-aV=5ot0Taq7)yVTg@D-&I8eLB(d5ET~8^ZFS5c-(1JfZQ>3v8Y||?vDyF;;x@M}*>-RH8Qt-KJrsn*IoPeIZGAE!K|F#rXlXBgZtQPHLw_w!tjuA7P+lP!T4oJB9i@CzHCcmrP2xP8?P6W)U4)Hbc! zjY(O4{LU0(1iyUCw8Q?^52jF!=#zcRZIeaAXMbqQBa^mQ{%Epl`J`c(J5;!+FD4A@ zLivX};&edw+qciQ3`Km=}aX z>y^KnGS$Xke$8m+ZGJNqs>X#v1NmhSbRH()$xo1%)UfMcrfgvX+RxoL9dPAIR`e2c*tq(w2iT_< z|799a17^>CXo|q#VmaQ~#k@>of1ok1a^d^6(9R7lmXtJ|*|@-fX_n-Uoo%-}l+$cX zfS*U!U+RY!oy8(r>4EKN^ru+YQuStUviTxUb0$A91{=(2PjeJc^MY!zZu#&@J}7L< zCnhbW${QOH!&iBm<4{FB@4g5tj&2pUEG$K#H0*xd=P)#k=6Ui<2G~RKxBw#`I}W+p z`yk1sf!J|=^Fdy#uemV~^D}4o_&hQ`a_A0KRQh363-d>7s8Wul4dwZph3d2(?SeJR z@yAHEY(hXB4>UU0-U*naPHFG@dGlCBfLm^ATu%7Q)27AJxC5lIdV^zfxtm75oP|oFWsP>Wz z^q3i8F5}*j=HdK6qnqR@eJ(HIcV7$`9!2D{AY7;_$f_)fdk9fR%L8k+~yebY}D6L}#BFR#W=2CR2gly8GnUWQ)-{OmoZm~VQ942kJD zWKc;=hvB^j_vuy9C#GZnK_yCuj`jwxn>V@edvBPp+P|7@-fF}iZ;7!_d)GYAg|932 zPvv2~{jn4F_Alm@h5lN*&uVip3qPnoh@YQms%+BKz^~c5!Zkv3M6*@z6}XkxKVg2~ z{fd69u26S{KR#jZ?dtF8&r7~AH`g@ao4+tK*I)F%@bh1o_qoo|&*5*MG}qM6@w}() z@0(-n#lJdfK98+%78l)L|>7!W(uYq-}aud!Ye zye4@~^_uSWs@F`fH<0pW;|1@bo-g>$bgSt((JkNYy!*?>Vz*4U4;AX>IxlxucUN*9 z^lG4QAZk44HN`_a1;6IiRH?)}mCVr%GQ6|AbG&DB!MeQLYB8%RTa-es!mET1_(wOl+kuLs-=Y^6=p zy6ImJ*df*ai))>rmwCxq^J|*@cwvV*96#}8_}UzsAK{he)!A#V*G8|yUKhN6_44$N z^RDmR!Fz!BH1EaUZIuta&v>8rzT+JWt~`DOM?XgB#AH_)mEah<3js@HSWi zwt`*YW1zv$jQa68=gle27ker(9){J>i=r&^RM`r*Rxzxei@*=rr4U6KhnKQUK&FoP zrDgglUInklv*LG&t$0;SI<8qtO}qXZvzw8R_p(^+K6lJ}y=|q*8YND#C(-pL{xm60 z$$OEmO?uI_ZLvn#7Zg5&+^?3V^{YFRO$?JEoF5UQaF21mnZTG^ynoQ-G=INM`3(t%_zi^<&L-Bql#x`Ng zi8b@KyrZe*yW*LswmZT%4%!i|#A&Nz?x=mbG4-3GQ?EOGdFvBbcfiuC#=W|(!|FO4 z9KOEm53e5YY;M-3)HQ84IpVI)pD?153!e>&`ey!!5w}z?d<*){YM594bo)Qvylu_J z&F!>_nsAMykeLf(w`^SK@HN^sdS}@#hi~A*zFST><9=Rvev98CN8Gz3LOUI?IefM; z>rbwp<80@i5tdHh;V!OB^gsV0lSo7;<3j1<|Bg}Kl#I@gTrLaQ$zSX{< z%q@irVwvjw%?GHdN0qL9^_sF0aXg&rMPv&Ca) zWufyf_fTdy3VFNujCq4F&f%i!eIoCYwT}2k+m^0hw4KUZ@|+`KBbu@Q_3mk1E+p7W<2Qo%N$3FN!x$4Z7}ShB-_M9`B+>pu6}y-m+v^a@xvVj z+H%b#=WN(izNDb*I7dO1YiqAQC-Sx^rP3Cyqic|8(5(^V4jxI@O6LGwFYawx(aTk_ zskZy_h8NcS;2f`C2cF7oInYsfVQEfknsfACS~Yr^w@~?|fmGy{GDo`W8*i=lD5J37 zRy)Gnw`$h)*hXQSL}P3s=f-u8_-NbK__cMmI=mmQo3VP4SSB7j8?$*spEW_k@Rqlr zf;Nk5Em2(JW=GD-@*fH+#!2fwpaJvTn{cXa9d(ADkU2 z+V0wj3OQAiuHV*l6#sDAAH^Tda`=K@I@>k%C5P|NZC|bn6sES7QLc}iYrtDO{kNUp zNnt6D^)9IGR^z%+s94o|b=$i7s~81Ur=k6|vt)bpE~@$>mhF8(-s0NOIX_<5+-_|tW}R(c&_oe6)TuV# zO}Ez^avI9xsdtKgdficRMQKH9eqSnZO((kU5h@=lG?#`S{n{7whbV2n80S!Dnem%e zWltBWc8h#-8_5!FL4}1a(-xLe*8Wbj={~8va340EeL=^v9aVq5;jJ};oa4Q0GH@vrIv$Oc` zw#9F-Z(q00e(tfkkH+?juTt;s3vXW#_*5}X6yfg9ila0mPh?t?!84sQkSz!Ug`P!J8` zfC(gkWRME#fNapfU#VBn433td4QK}nK?x`WLqG)>0Y-yyU?O-4%mi=pFI`xGZ4;bZ z!EW#Y*bfeZPr(=96gUqqg73gpa2?zMKZE<=Z=f|Q1zx}h_=7+Y4&p!!kOWdd2FL<= zps7)@6|{k)9q0(Ufnv}fl!0MjBp3t6gQ;LTcoobB94rCL!Ah_itOFat7O)-c0sFuK z@Ci5uz67Vi1!H~m2#z1X9q=o70R9F_fKuQJJb}+@rRe*0O3}Xn{eqkaeh?`HVRN}b z%ThuM3Kb|H;rNH!MB%0bqrIb+tz&MTa9(W0|4L-xom%6KeqE8Gt(5J>K~hmV;KYsp zI_m+k72eP59g3jXHynuBMF7(xvF~?cI`CHy4ivc;hF% zT$b;!vc5b%g)K8CA(=(TkTC_trRy5%`0*5$U@E}bwF0kwrHV_G2Y4qDxrX4igXH=I zjlxUaxqB+B?GdNV(>Bs(Yk8Yg7VO?cR||#I;k{DX5AID-*)XJQT9egw?0q#fi8NuKb>_Bp#G{oR=Y7m8P3CNvq*P(`!`PKynbyq zw1-8P4IME6Eh6t=r4-#GcYkU;k}67L$lmx+L�#lDj3+41j`0!d-w6dSmWbr~4ab>w=+*OTQ%PyXsCNw7K;03qRfd}kZvfiXN4SRwv!X7O74%hp!l;&HvW@O! zXD}dMEsKR0Cg_@qam`078|aSf@^x#`HbrTI_SJ%$THi!RHb>bMWqOsKtVMbXZGdn$ zeJV^M39ZIV(r4;h>!T6E2WPPez95T*Mz@Byo<0Q8Nw}KfHVb!_zP>&M9sN8D9W`gO z#qMn}hIoe%{~()1^IO@hoDa`IDP8C?JBM{#kjo;f^;eQHv1nN7j*WcH(94l{(PXt; zmh43V`9dB2d81rb!guAeUEb}Hfox?2u6#gUcAC-94niosFA=FvY9xau$V)WFI5e?)oHD=5e zisZ{1!|+ZtW>I=t9)#-nO@uXSfz-t!r$f&)y3|$D>eBQ+V5^81$A&3OK_Cu*dzO?=|i!Emmmu*;*JK4z(ADo_nR}5K`o(|c*k8Y?$v@- zkL-x_>O13Uh}1le<+wjjY{8o5IL5_MB&`%>fTkanNSh9gFxfx(+Xy!ep2B~g?GvPL zgc?TRGmu|Em33(o?hPEfj-w2kQx3J#1~;;bpH2W`=jS;sS@j;2r2~{gubic3wLo+Q z7zrQsf>s53Yug}LHyL3Igws0MU#xy=Gif!X-ISV5Zdw;jLI)pwXhGm((|ycPn5Y zacetP(4#3TBW07lQem`6mx+|B@sXt?R--DF)&Y7Q8KqaxQtjYU^Y>DQB0n8A$V^0- z{jYW`KocI1*&2cAtfR?{sjaSvR)oZIeFs*@R)V&Z*2h57Zb!>DjdZc{1N_a=9BR}E z6ixAD1=JO4Aop2}9s7JK&(=h_;kv@Qb)(LsdbZQa@ zjv##|PwWg^tS$27;ZW67AHrL9X0;<~=@M{Ip~D!Rz-isGV&$qM{Cs?8X5qU!Gb3L~ zmq(phJpZ&a%i!rRz#B)G{1;d-|At)MUtlqO8@X=LW&8_BcNi|OHs}N?6Wa?P+J#l~ zqQ#rer5Hrsx(iE;?0|UMUun$LN!1ZTtuYn}|R2ODUX$<{1j>T#^b;8m*M*B2P zXIdoW(#n7C!s_yCYEC*CibI4WmIvBv$)xE!0&1OOH|Z)2zCU^?_Y=g^_8>~)-*snNnO(@zW1s$xB2BdV z$#RED$d?zgmi$p6GxLm|>>=;di}?l6XwiDohf33k6BvJ72%WSjVpsW*-pu0F0GlbT zyjU6eoRK)<<@Q1m!+Wvr{BR#;v|sJTu4!T&Lq80ir(LD$mnOCFrAZq9vp4H$AalBj z`i7G}c}XAEGPX68HdHiV7*s{;L;;3~)EWa9R$Tj+eb^fszb2TQ`Iw{4@HvhX1~2T( z2K$C#YG;WhPF(rXzHCUk%N$GT=8~4}d|$lQreWVV=i|5FWk|IF3kItpzIqR=9CU7M zD%J&_QOXMWno<_Umy|M3|0nvS=4U9i`RAoLH~RHsfwB4M0oeoHMNxyFPMf8q^T>W| z;DY`vke@?(zPKOD!)Z)C@($;d`>}BTDaC3B;9?R&{M9m49A_&c9WLI&YL)d|Ycm`}#pF(VucRKznJ$rHL?%*Brz` zs*EdrmseBCE%#OXOWgp=Cr?!f$fhGeWsHK)&Bxto?!{#4+pW){tZ#; z2xT8CLD(SL4RgDY56lXTbtnPknU^r3dA_CLa)qvwRx z;`1xmIG#EZBjGoU75LLBl-73jJPMb+$1t{DW1zb{$30ahPacQ0q3bwiHmOH`dWJ!h zF<%`2p9~H)rjC-q+l^qQ{!K7?q|pj&MRe`YcaC7=pbt8HQiQ6HUcA9bHpiDXEIKaH zsja7`KmU9rtL97djrJDGjw2wyGLlW;6{A=&Y?@Ydwbk@wi`FnY?b0ewmQ6>OVf@Qc zSVCUp4SMjy0R@2Rk`XnYn^nsqt;H{kKl^K0Y;+w~?WD~79jYYD} z;!cO2Gfk8k@mgQi#m|pHXG1Vx^sFWp>q;7Ks1kVHvFuHLZ7ehT(hyRt8e`$VjAiwC z<8dt53#S)-jFNzSwe4fZvHq^y$A$&rkBPW6v>1#$#)c&?ahnw%X({d7Z2?dZ>=r=aNelw=}Z`q5>|V*ID0L$N-Ae9siN z%TJwgR1X==Fg&xFil;%9Q`tfjO<<~?PCH}~)F7I|bRwV`8ADIQ_|$34&Ziylh6Z0^ z3j-a46^$WL9}v{j^G7c+D{nZRHRRV`MiZt@XAAkAS6CcRc$rRmuOh7IW!Bw5&qbUI z2H*ZNtI3V?u$_Cq!oq4e%#w6ND?jaM^ms#U937l!6U5ratG~jIa+g=x7XIn0FwA)~ zm>*UnIuMf))8fN$Vn6g6 zi_r!oiU%dMy3h@NQ+*_E>A!n}_3&?sM*-2W#t40L?2fJRB)86N)NK9AMn zgXgi(paxhU=rl77W79w^I9N#dqIoDFZjB`{oGPe#>Y-Uc+Cn&A{(&VZh!W6AeGE*9 zp54(wYasuO3P_tzou^Ct?*4(ia6TSDR@8+CX3b~m{_URKF8BxYsn!KZe{VjN`gwHvr4|{ZR9C@i-meMM;aPbXo7EE$AW@luq8T{ zM>_i#keYad*Py~j3z^PWwRPtX&tH3sT?lT5=lKa()@os)-i+01BG$8-I^O4P)*`u~ zPyl5c43(+RtZDaCZ#vXtIE@KeF`huYja_5#LMWP^VGV<>8XzA%KUa6asS8=_04k~! z&>31SxRigkkVQ74y_}Y18UQ-R79)x5f{3B*hm4tS2-U~e6w*{^h%|;8`CkiJGS6GY z`qiL1>0lm%6vC3w3c3-l8cq+rhuN1eVuLh1_;(x1R$?J* zYIC&pv~}%^-eHL@g|zxNgStpnjp24Ysi!Y&=u=BqfCuIUP$4}Lr)S-1m_+o9o9;tn z6k6eH;qFu~PMGQ<)6^NxFD_;20kpB#*2nAf@UTth;9kpENh00Qs<*gSM+Az>M3L&W zOv9lyQ)H{h2QFjZ@jlD3HMCfcgX73?qvyOK4(vDqBLk1uB(dG-p-y6GzrS+viB zwRjsgf;}($d-Ibkkjvv;MBH5gTV8>5_PBRhx`vmpWMLtp&`-KHQ|KvGTOS(Afv*8y zzLM1mX@yaV!APoSKU(4F#-|rQgGfFD*}3<7xLkaX;eU+2#};$HRqP}muohu==u*5J zYvsLFtUQE{pEL)0VXVn;2Vpkg$pP=V8XLmdb!g&^H+_Qb3s$q!8op->Zjt`jLU)W? zF-g3)p{QwVSwF5@$EGFI$&2on$RyOY&~cPgV`!Ch#&FFw?;xIk9k0zA#Sb2^1cekJ zt7@U@L5OxyY?S={bu2QZJsL>+3UxIZ4@c;+J+@f>(>m56grdmQDPk-nopkUu8~1&~ zKiuABJeA6)qvtpoq&PI07CDh${T!8b3XKiImLuu8KXIeBjAI+sRc!|Q#ZpFQ+c^m7(7jDC5IAt4#py76y z&Z%v%vt8TZGLyHEF5Bobc00?opV-dMY21@xKCQGdT(b+u-c>tUCf{R6ic33j3EqWU z(rxdvC_IfP_0s-GBcZM?F!!>=w?1`w$YEv= zZwc)T!97Qe(oLA4xN%2VFQte5v%~m?m<-9Nr^zI~s^Wukd_wHmpRhm|Uw?g~u$b23 zhS$RDA7!yw^w6KaBdHB*kzc)4S$2{TO3&9KNoRn*7;vmsJ&v-!_~>KkRp(#h-I%vUB@{J8Nr%j508LQMPP?0_b`>bgu{l+p>G_LM%j<$N4%38yjijHLT7dI~+} zxjjrd!D_ki;fWSMd&Nn%%mp^yTuhQoKIBI{2{C@f^6V8~u|qEWQMOMQFF%X(Ncve8 zXWx64P1D9Citf-#8isC!IKJm_bV<+aU0^d}=!?S&d~Hgtqoo8l9JqEwtLSE;zrv4P zV6(aPTRgRyz6)E**jqU2j=jis@Do>AygNOK>yPdF=O4|{eDSwzTdcZBl3~*p_MD;P zEibVPiRx2N_2#kn^O9kAqgjCmPJHVb7HMzs9qXs6+@G{tfe)=i^tER%`{v6m+C@D2 zbP)z^!P8KoqOAU($ADN3Y&W=Sm;0?HmUFNXC z5^9I*zAN7!VTsaZViu<8?I(X^8?@DFZkM5-jf7sGJK}s)CF@}7j0AKGLK>v+Ch2VV z5A)~UZn9|mjY>9LTH)=Vu{hDP${SlP(zWL&7HaQ$kHxt1d#6}bs$)r2uxHmp%V-wR zeoWtL(!Cme-$malI?~xk|BK4c{eva&X&<4Nx$)@l3UYP74lPyO#aedu5A^)dU3e${ z4y7%;fWK-OeG7lpFq^Vrz3Ry5!InDP=@3MZ$xENxr=FDz+i@$jatk(L>{EwTG~Sc)`! zi5}DZel1I!I~h3b{dJ2lk14tRxZbi~W8dv%`9{kN11&!Kr}n&XK0D2Vh%}hq{sN1q zeTyF+-6TKRA<2lz(CJt}6Oit-=$49}Qc)P}fye4CiEj8d2(w`*vsCAU18LRqu*7hm zKuZCSv7iQ06<-o)xy&a=MtqCvp7T2kux|>o%=6%$4`3#5J%AqPMp^PS zJpT;*?G2VVzTgrL7*?1u52edVZ%Y{WJIB2FgJ2AWcQ4%ath)*Cfdp9k%oxjbx0FOI znXR!j(FRL9cZ_1j))S*x;HIypX=BcMvXI(+&6X?pn>43J(kj%S9dUSZJw-XXloyR7MP` z#k)#RHx*hgYWT&EnYaCN5k{R4?`w%#&;vDgAHMm5)ZTMqEy zy)CV%cMJL69;kIwiRGHeyRf&#Y)47w@Rx*WjvdYE;?85rE%R+b)5MdQpu>ScJdHu<(+|q<2L%YDzX8~WKiP^?HYd{cwmV&qb)c)a_$z|(L&*K- z0J?tDg|63x+m9{kNLVdM-=i-0aiT_|1ILxx& z-B#B(+2x!IRZH(E&&A(KEb$A#9~Y79T|7E)QAU}@q38q+rHR(4F=3hn=_)gR=BI|W z!kA!aQr`i-!(>-_8TZNDMaI3(^y$7&8e;oSdqyT{rwy0Y zmuQk*)Se90jnb*E0h)_4?1~G$Zv>6&P~CS5=Hjr4ue;E}##eMy6J z#dU_b-u1)#iKw7o{br%Xq%cKMlTDXB@b_OQV#c}D@m&HN8Rru0PuC%`sWxp}sdRV$ z6-b%y+fC-2X8c>E-z2J9AVamo((&dGp^`$z}Woc{tcG*Ph4vA~NRNMk% zmZ*gOaABNFJ>hO7vo!PHFG5@UJ5-zJ`()t$@LMRWPw?L@OMAnQUIeZh@odpV^?F34 zw5fj=r1th-F2`i{#m4rc+Iph*XGN7K#MNq~Mokn2jg?ir;NMF&ucNU$Ty1^($a22% zT`SWZF>Vzl_LV8+tgvD9$$HfWtT2|#=+>IfqM{Mfzs5LLy4o1GiOOq83mE8sNi^)L zxZV&~n@rnI^FW&FTmJV%OkJ64lX048j_p+;a>TgkM8UH}$Zgq!cl=#M=$o=gnwk#P z7y3S#vbT*oyuhA}`GM~vQPo{>4HLP8We1OHJf-Wgi`EtCssBEHn?#~0aW%>W8~yf( z0`AL(>@cp7P1s{xEnNqU8yqfwtH_-uu4Y-r7ycR2rFV^!t`GbZM4DY9C&quV=3_X? zKzjLB7kW4*{hfR}%RU`9o)%ik7Fo~BN>3RtNmoPT4Ch=Z_az@$Nk1`!b)@y5Gk!11 zXesKbhvuM8n@cNS)gBv)EVo3GpPbe`$T=}v$o5|{-jkJHGyX18w~;Xq{kw`XTx7h) zSSVwbYdVXVV(G6mddZI2+8Vcus3|ha&)8SG;*Env%mC@XZw!)|9vZ_$&!WY(hPYP9 zR4-{)NfUDk$du_l0_sZFbiV?l!+IKNmD%l*v`SI9Mk#Ux9!4Pkf}`kIm9UrGl-Z}S U;njP2=wu71VIMj<;pZ3r4?8xXE&u=k delta 273341 zcmcefd3?;*_y6yE-m^r!XC}5Ff{2LNiG3}hnZ*{dZxyjuL?of8npjG!mJnQ2)m~M# z*VJwlMeQwuAk@B7`}%v`_dOw>{(hg|@AucYeLUaio^#JV_uTD0@0re|yVkE#ve*Bl zq^El-FvhwmjHQ_v8wr^WISn$#%-BzmyC8Q9`$tBW1sPCLV-JOWiN^d4jHP$AvoJ{3 z&CcpW#`UnXPau=F*jbv;_u1JT$dG^lwgPft{Q$NNk~Iim#|+HF(onc596AOtlZr$j zLm)%S=3})X1NP@*Eg`d`^0OY0Nks~H;v#1df04k*UHgbc}Fj4gzWNiV~;L9T^7 z3Yk78oZW;BI1|p^LZ+!@Ss~0;`rrsw4U#2AFehZ=Wpo@2e^siWSMJN*+8o^*<_m8j9-eh9)QfyIr~=&?4HQDx-&~ zkRC(0{ckbO8bX!Gj5mf-xRz84*F~fMOd+8P(o9M1ox5k`+B0`uLY2h61AA3YOdgao3)0e~ zSKogbhYpJGlRO}?U)vEWseK0hM+XU2k`jg{_e}V=aq!@ToWA_U+$U5?j!*0>^2PY4 z8UynPOP_uN1}6%eAu>UTg2MQ($xq10HUy)MzbPmP)v3un6H^ifr2cF2G8&nJ;MCbv ztP7lmrl!=W^`B$-Y(Qe~!Jnmc8JyVXU#X6S>0i+js_4d~T!YZ}&k>WpN%YEp=b53H zi;4V2<$%P#gKO2$$G>vrhRWu6rFd2Qy7 zp<$-sLZi&m=No3KC>wzZm_Z)k5Ap&Vu!17+O@eP>l#7C(3-!VqW=6qU7(vUOZ@|j4 zMwtasj(}GHJo15Bpc$}((x42ej5YxtI8}jC9#jA|fCh?zU{D-RVerY1asf~f6ar0Q z&j)+t1<_$$q|gM`Ku`jd1YsZ)R083kEQkQ*(6S0zRz$h#1y94wYA_5%zQbUwj&ga( zny4%VLZDaF$J8*hHp=WA|2^BMQT(=w9E&e%}C z>b7DT9a{9yxX?VwEM|W5`HUJZlQZ_Ukm{N98NscRGgh~h>e=%d#@5Lhvs+2^-1&?< zP)E0xYS#ITzhaUz`o>80{P~P+ZIUxuwMl9uB40rMA-c4NG!FkzjzU?~U!?kr=Reeo za#Z;Gi1L0L5@T1X86`SY%-GVQe@0XX*~RJe8FM-&XO!=HD$g2b z?!rtR0;w4L-=H_f-zRH>U#FQCzXq8{u&EDU+%Uh#E_FjpZ?_uND6=}8R$_vF!E|pz z*@*_Otm2s2Xq0Bb;>gm`Q&e4A!Kw)c` z`Ax=%G9{JC8FR~&uJ%2Amx9G$30MY}gB9Q>unOEj%=_SHlv6V94*o9VP`@L_hMA4B zGUoN48PF&*4IM84>0tW#4V4ERQ8ok&G#Km+GuLA_AA=X*$%b-+{xEEqloW0>HV%&p z->^2dgJM{dHO@F}qH&nwH4Za8dZ86%2Igkv*i%Je+&@VTHk9)7MkJ}-i>md9TKTcB z)Xs%=rCNPE!4B{%*aEik)l=0fCLfBsdHG4I#~hPl^|eajC8w&PYTi^UZ#+pIpgu*R z>X&LWr|%{_?}7*55x52Jf!m-Bn#O{*pmmCM7w&?&@%;mz$KZ*K7R+yaqmD7f54HMw z^2Et%1@(rgNLS0KccjNx5x!4Q+a2@(aYOZ(zLAKZ2Bv|TV0MaZ*2|FkzEhvSbQTHt z(&4l%`9odz59OQ$eW^n})OSmg9sPo2H|2`?C(>FmT`g`piHhUA#8kC(-eV|MPO|#! zNmjmax>_jj8`;437S6(8$%MxlC}~sG2)=fzS}FWI@;UQif_z!B>^lqlIVxLHc#mnS zo41^%1}F>pC)3pCjfNmn9r&a|z5}Dc80u~$$-}T2Ka5=;|4P_q$Td|u^BptQK(lWi zY~SjuZ}|lwH(?G%wgqNE8Ivowu~bp)3K}F)Cl}>p`9{OG3PVfEP^(#9BwKw?lVups zDJats>J{XE$cCUU4XwlwtM5RH^*~wx^S%DC6u!t0-M(LzKC(xB75M~`(>tPWR;8op2AgD0!yxpjtGL&@M#Gt|#5 zKO)#qL##aHD|HC3nW0uyH^UtVpblS{p-$&zCaDGZwyA2VJlm0i7i{H;Gu77SZrG(= zhw{NQ)mF+EJpU~9Ro=F=Y1`o#iVoF_Vz+*&4mbKP$WmkeV77XIZ|7>S0N)gHk47X1 znq*H>yQ?k55uT|wsp8Hx1Fhf@3)+AVzy+Kj2DAX}(MX(GKVNfbt)*7S2DkOYQ+WRL<lr4c~BVfVX1xNppOS%f(c+E_zHXtCV_9j6m&Wbq=V6*1Lz1kfzF@{7!KNlmLLYi zg0`R?_zZLf-8{H_0(yWr&=ZUTLqIBs2faXV&4DHsS6z#xza27^gpGME4+ zg8AS(umF4y7J@}U^zHcum&ITOSOS)UWnej21%3vr!5Xj@`~o%sFZdN~2J6AMU>3*# z2f=o*1MC7mup9ga_JA$m0N9yq_4wwXuo6@H6Ih4xJjidsZrsG?Lw*Mqf<<64SONxP z2Q7tM29|>#zzT2z2jzUO8|NC>R?#Vcgz`V&ajvB_mmvQHN5M&O44eWxKsI;)9)joK1$YTwf!E+Z_ycSco9__#6%4|t zN)E9eh%3qtWS3&Tb+D}k#nJH=$gQ|X#g#{0B&g4Pbz!dqcA{=G*advxH*gX&c?O&X z+2AsG2mS^Z!8woxJm+z_0Iq+y(c*eeeL3Lfu2iM;~sS z2eO;71I)pEt)2FcFBhX0_oyJyoSxF_%v*yuds=}1`AQQ0$c`vgBAkJVhrRzkjo%ff*-&VuoNr;Yrtyo zGgvzW>%SO<Vg`eCa48!gF2u-XogsRkg-*9u>m^>0Qo>$&<<1pl|Tp35p)4v`MiZ{v7)_D>+c z@-5^$@CxPEU;}swih!aZ2oz4mqCSIDF(`%T0WBMIbQStFa2@Og`@nPX0$hXtb#MdR z1ZLPQAQ%(}13>~91O|Xl!Cm;>1JzLeLfA0q-y!#loB9D14uU_xMo<}*RY5fn395q{ zfFnQ%>W72DU<5dX#T*LxC71w?!{;=l1^y;55F~((pcCi?dV@ZoFX*S?(jVMMqlfx4 zt>*}er4jcfcm|$>Q#3gp5x+C&3c7w=x;@gF?14%i-Uuc+Ti2k1IqxcUGs=iie z-x9P2F}dtte0a%y|C~Dv@kZjARlI-7w+>34Tn+s7_bRG}r`ThY)Ci;RGCkGjZI94> zK|gwm&(j}DC(v1MQvGuj6G4?+(NbjDSM>jo##W>t9&-z9`_D?Bn;y75Cotel@EAM+ ze}eg`R+DKUNC1PtV7$iQ*sH(@T7V9~1kAt!LO~wj2a1A1AP|%V5uh9>52^wU_yeoB z0oqU~4Z=VfPz^+aW}qpk0fInvPz=-pwLu+F7nB4cpgyPxf1C;~WC6ohkWfk8**b=}XaTl+m_$G@TQwQ~p72i}$ zuXrcmabwGT3~ay-0zf{H9~1xuK_L(bih>|e3Z4o()C9Fbb&!ZNISHHRXD}D60Smxd@I6=u%ENDU zDn{A{qwj)I#w)({u>S-WfyH16SPG_qWngM*QH%_Gd>WMH;0Le*{3tdV-o=)j45cs} zj)NBH;T!0OKrNK#zzJ`RYV`9Z!}1xZ25S{i6*T&AUiCMMO{DINLS55;)ww?Cz6PkT z04jlc;4o+oD$4iqp5j>1iogNdg95+_;y^y|IWipuCV=taOE3+L0AGQY@aY6xNjM&f zSR9nwh@CS~@ij-eAjl7zfLQP`Xbaq+p4j#~QP>5hAXp;Ugz|Rqo7iS4nEX+g{PBt} zSRUL1aZ{87yQV4!8goUTh&DK%}4Eb;CrwD%mGPY2$(yBulY$0&HE)1SE=Pa94%LY3t%7k9qb1Oz>iqU1>iIoi*qv$j0b-qdVWX_Jm3=aG{~0lONYDy zc@<1YITLaQWCoZCW`WtD9ypO=^&VTL7E(M7hgzA5MYGC7q^zV%2k8zbbtmag(p{vx zNOzO&*7YwDu_odQS({{Il2IgUN$FvA$WWJLJ(3MbHX`{E$tEP5LVk=6nvwo7q!@^W z24bdxNZrAt?xcDr=^hsuTx4*Q?j}8&m7#!P6j168CUqy(J4ttu?jqeyx|{T9R)OM` z7t(`wlhWW|x`8=KcarWR-9@^abT{eItQrNZN(oBc!KCh_dMD{F(p|dlG2zo}*}zQ> z(JYh#mZE@CcQC0tsoqJti*y(1ZqnVPN3+k9n-XwS0&YscO$oRu0XHQO%~sK#_=)z!s+_f!1}8Z>GGX<2ogGt><^-j`Vq`OFWlkO%x zn*BoYHc~vPJ3LGpoaEpn-9@^KbT{d4(xcg33V4SCO5MSv?xcDr=`PY;q`OJ?xXBRB z)>FWB6j168CUqy(J4ttu?jqeyx|{T9_L}0oqIgnwFsVCby$8on8eG)CMY@}GH|f#r z9R++#0j2I>Qg>3llXMs9F4EnkyGf5`YY+$LKbozkfWjbN4W;hX9mM@X>Mqh+Pf2HHss32kB0#carWBx;+1~ftwuM#@&3tq{g(zOIXIcrU8K86ca!cWJ(@kBfcGh&)E!LfPO5j3?jqeqx|==l z(;K?keLi8U+R<}`;{8qWr0!r+cQUCvNq3R%BHc~8oAhWFK~HjJ=}AuN4kmRc)jLUd zdC1@*gPU|W>CvnP1*}d1rS4!-cT&BRbQkF^(%q!HNsnf=DPApIdK_eMFllg-?j+qs zx{Gu->2A`anUMmjl%UidOzKXmcarWR-6eGooYb#!NOzI$Cf!YXG#g3r#>pE( zG+RW52_(NJ`31>uNiHCnMsga-IV5M0oJ?{S$)zNJ(4~VCaIkSX4+Js+2a^dnm`uRI zWC9K*6L2t@fP={d984zQU@`#*lL& zN!>~HPF=_OcagzG4sO!jq(`%Y6tEBll)8gS-AVOM(p{vxNOzO&COw+{L8sx6JpT?d zI2a6gB5{)LB;7^2i*z^XZqlRK5ej%zmk!b$OzKY3ous=+cR{B&1Tuh|9HQBA3V4D7 zO5MSv?xcDr=`PY;q`OIXlOE0fqIf4Mp41)eq&)vla&R)~;3C~cx|?)2>Cx;o12A{9ERSe_e|)>V`*y2s6s00>v`;N;sT>tPQY!@lHdET@G30FuPhepjosO|Qus zpG(YYe6AnxWWjB!u=IkKnq!$(m4$?(CIzX?${kpIofPAoT@7DEl_h*~o5F)HsA1ml z{pvu2C!_57q{F@`6~%RS+67#f%@EfWeY5hgepz>DN!#`&YxLq|J&bx>wg63+lV+UY|Vjh~{11hwJ`-Xx1TDvyOVR z&UzB<-?!={Mr_Aa=CtlFQi%NqNedrcYgLtrbpE#**I{2PGh2F50~p`@72^8+ZE+oQ zS6tH@iR;7^ah;SQuA^s#pkSU%OKYGAH0C+K4ylry%zXiXCum&>cC?$t|=*2DjOxOo2H zh+4?gW`LNHw%=ssMA7G=rEYC4X2u|A=Kt!KYnr~(r)i-+O=I+*!Jn`J{HtQ26xLWANliZ~c}uW;K01HLaMFh9 zzNu*cE1kb%Y6lydZ_z6@qhf=sh(9hXe$gxNZrpcUR@^#{ICpjH9az^&Yw`){zFx1u zdt={AS@Du8Uh5TjPwRUlE5`n*cBqJ+-{}>2v+DcVfb>l`y8hUMIYWWR8r@^HJoF)d z;cjqMhM4ykQn{|zUPJpE(i(aa)?2#uCae#ob)~TWqgx-rdQVy-Pr>>?x88^KqO@)i z)=RoI8`jIx8g&}hE4o#D{U%&m4+?99KG}HpY@gjfjAc?R`GlufYqF(pW~(aIsQSv8P3@zZizGW zvpzZ3>G)PZ9Sii+k*1%HY5M7ypr4Mf_0xfGV)(4$zEubN#>ie>3}Af0Q8kcPyoAx% z^wHq?$QQuVFR5ST&8Hjifa5D5N73Li+zRT}LKwn9zVNa-QXGgs^kLya!*^JEw)k64 z#1Xv$PYk|eeC^-T`M7Swi@xtq>D=v#bpA`Pz>Br-6yJ449a#&JPwO_kp8C$@+T>?- z>p57na#_#o)(hUGtLh!2$$pjv4B$O)sb%o%0$wpm4e_qHrTSIR_rr4*u*l5f@XN)x zPeU0i!t*7mg~U$~GK(9#g_=G$DFJ18-NwdB1xksZHL`#ZgI#59^`9)1nqmx@a&AyFgCcV&DL#>TG9|2>bXq}9`ZpH-LD z_D-*)HPQII#+pCBlW6th;Ww-{?}@rvyvEbJ+QPh%(OOlUovyYBUL#s7$OCp*jl61m z&FoEcYKzU@*w$J?9vXuXUbG`xm-y^On)V-4U%R@5p7uY z5O^lC2W1WH%jykLUSOPs0mK_UtI=$wlGYLpOgB(|%dS>8u+_@bSq3)JcmQd2P`>;d zBUU%OK)%L-n4uYlJO7}pbPqK!vw9fGxs{Cwx?9bA+rX|F0&pG179o``N@XPHHdtmO z8taPG{f%Q$8?HXXU}mr=4@Ml%rlMlDs$n5Uv-@bEunuN4Rx8|q-LL?o*<_dHRH=rvK2biwSX&t`VXR}>_lUMh=~B+X$}8uPR+O=@@KLK=GccPm z=oywtZL>rFcPkW62Xny10+c9pn^FsrRHXcBVTMR{!P-S%}lAg^PVs_WFmUFS? zRUc;8bJkGo4gwk1Lph?z^}5;Dm~D_ zR6{g62r?>I*O8`j_mHA;8S@lrOv1pHt9@V(GPH+J3BwW0Wo0E1du65Sd4aiMp3zYH zvYFV)2ibS{3HK3o!fP}$EW)*xG8MHKlmeK86Rhxf%z+x*1EW_HD`1zfk|JHjhZH|m z9S@MGItun6bp|>PHKd@+%WMcz9A-QbfQ3_kKyufZ4@-PmS&Qp6b+hLdCczMbF@+n( zqQN}FT&(nBLmNz#+c*lx>?N~c!pE2*Z8&mjFR}C0;kb@eA0frDO1;?zHbFUqI3_j@ zolPP6Ff_(e@@I}v95(>Kp$Nqt-un@ZRmSE6t$ z5~Xujvneg#m7CN@@a;S_{iSZ(WXYop@oZfro9rukBtn+%Uq3@BOl!~}XRF+9LyfIB zZc^=yhIhKi7RPI8U1e$D>lwHOi4=<6{1K-@l+2BSsdoIv;}&VFcjE=3ctmx9Yr(kt ziPEsgD`+G~u9U(}N7!aZG^N!Jdt}2Y5H>^U!Hs08`HSH+M=i<~!BG^ole@M`lO=2I z4d2UB|8i}=kfpUj!^+80rRSAAG=&YXxhRGF+l$kNtNyGH4wML3W_vZV?YljfW?@O% zPgFX6doFH4!teO?12i+cBDPY}oo?izS=gI4X0i0kSUhCAEO}C|+@NjI`C30pVfCv} zn!@?_KcOh!VtI?nwh7(x zj6unRtV@5it(!DXZTOn@_o{}$w6ZsE-K6~My{ktD_2sRXWHXd6_>pXT`O!&QoO5%x z)9Cu!`%-sb-Y7>co{U?wRJN#l>&0z4CRGYgr>ysk*&y;lT5Imt#cfuU20d&=r7N!* z(afY23oR^b$6Xsn^ERbeiSp9cqPu6TEFHTsf;z5v=O`^$@$1FuY;^Dx-bfj`Zf&RP znKwF9lY+zU&Xr+;uYOMn9x2v=Iw>=3FJ5Lvg2COdQPOEw(r7uiURy$GRqS4$k{P%p z&kosQz%75=#P$1Mt*Zwpbmo&ybcb^+c}i3G&)wa0^4sqyd|EdC`c^}|@foFF?N!~S zZR(DXsMd7tEsbtl_p8)#>&BDG@5cQxw4(yFjrr*QSNPs5>g4LRi9_6mYT6&SAD*B+bNcl` zvdyW`s)_X5cxQ-A!K0kIGmf&U*kdn^?w@P-Xciju_;Z|WGV5L!8q=T$Khij_K0HL7 zDA(UmizRnzke|8u?h3MPLXW!RW$B#XIX_w2d@l`t`u(rR&Ze2t=*jd@DWS=>9@5sm zNq5RREA~1i$e)Qv7P0k`3X8`UQ8L{-NsE}gvm-^hx^xH4%#44w;*mr6C5-=*4q){w zu^!s3Qy#_8>0SJ&FO{rsuF=Gmzj=U8#GM{@D6NbK+i4cET4lA8q5BsKkC3JLw)r+$ zTJt=Lc8~Yb3W~h^!EtKqiF@)LjikrpbXw2nkAf)I9slg0CeFvhsdnPsVKmNPZV#m+ z>-V%E-N?W3`zWvMxW}EAw6Md%iqbIa{j-!JAAaysq#*8ptzTXs$C#^jIy!6fS1K;U z{BiFOs%`qF#5-x**CaSjmXwzfZ)EA!vzjku>GHE;RN7?TWEOA#7vuf=#S#kIFg99c zafge_ay^{CI8Pm^4Eu-0&FU}97vOY0NtW-SoHjz17aLhzu_3bD3ie`yWjPe(JHusp zf`P?Vi;?B^@c(6`EZ0-u^N{ID%z%Bkh~q&<6VQ0gXVPgB%0nsWRFpSSXHQZ7dzkdu zg7QhSPemY3<$LI$(skKEG?F-5Rr()6`MD;`$(V__C(C@)WxJ_q45&n(N8VedIqmgk||ntbLViSbdo-NPn8 z8AciP#mE*>gKz}8lPnv5igFZ<>>zwxDbk(@dj(491V%aKicIbl?ByxxTPTNImG%Yj zIYag%=yxjf$Uu*vM8A_xtKsw&llBX+x2Lt7g!0xx(monNJ5oaRkWdp^nw4lfnFfQq za$HTj^f$vlFC}pT{=d;o)b(t{)X`{g#N%2-$_A6rpgoQ3Qxl6DR8rbcw@~7eXjWdM zJdMgb&^F#AeL^wSfi##_C?`{SAmTit(bt2$J~pgJ9En@VXdvwa11cgvmw|Sm{1NTm zE-3fUNfa~j^opD<{0*YGdS#@)89sezPXxif2<1x3C}V)>kSWbr-ZI|!m9d~{5Ibi2 z%am!#GF7%jdMw$dA?%7NFDqiYVG1_gF%4z4EF;(#?1AaA>A9(%rI97X6lIxgOgE0f zCv#u3Xv=F8GaJo*X3cD8Zc8gmtYr!dGXeHkDEK8~dAPTl$;JDV3B2(;;J$DZ!j% zuBObhq?(4CYO_@H0!vM0xOtQ*%~V%usEjfMYE(*3_KsHy<(|^O*lKXPUFjty#ADius25j=3#+VD88s zo7Y=5S)QA>ST>qon~f%B*AV4;F*%(075~z&>yQ z90Etd32+i*f^*;kxCEA=-3o98k10}kK@2jJKeG6u8-hoBz?9Z>EJx`7@b9-M%^4`hEZ5F~;jAQgNDMuIOu8W;yA zfRkwRb$RAVpA2Ohm;q*iIpABc04xGa!4F_1_!+DP8^9*88EgYP!EUe@><52Afg#)2=wSKu2k z6-);vIL?IRzz^klkl%rYUum2|{2$1z8&M3}hAvNBJV;WpEYT0Oer24S5ed1QnrI0gq9B23~?U zAQCoKk)^A^4DwXO`L79M9Z(-M0!@I1N;_zVa(>7{pa>`iN`O)z43q`sK_%dTuN$-k zF`zBz06K%JsP6_@9kK^xEy%h6&wt`A!OE2*@!xuA5by$mS@h=uS%18s5?6b`hx&Hal((i zkOeM*%-Qag{2pk8ez&Vf&u7X?OK6ngXcyM_O)XFTz4_HBdP#6S*QXm}6Mp6|Z ztAd)K9{30}11``Cv<02OJot8pj0gQd0vG~@fzLr2_!3M4o@uzu1Pjn;u8?2}SOI

wy<+13s`1`~i-ElVCC0orSyzu7I0hIczJzJ(T|e&%tWwZy*g-Sd0a%hpts&o|t@4 z0>LI2ia~~eGGGhz@{m}0~1$hQs0DpsnupI$6P`(QufoI?~ zP^#ijuY(h)&kGp<3V|R{5`=khIfcq{kd;AoPzRia4c}mki2@GL0$hNt4P*z<6ps$}<25^MPj(E{{;L9P%gd6y>#$zkn@ZC)fiH zfFs}~>fZuGFbgpQfAA;lnczIILB9-{AM!fn9e_Wt&VDuRQ7+;^H@+wf2}IpP*z3kB z*0`0q{^8lnw1{96K9johvji=f_;c_=*S|Rxwp{D#9k*O-Z?bf3+m3bW)X97CC#|W$ z^iv39D|y+~T2o6bOF@$;K4i64vVa4{XqJj=bB1ruu~?SGm#o%G<%weWFqE}msr>M2 zt+1&rYraIrREiv=a8V@NWy*0`X*hN3;?4rm!#@ z3eC{9FgUS*i`Hlb)V8c0Ke|S%X>E_1PN-|jTCruk=vu8<8Ig}@??$%EAX}he3&<|$ zPsDEzJ&bo=t5s;&7AXtYD5MYt*%Xyxhz{6A69;R@+UWK!8DuX+a z(R9G5IzYytiI~SI)QCO=^U zpc4s4^K}@ur#TE_!kWVxfn&cQLI}iX{+pfIXzk z7J7DK#hXHp#)64BB1#x!TfHR`Z;!;Cx}llgupPpPfNk-w2-E_a7+y5G6}!0wrdsG9 zBdiGIM1n%LWS#h$4O%5@Cj=CO6k%HMn;W#|yun7Tj_G5u7x~v4wWj>9jao>dXiSR8 z*nz+zGyKdByZ^;T?QiR0Hc&sq!nDMD<`+#>T8Z5)`fZAA7z zs++a3e(|g)ZfGftZ`rIp^8UI-i&tv&VM8$&gYnhXj+i33MFy}W=q=zqSid92qNWw* zsvWE^J073TlecMg0%9;?5pMv#AUTu`VmxjezGQl2o3@&#Z`bnkk=wPP!jY^hvWmq2 zQ9%4(1*)?;xYlOX`K#?($vl10b5FGH#V-}H7En@n^Br1+GWb=#w4%4Bm{&34e+P)< z>-K7ec_t5s)p^)zb!M?7JRL`u2)5Vq>9 zHvfL7=H;L6(jvUecWIh|Ki;h+^7Xs5Kpy`aN~`v0{(0KybI_9|^TWSsMU{5E%>g8~ z{x3{Lm%Wr~+Vko76ohsVd12`ucbyjKfTc>jHvxORKc!^nMF ze4cjt;$Rf~=sxWWzn++7F<-pV@7jF+;CC$I^Zi4= zqFtFoT1juWLs~6`FaE<8$kPvN?n2G?$rW#{BbRf=Rcukar2*AD&Ke$j=TQUf_cIbEt=ymVHx?; zKT&G8$5xOZyM+ibe`#k6#iQ3`z0W?_HFq%qNvsbqds1u3C!f@2@;axqd%V_RbWrQG z)`HJFtyT5DJgx0lyl2m7AqpRLP7C5|&uKOI%d=Xm!XL9<2sl^|GXMjLlHqxkEUkDU z2h3t$_hx-i<-}wR!0R>sT7M}%HVcD`7qK>GY5kQBe9=R!TVFops#cWOIuHA&=P|qO zE}-=GoK}k`UC{a#7JDigK|*jp>4V_OtRJ+VyjrAIVD?4K!qkh}4SwQ*t%!F;w$@1D zwL&9orWAN4@QatQ21PDwj||-J0!HR{Rh#TxeN|hp@TDiPPj=najQqg`&FGzdT^q0P z)QgzQA~mcwzA#oZ^Qt$s61<=jlRWyS7VEurQ+yM9>22)@Uwl#vR0ewo-_c4deAQho z#v6D~1c-R41>)f+iI2I7F|EI^{pub6K#Ml^r zwv4{V_`s){gCBgR1r*J_SHyP2roufz4E^*ott8L?94GMDQ;edVG}>@rx7@k6gL zMVD3UN~J)ezV^*e8mxHl`B^g+?`41MerwTG4E`?q z5Dijr??}a@=(kMoZ$+$sD|}Cob+)A~W@``&;Y}`E3whTUv#vLaU83>zLDu}dcZhX3 zUtG%`%!d`jFN|V&>$2A3{K6GmFke{PX5@8BS=W30LalQQe8SVRHt(S@Yk31NSk_v? z8&lS*Df~z`d$4zQg!Pb#r&YFA1<@nZn%WyO1*9KS%^6VzocD!*}Yk)UA%KBR2-6D`rXftc1zc;y+b+p2h?_q3NlWaB~ z6Ju@6kHz2zGJUsL^XHAiYtB&26E+UN8)GfaW7=55c)=KSoz%vj~av zvo*+T8*CkK;OmE2C-6?mi27+`I|lA&4d(tS*5y2@vo(}&*^Z9!XR_B97sq;pxF2Hi zTk7`^+&RPmVP|sH@t5R|Df~t)Ye7>lOh6xR%VE~NxC!G2hdloXYhs?Bu!?hZlOL~b zFT_WWu*UJxT`|))cH<2vE#l|O2SL9V=ufpqa$GmRX} zVe`g~w;nU{V?C`Q-l|_)<2yh-Dk#EpW@4p>V&p z5gKp&EnYd!-o{>Dcn8gH+_9eG2@Me{@T#?-cgI~3V8(rG9itM=hkR};!0%ndo;~=F zb%K!x7Q~^8yJ-#QSMu9KMaj&QpIcw^%%)li@7fpQaJ?OgAIStX#5rud*XqxgUd0bz zcD%IWr7_Fj7Ru|rw$9|&B5ftS0dK4;jePlSq`gJ49Wn4xBA-=89DvzITL+$f2Z8jp zJaz}i@s82v&$DXV{R^bfhN0W2xK;A|Mq4>=1C#Bn;vH+T?NNE+eQUVanb$T|;ls{HY#}`DE~ax-Lt9_3 zUnARk6?Y6YVIlvv=Y~=%Zh*{384UUYKV$wdd#YlQDPMJ#4sT z{$NYCcxSA!wKIA1|6)62rpj zTZ})C+=q?#AHO2=%EPOAFooCt!udPaRm0EMF4+zl__jE^Kc5k2FYjG& z#kR}ropIYXIS_wO7-59?Mi}jtz3E1K5t}!pfIVCBHYj8-VfM}`W?!s& zHA1MxOqUtvufpW)J+KNTl7wlhSY`c2vMG-ip+=@8U@z z*dz_=*yDKLXV?`hTjF59u451L#@Ds`DSSsKEi!Kii@+O(s(3$BhqrlUE9@Or&prvS zZq*`+co#Ra_cwT3HL-^){MRV^q0;{!3(dC&*-LrHH?`MMxvi1i@BO9<;e{J%?C-Y9 z-fivdT@2pk9ql2C*VfrS9B%>!+tb7LG5p>zC6tNZ8y+L#A&o30RJ@VZKQ(KXWRLWS zcWyQD&W$ngqrDSG@oTyZxcVz^aed1S_~1=p;kc$5ZMg0>JcZrD&f==F%edxO0%1=u z9zl7Z;To989O0vW3I6KMCF!_C}t4w^? zN_@-eA$!8AF!{Zz>MZvcs){S6lroC=!c;XSpf;yO>hKtm!@vgwN9O zZ8<&z;S5MOs53Ms~rh=#+darV1+@7UVBSvif<;FBL;5XD-tasS2V z>s&sQ$>*Yo)2-jhoH#S!Q>z_@EIMp2DxdrB6J_D}&O7C-s!wt!!(2EX#1}^ALyG!Y z2>3k(T?3un825Ef&>!G4m3JOyFCHLAwi48ND-$a#18NU-jFgt^ic9G*0ED_H7C`o@V|#(VmLUc zx(|l=9|xo^e8Tx6bkA0K@hQena zpNW}Zkl4vS>GSwCw^G4iVqq2J~!M8vqO=FR~QTMwIl8R zl;BR(h;MT5R(Pu&_QHia_Gyz7=^&~Ms5-3hkvr_c4w?H&SjG3l@po^s#m#>i@?8VA zfW6=tI0r;-!GJBCaU^F9*U@GH@BF#Fcx@RBKT6Q=EBL=m>#KeX4Ifiun`qoA{`~~J zhR<03GaA!`W5Z>i#gQ=cGceLou)%m4>E(kIr~DnFv4bkmA^&+Yo%)KcpsT z44MOx32w-kp)u8SCZ_}ZBWcrhCZ9~<^ZL{uIX*q$(}>so;{9;@!te;44S*CuM~kB} zc}6c$-Yf2@O=BA7tmhE;Y{Ar|^63abuL7fBoDHJ~Qrwf`(Q^X$42-2LE{UMdZ|pf) zOolJ+p85fwMn0#6PmQ<@IX<)CGnIVikWU4~XII7~>OK{5i(LSxoFOkFr++Wd5AX@+ z`KG=<$g5!xubS&1#V}W*;YMmKI$#faZ_ddAuYTFMTj-hYB%iw?(@t8g9G|`LSQM;FT-S!lxeHmJf-*1;@3st zyfch+t}4SQer8k+QVejI2<_K>izt5s-ldeenKRhB@RvB5^$Ygp>m{z()YD3L))*=;^AM;*BfDe~H1jRV3Hk$kVtMDW?^kIx4AIDB9W~ZpD27LWD+2wk_w>W> zIX!KLPX~-{8()V2bWhy_qjig~>UT6aglq&m!9j2mh#v6wY#7sS zhPI)9L%0d=9+E*tH>rb9}IAvfp9>#K`WD&->T=>J;b^oN`|9pODjW(OKMN z+!1AGui$eE79O|LUZ~L4^}Tb(iI=c!@!KPlkx$xb52i6$VJ#190Hk=Gc#E)pMix>4 zh_S2?;e(IkG|BM6@WWr8)$=U*Uwq2s@`)gyqOUOCzjhYOiBs7FCp>D$iB7A*$%=y> zK!<&`*ci{ZW4UCfb>W+He{4Vj_1jnf|3%xIz*SYX`{VoUedcra;c%D{kXdE~nNegG zafsB+ED@D3NinrB$77gdW@^PQ=QJlYOf6JWQgh169MTFDjmpZ(%*xUne&2P@+H3Rj z_TK-!_jCW*m;LN#eb=+*wb!%uaI&y!c5-sTIZ7+AfO4Wp=2xc1%bY&o)X^azU4P!i zb2y1RgdYI?YQ%jAN0J}B4;DBCaHIM0B6iXmT4XyTz>_PXoTl|W$@3ReaJ6&hrxF}q z+OmlCo(WJGQFBj|0N9HpO?~G+n?k2Ue-eF`WMCYOP6kj(j#daJBh7s^u5M1_^T4gA z1z89Ve8>`F&WC3B%3bjDzv<`TTQNVsj0l5i7p#?B=dzBz5&;;KWox7!igFW_WZhRM zje+uEXC+}Vb@?io@8U@ExDM&Q1?-`DJVknRTJU%|j|aiaqIrB9e6FbGVL9wL!j?%F zVO${7Udbh*)VHo`gI7f|_lL{CT#(bSt@Zh+Wk&1kfgoT<15;+36?=o$Q-08ms zZz@XiJ&q*&E7<#y+KeVOHssX!m*rgj1`=5s6a7s}Vq=ij{2g%QA$Xs1yhwz@8xmzZ z8V$KrpPt7`XNCgTr7{;BNiOsnE)Z^{qiH)1Fkf(rX|>HIed_z%U=jxl4etKdleii< zn65sGeSIwhmZ*jB*!eCOvxP=8r=~dF1}GU&+q6a zm*+chc2dq&%K4aZetKww%(*U2dBG)!F53P?gqetN8%NSAzai3H8nI)))M!buPQSn^ z%M3*=8CB9A$ zM8sh<@?WF}hIYa*boRiPU?*|#Xi8&$z|_lNiBtchLVSm-3sKsi5>jIJ#4kvaRov0 zI%n^6BVF~eGIou$f>SEpeTfZuFDQc1UcNYz1l$nOpGICos&&y9yX6GJ!0AsrSOn#C zoTTHxk=s9ka^SCFsdVaZ*-k1rHKBAIWl+*HgmmZ0Eix$^qy}mK66VbHf+7kzEyj`L zG!GH`(a0U^@gZ=W^++#tk3m7|aX5`U1QAEl$Q^rFr8HtGn~f$Q0+x|wPt%Cw5NR@v z_%+FL(xzi_mhIq#OM92H%AE^EDZ0P{8o34$7tzRRWMsa!<0(1vE8xg|R-&9egmc`( zxn#qNZ523$ba1VuoC4CX541ABXCpY*LXl(A@>?kBILT?KEly5sJ4lJrlw~ZZ4Nxpc zPWR$SDpy%saa=6U?@OV1@@4TLI2I&u7)NsL*@;B<0mo=!4oB4b>0CLnQ{dg8xjsud zUy>_HXaf0+p>xQ72@=*eNI3x|}m6u&S={Wuy`qij}dpfD{Www*0)uT#~GlSl-)kmi+ zS7^yrpF56ZbpMI8RC>Ib0eAt#b`mM1HH$3~g1{YsPDsL@B>8^+JS$rS!pK^KgoPr0 zG_^61)WNpz_se-tw1bF}I4UZck~(((OmO6NMi%9?5krC9v6gjKWg!?2|5dg#J{(HYk4NH2dPfOt4+S2lX-tBS8~ZtS z{haxz0dF|X#3(w>NW!@VeHbQtab| z^F#={l+6L>BzhGIb8LZ}D&wTfud{h$5yI;b{*rX}br=8P&JHg@Sr6rM97)a0hw){= zDw@dqBoX&NSf|(sUL~!WEtEsHNx7IEY%#hWoDEcBvola2iL>>dA^p!6D^tN9(lr}VfB#y+^ev+Sk&pPByIKMwSE?S;26Tl&ZC<#Y$ z?e#+XK|l2SOQ#Tnu(7Y1T@iEQE3djwHE! zB+(yu1SqG;<&mO4@54NhDsXAhxorsI+-Ep$dlTOM**<;bqC5j$BkBTIwN)%@v!KL1 zg|gYwCs5My@dA{j(2H>-xtM^IrvY<;r8F02lF}^SOt}G8fLlu&dNt*|Ln`*09;|!5 zDfM2>R=ZmfArXnx<49_86C&-P5j)oCUT~aiY`T0p00miNe_)iFo@SfLA3@s;?MWQT zxZVeIM}gDStYg@XUBWKE&ETD+o$F0fo}>e~o5gX2cmG(!PPyj30`Cx7brR z{%^1jIUI_0$lXY(Hs*hMF!#1T=bv`m`S#u9oa?ZamOH&TsHI$gx>UeE^(vCp+;yM}zs;CiM-BGuHr^-2g z2E1UpUVWBw9QVN~oaUafLV!9C?Mf5S$()SGYffN2AisvY{m) z-K1^wGBvc4aAN$~D*JVCs-y=uvMO8)#R*i)dK`(-m58{JM(#MQ>cNq(i8IOG)ngl< zCUJfO?!O$5``yl!;Je@%VRH|)xdZmzqc$De_2l-lnHK*8kUXVZ$PwLcJpn}u8ub$z z`zT_bqOq@&{{4h0OfK>l;7pbJZDPg2uTnXDzcw1V1rfickvmrE&)~?FdYy7Q-hjLb zj(h|1)_>sKCmh_=bF?5YI!B@h>V#YLDqCpkMa<{4f14=Bhm__W4~%kWPjCh23^=4t zeM#89IOb)0BaB=#NSHg~ccL~{k#wFO{fj|15-d&F%%-nM#PUR}80n48Z2C%q5_g2l zQgI|BAq=MCfedQ$0Wvg~NNme74?MXO7gA0nN%nd^9`bNzy)QWDCI2m~AqGN0Dt9oB zB+m~Z;v+P&V@u=R6Fi zKtV1tt7&8j5#OMZJ8t!F0Y~mv+bHJ`;_Mz*e=8SxCpdDG2aw@rPWqKpCE?uR6N4!NtwVt*j>h zgo51Qy^SNuz;B3nmqzZmAkbKxwM3>*y~R2BdXmh0pJq==S-`nU2cIkDbbQR%3!Lgu zO7f+ojyVkkDO?)2jdhqVP>?o{!ja@O1QBCtWHrfB-yNUI)td~CuXGTR=^d=@P;5j! z_N0;15HXiVwvfmXho{Sti@^z?ZSymNxcOsGlLQIx{_LyI$!+r>c;wdqASvf9mdnSW zM0Y70jw2cI{gBARz({}?=~&DsrB~l_38HI`iHKB($j{(N$W@5+ERERl!MIuAG}24Z zY|43#G)Cb4I=LhZz^R~|MU;~cyIfy;xy)Gx&T8UvlLVD{8~5IDem~?7Joe=5Zm)w# zrkRyE67H)oxP}^aOs{L#oso@h0_OxxxQ=qHq?$kL$7avB!8r*Iu_e7z@8U_-jdf#$f^euvNJoZGG7giEn+v*GClg$0%2iz7+E4H5lmWOjY0k;B08L>&>E z5tI`^PWsMxNlqY+B!Jo>wj9f_19i8FOnCP|{NNHYA)Toknh`89e{|B(a0S~Mmad)(hNkV zqvJ_p4dtt%kw+uq1RB|~_4f27Z09&Datb)|N^d&lG?Lt{yuz+?HQ+SS2AM-Sw~#4r zPvc41&I{m7m3(%xE&F9qRH9y9#gUZYWpcGRUWHpq92brR?wht^Q@}Z5R)J##cP);j zx)vjm*MRjju>{gMA1}<16Waz}y|fC6(K~Uwpddq}0Y{R+c0}AuBRiV8oiBAz`gx~I zP=GV#)f9sQ9oaN^KQNm(K& zhxAT+`{z^QK$1t&c9MwxdNipG#|nMT0@SRtDU!h>m#s7$Nq7PbW>TXL|K!x??8=h| zj@)YtDd!V1jo`E7sEIhoqr!bbs>UEBxqE<;+8|^5w@R+AhrpRB<-E(L%EzFnLYobj z#z8sKnYGbSlFLmcj--DMfwhsqIBK=y3cVUUc_lT4a^Uh}=i(B^C9zpoX9tJWuT-+z z#h1?LbD_I}bQVZccC)!;DU{@%+ABDc#A{%15g<{+9cQk!;MGav8d#AwL6HHgb<*ol z(tWj^gazfh*7om7?1z?g^#eGPmC|~o@fNTL_<*MO7HLDjkFo4?7UUCfuh0&6igJ|8 zqmy$UoHlyR_)_YJ!qF1r2QwWdZgZ5Fu6VCPNlN@Pj-)4i3#-?uWff`7>}BXdPRoCR z6E1xMi*)k4Pa>lm@vhFue}iT12~AFeN$eSbwvL`P300X=xoqQ_cs-6t`{p@3Nr;aMnpX_OSX% zgQ6IQGo_1A(zeTklC)i+Yx}!E{h=jo_aKg>?UIm27SJ0QMAO5>fE{J>BXG`)mx6m6 zZAU7{anCB|26i^c0LE4Bl7#!#gg1nL9K18I{RECAd<5)0No{7^No}-y)MpY%^2||9 zN#EQC=l5Zea>COohZxI8liqjpnkC@H!A$iKJ{Jky>#Hi84G!t>cG&2QEtC6>6oQ%Qln(l-J&Fi`=)*vUYV0~-&OM6=Mrdkn%CM;416x(Jr_@V$9u)@ z2)jb-*~{h}lZQxEC0%FNCVy~b&pwcHI?k`*;Nae$;Xj&wnUig4)mgCFOuv9UUnlb{6291Z=+eR$r8k=N8Eup zk_sA3@TcpS}c8ReXFC!}_daaMqY=X{W}KF*392L-tvK7}JmJ(NU9 zTlpT59Z%1ERF1bcoZM%@smC~;h9fD(7^E@@m?;G{vGUJDASvoXsh^@;Myz9kc~zPM zC0)L*f-(cjwba~;F!dU+9w5m#kxFTIUvC?+ES-h{+HZG3F%$+Ga3m47BjR2fIg?b? zkSExafd|1^jl2`yuf*`%4Y)hWafEk&*W$nAG9Cxdg3j|1wRsr!PEwnW`#q19`r|p| z_gzGKZ8;C37Mb``TJSzwSbqg&6qMgkD;HqlJ8C762@N8*xE2lE`%8zUlhVc8gYQtmKT(XFyM2btO!#Voa~AH2aJ(+Tg<7AF%D=)({BnL3zm{LmZ{)Y|+xYE#3HOq2 zC;u+LhkuW6;t%qN`D6SE{&mfhx=;A=x>NjF{yhIBe^+~fU!}RkxA9@xZ~5=}ANgN3 z*Z5!g-|f6cvq|?S|E=~mk6k4}5Pr~Vg>aQYs8*SU57jP$P4Eyhbv<=iswU1`=p?+W z4G@BaP@#(uCBzC{h1*;=Aw`&>O&7WgJ%t2qu8^xL5Q>C8!t2`p!h^yf;bCE@Fia>D zMhO*yq&tBhMIIxJ6~+q_g=Yl&v%)kXT4&cqa2wP!h3AClg?Yk4;U@Q@a1TF=@Umdg z)C%9KUl&#iYlL;eY4rx-EzM?Ot5C117j_8m2)l(wVZU&m^Uxd++PDvdqe2Y#q42Tr zsc=Tvp&i1V6TT2ygjV4z;Txe?^_}pCmREJSMS&E(CpS})Oxi^ZBe_b-POxgUg`%mzG{DUpn9A(L_Jp( zuAZQcR6nGRQOBzj)$i$&)$i-l)Vb;cb&-0DHbK)z-CzBndXTzO^{{%V`iOd%x=g)J zHA+20W3Nz;!S@&H>bhYn90uT~;j9_JJYWg%CU6+I4*UT`skm9GKpz0_X3ZJ{OafK` zn1W~B0&pdnh1)r^h5_?{mw}bQ24FAn0q{BSCw^{j7Pbs#4F$#kc$Z_=JYWg%CeRFg z2V4hk0p4nERtOLSBm>z%Z(tbk1TY&|3@inf1N#ANYtFh3+y(>= zAdCPifl0tTU@5R1*b6iR-vZYFUdzpj1=4|jz(`;$@C>j3cp2CP>;M{p4}hNmwT_!* z0fK=TAQ{L42H@G!S)+mJz*1lZ@FwsU@G10*oWiK6Tk#uDli*Z2fPIw1U>>j1160G)xJKrv7XJONAxmI50^wEx=> z4g)^|yal-iJb(Zo5$FYs24(>BfF;12Kt1p^a2-&)pnZX0AO`3Ii~y>ES-=8dGtdN_ z1-=6Q0PfrIM{h+{0=_^95Cdcb#lS#dA}|A32^1%wfizbeH>(p63d90^fk%OIU^cKBXaddxKLNpRs1ZOq^|8w! z>CQ2iwbJDiF5PQC#CMCj9(Re5%pbaRC8`MNz{f7-Qp^dL66wG(7k479m9Bs2(p`G{ zxbw869S@eeN^3uMc}$x1k;}7$muBz9O~)5x$d9CvUppheWah@brY65%Mm~wNgIlX6 zKU8)Q8`T#bpS~eKE=GP@jQp?|`AISSoS2&YlGp+DVKw=+F!I@(kJSnI+RZ8TgQ`dH z6JKLg6IA4Buul`9*eyrJ5>qUieN+AAF7GVNR{lYs{MO-MPy@ z12=#_fja=cVRL!+g-=}6Dr{)x@Z&L;4#CB@k0(C)?)dNJIBl>$+>}7_7+W_i0^n;p z5D6Lob4k1Ved=OX8;1_$1{dT4h0>E}T~?_gcN;!)8OU!cJMW@4JSK2Yl>%F&3C%8R z)Jb^9e|KPu%jMpocs?gk-?Q2Ay(5e~j$km%s=1!cQ<3JV=370b&@gL7Y(IQps|q0{ z_^{S!90zdZGq>dPyyR<#ER|F^6~JN@{>Jm zLLm2$^uC`*C#lWfqe%Ka+KLaN#ae@tKn0z{3yUlbsCKSUI8USgXT~QMwjqZIn(X;Pm;C9)Xf00C7{K zjCc>D^hH-|kyMso?N2DaPTj;roX(85>ZSRKh&DY5^atcltKt zOH5N$$GQ0`^E;15XtOK*y?A&E!ZuY|YgwyP8s0jbN~Nu(R9cX)SoENr?zo6nI z+;J}-6_D*ev2SAHnzS|Fx3sm4@{Y=m${yuC$~%rL7b>wb94(9ys)SAIt?IXhx7F{c zpB5$yGlV(9B4M+7n|h0|9m~G=?Lvs<4Aypwg{49*)`yoYJB>Tk@2aC*)(g$TT44iL ziMxdNgd@U9;d872uLzy_ZvyLbzcA1Ao}IYfmLD-q{fzhU#6v-~FH}DEeai;JjKpI9 zbG*6yQ`?&x_RQWpd%=L>X3xuBQ+74a@Exk}o9I8$&HqqPTg#!Ky4XuCb`tH?7f1=3 zg7ycQxv9=lSa!UfOETx zmt_5!eP{N09ChlwE}7w3lT5A`T&Db3X!qDApZ?N^{4;a?n+G%xZXViP+B~wkqPeoU zs`>Ti)y?ah&784yS!-eIoYs36<66TmJ=+@Gn$f!RQnyP=Zx}Xb)SU7;6E-Wo!NkSD zzvwPx3k56X9o8nD{L!l?)D+>^dC;3iu|8+9@=->_nH5GkC~|-*l*8q zd-M}}KnW>+tH&j+0A>`W?q-^uO=Xw91^#=RDc8C9EZwSG@4(Sb}%15!@F#HJl z=hUnEd@xFG=D!d9eW>oZQ$MiWzVtacAY-Nak@|P#voV{=Kc0)==U^U*G(L>`xb0=H zusu_y-Tiy4z6 z_zz+9i_$M)bdLW2o56EWaZg}2j_14LZ?d-7&hebffRAu-QZ3YD+w}jJN#?)kRro{+ znO3$~{%Ml&r`_s5O)|P}b6B_fqVbEyXxiO8%AaGsYRWU~bM|hQdzC!L^x=E*1Nq_n zCOiKy{{a6!|0w^9kjeKFF#WU$7xp#>7&h^*G{4mB=JH;^;Fd7o+j!cH{7#9cTQQIi zxfm^6!hNPs=hgTjgdzBtU@0zJCoeW%ymIlzMKxEgeL&MiQ>Rus>CFlIBBza-HcIKF z9-LjiD$(l^ol@2dn}vFzL1+?=3#V}*`bzjgAQOh?<6ECQ#|JL>)E2nlE$=}S2TiQf z7bJcAF2Q4ci1CBw17;OQO8fc0_lDjZI-ZjOc*(NM-gpof6^96k%Tr80PKRG&z3F!zY2T=TSMj%JZ& ziEf2vt!A6%9nF5tNBCvspEY+h0)8O5v$m`Dn7+660d1Lfw05j^qE@G#p?yiaNxMgT zN_z=Ew|he?=sa|tbTPUj-C*4?-6&n9ZkkTg)#*lR8+0G&nswjn@K&Jy6}!f&@1zgW zZ&O9<6ZPr(KKh6C!}O!{b9CeNbM&w2*XZl@hxBgxX8pIC%laGoyLz=DLu)hOhr0~P zhUc~B3&V!K{KPOz&eZwGH#fhWI?c`F!u4UQ>a$~Cdg-`vwp+Is29EpU;EF|y^=?mI zY@V$9sQJBK``jkf1-`L<+?kcz``Q0azS@+qYRi_>%|cbmhv)iF+!S`Ct8ZS_q~qI{ zjP8D^d3ajYo-u<`ADHYHJ-p9UuIt8@X|A6)hqO$nKDcB>jQ{wbjN^OEIDT;WrQtD_ z(bX%~a{Gm@oOogEE7P}x_iS++e|LEF8!zUbY&o}MYMq)JY#3{J-mugV#v3>Rev4q| zb{XnabHzUc?iqXgI_JKL7emsV(&~$Y^8ZPv;x-uuw35H%^}S67e`}3?5GH6@A|bCC zoPPzHLa($(9MxjM2Movr{BWm-J2|Blfhz)KM$Lub zi)Su4^)0C_co>&(@nhAv`BkTy6zDv!ySRp~)Q`44iAUfFXI1hYb3q)X7~}Hk%cJYe{JFphYO_ zR7Q)iA#ejL!lDZ?7cbBve3xqfj+VhK-;E`sj@}nDKE`SM$<`d2xha>fVM*m|u7C@J zE~HZ<?` z(5(KJ`Wr27V1A&Z$?TuwUM9)F->s);IqzP24117uDmf%GEt6JxRelw#qeoNhDWgdX zB5uN8kkCxDU2>;$<$pazIdCaVoEd7!o=psqA+%6 zH9nuWCvP=vEpd1^JXb-=wQKwr_>`BEF|*}p%W9fTPGAmA=E3L(Su*cj7<5rho6{@J zizbtipTX+v+|Xl>d^6N(`@v~bmOvu?U$d;oIyo6#OInK`O=e7|F`b;`?Sb1_|82TZ zdeK6Yc_8Hh+62Awd$D953Y-x*FxVNh;o>$r6wkKKW8JsQg<%(R9W`R#rrI1&?m?6C z#%IN2WNtD%aEbhV`6Bu2hrY1MFvB6waLB`$neAb(hW{AmjC<(fUYgM5)>j#$>xGI7 zeQ4G1ir+=k$;`@hq_ZYmWry)M!`0kR;%nxW=Jn?7kpq**dXL2(wX9j6Qq%iiHRSAH zHN=%5|CCrVN8o-p|7pH$eo3=gQ{h`zXXZAkcB=NM-d7z{ol-Tc?BA+>RozpW`A&G2 zWv>=L`UhacxddONDES1yS1C&H4U3Wsz*oQ(;78y(pu+A2HirT`8f|YAAEhX{4dBBR zCD_0&F#y=aE^!0kcH2w*Az(+lqziyu?UMh>SOUURfJ`78C;*Cq2Y^AqBS0xI3U~tG z9UCllbuS^4>i`WmT(ySF7hhL>tJ#VS)obyIffo_*E-=m!A&t*QO*{`7dKlOzMw6OB zI6iF!vd5OtimfO4XUc- zH1ubIJO7i?v?~nm6_mIGK0p8v1cU;S0PY=>BmgM}w0|Z9QX0GyU6KbB0}ld&fk%K+ z;BlZ5!2N}iYG4MSMy5YRwmG4$?sb%A6H3?w;FAo2|Gh1kvuGf@yzc!%?c9iwo#|Gz z64`|L_jT~s*qrT*LH|u4p2f<=qv~d^Y^FC}RZGOHE;c-Z5P=)`YCO~o-Ein;>hWkn zKRjS^oGUAz!}T*t#oaYEB^{ryzcSsl? zd~hUQfyBw|r^UPBDh$CV9Ou9D)l_eWUe7(lhYD-dd(~HP8zfm%sHv;_2=mB2AR2Z~ z1NQ;Ffinc+BM*TVKw8`1+Ev=t-)hDu)&6i%TSaS~A=bqo@1q9-AwW2Q`QtLrePB3Y zsH?+Wy^>5oz(usq&|oNT!GjVwPl7p_la2ENfH(&Yh(kC%+J)m4yOObvaAKjZuFQ-% zsh}MJ@79&fXh)a;xnH~R1vtlTL?qxePy_j)cHy-+UjfLO+;NdB!z*+p!`gAy;(P<( z%%r`pZaao^MLWV<2;2$CMt*O_+=KI~cAVWf-v`Jg^&85SO>P%{9AS9zjb#+mLW%P$ z4bIy966dWX+)hh!1}EsGtSWJ1wB#2;py6LbeyLsf-#EuUI?LolWD+-0OYrpuX2Xnd zyo<&-PsZQ_qc~sNj$`+SBDfu??h;q#iF4y=)d(+$=mY`XtWJw&P60 z`K)%F+%&w=kMj%dICu}N1hLlGxo?FeBw$D2^h0B)?8#I_4h!Fgu8 z@Oa3{?ZR;bzNBxv@NCGqq_6@G!TB&i&22*Y4YekciTxO>crf@90Sj(T3tWtt#|^{xx6Aple6gmJOCQ5p z!y@xVb6s6lGuN$b%xC!QDUf**@BVy&x3F;GdiDZ7dW>A-Qw3xJ8yJq7c@hcl0h%pR z^+VR9szj;BU~8WLD_ZA$dJ~@ET#ax26U5T{^y2PSgRQPQS$$Qz zzbdt^5wufBOddUD%x?Qg>l?gEkb)k!hNvEp3LdxaPxm$r<@<2mk^55K+ftSz*mFwWCS%Dy*rUVpZuv4vRF!Bfk zKFx*w>l*!B{X+d>7OLi!>EGhFn((nL`kz0yR=)|mqVMYW=?~*3?`Qf8`mgmr>VMPU z(%;wX4Xy?+Lx3U75aVX(W=J*kFytHh7`B>941)}h7^Dd`LWZ<%tkpelgkiJ+mruuk z0{4tzCeEE_?%Z6%4&g<^N7`D$a>HuFdc!8eHp33XyN34+9~h1sP8vQlv>3iNd?(!+ zYmK)5Y`AH-Yrv}$_-`P-d1EqKjUGmSW3VyG7>`k#j&Yl3EW*egfU!Fqqj#KfqH(fu zy777A0^?$%WL$%Byv?}7xYyWZ++_H`c-(l(c+S{tyo7Q6Ge-8G#yc3>Mw89d$rOt5 zooGtM2+zS7?_(O2Y#L@NH;utCpM-%v!&GCMkD*>`T47pi+F+_PZ8yDR+G}bu9W{Mq zI%PU%`iyTjT{1~%)U^*@bYxn^ePhDMdK~R*cC_NJI4A!tz)wh#w)qR^JZCUxqSKM{ ztvFY47JO1h#ko8FcE;bjI=r(y-kKoYuCj(3iZFlT=TS;TDRR7ZvQLzj>xv(+QW5n8 zsGkN@xP_4~?HzA@M(OGUpR%SuRHo)iUI3N>ZvbxsZvptmTgk5g9>Xh9X>dgW5`Z+| z63_J|`;u^A3@LHgM^76HQn_LxnLs%-bt306a@ zYJ?Q@hSg2Lqbkz-ZB~!nZ*R8Nr|+(Avlf@wo87Ot-*8V>-E%j3czOhT#Cc?R6nYHs zDD|lHsP?GwSnQFlTJEvYqo-!4N0Y}1kMkaF9@ji>duTn6T5X87Dp1Gc} zTz}7@o)w-GJ!g6@^sMz<=UMOB=y}xhjAyI0)$^+7O;6s-i@R#QY2{rlUcO%8UWr~= zcCTWuPTIj<7T1wpRbErQ=6WsjTJ2Tm6|QaYI^=cItJ&*{*A1_GUPkW(t*7@`)d*F0 z?FiKX?J#YycZPSN_W(k$7s85B@M4y>H3w>&R*7?-?H2T<&`qZe-__X?jyI%FV=~HjzeJ#GezFEF6 zs)~IF`;PRj@}25C*LRukYTr8F2H!)zCw-fJulU~Zz2|G}aw{RjJx^sn-t z>OU8=@-qL`{&oI?UDs$E{15q`^sm!4`(N?D;eXG6q-&MyR99nwXFza3TtG%ZVZeZZ zxvuYOm$_C3>{V3<)C4RJSRSx3U}wN#Ra3x;0Q+j!1KLkjA8F5Pn^orn+5)Zx+z!xo zwsj8Z9Mw6cb8hGUo%6V%ohv#|>^!sc!p^mw*LAM%+}QbO=QEvKJ74W=3G@vN4@?Zq z3M>vB95^ztDsXDx+`wgls{{LUb%70mhXPLqeyeH@yb>ttZUo*7taCL6HMl;)c?Jas zsW>ekXAjB-x<^tbRy_{P+L%6eGz{x z=yuRRUK`x(8W8-jJ}NjRxRlQg?jJlfxFUFB@ECq(@WSBQ;B~?E!HvO3gU{ObwYEVqX@rI;1Y7A>>fV$&hP?=8!8PH$v`( z7(+cngG1v&GeQeP2ZWY}R)$uG)`Tt&T^@SNurYLJXjACZ{E5)>p>3hpLT`s^!)##z zVNqdMTvNhsxZZQk4eK8^G|bLdgiQ>a8MZL2Hf&v3eVE$V7U6yy**kum4vrAK#6J5@C znPF_}a;?i&{&tu7Ms0*GA|N6vA|)a>;sf{o5%!@G6%i978u%sL7UMg{nGp*kY9rP~ ztl;V+8Y2pejz*k`XpOiUan5)%f{(OB`bLIF{)h$IMlLZjD>BYj96300WMoz3)X2G! zt0U_o8zK)yo{Vgcyb^gM@?NAd$}=iBsxWFmRB2RYRCQEM)Z!?WX?fJfsGU(wQ5m)q zQRnSZZBd1`Yf-nO%qDHLEjl3D%M=xz5}g~}KRV46Y&ysv><*^%McbIm@HpQNZJ!U!|+ZKB*_I9i`&K4IC7Zvvx|1AZwin9&6J2;`eJ*0 zjcsuJ$oQ)G#kQ&ObK{rAua2*aZ-_q>e=`1_sX6{i{4wrE{JnT%SI@4&UE{iDbhQYD zT@B^|T}!)GcCGH}Bh++VXI|=$|k& zp(0^o!pww)3AG9966zBg6OJaFNoY;Dnqa?~z$aP~eG?NCvl5FFm)kbl1}Bb8tV#?O zrY6o!T$Z>xu`bcw+>m%Ev9tMP;vx5)wkBJ1V!UuA@kZjkL}RxM!LwU%x43Q@-3q%6 z=vE+{;m&ZS-733PcU#lCsSKNl{5BY!yNY9w3@v z7gCaPllmtOO{z$mm^3qKVNz|M|i9H7a$lIVCkWwSVf+ z)WhaBTSe+M+r-qFsS8s-HP@!DORZ0BOg)-Xy)b=1dTDx!TV;B6dQEz++v4=)>HXa{rZ)*Y)0@&yq@Pc3OTU(W zJAJ5|He+CspJ>bYo(sr`%1Ftui@6#7GlphVWK7JMnXxcqT}FLIV@8GBnT)F$tr<5n z_{@c(CDS)EJTo!#Lm?}(IP)`MaOTKNdsXJt%(>WmT9&yw^O8`P*^qfCvq3zW*_?SL z^G4>qOwaBU-GaNvbn(m9c3zp^GH+J9Iy{Ws! zGSlru_w(J`x?k&lySuiBt;cU%K#!;%DLry~^zXr`hxVxGF|&tBy|71Zk99rjd)(t1 z?LCh6IMZXHTWgQ2Jv`Mnd+=G7EZ?l~tRQu*TUJ(a*5Is>Syfq6v*u>S;2uP-y23KS zGTpMyZCTdpth%gumWHfDStqkrS(>x1WNo(G$hwzh?CIGvxMx4LK~?V-*E6GMVb1|Q zOM6!KtnS(9wz%gg_41w@d+zMn)bm8o^F7;o+OPGz-BX(#fJYuvvX8puX7|soQV-3p z$ex%zGkan7^Xe)1SDU>qyFS}p)tG%W`%Ly#OKbMk?3>wqjwQ!8=Oy(SxA2_A9Ft2{ zPI1oQoRK+IIi4<4bC#>;<}Axuozv=8m(!4QC})HEWX@H$=A0OpD>*lE?&TPBJ#$lC zf-`dCax-!Za|h&>=2qrb=hoyd&Rw2+(`{q!&fKP4-aXglMDF?Aw%lvEw{zcCzlVSQ zTrBQK)!ICpG`hR1zkR)RyLAq?guAZF*QM+3;SK31)nJvGGjo5d^6-RmY0v^~u_i?y zqn^s)2k7&L>U=C;X8Ek&st}~{8&wZb+LCE zw^h8M?(a5IztAtZ(-8IR`Zx7IX}9a2(lzSWTc_z#^5*JX`9#q(-CK89HQ05pD$9MU z>qysSt~XrGT$H)QlB`NL4{>=yJIZBQD-V)0VkL{l+b`SOlHH2d_}I*^c20Buh-+se@dO=;L%N zOq|Odz0HteiL(`nS%v|&7Yw@%SKVC2YFmx1)OOExv8~vBu=^g3-QV!4n5&L3gbMM( zYpRP}f#9a;X81reLD*>P&voG|gn?qA@mkmOwvq0Wv`x0~#42}NVTRDhe1W~4M)8{AK7X1W=>Yu#1}w{4-8AK)<$GPJri zyLMJJ3BwKd?Yb{DrDBxZ(>(9G+I634aaT-gZnwYTiB3wMt#* zZVT?uxvMH|aZwpj>s9Bw9#wy4@z6)9Ebgm~f%*&T7ggczhYa^P&n^X)6t^>0tM(Ja zR^C%x8Zb1^*WK5>BCoS*V&2TWg?Y7k>+bMu$wugoYot}LxvLK5lB{l;p4MXPL)J3ulh$gCis!70&^L@lo~EMU zqPQZ-no(3&w_Ba#>i35KrU2)r5qw;3Yk(88;BS+cJG^)IXmjnW*}dpH*EdvR)e}#0 zqpHS@$DgMs?~eY#b&8i^6nP)i!sPt^%roTz_eU#`cD81WpRM z0lRawHXqgQ3Y`sG3Quzr9q|Tn4@=|pwjgPx-gbHSLWAw9YIlvvRwV3hw%EF=q{FMM zF_L-({-juKxzd|f+uOTmx!TqV_9F2iJW`*=_2hKoTs+e0lol}QB`O`UgfU)&;N+dP zRAN_w#5lqvow$s}wXnFdq{G!yjvG%x?TB0?en^!%@l_W2H6|@$(izG-f=BM1W*Q9x zMW>__T`BK~MV55p6=wNO8hX|e$asGUc4y=xmV=B)-k)&R!X`%C%R&|D4aPgcLNi%r z>S$=Ap_J)XQ{7q1BeG??C7o955sQjd@LS9@d7s3YnO#hJn@VRbR$Bc!aW4zqN2Mc{ zN0?=q*Jw!8$@bhFna1yY>%;~Y*_}m}C7sxW=kiDv&RUeryw76zvKS&ut_PD0OghKv z=n#!@)-s&u?X+}9m>GX&`Y4TZ#Bz~EZe!9%EXE%?Fd?8BrImhdg6>&&EOEHhzDC-)Sc7{PRYR61gj?VYs@c35`If7ci>no4IaO-vWZ zbfej{pUi@A;#q!EsRoc%&(nY^qTGr{EXk}|`_fRI_yCgz&5f<;6&~#sjfN7E88ZJh8Xl$jYBX$Rt@tsO zj##F!$ciM_f=(=8t$l+fJek$%TGo4>qM=7DO6XE~{?mz*Smeb_s%Fv@CVk1I=~Oyv zQPzL*<*d=5@aC`>`&h%iKy^p#mY-R04U^`}!4_qCB1?^ii*ycXG(5&ubFZ+t5{r9; z>6TNe(a^x^cZ@@F%zsm9bse$DQlnu3>nf|5nYBz>PbJKgY(m<|Lbot!8BQ zCiQ1hK9iD}@)g(_y`%;>}|thQ=crjrEzuQ2xes}m! ziLP`BT_j#-Q?L&+6UL;6n8Ej0jFC)AVzXWr8$++FMY)9O_OQIx zGTllxP(4{@5}1_1q`pj2F=+^ses(qqS^ve;+~`C%7MzR^BRgGFC6P%il)QB844uNH zM_D;*m~J(*GKcA2VbTkb==x91h!4}Qq7&yc;sln##Z*@$zR#}Zzp^g1l*OoEnOV+s z5|e&oX{=I8a+?J|OWR2&HZti07Ue8UPGZu17WxU(J;!t#SmDMnU3aR(`p?D^ab@N7 zV$vEG`aNs+>8y0}6s!~XucjH? zF4Mh7r6O?_%k-DbN@vFVmgx>M-C>T+f5(_|3CrQP%ycs=yCT)FYQ4)$8(0Recl9P zTplZDSEdVP(hJPsDkdefp%}|}4XjAT%wA7B3m(Fh=}h-2%T^aAS=rBbVd#UvZcU;*QO$3pus-H*(k$fUl?{MVlm<@JtE)UeE4 zVijj%I(bcqopTn~z@+Ic5pSkbmTU5gOJ^6~VZrm5^dggGiLYL=}HO!qR&em@ptB@4B0W#ST+$m5K-pGAI=UBOSV zM7Gn~DiWJmy&YuIUB*jiR&KI}=;BO`%zw(F(2qr_XW5#-+H*J4Da-2pR97S_4JJ!P z;(a!*hOlgrU&C^)9iKvKbpCsgnI6QXhnX~#NyC^_#-ve9ieTBVV7f6(8q1{dOq!_7 ze+QWI11241(uYj?m`R^9=?s(3G3g5?wJ_;3R+p_*hxzX-7W@s9zGKo=CjHE$>rDEM zNjI5vi%EBwbe~B)+nUo5$vOY&nbO20(mKv|Qs#8(G@#EY>tM@VliX~MkhL*703Li_#=wXqc|M0e^VqX4o5qQnN~a<#g9-N4#g|L ztVgpCk3!!6Q(OvV8K(FxidUd`3W|RqyBY1B3wd)wC(51Q-?n zV%N_Pw`9+vm7eDLh*zZ7e$$Z6(>Z# z5a~qaf~7bnird0m50SVdbpDgQl_GH?nKcL~%V7??>@;6t~5(=*E2pxsDw3pR&p!E|GI;RXiePu2Z}k#ph90`-)eicutD< zqxe;dHwE`hp8pj8Yy|6Oibo`SD>_keM-EFEC2V-iv54&t>D6;6J=-RpIlBIb3>IyCLCNg zpp~5lx}+uZpX`wqiOM=xnFC~xsEF+p7m3H{&4(iKQ?rk1u5OWTv+=NInQpuB8^de5 z2IGDsc~Rwa^FVR6?y&KM=10Q~!zs;2#!n4z>I6%j?rmLz?v}w~xn#DNif4>p8u#fg z8#&`4-FL=o#y^b5b>}rFbr8Z0d`L z*EwytX^6g5U#_aQK7-HES~N7;={cnLh$G!$RrtkA|=#%jMa_coQ7CTdUU6O0d=N==WO#+uTMlkk$- zDgAWKbEapt|Bt=%j*H^x|M-@>y?z{fyC)#xsfdV(G50H&9S)h=ABV3u28L z3xg$w7)7H-jZx3uVoWSC#uzomD3%ywjIqTSHTwI^9w6q4zsEek%#Bt1iT)3Cy@)-YE%ubrgcWXKaPYquM&YnKZ949kUE+K&y# z4XcGO4d)F__3MS^`YVRb!VclScAC0@`G(<+!SP5NW1g)(Bs?@MP`B16=mniow_kS* zD|9|HoD>9OcfE(sWbC6qD@aBkov$uHcR^Ta+F&d&T@`*Z-VkmJ4}<~wVBHge)08*X z(P=f6jg55Gjlo!;p@}g{7h{aowKAsb&6@Yjl}+Q!lBR>vOJmn`GbR~RjUycTO=>@^ zGWv^gE#CcaqZ_YJ(ACp)(@oJQ>iX$s>6>VxHG_3Sjd7X`UA$%_K3*S>^*871zrnj7 zeKe_>t)_lvC%z-tZuT@yH!s(%)@2*V8Pha5#+k;&`t`cax_QR8^^1&InuX>Xrnk)n z#%IPX(|*%vO*^(0)*oV9niVvHNw8sA)c_$(s4FxSnhMQ?yKeY~ z8$1EnF*9BO24Dd)z(yDG*w8ZG7gPt>pE5oS)FZ5y#p-AWYbVehB!U!xeIMh8f-Hdj z9OK7>$zU3I9n1sRjxip4WW>J>3c*^i5o`fFz+P|=90te17vL1K13VwEARl=@h!eGs0IQZFhW2b&=5p`7!U{Af&|bN^a6cB zD!@)@@flzQ7z-wXTrd;N1q;Dq@D^AB-UaIcb}5VB26lr3;A7x82IF&p-NWL)21Vdo za0C1V?t@>!Q@~rXlmNgOHXa*w#bYC{cyCY%_<(1j0Z)&=^F47N8Yq2Rec7AQ7a1fmq}^ekd$iU=$b+ zCWC3fk@CCVCR?kc+e4a1HC~q7y!~hCKw6Efk}X6+6Yr|oXqqV zl7#_6nvf}s6vhdYgsH-;I>H-5p0GqH5LOCngbl)GVY{$L_)z#n_*6J4oDt3omxOD= z59o}379I)D1eHdoF>9>k+c>e3W29!hX0m3Q=5@_HEMUD<^R}i?vlc^uEt(ygy_$oX z!G2Gn%h8MVdF*t619lrsj_3f##70??Gt=tzK)!3f3N4Z*3)QRc&=`kTy(P zSKCk3T|3*MosVU(m*HE;HQJ5Z ztyuKsfc9hUG41Et)7r1KvykOCKpt2E3cyOR25bPE!FI3*d68RUVSqI0>pqg&=w?suAmp_3sS)lkO4-3 zv0x&|1v9~1un;T;Z-EsK81I7h-~+G?>;?zG$KV+F9GnJUgCg)PxB-3w_rb5=Dd0WO z&H)n;K{?4p;yd zfo0$wuo}DvHUTHt1@?nO;3zl&z69sMMGvM{{8d=K2e-gI@DTh4I8QWmzzE!d4NTyi zt6Pg{tmTm52!?Lanv;gphBQr9X4 zubba6FErnG&o?hM7noO=SDV+F{ltyt&E{?9UFLn}gXT}n$IPFZzc8OMe{H^KzGD8) z{Db)?^F8w~=EvrzX3kA;)04yTVlDLmw;^uB$ZzqYr+S6kYPWTyd^<5rYqgZKl(!VQ zlTPhK-`@T4Mc`0N2EGa$Z5eNwWNF}*YdLC~VVP~2XUVfHwk)%}ZCPn~*Ycj_eajZh zcFS(de#=Le!Vqbr8Hfd~L3_{{^Z-eq9~cDE!Ei7dI6w}V4rYV-o@l!BVR;iQ2dlt3@IKfI zc7lE2BX9(K22O#mzy)vxTn9gbyWkh_1h8J{XMh1%fDF7qMc@mngCG#*h3a1qmc}3o zv;eI@JJ1Pq2Z(tYy?}t4zL#-1c$+K@Pz}$ zS?~?G488+5!5#1bJO)g8bTmK@+<*i;fe)wx{6S3+3hIJJAQChOEkQi!2)cpZAQ=n* zX~2;QV{CV{D77I*{XfhC{-tORSo2Cx}y2YbMW;1lpEI0?>x^WYM=27Umy!O!3k zcm`D7Xmo+u8|80>#RF6Tl|eNS2tq&|&=5p`7!U{Af&|bN^a6cBDi{JXzz8rFOa!@L zCYTErg2mu1umZdb)_bG;KY(Q$*bNSVkHInUIXDfz21Vdoa0C1V?t@>!Q@~e1s|!p( z1m%D?s092#4G;`!g9e}}hz75LHVzmaKo@{jlH>b;{$MZ|2C~5zFab;fGr%0M04xH_ zz&l_ycn@p>POuB?2Zz8>Z~}Y@&Vh^ID)=5aZo#+*9)jNh=Yv)k7=b&mf%3o(s)7Je z3xtFEpb2OOVnJ)r9&`phKoaN&27z=i9E=7IkOQXsp!{dUG9ToFH^Fj%Z>8hcf%m~y zuoLV9AAuv_GjIxg1ulRq;5zsb+y%dYCxESpb^sWF1<1e)R0O`Ddc}rl2w({V^+00~ z1zLbspdIK0x`RZJ0tSMiAdB?WS1Xq?4^{$}g112-SPM3SEno-O3l4(A;5hgKoCV*2 z%iue36Wjq0z+-@I?Bdlx58TMx`f62PYXoZ~XbxI}c+e4a1HC~q7y!~hCKw6Efk|L0 zm<8SddE_?)=lBrTPr#?(Bsc@kgG=BV_yODoKZ8f$8BkS1)dgl?1sXYVaP|1e{Pi5}X4U z!By}*xCQQkhu}BBRYA=KM&J%?pggdHsvrQ=0^y)Oa5RC@48(%gpgrgedVnO*4-5k7 zU^o~J93Tfw2eZL^kPqGj%fTwJ4!jSxf}LO=_y`;UpMg{0t12k}3$R=P*TIkAF8BpJ z0jw{oE-(NKkbxJd2z)_x5Cp;+&YP&0l^WDB8#P^4WWdU#;}axca%fv><~tW?3F`8kXs;9Ib-smjcy%O~2IbJZlQ zR>5GJs7=O@P@aU;vPzzV87BD@`11FVpq^r=BXmGU0>c#P&*}@<9)?6_8@G@9gge0% zVTbSA+(RrxuEnD19=x6R$676Qu|0PS{tS1Kb8V&9mmkDuV)yOI{7me#y#yumQHD@>WqdUsa$(6|AbKiohP%)S)@{xbB3Vt&?y@ z|5H`zu#HqrP|l}e1KE7o=$5hc>PBo5OOMl3dvW|&^{MJh<@^kHUO8S?-B6CVu`8u3 zyr;@hP@B~B++FRVcAVkt*r%(Ox~{sZx`n!pa-pMQ_E5}3brXEze}-!gvy~}9vAY5* zYo;oG%euUx-GQLf)#;_TXP4S&0OO0#CcfZ0O*xwjGheY4s8_1rQ-1*acCZh8q`1=% zj;gkm7sg5ycto1h2+t!Lp`;rmE%)R}+MR-~Tt%G}E-ybkKDF zgKMRJY5xEGf1(m(vSJQ=Y491vS4I~f9mU6~rFYEHp#0BpMDrFFW!j)|;)%+~n$PHE z%{Q8>c#d*k^F*Vn z|4PwN(90BgS^eLP*#&y(U~%_(xcGQn`(>F9^}O~f&TeRLDQ<_<56WCS!#&b+ zI<=05Vo*$K+otMa>S^j_>TOCiC7IGqWzQThp8nU*951BizaG8GQC1lL{pfo*URpB$ zoy0g^rWpU7=zBU|qL(j5pQ`-q7-@2twsBLzfA(Ld+Lc!Nf7-uNQT&m3{&u&r?caYA znN?R_S4CF?du=q-HN#FD9dzAweRYF$nYuB$$!Gy*>gMZ~U<-}4x({^Qbo=lI(h1#J zU6Jm(?zZlsj?p``*e=6EZ`b?lgZ1_Fjr7s_R(Ox9hdx<9Sf8bAk}*raK)+PkB4e|D zm;OIVWZ8QX4T**chJ6Oc7-5`X+~qJnG4?P7n+BWKnQoc_&4V%Tchel`HrTC)p@(6$ z+jTb&OT49rVXkGLg>mm;@Nl1idFWf(nz{n^_y67gz%5>L<%|&QIS94>?}^cf5G| z@6VR~8wu?D-Stn3&yW7jy;vsyN%^1DpDq*Fg);WCf-Y;KI%UcS`c(f^9| zNof!|g9XP!$^!)t#ihJrx`M9+yRRY85LU+R4A)ROYliJn$|fS-&_y}FQyf!wdPejA zpiI2d6 zJ*b?9y}0t!AQ;U?ht0?ubw+oir%`3BWUOusG1fP}N^brlKmVHl#>LS`|AonDWlS*k zFeV!Z8?$~FYH|6GHRc#+8Rr@EiZ3rS78=+8&g);4W2KAd9T~uBx8I4;DA)Ws7kn{Y}y0 zl!l1mJXw)0jwk!lMZsBl7*@e{W@m`wS#md19ILpJxzj{!pfp2Fpr=0MdX_kWoERsn zoTG zXe5bktcfIaH2l%{N&3U8HZp6p7)yd3@aHi`v=F~B;$rf2j2Ptdvax}m2Zf}qman4lf*|PFb4tLn2clu z<%kjFmf)u)*%{Ud(j!;&FOwi7%|;?tB9R4S5PYK9PeszFis7VaD!q5H7(m5a$0cLS zbkUp49f8;ar{n6)-c}>Yn~p?wOSB^UiPm76>2R7pn=AW8GsMv(Z>D&Hx(TG;EOD9B z`*krvMMl0MMmu-BA+F}gzy+c&nY92CyuUyky=w46ktO+gSYuisVvsYAi0Lf3pD#8c z!HeLyZjtCmlOxcqR3_%dFw(L4hO^TW@f=I_CYpEzLf}PjLL#@{MCmBpZ<#P00zzW9K1S=(ujU6e@dUQt4A3oT8k2N8GRexDtXF}!I>dV44i z-oR}|71m6WcR;$qJ8=P5y+~r7RiZW(*|S6RLP(X#*&QhRn>&!4CgZ8LOoLXPSZEdU zW}uK!f3)PnLf1{+rF!Q@0~bl$PDpyiPSJ*df?Q77JH=p}`6@9f;nOG;7sy+5Rl}k# zR;5mOksUjcZs?qaBxWOxG+ttvfjU;SQ}j`8e@cDWcR>Imp*l-7^##eO$fR9RdX!-R zRj@kbh7+|RARoq)T?qJ*6RE+enVjB*d;Rhey6pN1L;+wQvE4C0G_ofcc8HdEeRP6W0_7tsN z=_42>_89o|_mEz-tR<6!`Nmy_0#-5|VEy9`8<9Z zU&ycLw_@AqL;MkJD*Y9IiT|Fz!~e>&DxJz*<*BNqs;&xA)mKHTUQ@MGb;T?no!=X- z8mG!p%~CB;EmhH(z4fZCsu;dCzejb*p*o^EsXC{+tT+^@uB&dVeo;Nf8U5$fdUXsh zs=Z*w@Rij8>QLAksH2qgICcAC_pUf5sr##kD(5kLwsIV+&QXpt@L_~2ynN+YpkAdM z*Qz(E9Wne4^?vnX_2=rZ)R)xPl?y*9<^%OpwIJw)d^3_DcnLB5GIJs9fAnw1RoB0N zsjbB2e?2;ITd)vZd{Z5v5p2<=LBti?T9>-ez!H?R9x#&?+hAdsFiLR1J_XDIZz%4I zgtvuvh4*3KChWtj$e-awp;ihn3c!F1ujT%Yg@YeX^>y~g$BYelwN|T`Jp-I*Z z)?{kN;FaW=n)!Gkx$MN*am^Q+82)R`70nNtdz!}@UK_(3fIIm8zb9TsuC5Ky*8hWR zrG9Dt|NMUwCCDhnjQxY)^ zP?w<_t(&Bqp_^Ci>lHHgpXL7*0)9oQD*6BGg8S1U{geMcEwWcE*;fnqpYs1p#rbMN zFXQVU{VyYo|A(UZNB{pHgkGk|pX+}s)neUprQ=)!bCa%>%BkC{`v~@9x-ZIfsONN- zadusIQ*pba`?buq82&e%TCdg92+Vq$-be2TdwcbI^9J)q^ZVva<`2vV%w^9UFP{F_ z&m1qL=D!}j*-=&)|NZFKJ6>8c|DD7*UZxoTo#;0>UZR&TM!!S(*>S}Dx!I5Z3cULN zapQBpWvX3irT?e>D;32biRW*3d*1&2XHf;|>*$;4o9o-?J7MappFT~Wtsk$?#isXp z`ekVQ3ia#tTe0c=A^mav7y7UDSM)#V@97`wd4s`V#b)=8Dux=E+G%K@Q#lc}RX1NtvSo$ks>Rnm*}VW?&soHHae}x_luQpre`~5$GEJ~v)`|Lf{hWW9 z<||-#{ejz0id$7Y+(5EN6T%fdAu}<9F%#KL+=wL;KVD|BDm&PyYX6 zfxe;!bT)Q2(n|TiwEq`=SJ$ruC~ zt>uj6i?3CFsh^TNs+aNcg)Ycg2dli$Yt4@C#(vQ+=x-@iYnlb|p4^}qFhpBc{>FB-o!{#bnb&o2*# z|IHYzWlUjOEtVShFxgH1rYfdjQ>eC*iC(FQEA>njOd(pkDZ&(MiZ^vJH8Zs|buc-) zo0^;Yng*FNO=CzC{!lAdm@M>1Zsws-kD z_?q~x}DY-j!BiF%Lr z)=p$bdjz0N)ZcE8G$(hkDiierQ6*SY%gomAO0X)k^*$uNBc{I(cEnuW^C|m;POj-m zWy;>4EbfG>e>86&*V$S;Z@;YzQiXYYf8yKKn(vyte=r;q;6**GDw5g_kz)c-nE($a zTn|KvOsh&KaV6@{ztrvd{JvNmKu=tK)tUZm(NCG_@Aa}te$g47WVNtlZXav$EPrBO z>oS5_e#se-Y>iNnj8tp1b91T{Q~lbCewaP2=odt84YH12rMLUBq)sKjsJt|5kTW{X zikbdfL#<7DhP9KlbVxxQW_^u(+zeCC&+7PT$O%6`J=sL(ua$ZKjTzQLXI`ci^Zpx$ zqwJM=e|t9Ol7q8R*ost+WJ9c~k=6^&%A>3mRKzjPI+=>^`E0-J3cFEVKbcIg<5!K` ztb?h1Ux(F7!W`DRWVFMYK(rI^zQ(J)2B5s_VRXF!vA%(y51mZ@mlp!oPqKdE)aF|8 zLV$LLl_jc~*5VfeX3w-f;G7d?TYXvQ!8z6f*4gI`E60&O^R45_)8Uw{|J~&Ojro|X zPK@`%>l@UtEO6@At0^1m{`*^_2lL$;v~u zD@uU+JU6b>yCG3uT6O-^%LFRb>4eh>rS%N&S>&OJALT*vFMY2df}oh5zgKWO4eewW zL5A%^(YP!o*1^Pos5O`zCsr*99Ew*qxP0qK*Hy)BbiTEK6y{sARMAnyn|Lj)5ok`97QpiaBetl`EFqKIDM-<-YLf*p3DS8cxXW`F96%lr+wIV&!Z(VA& z<8^~MR(sw6tF|mGN8Zm7s}gSws^9NkKv+K+jb5i52u_XGc zn}tmyJu{_>PA|JOk7WmtJB=l)GrqDE*uToBj6YL@31UK+aHbzyk7>k2FwL0eOdQjO zX~!fmotaC7x<4im-w#*$B_Oa9pDa47QybA~y`e8aTjikK_R zHRgNfCi4?>m-(4_$UH%!c~-;fSrcnvCDw!WX6>vmTaB&32C*S*I9r!(z&2r{*cdjJ zZOOJ}+p`_nu51ssH`|9zVF$2-*>pCOt-xioqu5H^Sk}Q#VsqIU?Cb1)Zmxr!&*rg< z**Dp@*%fRcznWdgZeTaDTi9*vE_N^bA$y2D%znmR;7+oq*{|6P>}B>EdxO2j-eG@c zAF@xd6m3)N;H=^FoQbn=66e8rb9T;`Tgg`A0=Sx7FxQv~=XNo5xrSU5E|QDkV!4)F zTdqCVk?X>Rb?16~_qj>j6mB{cA4^rE4OAkDNoM*p*~}zyB zm`%(!W+$_kIl+|GkSmIAP|Yww2VCVJTU^#V16@d8Inkd|Fj)>U4# zglO5&l8I5uq|6vq5m z>=ed~A)mc2m8(`uxu-r;g?0J82fqzp2#1C+hPcg^YB{!WH*FlVkK4kTH3P~O+kD$q zciEN&^{MQ#y&Zn79IyC0&;1t6 zY~jYpX3bddlC!RUc5bpmU2=LhWLeNHKUZXDxS=*x@lE$QcOSu6+uq6e+@)_VFT+wH z)$rV9b=cg1TYj}`sF(nrMs<(dD%v@3X% zs%%vu|5_z_g=MyIbgNgI3`q*WMiA82f~6aZP}?W$T5Op~Z5P<3xay!*J6GhvA+jyp zOz9WwLqu)A7w>1Z1skSa%KqMU6E{ioudegBShxy|qa@IK+{?jUyrt8bj39uqtb?D#Ps5vd3;0F+Tl`8a#PL4w zS3u9-~*}ve^3*IgN7gqyawVy zXV44u1%ttGFdj?=bFmjt{32MEgSB8Y*bNSVPr+Gm1>6R|0W>x7YM=*hKmwk?2UG$6 zpe6_f^+5!94YUW{K_VCcGQc=6tuBoDpa84{YrqD;W2uxy+!}6QZQNK_SzgOdmrE)6 zBSkBX{@yVvh7rfOz}SP~0X^?~?$@Ty==stRR+ZH%CCPbYffUO-tK>_!HQLOqq_pIu zjAUn%0%-?NxD}EQ-(pm2;4Tc*G1{=*`rZSN* z-Rw0;xs_78N>NzNnO+K2%rM0aSIiKY-I<#`dt! zWxK-k7HYz*EcnCyXCWMBb0&i!H&#lyd~0-eLkguZmA*}E2j{XvDT+g?hN6$7zEYSz zIJRX5FI;~2>dR{ZxXj%6T52w0j1aU-^3e^dlCo=hBLnXXJH9BC2|ZzqOk*KDT&^~X&N zJf$EihUv&y?HzGUg)2>9Bm(Y_BfYV2@sTFbY_F-@-vRDPIB&(=o7jp}SR+*-v1=rM zbtE#ML5ASG2~ERjc!@&<^wy-}AhR(Z=!Wx3Dht-IVVGc5Q!HJ>FpaQ?O&1)Ss2ZrE zROIv;X`m0yfAe-I4P2|Q_zhKs;TR~yV#O8GX05c8++8d6Qny7avq4aZO%Lxe!VpM1McYDoOw zll+X`nRl2K_MW(Vd;ppCp5&dBjPUIk4bfa>09xX%G6{k$24&(Z7h0~Vr6pOQlx++X zhM)AZLX51Zd6t- z?K#8T!5TBjB#Li1;-^;=Adfz{pGqbLBfx>WuVkbFrRX!Usw z%HT?&OHpV@E={L4Mb}C74N}eWNs2yEM^`aZTNa`mj#62)L8{7+VuFZfqf}{dfDnVi z3q^&B5vmCxSS+1^delU*P{oZ@6rbMh(m-nKfCQ&2ndr_K?IxulTz7Q9)gej(sq$CG zOTIKjh6zWtt%gO|$*ql&SEa#<`nmE-!&9oJ5*`%@Aj3CGRU!)@J(`3S47JhPRz-*_ z4zL;)91g?E?yj0OTDiFeWK&D=*9{p>V^WCxzEndqz$G%$_b4rSa~cXl9bk#KP-mP;jQ3#QaACGuFvqz~?*MMTwt zDv{F8Fqz~rl2KKu5Q^6h@a8J{j?lZ-N{W-9|NT)SbvH?syj>Y?fe>6a+5piCN0ote z+9ZXmyWp%bnX(B59gaHETt&s0394KSja~oNG+2XwhzOyX}F=bsv)9l z2sLelV~moN#;PW$xHM6bNNIGjtr^~vr*2V5azprVRdAPETUF!YJN!`^$AoC-n9WjM zw&(bOF(~|T_?1ihiylk^rcPyA@kgOjj)M58lp-O*TIhSJiX2F(^N z8#|hA+C;c2CaNYWzg4Q$nBG?6MD>mK1=)bgr2}rxMxZpKC4Ol8Pir>Sr8Z>hR%vKW zS7j^_TPkiCp@`7cjkr?as!0Qw!K8{)>Ks!N0*#TjHMLMUw0$gTji{hf5N~g^&7EP- zKn7gx4K3*;lr)r#>~%`jVq6UpLWZ|UG~P{$n~gTb%@WQ32>fKDU0f3N18HO+W7K~v z{_jnMNi^G}YC2je2gB0wIK}D1BL|dlsd^J zaZ{CH*-W&;M#7iv zmJ-O*-O^zFwK=WYFYI+~jY8Y7Yhf@{ey>y!pHNBO20B_uS5lBglJ-gy@hy(z(Xlq}UXKr6R~XhCJ~h@ z*x{cR><}DNAwJst(6Xd`svS*I+576_j5b#T;1?ztv`=bisQEk~=R5nP@~m4XZl*fo z8X(mmd-qG_$@TqGfai0+bf`ot#{l?Ef(-i}kZO{k15!Zm7(^S3+ByXP)Q_uUbtT2s zBheO?R}JxAH^jLkq3+7PL5FXtN?|yE^iq6l-{XQ){yOAPVEgLCM?m zxsWmPDU-r>#Qh^_VzZJ~ye2Y9vr1d?=b5A8NoK~gv|0=)%>W(3r7N19hAgF!?H@@g zq!%J1frq5#wOc@)>HjEYX!JZ)(DyPK8>B?%D)L)s45ojGavMQ(A4@5oF8K!)%iqLPI7kn}x_LDjs&(gmZd zIc$w4bp=Dxjz~U+D3tUirPazJH)f;REL4k*?U}S zW^#?J=s*)Kv-8<;sR~P?PDr5*X>O?m=#f?|*C1&$&XRCWC0rtHDrq`ep^Bk&AY{V{ zN!C#-9U-NW-6y1lCaNeypfawpZ12yJ&XNv}I;W92pCdW#ic<%Thq``7eI-L8tpOE& z5OF&x9Tf@?UmBD5g%m&8wx=W+Eo5=~h}zTplvKq~Mk>y6 zr=%Es68oiOC){Z%7^>sSz-XkIX3+IxqZXo}4ScQB5O<%`(kVAuYv>ONSK+rNZ$FT% zq{|tp2RU>`8c#Z%m3+zOGm=Q6&%zjeR_aFdUrC3^DO{-FYHz6=h9VkQH>lKZL^+E5 z_?1+HT>eTD-RMwx5F{`P6%JiDkNya(pMy0aVzBQx8?>*PBB^~}ogA6j~Yv~yg zZcCV%^SAhu+2^HLi%ZZY;%?25Q|F~NhCWEaVEo^M@XLQARdXhMBjH=%+zZlRi|dyW z9Z^tSNy7BX1aNQZHGyGO(6hs0Uj;Txfa;QXYRvYUJJlNlpT^yPzYu z407+1)SKA5_QhyISH|E_wi*vb6M(ijpw4vCs@S+cp)Qlw23#!8Bu zQ;6XThWWG$PQs-aMGagdKUZ7q>I)k{HkqXR6{!O`a0R)1dPNEj8GwjN8Vjm=v^u!j zCu*aEH`=GuT0_+{g&9GnUX?mjaJ4gb#ku7661Sn`nN^mF@mtAABEFRxxV!Yjj!r#oSEY)&Fo-RPsmp|tx4xC$A)T&C{^W9~MI;`#q3ex)ki5wFYtjPp;3^VZP~8$v z)>XG?iTEAr1ZSbb_)eNsp(GSK*m+(kw6wyQy2NlDqk_5LB7l0=rCp@eHA(Nhab1dM zNt+u|1X+GVlIqgFt|qchJ5lYk7)JN3WROiq^Ti@Y=+DOoG!ui!+doL2Wchum5fOfn z{Hszmp?MsDU@}oUR2f56sL<%*o8cIVE+~lf|3PX>cKjeMK*DJvLl`=;dNJXlOkHQ^ zo6`538`WAn>U2MtBM{}C8Wx!}`bml~rNN~{;7Md}jx0AU8MZ&aK!;$opQNK5+OQ5o z0SqYPMhlfbo=78a{v?fXHo7hKV9`d<=SM@)O;8Q%N9NzbXk5IDMyK9gX@^s|CoN^k zh5J&xGwNrl4@-7DkfO-x#- zD&1nqxf-&O1V5HGky9GE3%UGQYLMq8kt4huO?*|djl`?u2y!q- zw%`Xr5_v}@*J4vi+bME6k~>8W)J-l=HklDs zWolfGg!ckB*`L_mWIb8d5~n9{HovF9&5XT9K4f(QB{{#LfD*T%7I=8e>zwDkWr1}o`O!cJ zqOg<0vRtJ`DihW3-b5;msD5@l?#RZxG5rBefA+Xqe>#jw!z^qH>FgtaPtq&Oi(PpQ zw#$u3jvX?&Tu%0IF1E`@SQ70a2a!INHaDoZZ=$?M3$p%C%8 zYS7Qw)gZ*^DmD*tznYv=&NZN>ZM&;=clD{sWVpXPg-F$9FV!d}&O*|=AnidoC8t|L zjnk{k-Pjf6$EI=xa=kh(olHXbPpYHtv$^j!pHxSjo2eUDLvBMt1LVqN z1`VQL4Y@rzSpydu7@)kfN6ALEI^hH5c0{a&c+vu4EQe8!j<4v*`+4I;AE);rmBz@P zGMH4 zc!rz^UtexYPC$mvsQPj$S1ty_9s2Kjj_&$>g-38b}$=R)HaoU$mpgxy}tveJ#gwt+p2W5uk=_`sl>E? zV19vo*Ho@ZuJ%IyeeOYcThm|*+6CL#wP*|vP&aL4IyeYnOK;m8I*N44K=ShPQ#-S!d<;Asr^yy ztCLE(Q2Yte@*%Rki|m1}hn*^y*HBHt5XY7DlQFpYz%`?&p^rz>P%i9b+%&Q|1h$D9 zexo4bMlIw9YNfF!?jDFdE*f{mS!KO*LJN5`M*^)-2YWM{%F|U*U8Ps@gH|~szq}@Q zR@y=Ygn-yjRx$myg} zTgWP-E#i)%Nt@eNK0ppU&+gQCc?9ulC&!c1wJcsFFv!w?~s4O_wC&>FaBAr1&F6%5`Cwscc37#dYN1xP|{2r=?>Q;@k=qguqPUbrQD zS`8Z}jw)??!?ATiZA_7DLcOY!Bzv>On2Eb4^pUmB!ai~?e!LCCCI4jk5bHUB=3jw6 z+Hn1lqvOlLgv~+g{3Jy#Bv1Ou4M;+N=qGwdFEmP)He_x&ByoK$bdjoD+2SndFJI%x z^$-izbPBeFl4%2>hW7)JmtDbdYZXl69w^&+Dq4|j8w#C1<%g0jxQ<4pXb4nbxe+qI zaECTkdr-!SIk?ayP4;n)PLl)Cg$_mbRq3)Xxjq!q@J+|*#_f<@RJz=cG&m#a$;ouo z_yAhjSJ11z!(b#+Lq&~f7^`xI$q;9ToK0?RM-t9Oqs(s4LzV8e4JoXgDdTn4)IJdJ zcqc?wc{qjzD~8JxNOZPbM3QOs?lMAdMZ&AuBr>*%&FEY)LXN;YvZLT<#V8up7*xVT zqmVAuXt*65jhy+8kqgMxk+_;OnGOu;X%6+AJQmISrm+|Ysm4Jzc%(#zw?V_xe4KoN zng_HL5SbGi5~L!*?lu)Ue^J)wO_ryT zPbSOfiE0YX`V@H|{Wa!8nuJ&?lei#@xwHVaEYv?&u2O+MInBa2SE&)`Q(n*pC)$x3 zN&!caHq)TVC|ilt3AF?|`%RO5c(w((GYfTS@mN{Uqn4338>3Mym?}GIu%LqnydS{b0auj}bG=}!sjZnPt76>|M2~H1;MQ*p! zX9%mSLs=5v!_~R;G??n}vIzLIuS5J#`^X-7>)^DalFgggX|K`T&t@lW?m?Rp*CCL7 z>(EJMy(iCg`mdK~L21@QnYaClih_u+9M~qPVbQO!EwiA}Ktz&r^9DJBb9!u&532LF zp$kskj#~zAled!Q)K+;r~hdkZ>6=~};9Hsu0b}-&M;BQ4Xv}pWJ zoZ3Utk0e@QtZ9VYOxOXn&QC+CTkXIdr*_K8RF~0F?!wSIXD7XPmz+k{?8NE55ZvYy z3(;>3hMt{`hRwcPP9!UK%crP*`;cA%5XaSz@dIIV4b%_|&HLg#@;tJloXz5HwU>15 zuBUaaoz?fsEwQBDJ~^E<=z(S=alahLJC7eku1UW!sOD`xmN%(sr!}4Rn`(J6mXOAMe6H6vtf#ZTpay|*V23x^3+H_x*kCVb- zNYlFO@?y3>3ArLyCC$Ibz-em-M6~M)8lSXF@ZQAD=1V3GhtG%eAldr}%o%Z2zRfy2 zU6UJdBzLmxRh%bQYonQ=KSmH-C1S4z`K5i2?yCn)0xGY?dHj1>k47onV#oMTa3U`w z)g=240zGg?w&DANyC~PV?WpwbHk%GVbY0_PGOVV}O77mps4xDWe4C`+m)GD&48kw^ z8QBT`Szb;KS!}*|l_!Q&dVsdx_yEJs`@SgEpzTma`_Ito{0B%&;xA}=u0N1R(k9!F ztp7zmLgqGtGPK$*d-3@7Nh*mpYu+v>-m-FdV6g6?ynsF{K2*5fr9JZ&OL!;!z= zHM&K!ko5C+Af&m!A`0KCxEcDZB59A%*|h%+B8d1EnpdLO9;E0g(w_KO-a~?)z#kM$ zAhC~-(BL{y$?J4974!tRd4G=_7+G5aIm_DoNi;zTEqww5<1{^KqHtnK@#nrsC!2YwjgJ&*5<>L*cjQvX))Ro zS!*hDsm#v@+B1(Nqr7Y(&KV}#Wekqa;E`<_q)IkgY2hFi4FmP1rjeV#V7nGL}h zAJHEpD=-K>>}{(>PE|+Z?%HhgNJIeofxI-thgQc%Zqb2LuOP&SQLddlDTnmu(Gb0( zP>8)gMu{8iu?q)&-TQt^b^|1w!gVYdE3dE-}l1}sFtW(i;gdL_&RS;Uv%3){g{Mg+wDPs2ERtVLMsZCVA2cTKa?w zKef?{(dXZ^HNylvard)@(fC4XKXIFEt%|TLG7{UMnr#R1tzipx-mhkh<;eL!1m^9I zU>gP4ZjeqjY`sWyAfjIpXsc7LWFAUUMnpg-kX+5|3s(qR)7Fj&T|)Vx@2q9p<{Hrj1>4fl;nzipBvil^2u@2P8rZy?w?b`KRis~>&BJN0 zXUk_vvM+QX{VoPj<_5Nbtn24?IkK-Y?v0LwUZSt@AsbT=Nmd+ev)z%)f`-uFegTm2 zt!QdALZ*uv+v<@8wIPy?afmWkL;w*F(FUS)@e#wZ2-^hWO>0&}9q2@^#{!3v`-SR~>W zf?%XYB1SVUb6kycA_0?BB)bh#4@WG08HO~EZGdQ>dkk)CJ3zX`+xn1OZEgLWJK}BE z!ktT}*pj0w;EAE~<%R`6v^k=eL+%W9 ztJM>m1lqNYjx%W28Eg)y&o z&ync6A9lQsMQ4NPRO=}6lyO4PkA0`wYRjxW@=8DR7^(aTLmSfg(27J%JF@xDGc97}=k!9Ag z->Ip2TSv|B&D6Z9xI9o?65XiFhXOVA25NS+Q1cVT#iF?MP+XRB)crRVHMeVFhO*NX zCr%0O1M0+nq}*myZtJa>V--IamD`q(wx8O{JL)an?n68@jEQN2T&bB+{;ic<(Et`| zN=%|PF%4JN_m8VEF7(pzFOSbTKDy?7>{#vkH!y*GFyDxez-PAQjjqiD>++{`QkNz0 zA$2MFUjqAlF@T}3H4o+c^8@%a2fvZe;z#h~_$mA>ezj_y>Ro;VUTxmXS23T&9)q*_ zH?aKZQvRZOlm30x7FB@TJ9yc-KzRlF1AZs}5r3RN!(YJ5&lS0=_BBywjpIEght8T2mYu&6)SjC90VdaN(o!I6?^(Fz$`o9+7AJB-oW*Q^S z@?7RQND9!Em%gxG^K9vmE}AT61HP8x%paN@K05P{re@M9&#Go#TId<2>mY6SJZk;M zbBpP$$;X`Jv(dAWZkMTsG}^PT)KEI=8LNA2UFG?q^>b4dDN}lEI^fw|DrfHOW0mUY zj+mzVd~LmN3X@o77XO)%gZZx6J;FW0WqU8~y*LNGv=h4dF8`y*!MteRzjFUddfpe_ z==rYQyLP*59+~y=!3TB2*GrRF=A!v-KF6Fu(R8TLMawI;cgXK<)jE{8=WNT_wtBzIeN5eV z2A8UH$1BPbhk1(gZjSq z5o*I92WPRiM~!#g{h3EyQ=#^uaVR&)+R|FtWHP<4D$w?|Hnf(x+wnqb=y#cI(pM!QwM9RX{L3bN>(pdi8{0A6AvTPE9`;CQUC0)!Z63Kh}xbv z{TKLO@_&$gE&1g^-efwY{5Yj+=A}%&-v`OFx_ptmq{}t0Gx*4@m|E|XI-`&G@lx_J8J*ISP364_`Cos>Zt^OHYJS<|ITmpzNCP4UaDom+p3-{LWunK_#m#cepZXn5huDLZpM%5A*L zImI+}`i9Y2qo!8L{VZ$Z6n5!}OnFL++|L(}T{3^lmL>0Hb)4FA$}fw5T(l>vZsy+1 zTT8~}p2(k*TXWj8Db-h5`+dCV*GXS5`6A`}+%G4&=hn%ZmFf6k!=0Q~iz`m;y_i}2 z$&#kidT$t%+iuziDb~en^1quDIr+`Z!>ej<=rB2J!^|v_L-Ge^)?fTVZphU9#a~Q) zJ9qh#uDRKDE>DJ-S6qp)wvm_?sYu3A`ONz|gR3X^i)EbO>Qw@8)wjCe1q zmw!29%%m%mKb-VY;hZHKGOFgkK56!%-&UqB+Ay`*l6Q07pVX}1>#I^G_sSoev45&( zj(g$j8SJXYIW6;RmpTDt$fa2
Cy%~l9^bYWn$49{8phxSf;fv z=jo~OnT=)mcd7<)cZ?3f^zu5-F@0Metlf#}s!mpCsi&xCspo2zs0-BV)SK12)koFm z)jz7AsCmICRKzzfA8TI|+6sw6e_^nYA!t_1XhkD;8+~R$YVz+JDokbPWViXV=x#)z;+*8;|$wHb1qeIdb&0|KaRi zz@nRTG zj2;A%+lXjnj3HlA@{o~{hl)H@*dgN>r^v`d#wq&0o5AY)e}3oup6B=QeAZ{JcfIRf z@4D>EZ1!6F#?xab*T3ZO=Ggr|p?M!>R9D~N6gxb2Vt3~4Yo{vps~plZ#xzG+@ncsa z2OV-u!q!(a$4_6_@$YrBLu>xr-JLi_QwP2Kadd8{^e+MYF!kXZ7iv=23puU{8 zXZ_Bju0H#><-^-{V=vh!j}?vO`BAXM*~+Ib z&o3_jP&7f<$^J2j3ZM0$!qvJ*x{(_?H>7W%bf1r)LJfo_^stbMKek*t4nh-p0!sIw zJDjQTJ7=o2hN^1!hSxV7T`r!xT)Z;kkzu;epl_BhrCzvf<`vsVIkjPb2|E`?0+ z)p}+1qa2r=FYk=lN#($rcnIAgG@+lsH0(j+;gZ&aHrYJVeNGdk2})V^YAlq>`ZV-W zmiNvRJ9jUev0FBy*!L)>B|`@w9rQ=cGV5L2 zPi>>Tk9dJCOIzk+=t zmQZVWE&+>G?e6eg0|HSbW*q6V*c_D?;y?Y0rrd4v$iEDQge%e1pI?RPW=kcs4srW zYu-|T>9Et-dH96pyV%Fr4E7y{(Cla~G?PgRs=-vqpo*&i*alB%VB_001pK7$g0}?M|Mo0}dXjR-HkeL5 zLkXit(qE-@t$fbq2JNr#JjG->h#@h_fOJ4M;4mN$@DiW^Pz)#sQ~~}3^RfoG0dN}d zDxeE+4sa1ecrj*(3o1>slOwj(X0D)xAcf4KX*nKFR z{T(lVrPJp?mCZ&1?t?QZl0*N2MDO#yUa_Zuj0MQp4om}kX<*TljR<`KDWuK!yj{`% zdv1M4n^~S)ada2jZWxGEKp9NQLg0D|Ful(K0>Pmtpyr*xvw#dRm;;rVzqrHe!N|Q2 zczr7q`X^{k7zYV>7CxIsP3R;4;!Ujdj}FAI0)7USb>wRg;K_T<05J=-!=WKH zUjRSqi?=w4@Fxyw`#mpuhc)uQUH{`@(Fm@b2mA%_Dd0N*6YTH-0e~#9a|Cz^7#?Q^ zNT?aV&MbP!dr12)J>mtbPXKlU(g4Q+b$|}QAmFcnF9AORtgVp%4*=C8<5)ui&Ly}1 z%G0j4G!D+9HS>_mHh=yrZzIaJNFTRB0-grAKyE_|9!*{h#ciqSLXf9XT(#0MM?u3I zH0psLbxf`eBJ8#KzjsU|)VU9E1fT;n1Kt3<3%COif*mQ?eI3{gEG6w}_ztrz4c|mt z8MXCLb-67Pa2DX*(2B1o8=3gfe>q2e4tBl=tbzjWfX4t)fCRt`fUCBM@Groh0=~1Q z&QXb&#?m3LL0yHbkpKhW|K;$%L_=cCfI+}Dz;(bofSZ6103QMV2ABd+hyUM!X8_-N zLGS?Z6X0h6Y}XM3SGgG2ha(17(Z@Ig;F_Sp!+ppvtnfZ}OWW-2kbt#xq(%Y!Xc(>S5MdqGzt6MON3*_!Qki-u_uX7klOoJ}J zT#O{X32+VqeLj*HzY0m*4&~f(k;HW1t5Haz1K3c5d=Z>+f%4xTL=uCpBZfibz#L!=`F96=Cv~2I|KdB~`70-) zAHhR=E)wuB@R*Xv{B|bdlXo3))yfoJ3o7uxm6}+JS1wonT(}yLnNIlUE9Z+BAX5*3 zJ0G|T<~ZTc{&oROPPTN+MaXu9?Dzj*=N#CX0a(Fl{%tyS|MS1^eez&%HiLUrz~R8L z(3-O_<4-}?zYiD(d{Tln~+tCBO+cFq9_xaMHFDjjmcA6=E^L2Ts+Ct*-o zM~$JBoO6N0`}cG4pevrd(gVJrCj*s(-9FKAUC_=yQ2Q{L5x5xu*fOE4-f`; z2A~FL0gZr991!7Wz{y}t1;$sJP%iwf2^*o>$DNRXT~3xJob~vv30e@J0z7VMf*0;d z28eLcADZy92v1(QoD72E7Ertm{HO_LCq($Y)AHqH`+vL6)_`a2fd2t}2>1tJ3BUzg zUVs#^lL5Q{ya>F~itTJTNzTde%9VSBr=j}ycu2tCd6uT!^~Cd5X3sN_#l?|;L%>1g z-@P8qo-e$9YrtB_&VlS*z>gZ>k3+ZN%MIB2-x?r0Kx#f0cn8a&i_|)t)TV>;3i-i@GpQBAFj!Ob%02~Gk{D$A>U#y z@;}euc2Ij0a0@U4_z3|2NDdGKHUhQ*o&)3nO3Y6N<2H|e;}pPPr8AM5J+7AFrheo6 zmqVo+3=9D#0N(%*SLjiI4`4GO-4zjL1D64efIm($_2%Cu*V^aqxvd=Xq4?y= zMY<2f?*Zb;9bx$AE62sRAV`5S9Kr9?>Yf`S6vJk+aR2#Vr`1((<72?L02IzIeP zb3ugXVK|;Pa0rE4;ULEKJg(G-z_?RdDmMR7M|!~q_e^<^Q6F_2zE7H!AV#1^G}AlUy0 zrIzQA#AhMB8!Wnz9?`g%4A_B3t(Z)MoD9IDx|1M&6f_A+)04cq0}olz%!8a40gozw zJReESf^;M47LDf!EtMC8pzIGyVjhxs9MXeAvNsw(wqmLVBqsrnDy@L{^m3)OG2mXy zPMl6=?8HM>TGRyDrvZ;@e!?C}G*D>|szu91?(f8-Tr4hhKu$N{k?}JS_ary(gw`C7 z!9!QHUI%IaAGCTPzJ=0~l1njo_=?t5kiPu~tv4Z_X3^5_`c3P7kly-()(FIP~y}eUSbDc+}h_xbgcM(gEbl zd+_%)-&_4;waWSf_TSjE>_s-69hIj4cs#5oI} zkGaIT#(AIfG3PF4p0mI~;lnXpE1{L2)f%fOtdv$!R!_q>V-8xWt&Uk8hi}HzTD4of z24A4RVfCriw^skMqFZy}qx0*nw_ESB{*(274J{Qu&~7rFf~njB$5}5R7`%HEcogs? z#BT$C4cG+nAAuP{xZk117gz>Z2k~IwEr4erz7IGZ@Dju|z*T_L5N`#(2)GLIzW{#> z(9A$$79tM;ESLe-9&m*K_(0qr_({Nah{pgY05Tz-1FQk)AzlaE0=NM2e&FkXFTl|c zfd3Bo65{uP5fPl{A#MXK1gsSy!i^$?8xRSJ1;~g6P6P5TT2{PwT_-2y74}b6nEqBOS0|*D~{f}CQA*U432Y0(_ygdLn@A!b9@4!B@qCy<@cb-B0*<9a@BRdgQ^vtbZ(x(@q=G3DOif$f zVylHMdX}awfbA#|ctH($tI<4`h)-eW{)0Hjo_k=;V@T$KHEXG09TfzTLr3t-nvCbO zQ?u01hh-glKK#HD*mDjd$mTF)^HyZ@E@U%omGum=c`p*W9SPlmgoPnt+mNtl5al*R zxf6+0B9XA3cqsJY~jPX`?nuB0^30x-oH8bKoSxfhorr*EF#~|!~G=Tkw^qA?LVO2 zADy0+g=~TLgdv9y?GJxG5BA;5UoJ#$IEwrFBxPDuUQp*+a``isk^ z&0|M#l%_!tSnmlVvlR)4FaqBGqjqwOg)n@1Up~t&h+)g|aM;y{(xf(`*|sd%0oxQH z@DF%uAE{6%M}?8g;Z_L4K$o&fNuUW3ZdrblFdCNBQoCC{i@^54&n{ zphbn$7K6%V{YcoG<;|CHF^e*>1BoM@kK>+Z<#F5={(l4IDQi2R11J~wLKCQN$%jr# z1CEB>Q>X^VgH@`rTfu9p>D!P(1LP2D71aq;11{(s^D&@Vh{QK%eV_85D7v8N&5m^{3Kbo zph{8IP@7`yUe=&EZrQE9;8+BCtpN8~w+^-*2mqChV0Ha6!!8WK)bLR)fgT4l)PQY+ zxTU30GZODc(~w2gN%3xSvj%r?dKLzj8ro;U9L3a-Za4o8vQY9!5pG9bD#E$q z_0T=k>$V%<4}pCe0+u_C;mq+7vkGsgI224#v+*gFVl9#LC`9)0;?uBk3uNC3$9@IF%&K1k!LRC$T6UA#* zIEehZ2tNwi2ekN8Y)VRv=0>tri~F-FWok$R$=YhD;jR`xPNo*)ULI7&2GFD$vH?^q zX^WGT*Fj`!G45_pwU?R{8<%-Kc)AsQCsS*2q4`(|K8Kmrui%ZS*|q||g_&ng;NvJf zHKX>gcx<_^D5fS_1>=m&{b6oXa_2dxya%xvno*+`;#+|%3Q&&HKJVyVEqc`GSklXO z>5#FJd{&P~uCa`9z;Zci@=@g|rt~SM8bUEuj^d4Ew;n(0O;tlVXHnm{Tn&}B6tlFS zO0OrqtMQZrlp57%R5rzwRf;LA6jQAX0;i~Mq?q!GVoN!T_f*=V56&;=Te_Q?P=RE3 zHU2UhK)To9-Wtj|sti?{VyX`)rfR2{s-2pr7ClSfQnnwZE#)kIOvx?!mOiHDvt@o; zyrj|=eT#RH=75N*0D6V2sKL*ZA+@;7Tv>~^F=(-Hx$!1(sX30s?_p-85x-|m26f_7 zj8r&fA2Zu`;VcIFJZXO({|CCp{QY@+HD+FQ5r2rH8Rnl}!;h|JQCneBEzZ1#?`9o> z3kb}5@||n=FXY%Tu4Ju&OsZ!4w{agAi!Rmf!?60A0s^n#=fg|+DdbbX+Pjd2@8V2z z%-eV_YQA|L7htQ8Kx?V?QG24nVPO7h1h>b~Ao9l>_%pB|R88)B7k48=KfxWz%6IW- z8g)+k@LhZ>i(0Dr82r9>9>qQEDYqV5?oUfB2v%ef4(R#@lyGsk%oeHwYC=&vAm&1E zQA1AI2sCdU#lOSQT(kfC_%AGTzyxlGn)iHyo2nZci@ zo8|w+`Al>4_joGHeDxuIpFs{R;h(Xn%?MyeD)Qv7xF16edu^!5E5E|8zlZjOBf6IK z;Sz3SESDhcseYnn2DP~^6$>Ko;DmF7g5c5C!j%6wfY?Z*u8|wp5N-`hg5RJbM9`Wl z0%uWM>cdVu4XuP9;}GmYk@?2E#14#<(+I7(pGKsz$qh^Pu~bu*ibUPkR%)=&-ZH8h9+!>PI-x$e{p2=tLbkma(-MphkJE zdB+-}8a2-Z5}`C$$3$(3kZP6&5x-cOeM5;n8l3v6qp1L<)tLyw#e-Tpv>z^b)ZLvW z9t{^$YUjTrAm4$+lOIG7PM&*~?~O8G#=#c!5N+J*z^Zp9 z<=Z?0a$zrqi!Ep8m5FbzM4qFAKgQ~ z8cB%Jr^zdk#76QVcuPKrB!bDQt;7*BFN)|QlXemWDcD93?1R)ihPfR`KDCW-qJ<*Q zkXaB}9sY+(BB{m0TL=%@R_K9~+Xyi^vxVT1tF{uh&U=5We)n=0THM+LeS&W#*1@#i z54T;BWaL(&h!z8PByVjcT>g{|&B=vEQF~Wf8XX2&kK&Qbce{@Uh`O7y#P=)@9JQ?* zwOJH(rlU4dp)R#lCsA?gBD>LiYCCZaBX8ysuoibGp`&ev`nQ4CHq?#NqoLeQvSNtG z(QtA-{Io=)$(=DUYFD90$U`xNjGWvCou-Q+U|H98LQZ=cd6pz&2yYfO->AJWufz~f zu`O=FZ7ca>4B<}(?jmX;si~R)Cok$AiJIe&;?!ie#96)rw~=-_Edr}oPl;^ zrxLLYYU`>b@=hw@u{wRZyQyQ2+IT04^h_fn$^0}zXzoZOL~QdnxdiONslEn96-SA3 zQuGSM`i~OfB=Z=tk5nHc2>6o6BM;$NCSN*6c#yYu!4ZG@7@T{-wl^ zs5#^nViku?{TxYwLpI$UR!dmHMk?l=bwng;ZaYcb<)BB%SDJ~($;oCIPy)KdyyXnR zMHy@0?6ASSzlGRMV`qQ?H4Kc}eBo81lLiK!=_DSfnc@AR9&0qvoMk5bY3PgQGXn&T zLH51{9X|UOVGU>G)mI50v+^nd`zz?K5%p&IFma0w+oDkC#Tc={d}NF`O(O;4gpr&chqTv+1fOn>`Gkcj^Xf9bGCQ)e3{)faNp%Q4WoHDC$p5VvUj9;0l0-ShvK{+>^jbi8UQPw6^cwCG|QNc?>9cf~(C@Vk^M zxEbE-dQ>r$K34um$A8cJKgBE+|DST;AH|Q1{%>>J{zA!54ga41pN(M1{kJCn;2sTZ z<_m5O{9cxZyhoEUdadEXDjHij4xEk5(`T*Wp~W-krt~2Yyq=y=h{0=(tTdI?2&73& zR5%L!3|3z_54<14tR{fZr0gvm20n}^)0cot(^Q3Xz+uRy!bRX;lC_1lVCT*B2oLzPB;3(P)PeAH5nq{tw_H{0el=uvWf=&OL|{nJn(MpLE#XT-<&#B*ay5F zVOj-(JTi5nFbVj*^zuR_um-tYXwcATh!$B)%?Cj#a;vZa*d}eXPzy}MOqy8W6KS6n z#sRye_-57tJEUzXG5~Kw<1+hztuStp9{3=(r>Gxzb;=ao2zC`nFQ*OCe@%}s8UU_M z3(qtH|2^fR#svHrdOuCm43YI2QJF))WZJ&WQQ$C4#7Kg!dNLz5a{|(TOAE{#0p5vx zq?rW%Bt5jK44wo2BPFqj$pnXx(;3qsug0P|v%pu9qd4=xJj94D06&$|maz!zoOUrK z1bXt%Y164okhVd*G=-Qg4cU=;FO>;=6wS{R0Ixxo=v+$v&af39I3i^sjR)*>=^~mI@^_`ktb!r!i4|rB0dtTUngUpl zOw&SuHJE0B77CGnCSwdG@Ym_5i=v@|wa6kZ8q%w=Sy~zJcj@z1vA`ZFv79(y_cV;2 z09=b0inPGev?ZDf_#oPqkp!HA4Qi5s+f!tjxxn9{YEA)gF*ZTVwWA@grj=zXp@(BN z$gpM}JiU_^XQc)OpR~$M9q{gJ9Qp#tcVf951Ej+;m~bs~JfDloCXn2Hp#w@0bN9ks$gU@SWtw%z5A+(TkZ2z(&N75e?QUwyWXzM>95LPJyB;5=>u$ z7C(;lXL3OS$9gkj!5}L`ZN-PQ86DyXfQ!+POcAh6#$YB7cx&3F3?}GZL6z{n5Dht( zGRz4EejDv7>H~WT@RK!UJ7fgYxZnUIb&N9r`Ol;z(DfkiK;r1}8i-h>M$_wnyVH{B3BZ3!iKQEW ze@s@>^ME~5a_Mnk;1FVK)duOqDA%e3*g1o5Wdi;xSxfH)zK~Wx4+6dKlb1OCkPb%5 z=tID7p;t3vpv(N?p-Sy-Nx8p^q6L|FwwMc2~et>!@9 zjVL)w!0BkL)dH}0s={gtcz3EnLtlhQ3UV`p0~K6B1pE%7rpbUu5d}jId;zhX58g*|X$nZ+LIN3qz#k%cv>@OKB%c-x z{5ND44FP@+)g)MjLL?HM(L@73jtDX(>Zi$-wJUC+W?=St-NxWXSi)=%D98`h}D}s}bmlf1{&T`H+4N?X@xjzmzgW z*8-o=V10BIWf1MBt3klRM(KP=J76PL32gS<3DNy`QK9dypB4$|+W&7}^5 z;iuES(CFb*{3J3>H-Y@QvB@z;6CJuqFG>C3X?GhoQ2M71fc(6axAR?_y<&EwE*%h*Eoza437V;8C=F9 z2r>~KgJ}=<0cakF1N>r|iEa!0ej3-B2dqh(E93(=joLDTz_EAG5xM}9-^n^p>X{F6A5AjgJ2G+ zqlE&0j|4N6zz>iRMilUmh|xM4ScEiN#{w@Rp^P}-YPOOghl<{!MKR(b{R`4&odA4- z-C>;sjG!j#IvAQ)*kj$vkfx#03>7dFjb*5T*=QUiR|Ao^X-B1bz}9FyBOmxNtk^3M z46jBL7zL2#q60K7@Q3JtRUODTA;H#VkbVV?E-Hhb_!Jc}^pJihd5j(h=~q%htqqWV z1BuIQgC3|#>9^{D^ar#g#uyDlk{R>x;W`x~AL1G{w?14GIfDp&xoW9T7Q&u9nzItKOmLL;LLB+ZOah_^9nK(m99=Lzos zFybT_(#x<7$B=$TD69z|U_?PU%=i%G2AT;hjA$66UKldU(1M9EMkJURXZU7f$OJiV#X+$xE%WQ)jI;GJ=H33I#(PRx`wHSvm;0EG0O{V;LaMXWayS5laoO$XLk` z%30$eNk(r&s9;4w*+ABl5*S2QG{l2h38141VNF8eP}VSnN>&GiQLG^dqgkU6#Jtz!j4sMoM!!DtBq%V6av^SHQQv`VX2pY~jWq%$I#_uS znpkmAs+Uy&@;+7q#QRxt(5yrCAQ@oQL8!1dKxjZ^Adf<|5FcX2gXS=+4B{g!6=ea{ z=pdm&lOQpL9+kp)vyvgMM%54oVo6YVj3t1ujWz}qkF#dbGNj*nzOxbG1>cG`Ot3y_Yt{!G`u-MhMSn_JsYVGQ>)jIYt&A7UGbr3eNdTjN?>gm;( zozgDKF4iu|PGzS<3+!}u@vH=v!EV@Y%x=O?Gif((r^OWLlAVEt*>mkh_I<2=)?(2R zON7a=5PRq-bQHc9Jjzm|dQ4}JXzT0^m;y7}H`}+_o9uh-Pr(UQ#ZWVH8F`F+Mlf2y z&@##xaGqq;F^r66MjNApVPf<$1{lK(18sz%vl(NIGbR|5jA_QKhB3!jU@S707#Neo zv}JOcJSLwhV2a?IWD5A0S~D8NgwqW(6h4y_#f)XfG2@vD%p_(Tn#@!&)v!!7kD1Sm zM+=x*W*Jk*)H4&%F|>|pU>cdt%r<5R6OMRhAG4o1jt((Ln4`>Q+8A>J9cL=h3FahI zGsPUDO*3bh9q^guS>_z9GF@OUGMAVbi^<}!Y*}0ukHu$+STdHJm5eG_fvg}_Fe`)= z%2KkTSkbIlSc_VKCb5!XHL9AG%gSTrvkF)yRLd%3=~#MJ9cvObvYJ_KtPWVH+RKVU zhgrSo7^{so&f11dYwYLjcS?2KI&L$!jr(ER6nC1Nq)JugJD41<$)+4;9A+Kv$T&`$ z!V;XOo%p;SPaSWT$H4>f5Ii1_BM{R+*b?tXuL*WMcZ#5t=*$NkrA&=)Fx{O?1$_#w1_lUTcXuzhwW=L zT7!1P{N#fZ;I!O9~Lha(@X41tZ2NF#uV2QQHiqT6Ks1)Y{}k|Gwg(t zLnYZIc_qh7v?b*w`jSt=>Pu*z#*&tj&%!!N`btJiZk0@OCrUmmnJ)QWBe_>HS3*i2 zlq{AYrOZ<6Qf?_xDkznd%1Z-EgGy((Pn6DbLrb@mMwi}U?jQ>Cy}Aw$deTS1IPebl^DHI&d9$4m&($4sr*D!}*-H!{5A2Wf#l( z%b4D64jm4IWxWo44*d=blHsxeharbyhm7(OhnLV%hurdl@{;n&Ze4jzxuN`Yxmq>m zkQz4b&{jU-&{f`BeyQBbD@!s^ezkn0{D^AO;b!@G`R#Ig;Z*tEayze&u1q^*d(M{M zFJCDCxg4ulRiUx1aID~02rK3s<{d_4yS!u-z7-1&iw;W;ffXAnFvpOJ@QSDkrejP6 z$1$$L*3rppUj^4OsUo#PU2&u$zoM|>Jy}^rWd+Z%uA;Gm@5m{P2opFqS44%~>lQhl zt&lmID&&qAEBY%Gj)N7$722>s#~{aG#~T$Pj-if9jpJBFlw-7Gtm8)&agOnhr`QRO zlNCvh$&M;VwPUVhp5sFmFFoIJZ7#OzJ8al-#BtPd%yHat!g12^VTH_Uhio_)Y?+BVGx*ucSoSAzi-eImt%@*}6QP$f+*nMX%$!^i-{Gx2#;J z*U6mZPVZo|QU!eeAjm1$Da0w%N$C{j1Y7rd*Xv@PjJi0dc&8+%7G1Iv?1NnBgsPoj z%VDS2v3#cj__nmxsm!TEr*nEGOs{dOb22#f=!{NAt#t8tWV51%{t9F%{#q{eJ&wR zJaOXo3EN7?N&!#Ad(BhE`xN6>3M=J2S*35Kf)}R>tPJD@@q&39DnlwYA-wR)sLD`Y zOr?_NsEXo6^I~~%mHR4_DpM=fl}9S`EBig;c!ibmyaZknFEgyHGMV>mYGq|zrHZHK zmPS+%_?wrX#c442~yJO~fQ?|Fsd z2~|ow3XjHP@i@F0+ld~kqNl5>67VEE8PBfLsBkr&i|66LhUQfruhLePSLv(r@%k!b zRZCT+ssL~E>Zt0e>Z`h3HB@!IN{g4_brKz}$LnwdZp25cn(0_#Fy~Dcwz*T;1I>td_q8o2tqF-trLuC^1Hi6BEQFF-1%hGsG-$RX;}r z%YOD6(a#e%_2c>}{Q_}Uqo36;68H5>#DX4kW;%16ZJoK!KkKn-q=@Idsyfb#?<{Z@ zIm?{o&bHN#)%IgzAE3jz**~D<{VY6bB?LjJI7UP_EjfUr&iZF8=OyJM%Y=d z&AG$bTFFM)g?rN7a+n zF6bB4Gu5kU-&DUMeOS$rE>+WO7*bA+T@A0swI(xT##vP3Rimg`TN7Nfsm9w|S+l(+ zw#FfRZ_Oc1%{hsxCcEZaue_Q{>G2wEO?l0)n7*dIW?EvbX{niY?x+z+dusY>F4qjz zT(23enRmWbGf}hP{8`PS^K{LsoFthfma2h6!pV zwE?xZd@i5I=ko>ppxP&DLuKZ!rP%20c{wyU67+g)Sf5;P>ylB=b;+$iR$owGQm?E3YM`dx zP`^#uR?qe9s_(78R6kIEwSJ`jX1!*-{&xLT{oVSDlKb^P*JBMYOC1~d4FwWmgRH@~ zLE#eUa)lk(u%RKO!C4yB5ZAD;Aww4D67P~DOK>?QO=?JO2ntg-9BIgJC~PQeNOGxc zXl!V1INM-qxY&^Fa$1rnQ@L=`-Mwx!j5U1JFxl`$gI~%_!#53Tm-&W=4NIB^j=|1Q z=E5`RT=XukhB_CK!Qf(axi0ZCC=AUmYYlBK9WKEJlS{8llxmYfY1nRfD2p}px$HG0 z7*@#+8B~UoUi~fuE<-MPhGCZxmr)m!YRqNa<+x$OMQfOJnQ|#N=nc~@GcNC8^#-G1 z)@9CR-bKOgz*-E8E}A8mZ#^+rrfY|R<0|p$F*wj{UAeA2SH7#jRpi=dkh#iT6|R>J z-d=&OqOd^KkRix5*tNpzx*^ncv2fII%P?X1%rI@ZXHdFExy~7)U1MG2T;p9I7;xI6 zA;C4tHQ5y*nWQzzB@bWw{B3w+gOreRQst_4&3-39L*}~Xx#qjxl>Sv(;QD;(r&6t} zK0Szhf(#{fu1{wuy!5Vhu3N}x(%`y>j3yYcPYm}^n)R8r$fjmvlxVDj9Td(e1Y5;U<@(} z1R{Y<;O{9HJYiG_0tG>WU_q!c+883(V+<821yO={W1=xyzz&NQI7*X^8OAt4vRAwy zL69U!7N`VjL9QTAuqHg$c+6N}ED&e~WdfZ*FIem88&)SU2p;p&8I6KwL7SjMU=nPX z)EEuMUX7s5*k$ZBvS=H;`UL%g0l|=9STG_O6^seS1rve+$tB}}@v3pe*yDB6IBvXc zoHE`u{#!C@yl-4E{%o8S7}@Iu4=Vyb!_Fg z3R_)hvetZe-&U4qV5_xffxA0xLu*JY>K)!1)f&?p*IJRPb>G*T)LJMjbJw}2w(8wW zWp(aPNY$-JTJu{ATMh1It(C2ft!G;`uAZjWi>;fb{jGzo!>u=3d7cSjW33;xPPVqW zf6+SA+Tnf$`=<4Z*L>^4)684o3^dIP2ct@d%%6jy}oVOeZ+m#-PktfKJKoQO}J0Gx3o>UceG8r&wDm&*c#6g z&mTQ!+<*3LlFhpJwOwv&mTmOx!|q`7XZvXn&%P>~bDwwb#}?cd-CxXj*u8Z2yKZ{> zl6$iT6EcOIcDr_tkk=mKX)APX=L)-IqIR!#zEB{v4LdJWw2OpqOJqX1P$3Kywy}eR zUt(+9gWD@SH?^Z)%Jx2)CRi9EWO|id4;2nzO5yhQC}Fg4P!=nU6MiR+7v`iU35T%Q z_Py;1?T6Zvg({(1_!c|6J+J+E`}Ncj;i$0FtGr#`esg%+jr#U6;keM)-qPODJ|UbG z_O$o4Uv8fgP77y*R^G<+S>c>;UO3dgAbdQmLAofs-o7NnG#>wCkG9`xpJ@NAeY*W# zd$o+|!SS&5m}?(YaXok*584;o;n8ge-$USG-68UjdB{B!9)TV~9tB>(9w8nbY;Fh9 z5$Yl6P<|ljMXn)+5d%-Xp4@&w(-Gg1 z= zq2qK%fk#`1)}zcr=h4-n_o(ye?J#&;>KN#_+F|r)_Gt6y@GyCdbc|uW9(^AD9ydD% zJjOf5vD+OJ*i^^ejvJNnp|rgPY1#ADQB%wybR!ei27%46DN#$#3I ztcPvqoQGrQB*yQY_Yih2cr1D>d7Q&Ak*t#`^6d=l>}PXCwj!=*LnrJ!EfR=CqL9w; z&ZthANG^)$REPpaL87?MeVs|21MJk!V3E4>NN0X$VP}XaRHPJ@bw-JzMX@4HoG3w5 z*;&__BuW;kM2(%zooZ38=xnE{^I~V7sK0ZtbGY+HXMt#}^P|qm&M!J=I<=xHtW5Mx z=QK9oImFh99(L+Qb)uzCgNWWWgBeB5qBc>7$Rz3&^@;jLoG!br0nw0X78@3ghf(tp8eg2gdw+boF&z?urr*bw!J>cg2e1#G_sD zVkRv?e5-4eJ;t8s`m8HSd`U9SP8LtFC)v|o_qyh~9&{~ssl;mW7SCL9o;Y8ObThjP z#9DEg*t%OM){E=J2C-4xEN&Bj$L4ku-Gc58F^6Un_lo<(Q|xJWzj#0_=@y}KP4|#E zpnF*SPfUQ0h@;U_aZvXY-J#v#su}i}cuV)VIJ(=Gwx`?6JHC5DJSm(iX%#+M+nO`&jpq7?Ut11>GFUo05|57Riu=PZQ8|-8J2Y?$h0! zn5~2>Y3t@mX4xW%OrnuX6p}f1poE4@@z1LG5^H$TNQ;DF)tDasQGNmb;d&VR5d9Q= z10j&hMY9?AGZr$2imn%7nX58wGe?UYGbfVynZnGzqH)@-qIp;wzH|8iBBxwx)bNH?lPmF`Kg?EPcgufPkC(S2q_qD%-??*?& zzYM<@{%!b^X+NdRhu=y5IUJ2RgSunSA_%33u)gc zhep_^;;9<9R2S@xw77`pA`&CKQ+KDPz(2(!(Z^9A^k7PHM0rG2#5-wq5!s& z5q9wZ-g6POlq~eaBQA!H>c&Z5gLHP>$PVy@$RVg%t zFu9v#rbZ+-Ji+^!@RI`vy~D1gdS`m)dgq59^?qG5uoU{9lxBKIa@@Pfd#9w#`@Hmo z_bq9S_lbd111G~@y3*in^giSL-oU>H`oph;UkyL&-R*r)((C=)l@G!{3V+@EvNy-{ zxA0E~Xkk;~|Kq(X%qHxn1`MBS8v*t;(-b8PrdC; zUwD7zJ?s6Qx8|{k2i`w)7e z%j70rGY7=OcpUgVLwu;qtBWX!&mW$I^m`VaYXVv~;iBHSF;#f08H3Q{+}x z$Ow1z{7*Q(!VIWtc)5xpk36fO!3DYERmcJ_Rl8;Ew z%dbbg8!;V0N5&#PjJO@~dBm&8VdXL9%Sx^C6=h*qrLtCOP@Yn@DBG3!CX@1l@{;mR z<&g4ixg;j^WylsoDK1{o9hwPPYmD_5!We03nGo*WR&4^Rz zno(Wkn(b?D>2|G&TQlzT+?okp;+p5zOzTu@?&-4D%;}D-d2vm^iJ%h;nk^@yPwY97 zd?MpS?ulb33Qk~!H78aTIu>@F=sm$NymVsV#MKicCvIv^jGtII@p4S_h4u?Q7hb z)qJ&3EmQld1JxVUA?k2-lsZOzGbK*FPo1QWF+F3-Fda6%C%+~CSUxGgBfl&ET0STL zLHOnQ; zGpuI$+)$6H=cFI0C)Ho5XVl-Q=hY9@m0n9~iHe@Z$+FAhWw~aFvb?esS)WSQW(8+$ z%2H-+&yuTRv-V~sWF5--LZZsb&dSR=p7oXFC8;*6*2~%_KvkZl&#KQdX0>E>Wc6hA zW!d{^E@us8UC$B@j%MA;n#lSrYdWh?dM|4(>x|?<)?yZt&CKTcSZ8yyiEKf(B-_PD zo_#jmYcL=?DEo=*?@bR)%yTy99M8F&6P@!u7jTYK5}LgwJ34z$c6@eXc5-$`c5e3V zlpxiy?1JowbKB2t7%a)wW!GdIvQKBXWp`!wYO*h74`g4>9?8C$J)V6#d(+@l_TB8+ z?EBdZ**|AvIjeGPa~yN{Il`PLRI(i3oWPt7IUzaWIZ-(=IdM6ms(m?0Iq~NXoJ&2I zcTVUd^(i^`gH-P0@3YqDp>(59h|e$5FrO_xm~4kntj{w(`+Vxo9q>u^N%zV2dBG>& zN8_U@@u~39`<(P?^!c+7OV(3zE43%}a>@0QHlI$P9-r5I-agmwbH(SX&tH5-eLnE{ z$mef9qv!s5Zp!CNpL;&v`rJNu=iI!{k3K*9puS9BD_=WbCttp=yRXF8+gIUhEqly& zgYO$DPx^-XM*42|-Q^qS`}@muY;v&YfT*-zjn_Ve=d^9%G_ z@Arh?X1`FSUtG^NzZk!#{o?)h`yKL2^HcjB_B-ZxB>?97k;)$hd~x`M5+Rmf!y3PRzgxX>+9cq)7q zYZO6>#})pvO^OIblwz%Hr(%y{qwHBlg5sbeRgtO4RUB0uR}?AA6ekoliUx&I5h5dR zZFY9lyw-EM=dGTRp7(n`>M6`A%c;z%%Q2-k<}~M=%`xR%%<0b=%o)zPk@Hu@Sk6Z| zlR01H%;bENGoQ0X^)P2Chn~yHwaew@y5@>b<~Gpt$Gk+M0~JZnPnse*Cd`uruY zMb;OJuN1S2?-UOdKPi?JH2+opHvU|H+~3uINyGX{;^EIfFZ1{D5Aa{-|E5>a`C$LO zgQR&S$?cX@K+rMS7S=u%Ds`TREkk{qGx4mu+c1dp!?)Cp- z@P^mD!S}uH5B|wN$v?$E!#~GA&;KR=LjO{Koqx4|z5i}$lmA|6tSs?-%K2wx&HgW( zFFvn3uW3Ag=6uKb^XD&}A3p!?`CI2dIX`v&i;9_wwYfi>|E6NT;#L1H|MUKR{$~F{ z|7-pu{_pwU^8eU>(*KVCUH`BBgL60KDs$)jfAHU)%Ut!){}=z*Tr7YUU>#r|zzf)$ z>k=Rg*e6TKl?MEOti5+YR7cl8J}e6^sECLNs7MH9QKPWH0=v{j=}VK|71#oc8hXDV z28bjUutkanh*4Cemqn@#ON=qb7&XS&V$>L8j4^8TH*;t2?rO~QKJWYe{c|}?IdkTm zGv~~`d+%qGGg32FXXIoQWvt1VZ?)LU*2>Y!#ma-QN;mVi;#-ASEoh6d(qzP1Ew>U_ zX)#!BX;zMH*;a0C%gqa{2&=VLA6l)q$}p?7+HUnVGt{iXs>$ketA5dbE3dW=t6r-? zt5K^Yv!hlzjFVPhTAjE0&ZT8|&1z_uGiJiZ(-r5yOOG&X~`r%2=PVIb%mgU)ylo(YDiV zU$cS9uj0qGBYys zGD|YoX0FTJn7K8xJ~J`3DRWO|Tc#kjJ5!oDnt3eqbmqBCN$SPStC<<8H#3<-cQYSm zKFNHMNy}nnX=UkV8D<%0nP*uI<)tpn+9+gYIb^wHm834o^34j$3eSqoTASJ~au`~X zCCXZvMPy|aWR+&EORdQID61xGdsbuC#?+Rq)~xod-mI;uhqA`ACbG_CozJ?IbuH_5 z*8QwUSx>WGX4R+Cvo*7|v-Ps)WSe9&vlnICW^=OLvYS#pv;DI}vLmzOvy-z^vsY*5 zWEW+x$*#&?pS?MINA{l7UD>;{_h)xz_h%1hAIUyRWS`BxkbNcldiI^{2icFa+ftup zgBdpIF6La#i51<<@t54qd6+Yr z`XuK?4nfOh-tjn#dtUtD{u@;zbv#z)P)Y{@;oY`*ceb(*PJ=Rj| z5$hw?C#=s{e{Fry`g`l^)<0R_w`MU6bJ+|I!-bJ>@HcB7c*>YZvP?Rx9futD7~z z8fG14eP}+x0_|H&*PDOA5->VNwdUtosf=$~S6JUN(@lS5MVa1a-D6#0K4ksDdd4DN zv8>zaHX1fsHZyGWZRXmT*jU&sw6V5f+i-2%Y?j)%wtKeo+XscdHi0%V?V&bNHt{wq z+LLTVHt9AQHn}!MHa{}An>U!3*;Lq6+ibLHGT&lzo4Lbgr%j6u!|WdObMyV?du`fm zx@@MJ_1g^DjN5dWuWrw6KW=l{<|~^Egw3G&Wt(d@w`}g(e7E;ko5wbz<{!2HW%JTT z)%K`)Z9BtuNBdM;9ot#9b8O$S{j_~g`$=3Y+O2F?GQKoF)qdVQgJEZz z!}!kps`(A`0tUy{)%K40FXl^ZOBg=3=h_2om)Wi`i?m(Ch_hW``(1klw%K-%?E%|P+dkVvwqv%(Y){#qwf)BS zlI;(+H*J5mePH{$?VsjPZU45V*-f&WVmIAR&u)6hY&&B+GrReAi|uUf9PM1}JnX#f z_;w+75q2-k=XIEOyw_pdv2J~=-EupDU7Fo$yKKU)z>ct6Yxkkudb?V??RE`zO?IE# zUEBMRx!VIkL>=m zdts+;p~9YQq0XMn)@ILS8?xuIP1%<0MQj^(K}T7K1KXKh)v=+2$M$0TvxC{;>=^b; zi>)0*B0GiM(2>e+=~%_iV&}6<*yZdh_P&mf*){CWj)9JC?0WX6?9qn`(Zs+VylTNEn`%ah6 zrJeqrts9=hkHTvh?Hjf-b}$+l%R8GGqRw7o!*0f~s1>5ccQSezYdfnu)$FB=PSsC3 zHSMR_>)LY_IdWj_P0BU zHTISEAK5?deBMdx((anoHO?^WI>uPob&_Gzb%w#|I>&JDy1?-6y2J?Vy2=Rey3UB} z+GM}gzRrG^{b%-zEL!ak+IQOz*teMu+aI>Kv6!&mxT$GVephK%W!L(yEnW3pU)Z0s z|JMGB{g3vy?eEz?wEx5Ynf)t!x`T#;mctCf!NEe`!P#Q2gNXxtZN_1tL)Fm6q3uJv zhV~4#!^3JuhbG`rG#7_f=0-}gatm@xb5EyMk#M= z>Ja77-xcq$!<1){Gfz8DFKU`tyeKj^vd& zR5(;S_*(>9gj>W|BwD0cq*`or*y6Cm;WE*+)1k#-uR|LIxBt1T-{E1`pIt)^;||9i zPCI<%aKYiS!!?Ih7PlPkI{fPJ*x@gSmkz3q49BUCKke0VoaH#j@f}BVN44%L-7~r$ zF`mF9pI$P~);=A2n0hkrN$T0W3wc-a4vDVk(KPPlJ;-~U_bd*uR$ z808ZcBGdf&`Rs1z?gfrZy8XJX9HY90-7CAZyNkN*9Lu{oj_bNz9gQ|yK=Lh6p91P8m&QHu2jKDmpMi{#yPHV6go;A-*?O*919(*EJ__ea9q&C>T&E@=eWVqt!K02 z*8EQ#b4?o^n;rK!9&qe*>~qx8IOI6yc+ByX<5|amo{ufQalGUh*7JkoO~;=dbu@}h zXPIrYsJD3F_^HM3j=rXP8oMoCF`qit=Qri=$#2W=&X?wo<{!&HoqsO>Me4C_@@WN(0<8kw0>c910`r1o$-;th5v#zVAhqZHo+q0PHHx>_E|)5+AU%^ z%Q*s08fP^pn^V9cI6W47d)j-}az5m&=hPCM?VJWq6X$czeohBRYSGIXu^8lxa*lFN za=zpou{h89j&qfBgL8-T3+EB%PtI`93yum`ovS}QlWWMG$2H|zau;!JxDH%rt{2yz zd&1)Do=ZJH_T1^AZw=;#b7Qz?EE2gX+*Ix=ZWcG6`?W<0_o78P_wOEh?~($oG{Uza zs35!`wqQkps9&i0+#}o*+{S{Ig4Tleg5H8d1>*%11!oG*7hEd1R=^y-U2wnPQNh!Kmj(2~)e_A@ z?Lxi63DKNFlR{>pZrY+k+d@vE8&T+4=wBF8Xf+&J7+;uNm|D2HFsHDna7|%V;rc?~ z-r(NI-h|%Gg*ys&749zFU)WjLUpQQNr0`_n*}@BjXGB*DuNOKD-zjt(eo*K={J8ME z=vg5sQZJfPq*J6{WK?8YWSC~0HowR`ZDE>K5xdB#h*#uY6i^ge6kU{9Bq$;zMHxkT zMI}XRi`ErwEZSOBU({3-G`y#%t*E<5S~Oa8tmt&nxuQ#=i$zz9awIp4?iNXf4~w1@ zy(lV@(25zwXSmlbzUE%!e$Tzm{fT>@`y2NOcaGU}?oSrLNzF;qX_}L+lYvuKuaVQc zPE04QV%=g^nqhI`uyL_@@xo#jQS4BBR_s!|q}aDOsJOBBv)=cdSWXUUE@?~BeA9x` z!qeJ>*F?8P_eHU3qTv;3qBM?%wAbFr|C8`yCnt9&PbWX8Ag3^=Xr~0HWT*QUE*fH| zl}?#Xc}~SnYn&>bK62XRbfK4Sxz(x8X_wPyPOVM{ow}U{oQ9naJ54x!;Y6Hs`qt@+ z(~nNKo$fh3bo#^T``%|xubk-48qW86ANBs#tL3a=Im21sIktF3@yaw&@oyF@i?fQK zSj=@UC@w8Faei)L;hdFLQCyHVsjoEcqvD$4inQ&;jm0g+5B9beFLZ7%ws!6P6sU@pRwx{Kk91|9m)QD#Gz1ugxFVH#E zIm$WSImub%?9i9)oZ+17?Agcf3+*d%E_1GMu6EXBZgk$_JdL@-d8c!W^Im77&AH22 zm)Y+;Cj|-C-;Ihmm(k0Gih0A-) zZD)hvE&3-ejV{eDET%nkkIMlUCuXOMJJXZd=W@tp%;lI%xW-kY`=2+3ar@n(HLjDX!C9{g`^LFZ#+%XS=>*X6y=|s=6+AwRN3g>F8Qv z>f-9*>g~#R4RMWdjdfk_8pIU1rn#MWesT$mVUcXO&P=7>!e1A&6q(8HNrN(~OFy=P@od(84&8ImUjh{YYHuSgj@9XdE zALv(c8|^>d|4sjm{=5CZ^*`-@)vrDjD!*-hJRrkkPLJU3G}OSeUCHf|1X&Tc%nZM$|F z=n*Au7M6a?7qgm(*3yb zBliTRx!ET7t?qU1yWBr>Z*@QD-Zs$fKHxs=zQC-@)XMCz`-J;kOB2ga%)W3x=l-pG zzp0(skSWK^)$EG<$$`|*)_nHMz>n^a2X4DRAD~I^xob$Zr4QX_N&j$v=58c4lfH7N z^E7yb7H{HYunee@6f*6`+nJ{y?@qzv;7PA z+w6DW@4Y{6fAao}{iXZ2?62S7yuWq-_5Ba`|GEF={uu|}Ilw%y_<-|)B?m$dL>*Xp zpy&Xx>A>KDTLUgjnOu(ZEjmwTT)wI+sAF2+v?id+vo=;AJjQ$d~nf0yMs;# zJr4RF3_cin@WX=}4{ken^WeRMj}HEIa8kQg`@8M)+a20N+r{lA?H{xsX}{L~Q~QH< z)eg-L{SIyiuj5L`jgF@suR1I{mvu&WuIkL`Ebgr7+(mRA>O9^Cewfk20+#b^& zub$YRq@KJUqUYnD%{_HJO+9@*M|)29{Mz%RXL7GjuR*VI@1kD2UZ-A_HOIl-%E7$j`dFTe%X7o7xZcM&FQo5bM0HvC+^Gb`=IZmz8!s^_U-9A*f-R7 zs_$IicYW9Te(HPB_eY;?A&4LSj@4C<9o&pkJHA# zIJxk+^4(kPeqsC(vy}6?= z_C^jb`ow$3+8y;fN=IY*YWwte?Juhtts7;ISdC2Y-`^BHAR5RS*fnxsw0Cr5bYfHm zaOvd`$U_fe2q3yzssi|QTRDwtQOP?(+!E37h%v=KUkfOj>byV&m540SwU+EmkR@ms z3*qrM+QVL^G|*>;hIxIkV`fwdE~jcu;5WFWq%?Tt(@#mU{SBA@RMiD zIq(P0*F+&?l2Y@VD%S^9;!4gK&)%A>?IJbNqcnT0*qMV0)>!#ie|S1*3VeDGJVyyl zwOr~hf**ZLiE3%N6k!(F!=I(GE>JT}*TR|z6?>I0WJBSu>6Ua-3`!?7hzl~PBuoZr zE@UD!P_C@CLZ^KCBB&8mS1nZ~XlPJ8JF${uR4UPUI0XYPeE~UB)C+otDZ19lhO3q` z<-(!aD!AiGB*|K1U8n#8b*28H++vLERtIO_BZv@=z>g2H%F2|4!fmkPZ^_!f$p;C} zr!SVdED{AzqDZD8SVGW0m`?-cQX4oUK7Af3JEgiV={DGvngyCCpKe1kLmohB&Hf+k zv0-Xu8Y!3JnN!oG0c3JYFgSl@#p15Wc_>{}%GhHa95+=MgHQiat`9C;J5(P9M@ny> zlhaUkPx+YG|7oC0ijIPOecfXzl@IVgWK=(+%oHIa|*BH^UOe3wsvD1y5kZ z{M}Ui#|5=g#bV*p&17LhWJOfxA076&gs%zB5Cojc(-w?7GgRf&QCNbv0- z2wOCgwg6%Yol2W3t`^T0&JcfULibF9Fg=UWYK%|*S2>LRMR<1G#Eq++VRb{U@PKXSh2H!xk6Crc^(L7YN0pTWJNXSyN zAm)?1Xp`7pvQ6wPX%M4#q-G9&CTtdaNbG5Q#RtVb;z9A4c$w(9*hlh(SObDiRf`7& znh>^UOn{hEUPQTQE_CqIvekmkh2wzCQ3+Ytppl6Nc{7!45dE1fz|bK2kFsaXlX*tD z^cNuw>cCE{9t>$04>POLtvSFz`XF5jyb5ZigpUV+O=4; zSOsPNW|;fYYg?5n3}~!-f@+oDNDaBtD50Rx1XMcq>VLoT=|UxM$BR$Vi%(bhKcB9g zLw}RU32QOZ<~@0mR&2s#`yVv;AQ@E%4JwM_&iFG!OR3N4?>r>=ZsFhAB+5--b zlNEKveMmnb$Zg`Axs2+%jI=8j2C>EampbY1GMdsE+(;_9af>Vlz?0SB>ujb=QL8Q( zw5JLCpdP7s*#=wj>BPUqD=gy=auwQ>vrx>f7A8>|w7Nq1|I{F#jxCJ?afB??UzYwZ zbHX}l4*>`8gF9Ios3Ws74wrm7&U$#?8lbdg93tn2%|K}c%}-Tn@7FJHgH{uz%Xdj# zQv0N4S)eAAnV=cf!XSc>-ncL)Q0i68jA9lhUx4-iwMMTs;?}r@$6y5X4&}5(~3yH4O4idNVlgAP?9di9E zHk^1hl#&kjW>+r#203GekzN-Wv$r6HQg%md4m1gB`$~;hF5QGOJD-mBF_gurCFeJ| zL&*p`$riK8T{039ZL8t&!|+vH1zS7>zIFMh@K`I#xqa5t)Ekljxoa-{R3A zm|@cE!lU^2x<$}@6!$z_`f>UCM)SceUs@_06;FV=&BW8d9)#x|0j-W#3-+H^au?^* z{}jm9KXNfN55*AW(&h3PKUXOYQ})GzR7)3=Mq4Idn3zMgG!udmp#cw>;gFq4CMcAK zQK^nB{Z!-lcjFDKV9TL904x~p#E^Buf+DTqc3k>Ym>*EYM+l*DaHCCwK%P_xE|;pw zG9S{zn~N9T|00!9jL_^}-|^rQO7S6ge0*7s_m?1P5PiqCb_g2{j3d7xsi%P%QHPe-cD; zohkH(Af&$uX3)aKh!u5HiB(@N<;a6Em;M!;B^9R7@RTUnB;!gBiymuG#>9{7-ngeE zU}xp$c$B2nu#=&Te0rslMsU`{bEEIJ#!NXjB5jt#k1>$=_(3LiR}=@f zsldfZJ^$p>r^#(hEkVP9;+aomJUQ z-+oV3{n|n%_kZYlETuM-5-3`s4@&iuX~>%I$V5fklhf^saG+?MS``14?^4iB2cQ18k`Ty+JRtO>LM(+IxO7U*l!z#HQn?W8QSq!` z5)`afY6bN~{X`LO3jH5NGU$yo6DZ+g8W+-N*F%SQLc5@pCUV_y>6hd-<FszW;I)b$uw$jaPugCw z4d>De$r9z3nEqWUFJMC`Z&|3oEx-S}2Y()+w$MnzcvHNG!OW;DR^=(_Qqs!!$C^{* zK&S*SLlk5cywJ}VlmV7Q^hs(%i#bC7rV;A%!dn3{%|?-4G|Aw zYs>giAsH=jS^lHuf?^jk1NA@NyL|$e3^Gc!6r~_O{mo#@r|%T1LDcvUKtF`x4us1L zML5(F{oI6T+`pFmDFT(swT|*XdN5KhZInmAH+KY-Fvn$v>9SOMfCilx4K!29{t5%U z9?q}}zkZeZKe82eB*ia)uW!R~H)XG;W~lHSp-jM9=>{29E_vPzROaF_cRY{G_k}p7N8-_K4m)J70Hh>IV$PCohhSGx4{BhA` zx$W^@1xEs^ISmX-@4*%}D$B;OnAkXjQtT;;cF13l9;nH1>1Y>#uV^oTIjIpOt6Sn# z!cMq=PMIBo36>6Fx;@~7F-roBw23LVs#ZZi!xMO2j%RU*11pWQywL78S=$pyS_`l$$O zOI4K`EMcTuh*Am?{m&d)(U;RmRUAYE#+1=aZ{dFOJ`x3Yl`%4ZxTXXt50Y3r7h zQm~&Hr4Jp2_sIEOlk3PpKH=?Bf^x3+ge6d!Xz9Es%$KQkz6LeBQ*sg7nN-;fRZ8et zaxJ8Ys9IyWsJ?QOM9Rz96lVfVlS{KvUj42alN zP1ip-O32oB2Bi=%M{YZJx%@17my>daKhW;U{Nsk)IHPj0-dBViDHU>llCOw;@*c#O za`K{F!XM=We=e^T4Ym(%GDH5+FTEo@?1A)lN7^q9w?vfRSoqkjK~%eaaMvIXt-A($ z_u?qJT~77x?cIxO!O+lNe@i9-yCe<{$qH$s6g9MWXfGa4d+>;i&E(M|vUW%I9+B0; zL%_#kEYZLNdk6OBSRl$uXeGphIB6}_^3w{^dLemSw)UjUadq&n3UghIscGBG?etGj z<{(Po0z{oq>bN986iOWwRU@Z9l~E{l;98V9E(xg2fhm+ZZjt;@=D-xn96WjEz!b_H zBt-y}I&dLM7??r{15+qXUnO?P;S5!$_lLb(A`C^ujV zp_q>;6!S5KVm_u&%*Pap`Itg6A5$pOV+uujOrc1RDHP~2g#taKQ2s}e9v7lWk0})2 zF@@qgrcivx6pHVdYL^d;qB<@^p`0fV<+u!ma!jF6F6+yL`5%)gmSYOVa!jFEjwuwu zF@@qbrcl_%6bjauLctnSC|F|(1#3*9V2vphtTAOz$l0LCj0;g@#uN(7m_mUWQz$TF z3I%3Np}>qO6pk^4f-t5~5XKY=y_iDr7Ev(&qkxMGQNYC%3b>d;0T)v!;9?2|Tuh-b zizyUbF@=IFrci9f6pE;rLJ<{HD0F>Eko#7&EyRUrw}&aT3&IrI-CzpsS}=vSDwsl> z3{0Wj0j5x{$JBN?g%UC@LunXO8wX+j$0SOdm_o@CQz*+}3gtFTp*)5un7w2aN;|l$ z6eb%?p=^RFlsTS=P-I1!!(<7SIV=!Gka0VhjNn(tua4u;T6wtgFs9D!J+~Kkb{lgW z!)3?D5(j(B5W{0*$7E$FU*L9I4{w$A^*!Qy1ouGs0@r?a_%m5;^pR*-OCUBVE8*(y z!`-s#)FY{~&a^Sw7_LQ$1u+ZMP5dXe!i`To-7GbVY_DW6`kSq+pK3T$Cs@kt`Gmgc2cBk|*>R zhlnG^izM;lWO1r^wHOG`3Ub6n;u4{Q=!jsgaGj6=o(XK%^$VPYcZClGEKvr0rDcuS zMYKdzB_`I3Z6%w<9LWx`uV|OpO|o0OU)(9~7Y~brL`TG_>pUeV#hRdAI7N6t+$6jr z-Xpv&ek@ocxg*vA+K2QHSq%mq${TbTOdQG^T0N*eY&`tosAzDbv`X4CdPn-z=p=A| z>2FJ)EPcKdc&d47dQJk$7%@K+W+otSP05=7SDY9InC7YLY2az(`K~9^^F2?N=M-S? z>E!9|>FMd`8RQw}8SRiFttfB>Bkop7CK zop_xUIs%t*6);kD4q+KcVQ^17iH+z5L-RRxyy~q22cc*us_aW~&V9fiN_bKnQ-rsm%^8SJF zzUlq5_XF?Wy`Osj?M?HU-y6yA#SFF{~6?F3P2z? zhBJ(2&M=wb?921@^7Z!(_6_$fc;67naBm`Cy%*zam#uNL@E=r_~Af5yMj z1Q-Fw1g!GS^3C`Cz@x;s+_%d2W8WIzZNBxspZeN)?DpN~+wR-rEA<_LN#um@8Q-sc zFZzD(d)@aZ-}}D5`9AS|?hE`5GS&Rv0slwz96|{`XA(dFIyE!4&cF~l+TijcO}}Y= zx_$-cF_oB5ycS6l7jBOsscR-ODleg_2WK@dGE){}uY zAw%M!fOwAaPw{Q6X8;H5v;1%Pm-s*MZ}NZUKj8n)f6D)xPYak708dH_&sl; zpav9RJ@AfI2G?T<5HydoH3H}1StEEJFKY!r4+54un*o94NSGetP6oo4TV zYJp@{n_j10ubxz|B6V1AT<@6Ppv6hOGkWLrRxtFy{{|U`4z`#gOqf)LCZOCcxM+uY%~o7(GTKSSxq|kR!+t|0f8UUh^5j`oVL9WiT>w6q!ljs5v`$ zmTgq7 z1QhdDoS1-+Wg!SDMhk57UvDsH&J^%(kSvSAHW6&GZU1@$W7f=2!_ax5rlFRhi$ZNe z9YUQ$d7)mR{-MF4;h{01iJ>W>i$QAWs?e;^{Lqrn^3bZ#ts4xCh>M}$hh7i;DfE8m zZ=p{@pNE1lwJ^=FX<@oy24O~F?}jnM-V0-e*@roWxrcd%`Gp0AX@DCRody{Ar7Er0 z071VPfJR0WLuxQ=Fm7Q2VQa!F!#)bz6t*?2 zE^JqrDu5_4iy=&mD!@Q7@BlIh5;Fzd4!aljFzk=8XJN0x=;0dSTHy#bW=8mQpliR) zXd@Kbz+N3FgU3t<|1*4y4q(|Qg^R-fGlUESU=W#%@Z4~WBBKe4!pp)d!mGnKhHnYq z5xz6Lg$UmpJ{h!ycZK(d4~3719}hnr{#E#e@XO)X!r_jKag1@2afWe@ae;A(ag}kM zF%A4@a2ZW-mocYQV3=yS(lEm?$I!x~z%awZ6Re03Mo1#wkI0EAj3|xxAYxs_hKS7( zpG0h1Q3F3ke-QC|#M6ksBWRJ6BBw-7kJO8t9cdg1aYQ2*N7_a@M!H0LM0!W^BSRu1 zB4Z<$M+zd-B3DOdM;1g9k!vI04q!6{$RKR~fnbvhE^fNI>AK|RraO|mn;vd5CQ2Vj zo@{z7F)v+M$|`jzbtzp^>Rb9u5>yJ(Uu>e)gqJdEv}$x~VoTN2r=+ha6_py+tSrqc zEhsgvF|W}{FD+eI!>VzpsVH@+SyJO$^HFI~O?XXB>Gsmb(w5TLn$}YN^c6Ltn)Xto z^p!PPHNB+;HKjEbHHS(+su?e>sUapxx7VC0ZLB$8+EUY6(_YhCbEsy#W}@a&>6w~q zrRQrd)m*E&U3$Cbe(C+1M>S7t9+keVq1S5GYS-%3&Z#x2W!5gLwXNmUy48Btz72^- z54;VF=flYLkt7<=^f%ym;9m7SGRt)E@5neeBJV^ZXdE+u!Et_xd=%O5@Mq+UNTG*H zlzP}d}lmaMc7BGyO7iAh{8MP?NCdz?`a*pCfc}4k01xJNP#Y81Wr9`Dh zt%}Nu%8x3EDvzp)QU?^O&N;&ihVYC;4RsAKP!qK+sy^z|sNGTfqS~XRQ6o`DqE1Ae ziCWUk81R*Tk*wsO>sHi$Ngem9yK{a!RH+CJJT+CADc+An(B znOcZD@KN-p=&jLp(YvBQi*AiR7~LH`5N+ppIC>)bi|BLF-$q}F{xO>4_%Qm9=x5Qd zqFo&)gX@O34euI0FnnbA#PFHnOGDahjTo!^X+SGxMvQ*U+!&J>iEz?je&J)o()&E9pZFklUF?R~ zA3OprH^+Vw+ZcP(<7bZt9>04$^=OXGvdFji+hb4cfmqs-NlQ9or!1Kc{uLfbjt;~C zZ(;(e0xb<44LuEG@DGe1;ti0WhyMe{k2cVYn;mByXBIakdRW`Ymn*2mSxZI5e+Yl{0kZhu@yTyNZ9+-TghY7~wc}^T8^+IzCrsll;}^x-#6!zMjG_MwF*F&x z9b{-KU}+qib8^m^Ip^kFm~&~))j8MaNVynv$PoM+?9jPw7q{Ie{snnR54?swB!eD$ zxb4Zdw}B5$2fTQ%c>nm|`0)6c_{8{>_|*7S@mcZt@g?!)@m293$JfL&z?=9#+Tb@X z@iqvc_dT}7V-O&1K*0b#+WxXs1_bmP4v;RWkN-4&cl^Hi_V}K7Y5Yk1k@yqwXX3w( zzZn00{Pp;s;_t`*7LSmEw82}jf(Qr}WSUMd(=0=PK{|k=(Kxqh?(Vs*bKB;2&h4Em zo%`L8nh*XRQphOb-Gu)Is1P&Zy#xwYNEfgY zq7xDlk`u%UD-$vk@)C*@)+AIWe3Y;$VQWHN!mfnR5?T`w?9ejs-vJLzBz%$Z8uSoR zd@kYJg#QA4=>I41AvJI%;m3sA3HK5nCQJo?Bv?I5c$Gj;)JW7yoRO%XI5*KG(IRnS zVxY4oP~a0;C$bYULXiR3cA?&YMd*NkLn%@QDVhoT6NeIyJ3BM48tqEEojTS0y3uVT zp2l4xm(&MFkBsi8J~84kSC~IDdTFEv#uJYxo=*HK@j{|1KyXGEoX-Q_x}du7y4boE zb)veJby;-TI<^Ddg~6=jn_@oovAxtcd71L-R-*jb&u+v z*1fEw*K5{m*Xz~KsW+)-)-S5Jt>@Ic)qB?a*N4^wY)IY9&Ru3A~8;B_lIt}^_Mh&J7 z^Bb%h*bPn%yaw-vfQHb9=!V1wL4%|rqam-Mq+xBtx`vGnTN~;dni}>rv^8`$NE=2Q zjy0TaIM;Bo;cCOphPw?98=f@0XrMJR8nqgA8x0$c8_gT%r!Q<|H99o9G%jiMZ47F( zN)K<0ZCugFP8T(wW?S|^+}Ow| zYiVq4Y;SZc>uo&LINs=4Hqm&d@qD9q`lZHejkg;E(*4WsH$G|%DSO%&n*OqpzEg8& zWSRC(y`6J*MyH$XWbRB%7o;!RX}goNGrr7ir{_-pogq6TcgF8b-btkHT)i`AXVK0z zJF9lC-Dv>41O7ni3K&5|{T~a$E{sG(oA$2QKSeHn?ndQGicrg15m>!IPUI0F@T_PY_gE zKmkIPo-z(7<>DokgA{{f5Y4Jax#pa7!^0JE0QS-x#$gMo=&&hor^o6derr#>zA(QUB7d^ z>UzWVj_WV3k6izBec`GOcFc?N$kAw{HO_m&)Cb!bjRqzV$m7n6UsgO?@#l&cD^!xy zfO^v8B<-Y`Nrp+mU|y1Gl4a7OB%36MBqzolC~w)Cw-c3Y&nN%xa}OL~&@ zJP9PLC2J;6OV*v5Y>;e}{BANc`MqRT^0x3@2ByTO)5MzfE>Cy^=h8$&bmmlZ}_$OMaOA zN3z+HD9dNbuafC08Yx;SGg9U+(NCG1qHj4H{C8MfbU-0)X@GxXZaD&#RFjl3q15e7 zCT8-O`kI_1fdyS>W!^Y#rt{^w1D5Wf=BBeTIW6GA4AKiDP z>`b}s-jcF6r7fi^r9WjTWjy70%ITD^QZA%iPPvwHE9Gv=uPKjH{z|#${xU^Xzz|Fo z=m=&B<_I3TzauagED%@;>;xQvt6&Ks@DT(E5I)#4L8Kr~utFddNCfW-as(JF3_*pd z17)x(i8fB{~vG=XO{Y+_cCM=zXQr4E*QMR~=0^?TWQbG#=5H?KgiBrlOyx>tr*wbyB{ z3tr~l%e<$8BCiUsjfB@0uOY8%UU$8I^-}eo>b=DKeeWD^n7qAmz4m&wd5wF0<@MO> zrI(I(oHqmbdUbit@}A?pz}w2($9n}VDf8Olb=>Q+*E`;>-T~f)-gL0j>n|^%w**ox zUbnm$-jUvF0G;80PjG-cYWWEc>VUbHuwBbp`w*VY;PO5V)WfqH;0NsJ+=jKPVA0wq zs~5gc2U}O0!*d#Vsj6TtJi}qd`)U9l^gy2Pu;hJJ&<)Re@P)1Jt~P`xIK;w|rqx$h zYrzs-c*cVRJlBB^*1bw-J^<^IPg4&RZ-CJKS4p`37goe%Yv>+Ujr;@r^;Umc(EwpJ#)mJhGS*s!nnl46 zfMcyT!2h)vpIaS;X#c8UImGx^w^jw|X3cy(h8hS7hzM97AP7hcPz82J4 z3gW`gR?i3g889!fDv$M{J@KWV;tE^v%IS>P%G4;ENkeOGp3v0=QazvpPEGZuP@zd=>!hql}y@ z62?c}smf;oppyX5DFDahX8*PiW0z!qX2t;b{k*@Js_h9$OHa^P*as8VgSq z&;yS%(0LCf@IVJa>L@(E;bLY9Jc3~nJTGB=_AYo1!WDS%K^{D`AY8=ARRf+u#BbK< z$bbas3{R{zS<_fyLG~;tGUj zpRl#ERRi2$hV9Z|-{8Pt8qk68`>Mbs_#N9&_+NZ*Qm{H0H5Uahu+0e04K53YkELxa zf`7GH80;22)z;j0iAPazMX(ykVfKDGf6ihoP+4#??C z^JN}4%Dh_%y^mEvMJ!CT~5d+A&nuX5Y;}? z!K~=aC8l?@QPZLNtLSMBPFgV&!*+{J~6Ne?x>^3aMe!Kq6ajnHq=;SrMYb z?hE-LL=8-~I1p0B{yD@JG8cxd3po|?DQx#ah#^}IjM}MKT(#q|KW4-DVE2AVVaN+R zONgFN1KJj=V10AQ9lLoDVP6V`=&-wCw;n3}yB=nfkQI~;Z{>k(P z8$LBcCqfPU8vZzZRs<&^4wn5D&WM;3K?CLy%i#58xDUL#MnuBvI}vuU?Rf5`+(mi& zAyhm39563lq6%ITxjP_!yE;g&y`8HKvEElhRCoAt7(|E`zJ-!P5O@*-I7cFQYi(Ag60|dn#P~@;( z4O}n0Q@Aj#3F2%|0tnKZvAw>CwOuNt6~lbIzfgC(;dbNgi4b;M9qfj<-wz5+i;UCO z6~PnRMCU~tAt<*xxKL;W(Y&`pcES>=;CJ!4G9Ppo>2s!>J&aMWJ4ryDWpRoSh%EU z4@3l40|yhj69y876AmX#0`>_`3GNA=34RGd31JBaV7Tc>)5)f@O&6N3G+l4H)AXR} zanrLV(5&7(rCFz0zuBnSw0VBBRWrNUshQX8-5k(t0z#Xkn-iM_&64Jf=Dg;TW@2sg zy5^0|Tbt{fo0|7DuP$qA?rxSg=adzdjW(|-JJwuPcDngo^Tp=%Ws>xa^vB}7^pbRA zaJBhn^WEmnWe=O5G{0!xQATTFv}m>Hwivb;x0tsqY+Hk)-rmyN(w5$x z{!F~9>`=>i%S6kWmh&x_TCTP1F1y_#O~2ow0+l;js#gIy@AV|p8uEHiY4{4VuM63?k-T0duXq|rEaIB3I$88YgB+ObaFArN zjvUOFEO|(lJR{pokn|tq^#R#;l!^M9kS(zgc*g6<+9s0Ek7RozvSfgyNg)WCN+o0? zHaQy;avm|HCfeaQme+Kn$!?#K-SkKrt8pFKo`Ho4jKEEh6bwQa4hPUQ6nDlNss%>qvGqQV1*;k8JvYWQ|J}k!@CzqC}H4 zhh+2_xsYU`rQ}eAbhFUC8SiR7>dYARVFA z14*=qWN{UOG{7)Ic3wnUu7d1vl`OeVUWdu{^d+ceILVqt_C<5LraM8J?}-@EO=N8e zsR=`p_9VFp$P(fL$?i5;fmJOaOP-NeT=GZ*F~WjQA-idi1BZ~p1&}RU$>GDvk_@uV z8gdwCQ`8spk&}Q$m6BKN|G4~_hk_k0@gisJNw%yZhulG4 zu`^4WMW*SOJ%o9iQ~E^WS!!GAU#d+aRC!u{GGX+H=yK$u4a@cE|z!#hr* zK`>{C!ceJ#&f(RNfk7kqXR(k_sRH&i4T!aZAtZkk5)d--1Ia#!JU3PBBeoF6h>r{4 zRwaE=DI@(ZoZ8W}*}_d=6$FKZSgZ)B)Dw)P6#;*6D$Q9E2+&!@Kc@+4Vc;(zMjriA zr5VhC$f98oMKoQEVM7_@XVlwBK(rXzEpaD+j~5_hC;<^2>{ZHDc7qX!;yf9`BhkSQ zz@;sKFiB&ARq&mPd*b6N(;$(L+FdeG&K=dB@My=BHTO^pbqg< zXNbQ|3#1uH=8E9W7zDk1S7atBgWnef3qyd17=fWq7g>saSJ8xs9bcu*5*<{TM*^K@ zLRd;J>~l`ls7xz;b!kqi8t|f}0))tt4#7ZHg9zFy6(S$vDA z0&DSRfPh{&z)tiWLcdT@xS9Zg;Wj|TBZORVT(uv3Po(+LQ~^3+x)4Gb+?2e4coAzr zCZs)Rm*EHN->Q5Kujuq@by!QCMvdA!ns&qQxX^VT^l0?I3KX_`uL_u_;s~FkIGUnz z)CRS{wNz{P*lsT>f%|{_hpI*$=D`6`wSpz?j{m2DpjnZ#98Dcf;qxBIqI)m(S1}M` zuL5hS9;lsiD=Z>eODIWBNr~j9W=9D`4f;=^kf;hhC{zEOHw^--V8M}qh!vu|Z38N_K?#AyeN$*<>tnsW*+MZi;)I=b9zlBMn=GmM zP|8xss~Co2Pl=^$9LjK18^!;MDdLGi`zsn@x!xuxwmT97FDixA-|VdrP+=nMKlV!$ zx<;Hxlb~;r(QFZ8<*u^o*UFS_kDX63grcuPAS~+J+E6Y}N9!NEhB5;*5S9?JP9xfb&-#mXZ&ZVMe&QvJSA9DEFd7d|lO)i6~AK56Zt}_DAsuk^hVXh#kcQE17EZ z8VfjcYEG!NLiq|`r+O=lObG+mKUGPo1ZhMuBT6IG5ERq5wSHY!SV&x^;7I*1(+cu` zY6yiWisrA^;tWA$FKQ0TEKw*^@Oirk%H9RnKaPHs+LYZ8XhGGJ$vdBXHRn#abGX7)P6wR>Hb?==G zhGw0ebz|0(SyT1R^||_i`bqk$^vm@(>3^o*qd%tqwf+tLNBT5_|BtZyfRpKbk4+Fn7j=;ky+!Xt2|@Jez4!M2+-I(d zBhT-7{>ke-*L}X{KKH3}W_H%@W{l4n|89Jx`1<2^~e4hOK$o9 zOI|IdnS2?i#?Q?7Zv4_+CAavuz1(Ux^@uOJ^Ysx_qOq>!@l)f2N8{`4%C!63`VAY5 zoh;0r%AD}ZEvBjQci5EN+y2iv{WIo_FS%vk#?bOslbU{4PhM{2mrTiAwOoBh%<%8V zs9g&L|2@QNYmUaN!}|I`eZF4(AKu8~J8o|{x4!s}^BW>I9@y}5>v!A3t9_6`tx9e3 zf!B7$%qG0rjs6^)l3UbqQAf>c3aXX98?W}ig&b%L2eE%fbpT&&y_sz3Yo|u_s?TA5 zwLkyofqr#jjK}u1c2M7r*CIm_I-h6de3snOg)LSWWB-hGcBu_CE*CzdcVu4fZL057 zE=qMwUTx;9jZ!BySf9h8W`?$YDpTRM>Zk^t%JB&e(uKW!bxhQ}{uv+0yn{Rc*D69A zsE(DoB*TaO)e+{4rB~Y%C)a}7zp3&6e^0W|b@BeL4O|Z!_)lFEs;%nh8xC+fzuW%Z z_M$tB?)>mSCr)j4_|guBpKw-Fu?;;o{j$MgdTYb0N0q2KzcA0D*VpI2>ieo!C{xRX z`~I?_7;QBM-xH>7m=lyRw1QBV*H;(n{>z59*bp_)TQaPs5BO?2w1Uto!#&mN!Xv-6 zK`rqX>no=3lA6QyALai(3-C{DCE-ruh(p0KmZhobiY27%}X|w4A%f@l01dHiiQ#n(5`exd9 z)|*mQ-#xwPt4&E!eRoRVJ%+w}Y2To4P<5WR_vOo%ho8opO?6C%=p4>WM^u(%`diOF zu+)f2Pd~zfCkz9fqCM`b&`Q4@z)DAd{zNTvQC51z(Dxc`wNf?y(rv7B!n7ct+|@DN zk(H{@G;tbPlIfvgrT1CziD95;w8JYsnva3{*XXCl(Z+|4ietPf!OT%{QPs+NtCe;5 z_N?mTqfa<9bquO7$rPoBp*;++P^`XS=&)v>9X_mS4cNdQqbjOp-jtPPH}uU(JG_T0 zchGl!{pYIhThg~6^VNnG(w8xrY6g$e>E60os#BtLde<;uaoYBlp+iZt|gu87&_PczYN?&`hI5U+uYFincCnL^Vs7g zQycoK!~VwKWT}fAsjS0zK7Uo==f?@hy{MqVF49rEO!h4AUX}HfELvrzuX%k-GJP#s zqRJ{{d_!gZB`c@0-U}Y6Y_MdF_3=90P}vB{T3im&@zR}-RrrI1omI!vpB7fxSjl>; ztbp~7$|g!SMP)tC&woQ?1t)huk{h`|4F8W656g1 zJ{!V^kx8bdlEtd5)dP>pR!NqivZ-4gDqAO6ag}LF-071{n<%|?XR*El08y;H?hwUmHi{xV%4vC z`AaIhDA^j7_4rG_H(ZnK&nqv3>|Ob>s^e`5kExDjFBDPP1IaF^Y)#%7Dtju~b(Lv* zT`J@AMg2O`uBv6XHdmQVGMmcM@?BGzTe5)4N*(N_eiymPFJTT9cD%kwb&Qd$=n1lM zjgwUtFIhR&uV^m)s(wSV6qTi>>KmOyvOy{v{PTRZY+lKRs?0g*oXQHSEXdVAUWE&H z?N{MD(s7!e)gGp@_avLGvI3cl4uB zMY1;RT+lRp=Xa`Oii90h$5xinDyuEoSd|qBJxl6Kwq9kodg#|o6UqKoS*5qet7V%@ zc1mS4=5JP6Ysns|Y}}yEWI@vx656g4jxKOeb?huzMwR7Vpl@Ig$=+1i{Q22czdn+c zSJ{f8`t$u8$@-{Mm-5j<)o+kwHC4Z|{XbRNa6RMrr>gK?7yYL4y>#rYvW3qksg6HN z_N~ggG+3ju36f3G2TZA|vZ<0SP+6C@7_-RI@%=J5tS``Ute~+WH(h- zYuRUN+29@tJvRyGtnH-21Cqt7?AeF)RCZXh!YUi=(eGx*B`c(|i5HiverF`Btg?)= z_3Pt;WVKYb;$ddh?`kLuni{Gwz#j)Ayd@n^sl6MW_EKf{CF`a7wd%4>WltpQa*J%? zi}zIaQnIgAb}Qu_m1z?~_k{y0E1IdU%3P9NQdz5D(`+h?kT7tYFmFJAb&8fOx61DQ zr5}Zil9f_fk1MHa*{qUPRoURe`pqZ1WX)AJ&ZMs+k7QTX&b3^DB)1mapK)F zDl8(|_bNM{VYbTNm28^I7HYj!mLyr8J7krP>la*E$=+32*~9BpzlxGoRau2M^=HmU zk_CsUu=xCrs^cdTPE%RN3;IfGNtW#{S>4{3RljX$C)r0TJNQ)w)$d!${#04Vy2DjAYy$uOLcIZrdO&#T_6rrJNym9AYxrEh z;KoR{PQ82Cej}sm_mgC+)E=MSSwm%0B-^Bx-Cb0Fahf67IhFP3!`GKdrn!cuuyk;slk|l&t;>)vu)ff>l?tO)ASdOnNj}JN&WrbPzg()Q3Gau ztU8XAthUMmwWg_Tv}E^H);Cgr!5S}F;eW`U<<>WPvSiIwR<_9JYT2J9o2jxjC9bM$ zj>^>gzq=~TxLLn47f46XS+e3=^;__7lI2v{kx^f$g_lbPxp+mF;&{kBThnk;BqIOvcHcS+b=bqs9R-&pLE>^qe;e34W2J0#gJDx1+! zzxV$w*;Lq^o-*_M}^}C ze5gXNblj}6bDjJuizB&@B% zd)-Q^j^9bvR%HhlexR~Zk_C>d?0|lb$4NFq^;`dzel1LrY@*5@tvjHWoi5obmGzyh zzbeiSZ{ao-)@oEsb(}99uc<6xFRHRdl08&e%FXU7TPB(364{yr{Y~p?$%?BiX5Jmu zZ@pyit4wRBZ_F0Sf>l-6@V(-y<4y@ntG%1};BS@fmF!d1uj6NzZoN1Ml)Cz_|4XP9TlWbw~2&o?hLFEOt$uQ9JTZ#Hi?$Hk1j zbtJy5Ip^3SN8@ATKaCk2+0N3@(#6ul(%aJ4GQcv}GTf48NgCVaXng))+30hYOO|Vv zTb6s4N0vR7iqVHGM=d8TXDsz&&Ra%A{t&q%@{{O4BWp#Ui2Nt=Vr1i(Yms9kCq|Ai ze{XIaJ>ERYJk31Q{8>y^|Fp6kX1; zExMwmvZb1(x}~b!*1-yUpR)-IFBp1iF?;{zNPz^Ou2My5_pQ9~0qAR`vUwI}Bzz}?g zQ5c6wn675d#(XToGOWgWY{5?K#X%g!Nu0$cT*nqdx{?1b)C+OvE(I!aOX*Qmn!{Y{m}!fj@Bs zCnj?K|Dkaa*KivT@D!#=rUV<@@FNECcmp|*7X|SS-a{#r!w0B>6x2q2G(mH;#uw;} z9_TZP^ZyNvK^Ttj@gpW+DrO=bzhVhi;&*JqcI?3c9L8~+!3A8!E!@Wwyo5IS)pwBW zwDoUwsJEq`9OZ_3deAC$^K3sQ^o^B{Q(krML_7R_k=lF}@bc%02h}%NdeB#WRiQG| z43+Ugot}lhztW54`a*pl!kZXL%> z0B3OnCZ6mbWJYcjK}l3Z3L4;Zv}WWk_!fCgvHmx$*{!*(d9C@aZ(EC4i(22amb8|( zmh_jk_Q{ZJ{lHq;TGjfAwT88}wXU^+wXwCSwRzCm(%Qz_-rCXH+1kz8)7sk_w0>hP zlWCx}-fmM`12jcTv`0sDMi2Bse+O|o1`vac$btmqL|zm?VH8DiltNilKqXW~N|1+I zsEdY3MRT-5J9I=B^gwU)#Q+S(aHL^0#$h6+Vg}}5J{DpLR$vX*V>7m6H-h_kIEW)S zj?*}YOSpzxxQ9o02Gbv=G!0I85kL$wA`23b6M0bpg;5m6Q3_>I0hLho4^uELg+?vZ zMMI>bIa;9|I-(1Dpf~zr00v_?(l8q1FcDKR19LDR3$X+%um7lRxSNN4IEW)Sj?*}Y zOSpzxxQ9o02Gc%{0G#k5fEZ*%79=1i@}d9=qbQ1_6w0CkD(&O^SEZ4HTBwVLNJVqB zLOXOs7xX}H^u+)S#&D!zG{#{freX%>U_KUN307bY)?+ia@8kUMrm+tPaRkS48s~5c z*KiB>@CeUf+RqVy6J7)mgN(?61mr|s6hL7VMRAluSyVu!AP-fMf?BAHhDb$ov_d;{ zL>KfxZ}i0g490MzVKl~JBBo*n=3qV+VhL7Y4c22bv?aWXEPr$^zKbO|8Oge6#xRalGl*o3Xvf!)}P12}{uIEIrr1FLDL^^o<1^&IWC2Tf`3@Z-ofvKypN z$Q_5c6lxw~hf(|#bwj9wMN?f)SWA&r#%E}az1G(U=vmQ}`VaX91W%jNE;1cn=>Vql zp5f)>nu#xk4p|#s57moQhiQZLyw#yaXu()5o0gDi<1|ykHtfY=oWeO=fcndHWp0?# z_(OSGvX-7+>V_%hE_rymJku3nW_~4VIIlwcW5aZH+O-VRb!gWQ@}L%MWSEgkyP2LR zYo8nP*0kH{c{Qz*VS_r5WtgruG*Rnn=--2OFTH<~_BH*@rerM#{lXjAk9olXdWU3f zkX{qDp;AXs!yVITkCOaHspF+imO4$Z$=VE=o-H+<8v3(>>FJ|ZnNk<%8?OGKV0!wn zoTgyvcEg?|vvnWpd%|CElr8>5_H3^VctGkQec;e3IYRrGo+oQ34fz?`=M2*qXrHw+8*=TPM|ERcDo-)wwQ1KiOgEt2*f8Ccc5|rZT1ssrwLLYw;*PXC zOWy6KDX1^d)6n5-+WidE185I|8hEH7A3;0KFg=R)kA~^-v?oFx`ss!vGllGo9GO`+ zIsf4;o5ze_5T0H{dx>FsIqg-3>9w@iLtP7-^qQz`HO${Zd$;6!r5@00l6EM(K|!7d zwx9X(NID#&hBx3O?X!mI3$!mo9f@m({3h)?lHZs5Na|B+c)S-XyY*_?PCMw*gV5FL zy~Vp}{c26r^085B&-~0+D~ysFD>b9k%+&A--k_b$FrAZj9>a72+J&ITdnZ(bS}_TV zOHGpcJ~cdWIocmcURi2Ysh>!#q1Pm>HanqK(10BXFJG5=4G^AgOuMN*9SlAFnlsT7 zYQZ-8j8NWzb|=ZZ>NQ#GA=AC6;Q_y<-B0oXQU@9452ZcAFr7ww6!+l{`G&Z?u={{SvhmhCH~M ziQi?$2E&Zaw6__ichcSqbxj=5Yoc~o>fe%|poUj?n)X@4^aa|N4b#_X-@YZ!|9ecR zL;q0f6GO-6v`x3wz@dv&-5IU7)sYHKZ_H^*b?eiiQ?{SIKO{#WgT7oS&qO;b)Or%6 z=D2Nm{^uslCo>92Ekq6P(L1z@NnTQFX{lwUCQJQ5ugO|vnXXC=k5ip?t?;yZ{?}uo zA=H*Nk=k6Z)wDK-J!?tkoAK(ZZqIZ_>EBte$yzs=?kTl5HGHI+aioHbr`GePK2DMr zRIkJ8kbYx0q{nHWGORcko%2DR`@o&hhDKAv1FPlZ?x=zJ^Yhg3o)%-768dt9T5(w} zNv}y-S-pR9P)nvmc!6YQejptyORXyP6KZ&c>WxGV!-}diMs0n5=v>#O-9TTin%30N zuQ6F8!}^-v;rzFhjvWjg+mN-CE$>7-yn$V5f2H?N)PhpKkvfPP?l+wFNPYU%Mf-z3 zerS43K2z#?H64Ea@59Ra$qIMq114*`rS8>hqIN*)A*n~G;T0aEebO*}hW0tAbA8c} zU!i^7Fde+b#9c%1fc9g<^fTJ#yRTNH(RLW7-L!p%=>Y9$s1?UajW^8CLiv^(P>n`VC zZD}0|8X7t_q5YYjCuuG2zPhTfbDCNi`n9F~h2Aew`%1BOE^%c#VtS}qYkyt>-@PG?xFE&gsqrK8Fy@vKWsO2{5dFblC$<@8vutVFJ z_a5VipT2vUSA~Cj&2mAlj6Nf@rw8bGNFOj+JEGS_?HDz@K__XSk^Gz?zexLva3=6j|T4dE5JXnUbL`t|(P^Em2W=uQ_)4fk))PJAgxFy1gu z7TRyhIN9}DO)FqnE>Dm!C<_**9Ud@|c5!`yL@i0L$=dreU5*;=SAq72hUt%Je*(4P zH4J%e+I0=n4QMxp{{Fw2VaDgQTN|d^(e9v6hmJs3wmv`a5yKnMiFpfT2YML#sf)Ug z9I0;%d%T>!tM&d#+TeS9{U07^1K}_RP+R_;)bI5HL)XTSw8u+6QR)<_)1}UoI!CX` z+B|A_{9kA;ibxUog=b;tv=En0mD-W-@CM#}jSgsxI4ub1=L%rUkwWmV!Dx0GeU>*5G&qdQ|V1tR0tnMwUA#^&&Mq@D6cCK#}3GjA|#v!+1~wekXO5 zUX!&S^_rxOmqV9l_N$9-BJ-w5|LN55p3S5^N1qN|L!;j^rT)V5;ra8JSIjWZq6eJ+ zC4_t@Q(LL8sG7FMus}IFCqr%EI=vrnH1rjOZXjD|Z#PWuqWy)gv`RYP72A z`Ja(S_z-2L{f2bNX2^5X&L?>RJr5n?LJ#?bn~&AQ%a7n_y`%R_*51?mg?6MQ?b3Rl zsFjymk*dG`SCXI#H9XMAw5uDYYtgO)btoH3ZDN@J8SNJObZEm`v0-hYZeSg#;c*wU zfy?ETc6w-d{Lub@`YM`~ZG{iS{@bqF;);BeX_CI3O{7^&l^;eL~7Pc=;cOncTt zdH&Be%$QI6SEvp7&5$pry-M=6QrGMALwl^=@odufI8nPPd$?8l?a=#$PQ@Rz_v?8z z?Qqa=XbuuSXTk6m|IPF%yg>hr+vvVeU|SMID*3rb#?8s3q_N1Xq6 z4M7Ror3}+$XqSf?u%gsTQmatI1AR=preXS1+Vu?64QV%l8s{^qE%f>F{BOlXTRjNv z*%!3GG)#A)-Q6(Vn|9DJ{SEDbP%9X$*CcHiM^xP>I&(Bt{Z8`l^}L!kS{?E5*Z)1~ z)C=J~8cXM&WPwRC&_Kidsm%Ks;V-Gw#Wzb0$Ofn{=|<3ZuD*PtHec!@y?0&>Or!0l^P!K2JO50^sA@W0~v6OY=HUk>qkI)tPVLFW>}$ z9sELOe5ua}9qM6ROkMOtSxx)OFyNaEm;>qv43OmpNgXP6gw!9Tj-iG(a2#VT{an4L zOxB8p#tCYZrQ1z#iKBpceSkkpD&dsN~1>nxvi5k5Fg>{-J$dpO!<+ z%G=9^UownymG%ua9e)1bX5t>y3LmQ(RP{W5M*F2<+VaGdVuR}E)N8Wlk?9Djk$O$i z;+}+VK;O#-#7mxqJUo7IEHe|B5e{-yhW0qa^aR?IgFL7Orx|9{k!BF zq;59M-$r|<+degSoAtk2{kSFiu~>1=8^@S@Z!dQH@>>orNc#VO_apRA4HoT@FnD;*w4eJu5v)R$5%&qI6U zkm{D|(`%9zcpkcyM^nQaIFEHKFkCxv^o@V6KmYlhP6o&(HK){kdQH{}P{RWiqWz9O z9eUaoV+CXiHHbVPeo8=j!J&hc%P12@mO?)%8x!MA4k+xJ@ zslBJI)tdP>Xj`-$+E(8lZND}tYMJLB$06;gc0xO&oeyf4wd>k#?Yk&-t)^|Gsg5m!qk*l7?K4{o zTWec;TL<5lwyw6Gwm!DLwgI-mw&Auk+i2T3+eF(`+YH+r+kD$XTM6e9+X~wn+j`q( zTaK9EcH3@S1NT1LLE91AaocIzIol=MHQO!QJ=-JOGuuXw$*$Q4`J8sIJz$TqXS8Rr zZ}lYDbK3LT3)l`&_RsBY>|fYB z*}K`lviGs~vk$Znwjb~ex2M@h+sD}_+Uo@4ulT0ghj}k}X4pr0=h)wko^M}hUt-_m zT47&fUuPd--(=rr-(}xxkBB>9ukHNH{QuGlq1fO$?=9GyCat)pQE6oh@+UJt-FMyw4+Z?+b)4h8ge>&cXIqdk`aoKj#QNwe_ao+L3bJ;Q1`;}J8cHME?ao>^X%Ap0_ zj~&--&mCr`&FOOboRQ90XS{Q~J&QBJnKS6j>nz|b>@4am?kwdj>#X3c@b>4JNvfp)XG6f$x zpE_SUtuBYl$K~fYm4^|KW28xb!~Lmydeq^l z`tDr5#_rGDOB|oOJ9*l;zi@YQcXNN`{@VSG`(o6$?&;A(-QT%?a0h>M|Ky(Rp6;II zo8?Y-|Kk45z0|$Zy~e%Xz1h9pZL@B7eC?SV<#q3N?{gn?A8{XZpK_mdUvyt}-*n$~ zKXgBJzjRwY4$pqC$K&@zdEz{oJa2fidvbeh_9*Qw&)c3No?@O7p3drv{{m!3MluAZKrKAwJ_L*9X&A)XPQRoeHSF`nOi<2{o+ z(>yahb3Izr0?#7PQqM}yJ27iL8KX9Mws=l>cX;-A9$NQ%4tb7xPI%6E&U?;#^F&?t zT=(4eT=w4g%yvKaWQ%_8F?(}I+q^EX&l~BD^&WJ@d$W3j^W53IxxCAKdA$X^g}p_+ z18v2ItKk?S|*6}v*Ht{y|w)75(XzT6Z?d=NR&EiY&<@DwC z74Y?ReC;aiE9!gCm*gwsEARWj_mS^o-|CnezE6EgF$c8zzM_$heV_S0_qFkT;X4r3 z$+yVf&G(h>Yu`7%Z+%03BYfZc#`wnjCi$lMX8Pv(f(v|$d`o>ReQSLid|P}wd=0%@ z+y+jxNiII`yTn8`R?;iz#ro|Uc$=1DRsaDA0iQr zcx1(!$b~$}kAf(KBGdVyxMDQkLkT3IG|HeHs-QY*qBiQF9vYzunxQ4yqCLJuXLLtT z^ua(3!S@)0@tA~Z_<4GeAAF-R7xVBd7GWt?VlCET12$nBc3>Cw;!hmHQJlb8T*PHu z$8FrlV?4!knE4laRyg1Z^58=xVvzxvkri(u8*-r_3ZV!RQ4H^)1WKbED&j*_Mio@U zC#Z?qsDpZFgeGW)U`rm_qCLJuXLLn(^g7>1Gf9%C>T6EF!=@H1v&F6QA^ zEXGnS$4acmI&Aux^S_P84(!4n9K{Ko!daZhMO?*o+{9hn$3r~EQ#{8@nE7``Hn`w{ zAJNEwcw|Oa$< zM&f&n!WfLlBuokN@H1v(9)87QEXQiB#X4-l7VN+t?8Torgu^(B6F7ylIFF0CjGMTN zhj@&qcnLHA>?G*m!2>@c5sg^HBQvrh2l5~v3Ze*#AqmN-h{~vfYN(EysDpZFgr;bQ zmS~I4=suJ4-;+ik^us_5!Z3`$NPLem7>@~`ePu5VI)Rj48~&uCSeMG z##{vF@vs2DVi6W&DOO@F)?ov-U>kN|7xv>%9L6!6z$u);SzN?rT*Xb?#(g}*V?4#n zS)6|>-}bY?1t0u~L@Y8O9$AqMIgktakROFm1SL=!6;T;gPz}{l8}-ltP0$Q2&>HP$ zbN)Nf_!3>w9X-(teGo)H48$M|!}l12v6z5Kn1X5e8M84D3-BveVlCET6SiO*c3_uU z!5-|#pE!iWIEGU=gY&qEtGJH4xQ~Z;jF+(TT@?ph@F5b>h(!j(BQvrg7xEwdnkbgMJu{yz zn1X5e88a~#^RNJmuoTO&8f&o*8?XbrupfWoFplB`PT>sB<1((|Chp=Pp3dR?zocR2 z!)q%XaKVE}#3BRYkrla+5BX6Lg-`^ED1juDMj2GZhp3F|sEs3DfX1=3)UBVJVhlE!JTJHen04VF!Y{c-VtOIEwSQ zj+?lPhj@zTF!O1h6%M%ILnPwyCUPJT@}VFKp$LlMJ(NK*Dxxx~rE~tP)2N9$sE0;q ziWX>z_UM2w(HULQ9la355RAb07=I_G~KjSbj@ZPh$ixn>T5RF)5MGoXbKIBKiAP+^5i1(0$GAM^+ zRK$m@~< zgejPYpD`1&F&DpLF_vQ`R%0#JVFUJHKmNpF9K{5F{
UQ8h+0J_Ji^MWa1Bp*wn` zAHKyfq+twx!W7KFT>OH?Sb??Jh;7)7{rC&Va2n@v1vhaIkMRQ57eRie`GqOXhbUw~ z7Gy(iEWUh?C;@FEg%$czN!!dobWq9}p)5lrTx5~`sF>YyQ- z;&Ze`M|8zk2x0(+;5&@MI84HH%*K2y!ZNJJdThZ??8QMG#YuiwS=w0|mv9|-@DR^n zHks4x@F0L#WWt-siF|k)i71ZJD31?O71i-68o+FdjA*;i)YoEqJECqxdU~qKoYGp) zgOL%gMf|oMuF8%CUGWuy7=R)84x=y*lQ12#F&~St46CsoTd)&*aS%sw5@&G<*Kr3A z@eJmmnZ1Mu0mLE`_zNv*Igt-8s+gJs-ikRMFXUw1=^qkx}Yb%Mt=;(2>gJt zn26vs9%f-47Gfz@VI4MO2mZjHID!-4FL0(^#5LT;13ZPvVotNc4L@QKk2jD5c~KDW z;60SGn1gBMXncSwNI`AXM-wzhYkYyu=z%`?27@ph-{VJ2z*NjcI)23xtiR+U;P?ISizij0I)nXbRF`27XU7HIRsb7|}h2KDD>S#92 zi&)M@8=h9n@at$zNAzXp>C3EU{#uqX&NG`PM{NF27F6Mm|AZ?0<9}p-l9|~k2JQIY zf&bR$z1qN2vVm&j)sD<#N7TljeLWBUJL57l{yXT+|FIGG{zvxse`GHV8)O{U!qHPl z)%qJ>cl;K7{jhoojh)qz2>kZ?VGN%ZwKuWxpAMs^|gAs=#{*E{i zaXR8`#D$2<5!WJaM%;)IyRjdC;RsIP49?>!?%*Mw z!OR9b5rJrA#GA02qWtmx1b-fXLH|4c^mP7ebJ_{;7huz#!>MuK*uW1(rkQK$zsIPK zzrMebKh@vN|GB@lzn#B>zmvbKzlXn<|7(9PYd`-0{~-TR{|J8?`!&k{qkp_#?cGHG z6#sPpO#dAJ!H9YOyjHcZzxWsVm-v_aSNY$zuJy0?Z}JzhZuRf*7v;AjbrQZ^;1)PEKFH`aaA_9>C z^(&QP0vQ6C0$Br}SQ7#{0_xW*?ip% z#oPKs_KW;>Z2SC~syC?-^=VZ7sK!yvquNAujOrHEJL;RL!BO8ujgI;$YHHN1sQFR9 zMXiYXJ!*5*&ZvD+e?|Qrbu#Los0&e7qHaXpiFy$ABy7?V17e1S|kf-7TwkJ%WrHD)J& z@g*~tUk>EQ$Ebtm=!pK9h*|g*5AXzb8?P#eMmD^UWbpTa)0&|bI-whWz;D=wBRFm2 zmF6Oi`v};%fuj&ULOrxb7mUS9Y`_5=!f{;1GguwGARq>BA_c9{6JszD3$X_K@E4BZ zfrD2XlanVN0?3NID2Spcjk5RzpQA0hVF;!m9e?2@&f*IEE_MXvQ3a{!fZmvoP=IAFjd@!C^;Myp1xbg%;?6ewdF9 zi1nM(G9w>~;$uJOzbTFG=!1UvG{9b?Ile$2@Fpy60%l<@R$v=;;~cJ_L?kOmHPk|T zbjB7O!b#jmOq4mTFp8l}6z9JujS-lLpRpFtp+$3Q5QF?EhO(%FT4;cl=!(7=f*&vz z6EPig@GI7LG^PGVU4~UyhfUZKN2coWlCL5 zT}L*Zx{10Cd$1pea1`Oig=A0<#0AK(fUB5j;dA9@&r=g-{ep zD2s}yhU%z;hG>S?=zy;1gRxkJWAO79^JzwN$_tp|%_$ljaKncHqT|iMlsFpk$bvVK z9l5|8Ia6M#`K7)swTRTBQs0wWQfg_bWu+!d{XlAEsa4~Hp%r~1K@F+3rPh_&Kx$*D zO{F%M+EQv8sqLk9l-gNpH>o|P_6|xTT)&a&fl>!c9VYcVsozT-Ep@EapQKKbI#ue= zQfEn>D>XP@8ox^YP3lsqE2OTL`n%K(Qa4N8CUvLOJyQ2c{Zr~+Qjdme&~#jaQ&Rtt zdS2=!saK`mka}C{J*f|+K9Txdswq?G6kDa*rMmRWuRrxl;FlUDHCAdyshOp|AvK%S zoKo{heM@RVsfDE`N_|&q302jvUo9m;8L8!^R+L&vY89y;ORX-omee{@>q~7UHC1Xe zsh>-2P30?1{^o}S9i(=W+Er=~slB9rEw!K20a6D^9V&H%R6aY=pU$JC{wQ^PCZ7Ll z113r^Me1~^Go{XvI#22^QWr^GB6YdcRZ`bVT`zT$)U8r?WRmCqZVC2EJs|av)FV=l zNj)j`jMQ^dFG{^4^}5tsQtwKAAoX!j8qcJ@lxoQwI%GDfPN^QL5mFSt10NNpvxt<*21ekrw!)b3KhlG;aVU#b12ek*lIW;y@EB^W972dQJEj*~h; z>SU?Yq|T5!TWY%01yUDET`YB()RjSLtdY7->PD$sq;8kGOX?p|_e(t}^{~{xrJj&_ zTIyM;7o-L+OXHfQ5|r@2lccLNR5^nCpBJbmMonA zCwwS#J|_He$EBFi2Od{rn)z?Us1H4E$J~qgUmtutjCm6CzdrnU9`ows4^!;xAAne6 z^IKp45F{A>6h!@&=1IFd8=|Mv07*$6%$3I0DnA;}YK{EVcj^{v=~vCXZ8V~wAc zsE1cLwjvy-N=|L3PC&12Q) zCoN-pTie8jK0|3A`~UnDCD1WeeT>pMwp(oYqm-Vp1FgMdLm#K4r_Weo3ie&H#ME~g zR$vv@;CHOYMr_7bY{yRQ#vj;+12~Aka0GwjI8Nd;{=qq1z$IM4HQc~0+*uMd^}R>q z0UqHAp5X;dOZngz8tibw4KE@PKonvShm6RCEO-M6$c~)Ijl6gZ1@JZspD+=VF%{D>1G6v(>6njSuy85o|2G;-una4( z3TyB?)?*_!V=J~}CwAix?85;Z#9ugqzi}KVaT@>N94_DzuHYJO;MP*k{~a3l@BokS z1kdmSre$0M&|rrXZg>%a0HP3sIAla7WWgKAh8)O+JjjRqD2PHR667Hf#qb_VAPJ>W z2IY{9iue$fQ3ciT396$eYNHP7p#d7937VoATA(Fbqb=H_1A<@j&>3CP9X-(teV{h3 zANpe;24M(>VFX6vdyK*ujKz3Nz*J1f49vnDSh>}Yj$IL3H!GihwKktlDv?u#95p2Oc!Nl*XPWJ+C%CKk~7Gqk`dewwKjH9;R}T51@Im!p$4+A;NN1PEp5KJ6xT7h z<4Gs0da2CT&f0Ou6U*t{d8`)G6<_wa^z;^VY`H>xo1Jy-7C5{uYBV6vOeIVMXWI z=v$v1?qp#-rRcwK>tCG`eCL?fcPgmwRq7|9y;|7rd}!}xF4yb&vM0kG^?quv)zK=I zeX{k^!<&|}_uFu^LPtlfD4>OQV13k@f0xrYVC>mW9@8N$!M4XW*6~r?8~ii)>~V+O zLp{M7aTD3%shEK|NXLBqg5TJaWzBuv$5V zQCjx6{Va0`hYd$WEnB!?=(NunoA2FBzF_ElpQhtEI;vArSWd;l+6VvL6SW}cSYKHI z(|Bv&&QB~;ayH<6*NMO8%H>t3;~Hb!z%AU9vDh}g+4t%iN}c{BwBcRP=wqD=E*NV) zefo)IP!2WNGS6jOEt?wbC4-n(@(npSR;mlJzJ4K|E_%JwzOQeFPL+OcUk%>z;(dM4 zvdd>$%eH%9DO943Rqaq9^Q}%c(aSna(OdKl*}Z6?wa4TqmagBlv)W8O zyjOe|JlkTj#}#FqcTs#L|JEKJe>YrRxc@zxf#>)1^`vDUY#m#;L?(BRE53_S7v1W*o4^>8Fby*e8+vSP zqY|0ogO&6veIYZK7-zDQedQm&w$j3buId|I_RoF#%J$WoXsgP@*vk5L25IcZA26Qd(Dk9NpHgvZkJYrg z)2X8o7=Guq4KwwBb^cXf^^CIWPtnk_YFaI;&cwO*e$r2Mjnsx#hpCS(*fZ{mZ#q95 z(=RT2+%Y!d6wcuSuHXjl{^!Vq?;EAI4zq4Q_r$VrQI&sRXDqAu&h)C+UuVMi2z5l% z4y3lf5!w;Yj-cKMUk_7ftq;v;ypKH$-5>g{zR@XA=fc0!9c{N??M?Xw*1Wy%S*&fl zTivE6{LJ4KUkk@WR|bAys*$IOerhAwpeV#34jGXNS@6cHpeZ3cjokm);;AmVA^mdi zwL?AitJ|+lFN_LZczyS$>lb*oel7KDK^^k&i`3ML=k*PCm_pC1i&5F*KJXpTO0wSf zgFKW)1yo`qs!~6OI!tBLZoRg$@J6lQep^46>mQA?*7e`AEZ*OWJ8eIHe$b;|@r_u% z37VnBe|9W%s1DeI1 zp5BpxyPz9-;44=0HPv_lFT5u&X!5$yyuf5@TGl6)+%xNPqif=G^NwQZD(;rwv0&PN zw(@k&t*`C*t^b^c!d33;TYsy{*3ebmIn7%3=6y?nzAd>etD9FreyS^b+<3;GglU+G z*{nw$S+&!ljr~yG32{;BPmj;WTKnd{W9iZ%bRN|^BF&_JG&6hL7WRBGgDk~L23kw~ zcaO*JFU`#)^fqZLGj{%Gk4!5b>nkXpI9z}JP2Exc->1w0`u`9w+6vUu>)*ZL z=Amw-s$ZJp_4f+uVpK_2V8}KJDC+w{HvhiC^^!__jygYJ(40$s;_2X*Guj z_SLW748m7liu;j1U`n%I`cr4UJ&6k=bk~kyxs1rfvT9>YPmk&w6<&7V@J;%3-)^fz zwS)cw7mN#V<4_AEd=Ywq*_V04YkPMqEp!^L-CJhu+w-xdXMrC2;Vb)SX=tF)%Q|`W z=jjDcM_&D|+nVunr|M0{H~hd{dU_5vDi`t~ANbWC2?bFIMOJe&Nu==}Tb)EL4dbB= z-!^v-_`y20!V}Bp3RVBT25Qjv)BhZ)!heU}maC_r+Nq9B{?Tj72RHO1*Y4qW*7a-d zTK4U!q3=ZD;3M^19caJed&9Ma%m11;J-smle}?Ax9IaSMJE}UD6F0uEA9^;-q8~NG zyQ3cT>rFp>#k_wo?nwC5T^l*x+9UmuYCB_TBbV|3H3`k z8@i@a-J$95yXus*6?*^EH-jr*+Y|Mk-neJs`*+#6MeJeyIQ8nDQ2tgY^%gDs3Rt$M zddKwoyo8j^|1(n?nRaWVzVg)ZYdi7%pUAkBUl!|udY7W_#k0lw;Y?ezL_gPi3boZQ zmXs}sb_>!-n4F9Kn@X zjkQ>Z4cLU>79O@?2X+uHgo5;SQ(f0X2No^moo&?fQ%OdgsB=Y4~x! zzLyi{h2Bnm?B`$9s;BCUKlqY6^!BMWm*q#UDD9ZN1s7y}UmrHQANv1)yuAl>6;=PJ zeR58EJ(MI6APFT>LP!vhE})<^H3~=*30UY70VxWch$yItfWSed1f)hpIw+t)KtTbK zCRL*pDJn%eBH#1dGkY?b_y68?zjg1ru%7&8&+Oj&k@O$O!vvTFQ(-#Hgjs|t7pXgy z(m#`G)vn&VtQ2&1zTY|>~uu89?J)A8t&oQUFFmRRvU2`{m0QSp14FtR`Pt| zknWfay`--#8KwDWOFer(zwJ&LCY{5jfihB+Hu@BnoPo3OhjP5Io1NR%7{O$e+i%5$ zbd_X0DUKQAN<+WAFPJE$$xus0=F2>O(2AP9y?$0vW7m+}>!7lzAp4|cFoQ;GMd?C| zl!GISc0P=5x8acJzhoBMrsoUu5lQ6B%853H#1ay_!v&r9DTlQO@*@m&=3|E~56kR` zq@{#Z(qEgGypsRIR!c3N5DB@&@`RgnJ-y$*?w&nK2DY?+uFqt$$ndGu<*pMy4=Uq& zg^N>8a~I0xz%cGM8Ox0&OM(Vb&92}UkPe}<;sQe7H=8nvfy#crc%EC~J{4aV$;Sh!-ak+E{)jec9f zXk$uF8X<{pV$zya68%}_jR_0g#JVOMO|o=eMZdTs(O+<2o2OLG+wOO|zaE`#N;0#?Bq*Z?|)rE-#Sf@=R|u1BI~$dXSzIoIjo zh76#NKNB&8#^@A=&cb;t7Crr6{O|q0ztMBU;fSuBlE>wGZg#)z{*B$&ZtRwNmd~7vl`2w2>n>v! zWADdC^V&4Y7&vSgzC?wlVGkL@eG?%KYYca&NIE``rM;mq^oN%qTg8ge;>qAc*OF4f z**)Mh($Q=hFKo0lCewWq4>cWhtw=G{6G2TknZvbLR$-xGUMd^y(2BZ8toPDw*Y9<# z=598}e+3N-7YAe@p*70Pr+9#v&lWj}j)q8GAGltXQL*8$)cs;kl4(ZP1{G67B00_@ z<{A}P<`S4GjVe|ws%NkymaLKZfWS^fpQ^HPcGu|aA(fJ$VS{SBWc;1iRaNo z=@=Lb<6#0!gh?<3rowcX0kdEZ%!dWA2$sMySPm;-6|8}EKK^_`T78Mk2c0%j3iO2Y ztV(@Uh?3*VTRHhWdjB$WazR|t$;CBP?x00`Kai)SniH8=60iTyg0-`DM)~_kPHSu&mZ+c#SgN~0d{kN#|jewohKNg$P!)B)n*Nr|VGho&xF=*e1g z%k7)pNIIKmxDl$3Y7~ZJ*+|HNF=o`s(8+GuiZ_f{kO75QnqS|TQq9`?p=vYEyx7So zdN>wLjD8ULUa-ssJWWY@4}0H-4`A9?uD;2B9Qg=^-2q8cu~=6=nGYCiJu;CjW&HRr zt35ZbUUy%ZIE2Z=?opcqr94-NTZ}!Qz^CvTthC39fAf>f_jOlGtDE__#SESFNcFHt zwaaHtT9uIWi0vMeSxx0JWd@I2pW<0k^SZm_TivZTL5i+)u|%KLmZ7SIEudpkFOu|@ zOQ`blcH)8WVK3~1LvR=m9Y+>`c2tUw-4mkLX_?u)9v#W_AG@vQDUjvPAK)BE-s9?@V{SYh{ z1-`C|bRXOq053zQs_*Qng$os8F!`4)I4aTHC{ENX+`FwP)x-TuF~&ePBg>c+ zUGbn%D((Hr74H;S<}O`6paPPUZN%&o^9Op=sA^J=?aG%je^8u-#^I60%r1KAs0vI- zeZ!5D;h~4ax2Q$OXCnKMsY(#)SSSr;pd6HkiclG(@zo>8%faYK^zE zn*;7-KAANOb@h)t7xZCp`=Ch1z!l=A(G>T`@oX3bLt!|Kgwc3t3{rbaHHt6YP_bFC z(3q{CHUBLSogjDYqa3Qo4e4deaAj=) zdY52EEY-zTij?+@$~RPscC|4rSXg`~`RJI~HRP`}DkHNIip$78szM{<260H%3#2q0 z-oC(7&wt%L>`EW1_HNv?U0+xSbK-=2%k;qSb+yu!5Y{An;;*y!8fo2eBbeB zmn~f-3Y(rZqEJsnXFNB~!#nqmR~lLU&R;Qi8h+O?@MF<^0x~Tu9-TUEoN9y4f7=wZ zQN>o0q?a&v1+H&#`K$~j4$I=Rgi^NPh~b+X-}ZER^>26PTq*PCqZWi!h`WbD&)01A z`PyvONoO5{D*Z7lcF53OqzrmR>LijR5W8zn@_Y7PYxs7C<$>;3KF0!j#`fSH+Qv`WmEZ>Zu;obh{8Dn@sVDwmK|}HVczE)IafrTdoEY` zY>9h@=Tg*d_XB0y(L&}1or&0h=cJO&%d3k!^`S8|frowkdDL`RZ^eQxSB>$uNbYNlrTYWoXWw>SoGWd z?;OqPUg5~o3p}MBzTr+U+nelhhMQt5#7)5Lq_1gLrecxZ5?LVAYU%ju)!H5F-&LL( zy|WdTbPbo@`D`qi2Mf)J&2?-M($&Hrb?sbm|O9+k7DQWfHrje z&U>DW6}Q|&M?FO>7#r#~V`z&*zoeGL+KyFAJu|M{a@QDUY?_eiL!F^@fFzqqA4K*i zuw5|fZC_ZQxSd$K8%uvg?uUaQ7JB2Fsu1HL_kT-zil4m5;m)J0=?Gv@ReC*?{r0Jd+W&d_p%#y(}^*uZ3 zieX6{Bw&$vPEQfZU|7^reT$SCe7mKRbn^aE^W#d&jGU-fd}i$2^OiHF3GTl60xNYg zN5E>GY;o%twK%*yo7^hmXbMz@s*nolP!noF9Xw=rP!FQZmY%D|JzH1GBDgV#eiZ#} z%mB!kMm!=VUnixE=DC;8Xqt0s9a9=)X2q^SmU!%HNd~b+-}S7#Y$FtPZVh9a zQAhpW>qfw2H;>ZKgq*gQ{N!`B{db+G=}))ZFZ^Td!jPCqboJn#`6FB#AHY@cGlHVI z&ir~rY3>Ox2#w>C?nzv?y&>#u*xPY+x$C-B#4Fqw9l%x29jW7_*VT@w?*JX4D|CbI z@Er7lKF|*aZl(MW=HV3>1|#4#@WJcw28@HZ;azwS-iOKX0Zaowd`LRaMmqC`gj5FC z_V-f3Nl8kMWCE7m+U}thpH)Sv16RCDQQD0~Kf-?a$;?36)eaT0M3;m~i;8Y9&?P|k zLu8mBp2&G`my&wPP&Xw$-OPGtF80*(-FBC#Qn=bG2BoM)xfVrqr?3nR|0(1SUECNh z@s=*%!pLVLf5Vff;4GYnzu*#Ffva#GZo+K>@-Nc0tw=2S)c#|8^yuxPnKR#4wcnw) zTBuqphkjrjh7%xhTVXMj%E_3|Fh)ya-s(g2F_w&y%WP1gmn}m&Gs~{M{HDI5#mS!A zWn3!r&)R^@z%*SeYnw(DD-L^i7-Lkub0a6{bHkxCYn0T*tzgzFrEZ$`wUWAmy5utl zCwh%a#(~-asU~H>Bgvq<47wcaogI7cZnyNSm}phBn$@FvJ#3T#lGvBq_d6whGKncK zj5P_P&X#VSSe8@P(4<%HvWn#uaZECi_N`3|c@dXakSI6Wgf&pX8w(bbyY~8M;C@=mF2c3(yPtzyNp|2E!{b3`W3fkOO02 zER2T*adrG9~^+ga2$Sy z0yqU{;5;?uU&u>v1+K$QxDEe;&)HAYz2D59!&LQ~9bLof{SMtuD7P0@y;4ERW(#{p zwC`P2b%@zzlZkf8XL_J)ZnpBp$+jP94$J<$%(G<44R_6r{g^stt3=#QrucUA102th z;(2**;P^Or7v6`-@BvH%Kb{iH_58HVV{5gZZIiOEbG_9a>+UP8!Bj6b$sAG3PC6{q zy&PTLUfQ%ny`R+DsNZwGmaQX&y(7Iarbl9ygXZ2QDNS0xG|?G8^Hh#hr4kFX#;@_v zrn~DkH`W@Z0*X_yA!m*H@QXFO!xH$R7nyl!9rqxyGb-%ya5;U{hhN8#6G(Y^ONfy? zSO&{s6|8}E@C9swFCia%U-M@hd;{OXF4zNmVILfV!$j|Kq>2%>xM~|@(B&47Pi;6| z<(HFvWwT{ev06+4xW1vShv09F$C9P@N|aen>e{*tAN@8su5D#X>Lf{Gy) zia`m8g?K0p<=Cy2TplVyWvB|NkPbDW7Sw_I&=49EmCcYkmUQUFlgU97%p&`!Rb+dj z_eIRu_3M)u5^I!y;^Hl~0$#o8&WP@+x>|SXYQ2QPK`_K&Sa&ex{E3(yTW+4GQ|4{= zSS`2wswg5@?`E;(nl;i(E1A%g29)DdIDX421W9_FjDp> zVA&*?0@JZnk|67kZU2#U_M&BsoC-6l?n&vcnwLen0NJgTA87R9tVJ+Wt&i{+bAd(~ zmzg%5du3~&ctp00sXU>!nH&1l_JPBNBP&ts7S-sinjTZT_417k5m`eHt5_KS=t56s z;4OFKzyY3EqO<|OD0Mz+06*STonJ;K(vIP7aARLI6Q)1%lRa{Z^%2;k@JY1 zk6|%<0-wQ3SPg4oJ$w!uVKZz2-&X!?hi~C~_yK-|gYc6h{h9_8og>JpZY-W=-I?xb z`r~bPR=e)xf!S(h_73Lnf#+Kzxpb`AyKH1$pE_YBX38YG%|D&<|{(wB6j#(Sy@EC-4ea_ zJfYQFp5e7_xHBiUqc|02Bzq+##cxu(%gpD>Kq^>C;WvMCfXZ*I=a z{qQZ%B>#Zygs^yHa;YsEGwr_fzn9I#Wuz(so%r~S{Ua{xwz_S_wdz3Po9_?6r-uIL z(ck;O=s)!$V?8$$m%nyFzp;Lujs77H{c3i@pYn1-G4nj>NHpc3NwT{u!Ug>R>eoGbT_5lYf%dZ-reUjky2<-HTueEOP`$FLzk8*XD3V_5rF8nNwV~FXeig zcDdz#k}YNCPqLxw>^QX#OvE80)xN884RCCijQRq$%+a`XH2rDq>Xsw zX2@c7UT02fAIjGGsB`qBCAR*?o@;Om?%F*i)so(klFW*MIF`?TT(N9?gLgbluU&O7 zTG&k`WG<7gD*9+hWT7}OG@rIVBkC>=gzjLP1ERsZ!&Oic83%SxUotnS$;Nd3-Y34- zlWWQI-&g5z{8g@4#v^+0EFKdF-wdk7Y2J7E(W<<>3Rr$0RDtR^n1Q?>#GDR@^ZcI9 z7kW8`F#573q>Z}HQ(3n7?k-I5%XH!H_=Az>RC#<5OPj(&@CdYo);Op`prYSAp(Zto z{k<$S=v7P6CnubB7sc3~$0njiU1qBVnJH~EO~*Tg^22p%vb7VAJp<1|Pv`}Ga9o9Q z^%a#IlU%k<;W(ntbV=wXaLYdXNNugjeWkNHF4u*hw3Bi;47*17`12ZweBBW$*|8)R z^sYMF)9LA3?sE&WtXkwf^iOu^mvcbkF}=K^lVQ@nZ>?C7iGE|JlhGIRN$V_8qC00= zEf!_3I;SiYDIOWyZLz1*g=_9(7yDA%8&eoEgq5h(jkrv@MN-w(ReRt&gm#Dsj{h?v zCcZ*kBtLnUm-itapABrZ?8@al4P%x9yk{-?2+j9bYe}P}&H2jVm z7myMgvWgYZR$zrWmyj=ZVxNpg8PIfJCU^u-jTf z3dD!U{87X4$@!@5#6udoYeF4|2`N0TrIvn$y466= zuRe%f55XhY*BU8tDGT8ulg%=u#*=cON)Igb8ALsuCVN!0<0`wE2KDr--p-**w^Zul zfK20vCwF}Nq36;!m)xgbH5x@3KgN(v<3mctcjdQCU*z{eS)$0`cQI4LPe+s^9=1ic z!?zuvBXowY&<(mn4|oB3K_BP`17IMb9E=plwWqu?!L#a?--%NuTS$K?>OZ zTkf~2zC=}2iFurRVNJp>8(niOod}a)3QUI?I3^Csq?A2&)c$nd%i@EC-t`=zCyB;a zH?qDy$0oz`U{~w7nW_Nz{*03i^^3502`q!10QTQ24?4j4qS?!tcsnfsDoqUXX(>N{sJNhp;^vl$~1kNWrEagE4DB|eYwCSGA zxmVpa8$6>zC3C~l0hOik3UMog|HiT#a0~8W={;l-kI>;2dwRdrUtK$q{auFDJqi1c z4f)>{@whK5zl^bxDI+2Ah_gM@HO+x8(>=N0-f|b8{+M|JyJBEpa!D+fmWDD=4$9+z z*dr~!-DA>Kw5yF}KKep>DOL7_h|dew`8}?Nx7Fzkbf^m4Zh<}?u<7b_ zPjaan?u6w=SuQANEJ8MIY&2JU@874oE1y#d?&1ePrMuDz2cCf}+;|@OBJ>7{9ob4I z?hyXGJjryrL-rpVn>eW@2J~iWnWmQzby~kxEl4MwGxkHur8!~b_A?R7!n&wmiakN% z{1`O^2ZzF|FcL;X4vc}Z-?8;$JP+c4J}jGk%~&(g)9HHGuC+1VJSt|Nq?X$8k~zDU zd%&3NI&gl4=jLy>+-2V}ZgjCm;Fyne$--Y>2EM*uLrSyg#F=)|wNKn-qHP8qnhCRD z4&=goSOAM450(+7E0C)|JinKf5s}sn9=nY3i*#S@$*H@ex~eYlnJb+#NhQ%bq2Y&~ zC5^ATTkSFKF;NXL7VE8l(vMZK#ad95>u}h!;eGj~-Qs~S^Ru;b8uVJ^B{+&#!P2#9|$dS*HuPZAtX%)sGdA8$Ay_<*JLVaaxn@ z>5GigGpA)2Rewk_hH+3^I=DZFObDG{d=UAfS^O>ByF>aX-xY_yXDkmv5CUP}y9%O^ z_NdeQ($=I-^LU@R?f!X`TnS>-aOKcj9y1aEeL&y2GAip%@?8hSI9@Mn9>XM6~ z6-Lq0`vm1sw9FMhMa_35xHq-mw#Y#8M^zk4g*2!MwV)1;*GD!4yQlRrqmjFZs=24} zafPRQTBG-IpXuuroMlnbZ_WW{-1|wX^-*!>zU4{VWVXbZ50bvETqB`EZ*CFQeFQxj zt@Do+JM8ii{XU&;_3~GHc7$GYSGh2ZXf-UB-i}PI*h3^16?0AFxM3510(}BS=r(aP zEABKu*a_u5 zk->PMz4ug+k%HuQ(Wfm^-7<4uh)l~%5pJ5lLZ$WGu4aBRD=bNhC^gXQ5ZXDk1A7k2 zMfLP?ekYiLLfP=sQA-HLGFT2PU=3`5FW^h~8oq%Ygmf2j4>&zyS4;9~wS-uXB#8%S zy}3jU{!(T=>+uD;ekwk{#0`&h+D~EOS@;7knHf`W@6>Di`h06svxbvB$C8osB8IM} z^)8yMDMtID&qHaoxytH`Yud(`HrKsgU7=WNc1i0{NOa5Aa+TB7(8tKA(oL7uQhBc( zwl*hlnnyzY%o}q(+1Xd!B^nv+fw7!J`s<>imsNB~vOhO0l%t?xu}mx{xqb{h5f~d( zTP;w&MDDN3Pu~9(5f&;-j7646s-N}df*AEv-WwtdB9r6SM%^K1@4`I@ z*hQu1<4+KTKo~?o6vRL=C;_n$52c|Dl!Nk65h_DfNQJaru7aA#T2Ke-LVaimjlmv^ z`hKfc`a%sUG7?QQ1{zCqO9s@X)5#Vrrrck`@E{n919nS_jLrPB-&Dh?(Nq8usyASq z&46?=q?c;9Ko+3H(FJoBsv>iwdpG6i6&#&}`Kd6&W{0G|?CnzNucp{ZzSoZ_I~pzK zT$Jz9P50vUaxI*3?Vsf8d04U#7Q<336T>nNwtGZEA|Cl?)qGEA_-%LbdPeV8megcU zOR5>!`?Cf+*1;Fp^CeQ{3tJ8OnD|gmWZEs)6J>`VUaF>==8o)(2jyBD<5HV%v1ljk zh9B*r^#_b2N()CG8GVc z8qV}HE~Wdt=0Y8Ny< zXh%>W)dE)*1#Gu|ds3*bo4kdlKNgo?F?vpEA&5}-~ zM7?VXosj6O?z1_9@Eb^7&X3Szi$w9BMHAL3%YlhSb`7GqCkk>-L2|X2h zG1L=QIlO9oQ1FS!Ta?vd;auZx9m(SnTv?RNeL6C6EC+z^M)XoMdb{x49@qzm;4mDA0{9J1 z!5IQ_9;wzS?RTX}cF;G8jcqer)yh+=)Ks;yR5*7rbPqgx98Cf93F6UHmAfc2$=Ssz zJjSX-2r(s;gtB_rT981-K))8}h-JJ)FHyB=nB+)bOd!>$gYEh3Bs zq4C%;0VcvEGqBk{GpFl;iSBJ#ZJn8Bdib6^+8F23qQ?rp-LHpXcE>JAoZUgUBHJ?2!KAh?XrZjo+YmoNbS%$p{qiDUxpqGJrP!o z)iCO*s5@kqdl2vg;}r;lD2Ra)5DW288p=R9C=V%68B!q~YC#>S4~?Ojk3TJ-6|{lJ z;7Mo)9ic09`@vPv1Nj2E6js7o9JE`e8=CgttnuXhbJP8FS-HsDXlU}$zwLj}uc}!NScs#wAAQTy z`;D9KZsnd-_5Ry5YP&GE_Xj3G_F-5wI|oP3m1MpDB)Ru^b#$od@P5Fb-dpg0heZ$xs0*K^3S5HSqoYNV{Wt&B?gf%_y#t8TBf( zR6ut9(hi8{PR-3z``Ws_+P#8R&c&eQ(hz(pGt!5{rP+KttcAbN{Dd-LmOcKO)6_s) zn&;kls6QT)n38){RFavOKIk;pTgdFSp15Uf6d;-(o}=oVZaJMj#tp)S_i_)x{-H1& zUWJh`8pil=)bbIQ$*PSwu6OQb|29m`F-7jIPLBVnxGXkL#^5yYn;zD;kLp`1<*=>_ zfY~{jWNTH$!+Pnr?Hda{KDhw?(cQ+0VL6o%YThy=t-9PZBrDswI5r;^z#>=zd9WN0 ztU}rYpy#voHbP_h$QYu?jIcgQ{LhoqJWE<#@wszOcUS9B>)4UfoGl_-uy8wk3p-)A z8A|*4X9}MhmAXe&`CK5W-xbvM8Dm~K zi%|H|d}mv8PzKdKibW61$&CU|bJD0e-^r=;|9HoqO1IC}ILXwYQF52pZ5Io3yG`;8 zFMr#8@nK^bS;p9b+)`Yf5+jp4ov`Z}$ilwok*b93@)b_)iZAsDC+CK-Ha+s4=^oy> zV>e4HCmUy%QzjS(W5GZe46ismC`-cPAz5}V)#|!C;IY=!O~#&}9Q2R1>u-spIwvow zGs_eD!Ack?q$@^>0q&A~LSogbHEtgx8tK83wx3)_b~=Lr}kBr#o-36534&bhgQVwhFnn~_QVf3r zpJLHUbl#MawE2QYsa^T&}Ylu7FbiIm~9NWGy!cH)bAZ%JdeRazXM zywH32Gfjhf%ELAI8)ZOCeW8uMdq%cohl`;w~#my`Oh`e>pOlPw!(_A)JE?@F!e^%kVc`+s7pL4IXa69k>hkAYeZk4}u^B!XRqD ztDqP%7UH2a*gdcJ6Ujyv$)Kg8XL@qC+;*SnEI$ijEaf!COmlbyyOdcy3+b(YK^ZEj z(qCPUTyJUpA~9ohK_$IiQBPn&J1ppk6o*D0TJ5RQ>9%{q)5eTb{?-3!WKtpSFttJ! z=AOsgiy%qn(=+Qv^;Vd{WMN9B?MFtY(fdDigCi&2bag1zq+X`giyU57N$uv1Ihw+m zcQwWDD&|xBUhUCngw*BAXu-W_!Pnhu?+j4;IkNFcG1r#BAm-kKLYs%~480e+B|{Px`;h!}~B9rV%|KBE{#{ zEm``CQS+Fs-Y=wQmvqb+=YNbClwPFXZYeP=$&{0|L{**bhWA$iQXM|sot2s`lY7R+ zVQICZm}4&;6v{CyW47>MyFqXA#EQy&y#!Py8GHrbJ0K_ z2OM*XR_lepT_oXO5g}pe#UAm6=ZDL6@^aGWQsh#~>^XdU0se%`@Hbq88*mHmz+DJ9 zK<+=_DhNS_f%cG!dfE!{$f=Kv-^j{(G?CI|^jgZJHwAMlMwa_lTWzweA?o(^lKI1G z_Ma6Ki)Fb)J0znEz4WJ#;_FQYy2_Pb@v!UPTVL+bHrsP5w`3o!p7=!XelxFowGNfb z?XB{iLxoCSI%-_=CBqyEq3fY-s(tAB?+BHtv_1M(FS!UK-gP|aRM7ou#pX=Jg5Yo2 zS9B=&gOEl+{0c&3#6w{f!&imhP}f~GiINMx(uksTs0DSPE;NKD&fqV{L0392W;i)lwMmmj}>uI^@w)_1#T}dZnYt1`oo@l0%K4vA; z8xrc~sf#?`Be&g8wl=m@7zb8um6zlG2DWKx0Ofxsj?6)k z3kyK|P|`cArm^NPQXF2;x1X9_C}>=bI=y1xR>t3}FtZLeV2?H{q0{@uDsgC?XZPFR z72apI1^wGazr72k9qIJN63>RFx82@xGTCRu#%>J!Xm`M0Zm~5PbA*p4Y#+tvQYKXf ziGD|AkZnH~x_%n{=ahb`NXjbhq!`KotcEm8=5&#irMN#q;vYVM%$Yh((o=MLfb? za(1;IfmHeTP1T0?Z`E40;rDU!H3PG?q256@k*cywN6&6pmND&WsZ^Y5@o?zK>7G(+ zZn-=3l(Q=D1zIa8SpG0P3T@yCN67W%y1A8o#_IJmk#jtu3$MAeL*%H4aay%22D?KK z42vh_A~L%t_L}!m>h@ZCFXE}3_uo(}g_CNw##2*+I)wHOX+yE;i(UO88wSA;?DhD} zi4+-CN_8j=hVHNH`3+-xg^|&uQ(??!7!xp({;C>PXVi+mlanUeF0D@{iS6&y8j5k@ znc;wF%zA#M3dxX;%RO``-8qRb5i3P4PrfMk4HtcvU*Y6`ypydOPJOa#-hAha(>{|; zCei9=f&PkE6qOe)r?+HVY_s@lk+q|YQ(QSj+newXOoR_$2F!-}u!tzlLw*Kp;B)vA zB>9}1ROCRFT0_^HMx~0A^y?iy$Fm}m?UWh4Nx!?yl0OwDd$W&V(J}Z1eub0HOl3~u zX3|EBgU0XD6_$S)GRgbBUl`l=W$M$Kj8nZA^Dg?xRWm#V18=(DIA&bmCLKR9nE&UY zLE*H)O+y=or$jx==HUY>ernU^U&KRy!!@`8ci=AE1J5Da_(Qbupo%$x)c+{|72?XE zAt2!Y#!sV9j+-9yVa$)wFUSASKaRdV?r8M#n3XZs&!hWdcEr{2Y>vr~*&0*R^L^Ym zF*{>wd;U*;BK@bhTQUE{+>3F0kH!UgL%mHs|Er%#_m%TL;Ys#Z^giY3;8DMm{{Qx8 z(tZE&JL&&_eIWQGIfv;c>9F?E=`-_Kge%2`wnm`wL2}Z*t_!w5fO{l_; zowR{oFdXK?ZYY3D@C3gzu?hZyTM)$c^2Hzt?uTa38HT{uaOF#SFTr1NG!z;_E9ePB z;4PR9YhgS51`+wJCP60{1@FT`*Z}7tn#(PlLvI)hvtb$Rg$r;S!nh4D8EQcrx&Cn= zjE5Pp6gI$iI0EP3283@VhM+z?0dwIPxVfvP0=T$_!v`P1&k)WL`-h<~42N+r6R2mB zLpar23R1z>oImX$3;M%w7z;CD1$+xf;13AkL|`eX4UfYBcoU|#-Hz9N%(;`qAI>RWK0t;Y0 z?1lm;!?>+AbcMd~5gddF`i)hg7fgXAunBg;LHHH^gnJN2n@|-Rfv+8ZUV!1S6@G^Z z8j2)vyE5ZD@e6%}_zm&;m0Vd`{fa~VszW^r^_r!H`o}oFk1PD{Qw~gUXqa56L4BX* z_&&p-{>Y)ub(sIy@qLl?-DiaG6NiS?4)uD6dZT55VLsoX-saH%twa5tR{P8--s7-f zzt&)WKjcs!ap?cqp+4!*|EEKJ$<)stIwJ(v92VSk7`W?DyAzA1aR_RA9*K0QV;t%d zhT3OksyK&+1c$nuLtVk4uIx~!qPAzk42Qab($75~ItH3JENJdfKk87oMQwNBX~*}@ z4)wDR{V$5zXDcTC92&A6>Q_+Pqxe;a+UHP@ahMXp|mt7&z`w|LU;d zjN|(S$M;K)?|(bK-;^}7C&68Z0e4bS4+c5ZF%ES}hdSP&E{odko-fIvp^`&GRmb;Q z4)p^Lbwh{wrVe$BqWXP#t%|P-%HzC*ngwLKHrzEJJ`8Ha&$j_-dtzW?p`e$(;& zuH(BqStqI4{s-~G9-?qdgV8z`cc|kX>aq@Xd55}^LtRCyb^D*DUzpAD{iy98s_RfU za;Td*%s=8#w|3}%%v4+L|5FYPPdhB=>`*`J(Epr6-P@tRpX2*WhPtr*AM7wN)S({X zP>(Szu$u324)p|w{z;DSGnLxb{?Bz7Sm02vbXc&?@%?j$db2}+zT^8=`EGCjcQ`bB z?@;e`s1J$-w*JFWhx!+X{!@d5FYhbr!&(jt>N(Vn9qNZ1>PH>w)~M}m z$77D~nLdYx_6`l59p9gEsCzi{zv%eh&!HaZ(C-`U&@jxQVWdNy<4})vsNZ&|Cpy$0 z6jl53{JfAT`r8#7^Pf|Y&&B*z^2L}wF_%kTE!jV2V9cPHS7L_8ycRP$CdD&0=0?fe zCCA0Q6Z2loq?jeqAH+=m-@0sX2-g@4K-Uq#1 z`Q6lJ-sav%y_I7h^JaS6dCx^Z?d{>I7Mm9PyeA{Jr}vNO7rec_{k*keU-CW>`?B|9 z^bqf>-cjEAu{qveo-5IBcpJsO<-HdDwzo;_L)QG_0ME0rQ@k>}nC+S4o#!3wS>PS& z@h$e|d3(fu>RsVo?Oo^n+`Gy9mG^7!ztPXfj__>v7EUhi@s9Bv@c!gI>TQxx;63R* z<2~nnEcy@cMQ?WO6>mVy;Mk$DH@$bf_W8t~@x9|;iXRgHYJ5)oTk#X(r^L^QpA)|z z{^OsRih)mla`|s;PpIizUM?W>7har%-{AsWgumei+<|-GIn3M*L_iFj#aszwJd}YX zs0fuI71E&=)P;u71RjP*p$$9%?G7^uRVOhZvm=VG&>fzGUhpLE`ymIyVCaE*81gmn z!5c6R-i7z!1MtH~Fc&^V|HsJ1@Ckedt6@ECgs))hVJ4xz<>7ny0rtaBa14HdlkhuS zfQ#@q+<-f94?IVh?@J2E3_(Uf43vO)C<94QgYOlQl_3?fh*Av;1>Sd4lZbm#dw=mq^?APk0K@EZ8w4HyUS!u#+6 z_~9d%dzAG5n1{vi348{tVLfbwuV5>D3*W;JupfScWAF={gx}!;T!g>j2Hb&r;5kN& zKm^1<35bU>kmTb}MW_s^kPfvViz>Ne%-NDzF;WE&q~euoSE^j8ZuLsf!kABDs(7SI zm1Ufo9$CN{7QZXzhnRz^?rcEq==K&a#YA|cy{$ZLJte)#=BkVDKCje*M*a7ww>7n1 z4{Ey3-e;`3Zisi7S8BJnyc4`PqpQW-i8g97sl)QTpL%=6`c(BK71LwUSG49JfgW?birJx)nLkd)b zG`Jt?KqF`dk3cJE3j-hVBOHLA;3%Ag^YABJf?MFKNB|+YJAc9;8j3+lh=&BI2vwja)P}my z02;$X&;nY+V~`1>AP3%n@$fGAGxsDkTAaTlA;h13Frkt^<48hD|D@dsmDZQtn=sPt z&peb+&+q*%p_4!N$AnCO?#_hv>sRbg$Pe)6?oDVfI?JvvIH=S+6GAQHf&NS1C-h(M zJ)F=xz&D$`+CC=9Q^6xSwo6R6n34&)^I&uxq~l=EztUYW)+!gq9Eg@Y{8RMNXrpsb zxFl&TNDkwqhvew6Sjp2yZ=iT=Y^>1>paAK~$NzW4q} zyKS`ECv7cuK+I4Ih|yLrjt?wW=LB~W!^6-To`g=&9bSY1Fa%zMG4M7_0zb@wg+Bf) zgVpc_Y=Ir{0~~@Aa0)KK6}SbipIMiNXo!WfP!Xy@O{fP=;1PHX+Cx|934I_NhQVm? zy~&>m@Bz$(d9VaNgLSYOw!!zX4~{?q{0@J?HTVZSzqks*p%|2cB)AXKpf)swhoBW? zLPvP^7xuBdz(ao+46nlLFdp8A=`b4>z$dT@K8Jkx7WTkFI1VS_JY0sGa1VkDxKs;D zLK&z4RUrfF!h;1qS3wIN+Cn?%0zIHN41}RD3dX{_Famt zAo8O^>mp?LX7`{`LG?qwi5MO!zuay7lKKac50uy)_MX~<*DqXtOhnGS`OXDhkEj(^ zF|dBZpKNI!6S%IVKQuC8cJP&u-SMx7{lS^|nNf41;v#=9o>ua3cuYj`K)FWsT%`QI zmuwqq$>!I$qsK)~kCZK$dJglka~D+WxO0?W6!vZf(tz(+6_=0lw= z+*iJkhb8a{EQeLF7WkO80l5*rge@Qz$$LSbxASg?`Cin*_o#n>eQ*elfV@AB{Kb4e zi97=rDl(4!i-*f_6>h>ma1R121xyNsNbo`lh=&9y2gxvet1GJ_vI?X^I@E#(paC?7 zhoBlBXn|}6Z6OodLnj}9VqM9uP|tYJRL?xmI?sK9uISRyy`x7)2gWpx*;CRN>xp|b zJ}*8ZAwHo>!uYwY-b4N7uB;PtT{%(nTsddwu?g=J`Y9{v>A`X+zsi-|4B9~6Iu>0w z@Q$U)x^zz#9A{g>uPoaB#-%LT{K+%_t^+IBVDdH=DHPw%?&V* zOkbavUM8#B`k9@}^b1^H{@F5Xi?2VQU1qpv{m3C@x~v~pJH0HFTVFdp@xg8GjiLS( z8woa;q|lft<&#}0XsG0>NsQI=7rU9*Cb0o8PbL)WMx zszzS_tec6+72Yx5Hby?E^vRQ$GF0Qd{%>w3W`xx@-!|}HzL{7)s*9;iMKEAeap^Vbs-OKQgq3nUl~z5Y_S z6Q3#hqG>>M1j~C@FRy>(?Zmz%U$%YmsxO1Q{=aS~Rw_Bz_NAEmGQ{goxRW@tL~l2ux2b>L-Nf?#ng1k)`yaoX z_>h0WKm3_;H?egwNdq12Ve;(Xd@u2bszD6Hjc|v08@d|s|8dtVuKxUQ=&IuCO8j(l zrMjxpfghNklsav6Qn0_}wM1|1{kSHPP(+u%*p{Sn{(?P8f&TICq-cM%C#iUBt^caC z*eE`Abv;WQHu5%RHlUlom?x>kw5+7SwP%uk4v6h04y!~l;=3+htn2^v9(fC^BmGSS zaOt=^Dc?WTos=x^68zi#PAu-vaVN$3_jrs4)I#$b@3^O*gx`Ed}ItXij3rs4WA{pjE%gBQm=}LrkbhUG3yLz~ubG?A7oBxv_ zmYHh$YyOm!;*~VA=au!%gOmEM9e3bJ()t5Ol2;55sI>mgr^?Uk9(-Zg)bbaHjcc^3 zJXC;+>l>}A^!Ts7YpVlXkGR%_yInI~lU+9guC3Nj2fmXp7v1uAd$|0)rJfr{7&`6+ z44)-$52$Y^EgKHj(l%r@)lY}(>!+p-^i%x@c&euyt=L?@Jl9x1eVU=4ir3Un4QuPC zHU4H(Q_2UN_CGf@CEa&LdEsSt2pfT@T24Rhw4VAU>UW#1rv&S%QCa;pCP_cNYrQ*a zJ&myJyHrL3|C)!t{$kTo;sc8Nt4>R)TJ`fNZT^wRM8_|p!?jrX@SJ+~M#!6k{@13Z zlz0Et**|AmO7#~y)X>I;S-~CNP`{gJ1^l@6wNa}6da$m3nrpptSJ&@8w`^YNPoGYt zRq{VMJtfVz#7c>$9@Kh&en>xkXQkan>uav0m`bovOJ9iP_Dj~2*Yfw}GzseVKy9w^ zKK=BIELIqnRVy!=Hd>knZx;2*K>1t4%xpITX8fx4zt~#7@UxZty`lcbMC)&dKGje8 zRf8eUC59kre& zS~ef3gv)MMSO3x(DRlzQ_4)?PyH~ZvTyh-ZOgm;^;5Z5jHi16 zk36Q|-598!mcOi@=C{!L25;6+FSgcSpS({$HG4@vy)almz0^xRRdL-5Sp1ZJS)q@9 zI@DJ`@$-uMsa;k5R4YY4O|hQhE9rM}$@*!K z^|Z%&I%V0+A~;?cZ@PIe;ClE(!{EJuj{e;nlJw`?v}Sv=!cSt`kjhK^DIs#7%Y1sK)#BBf!Q`ul@fvhD@^ zlBKO)?Em(ol(c}y{MSCh<0~vrR%)Vkw0>AW)o!Mr=2%bfS^7Sf>PrI|j3hQJmvtO~Eel#?qZ*B!`VVsri?^^G=TA5&@|KcoCW`RF` zc1kVZIx8@5KB>)*u}ZCecQ0T}g2e6~Rcw!_s%5{5!r#>2%j$3CXwg&HV*U`XZLAxs zpN19_Js*e4-xZ+&{++W^%14z76XgJgXphj%xG_7WYCsQv`8g@+0o(mgifG|~eNIZn zfPwynh??)JCZkD!Xn!(5+q|%hek$2gKP4#t9`N6qlTxN@@F6j9QW-Yd#l%RhahFw3 zPA{h4ZF)gJb+Wv_PI-TGsQ&Ws7h-3cf8gAdic#%UsB)CQ+W6=4Dxi;lE5bJ}QnZ~@ zUoKfbzF;|e$Z~Xq<uEf?a7>rXQ+pMBR(zk8s#*#EBzcM~f#y)4tSnrodK zEz=Xu>32yj#B@ZMR==gqJsYr4KL%_xGvkeb2dK7*DQVM*4G;<+=Z1v z!g_JAiGSQY@>Dzj`gx?#DE~1LANudjBj9ndqNA{F^}i}=-Lbn7u+8$<(<P z0ytECX=??mUr+7t$))tuW$Wqp()wM6(wx&U0{Ghs{qm&c;B+e`?pjW*Q%-fZoZ9`4 zc-LrLYpUY(lS-Q&>bZ$}PEm!;uil(if7hrtcX{?v#FfIMvT7~$_nKw>JEyg`s>~FJ zjK14sRmc{H>u(RX(NB%KimtX+j&pnUmqS)y665r{>&3ZB^byyKmUF!_#duehZR;wZ zo>C!rR{bsPHk7xljVqxoYhqdZKnbyBuw`rXB2nj9>RHpYnPzQ$`teu4eqxRt?Tb|h ze}(${x%xZ83e}+_qGP=BW*4hQ;YaGt#N0baKQ*;H`n2WIEX$)qOQ`U_rxGCED$|!! z#QLw5qcbgEfAF!kw7X^Lbj#A$Elby_&@Z;kjka{ZbY1K<+RMpiHul{J*ka|(c2>?T zZI!LD*1OnGv)FAmIpQ!>i$zaV6?}5RFbassYncs(pFcvqMxo= zZAlr+gMF;0hf0Z63k%KN6ZH@)4v$%m#+B4IZneDlKuOVk3@`eO;#Xsy)^yu4__Ss4 zlx1+JGI-VsTWPBr&&wApw^@1Q%vMpmtuoT-15xj{z6Tk>dzN;*w-wT5*3&!jqJ6lP zxjH|gJ^0^Sz3)|yIiUWYP=9~(-&vIMJ$>G97pI&E@c9=mp$B}>e{4xgxqyZ1Z!Jlw z8_?Kj!(&uS-bWSeQR=T>C6G`3?V#Q?Q-58mihWnTkMR%4OKIrau3oKGe=l1hTzbOr z^1XniCnPY_t-#c?Vr{w=$M;!5U#H?Y#)`RR!^QL&tBG4%TGYK%_0USZ;d9-uN>G^9 z&W_!qW2>X()FI2MM=htWE2qj@PId0?cFDiIJi~lm9@#3Z{aANafNO&5k?HL3Lned< zQBO^9RWPNmG7s9o4GcW`V1P34lxd)zsqtY`wlw8qrhLkj9ZmU+DSMdmMN{@OWwt3_ zQ8Llzd5Z__0rBy)@gC)YL3qIae$+=2l0?sN+k5eFzgG+ok2XEL$aLTnQ?4-OT2p>u z%CD64O>k{9U+gsH9#if&mp^bl4MC^!o>0jHqAW@bHYihPga3 z=OaWFF(_%$z?4l)+1!+^O!>Ge+nKVHDZ81nrzv}xvcHmvo>8WHswqD-9RApR zvBZ?0nsSvX*PC*aDYuyN8>EgANje=P1!j!wQTh@+`%V3aZTck!qXGkcDy{!;MA7`; zji|d~doK>?_cu)k3QUVHnDUa6iJpH==?RyZP2^e_Lq?ghxGCeqeT5+qADv!pWHPT` zic6xWtf{fQDep67swp#+oZzZw%Em~0jLd6b1f-H_-;<`kA*LMRGap8q@(ojtH|2Y# zoMKA9DQB5-o+%e0wZjq+UG5*kVf%YsidvfQeUqs$#K82{M#vvmKAqq?WwTJCeo{-x zwTYgmZ5GOVU0*z7n)}!EkSC(3hjg)iv8Z{URet-M7KCC@GG&y_0&z$er=dkH$kN4W zq-nmmX+GYRWldS$l=qo36=}AiMhxh*nrK>-VQQ>n$_A!vV#?;GY=yK(@ylh6G|x5d zd0gpB^t@o|A8E?hMfwQoTjq;*O*zSw(@Z(jlygnFz?4f(x!jcNOu13XM9&YV`lKn( zn(|LmUP1aKs&AMt{xM}hq>%){ri?J9*OalQOg3eTl8K&Lrn;V~e!^5gXUg8D9AL^p zkwHF{*2ByfBTf0bDc>^XyQZ9E%4w#YY09~#Twuzjrd)2y)u!BF%FU+yI+F4)G4QSV zVwaMMo&uy!Q^|ZfO-s%&n$g>)zI&z&j4ISGrAe2TWTijR6UKKbJ<$$*M}6NKjX^au zY6r!F-v$_&D8uo-!zDxi1Exo+D2pdBiZTLnzs&*hxVGmZhdr)z!yaEt)1qyr1v^c- z$CSU=EEJE$#Tf>lc32n_YP^5O@&37IjrToGcm6c(y<$k8>xTK_A5#WI8zBiZWjj-L zGG#YY_B3TLQw}uc5TrdObEg>|7~}BR#mD45?f-bkhxmNMz(mu>BTb9PIxLQ>ZRnd} z>YHNf^P6&(Lx0FoL;nI(f1c=*^8cA>V2vq1H|3Y6+-b@^rrdAJ!=^l8%G0JiZ_10N zylTo@ru^5Go*1+Ihw@;LvOg0HpYAbz8s+%DFw*#bi0^iDb#@z>_PA*-)?w~wCBxh) z^Lx)2v;6l(qZGqIrW|HUpDD+hastxsVDiU?g*QzLC!6}FoAM)5=9+S$Df3MES&Ui! z*O)IpH{}+j-J!~PhC{_aEE?iluN&`6Io@|VWxP-1y#(x%Y40^tdb~z}Lw)9h*OalQ zOfY4VDJvuG9vV5&aNq%l!=8J_`$ne24Ndb+P1(Yftxf5BiU+&JnZ*nX+L{)0F*SBK z<@2WOW6D=e`KBq~G3EQFoNCGsO*sc?bI+HxAXy_<#8-<>9D%)vBh}souT%Yt;+V!u{#_DII-Psy$GxMYZV~^ZD_UJ zYE!B$t+t`s?rO)Xov(JQT2yLCYT49!soTmNF7s7tht$ETQ&Lx^{+#NmUaWd@_4Miw zS8rVXsp>CP?^O1U>ix?euClaxiHynBH&;Jc{dD!~)kD&v(<-G+Olz9awF(`u}$ zv9m@&jRiF}*4S5LeeEqN)dGCCYLrT^n_f1ibIb#QM}l1u|3XkE^WjvAbY{r0$ z!5L#RS~J9L3rWm6JdVtSr=dFPbhsbtKquZc_VLgZx}bOlo`o#v3D3ie&>Q+fe|QOA zMgJ(sfj1zVckd!6!ep2VewYbE`8FGw3nO{{7&!(x7TyBic>cTt6JR1tf+;W+ro#+4 zfuRC831?s?@BTtwhO2M`Zo^%0F@VqI`+NxHIRc`g7?gx1yk8FSJST)vij`{*ulFo$Twj;ybBXyGJH4P z=T6>*hCQ$s_Q3%-1c%`$9EYFb6nu}NGsv@W9!{XXguD*_z`t;scW1#R!(F(>^G&z| zfvAHa6v83W$De2@32{&g5}+(3LLCO>$;b*&1s+1(0$M^FcpR$n{%K@qcm}#dPj~@( zLqB*4UWV%EtpOQuKlp0%=K-h(4WJP`2ui#%L`Yj6|pKo>M*K~H!d`a(7gf+6rKRxw%B)#hx(QEe41DlM(0s8g-=|GS@A(D(GbJ$=u==kx#k-^}NG@5^;x*S$Q? z%#)cL;1&o)`W^UpK^Vf}AOchYP9On0?mR<4c@PdNfoKqiJO}(l_{pFFXarI~U8E<2 zh9JcV`!_?NC1?ZMgXcgR=mNTfUZ5|?1Ove!Fa!(-d0-?M16}|VK}&Svg5MtgRQNA} znP4_}4a@@z0fD8w;Brt1ia`lj3pRkwU@O=Tc7k`nK5!6pMB}L-4Sb6D=ip0l4x}Tk z41Q1em*Ho?&jR?Kvp28;va!9+031p7}$U<#N4=79O&1yooF|3&zV;lBcZ z4p@fpT=*;C7lM_b6cizC6<7n-A-(}@0$adV@GjC1gKY@!06W2Mu;+E`|KA{EA0h|9 zA@CkJ3_buyz%g(VoC0US1z^M7;5YEEfG~tBf=EyqI6+kq3u=G_P#YwH`k)bL0-A$X z{64uY=m1hdXV4Y&0KGv!@B=y-1pgZRT=+NO-vkp8z778lcm?5~;XeS6fPm|8B@lrc z1Ogo}02A1U@)r265IEuBFcLll$G|7xB=`)R24}(7;36mkm%$IWuA^s2u zxX+Rhj{!!6W8uevc#r_9AT1Go@)D&hG8T~(L~6iK0JT99Xo|Gvpe1Mxosv0S)ka0^*;=O5){gTzX|?ZAP?bu zFba$TnZI_&fLo+~;?Zj}TDU&=Al79WVk5u!9g#9)yERAR0J;1ge2J zP!lAAx*!=e1Sy~yXbIYY_TV{?2D*UmpqCBy?~6bt7zhS|Az(Pj10%s0@B)|!Twp4A z3Csku!E0b1SO^F#1ELCc z!=$o+5D*Tc!7QY|3JSmiuox@>%fOppC0Gqg!FnK}P7H_zI}uNSp9t!JB#;a~vG>QQ z5cmQG8o@sg{~PcvxB^m;))X`cEkSD_;(og=e6_GP{-bzze57zGes27_byamj#wDYW z@hfPLd_$0`V3P@-t?oJQ7^MgxMIW0zOjs@m+kON$e+%_J;Ye^LWap;~!b0JT9IVFNjyfo8m8`pbAu3RH68#Vo6m)RaezO)m+sMKM~zaH9$2)m9H9yAGQ)j zgE&)F;8HD8Emy5pZB(sQy`|cvI;i?kbzF5?bwL#@UQyjt{epsmI#4Z&7Ila^LhV$? zsT0)=)XmlH)oJRU>i+5>>OA#0^%V6?b%FYI^_%K7>W%8{>b>ya#Sh+nsy?f}puVF1 zQGFM`)u+~&G)+|@ng~s>=+wk%>S$cSVk1opO$SXEO&`tkn&HS0#nBo#;zWd}Yi4Rv z?V?zqc^zq8?R^pEe=86x(X7*Kg})Q*(;U`phNz(8bRa{xMqq8Y4MBmXMW8CMLtwBNEOrU(8Q4E?FjDit zSTH&8CAhC5cTwPSgjNS`4BQ^LC-A+%V}U0EzYM$>_b53ox?9*T+`k` z>;X{fo*lDRcR^*0w-dhw@qz9*GEVEh)_teDq5E0) zNT=4D^db5%eY8GCpP*0Hi(*rKTYZ|or@p^_h(2FGUO!boOFv(~RKHTcPQO*ZTYm^; z{@~xA8~-0{{0|iS|FQoq@d(lT-@yGrZ&&@OzpHBt2wd$f}UCkc-+V zU8b%`cTsm%9i>03ZU#KBY5GD%q2gVAfWep2%rHO>7ege$=w|BnAZV}NvXH&b6zmI?cx z=Py~GV;W)N;jt!{sZ8~lexj+#C(@!)50 z&iU(k+I`wp>9(ls{tds(blLQy3snjxRc|__jLk zM_Xd>O?9G}Y-x&kTT9wgrFece4#1O9Fa{_raB32ov~cBT((%n;D6=%2h#|5 zL;S`6_L>Vc=>{JA@fr2|`}{+JKWYDG+kWe*H`JcZ`NuK!6J7o*j?=HGVx=Mmtp<$*=C{xd;;llNr&&yIkvthtPX2+YkPT9s_k#uV{(=5 z$(n9xm2@fAYP#0eRBLx@hIO!YfHlt=qsz4NoPNj|XYFIHs>`rWvCgy>SYNkJv(C1< z7Fge~&af6+*Z<+${I{*|_{I3mX#8sZ!|6}PA1uCWJ^Jr!_z#NmjQyWB!KV=Ato4%h zhkse5+tB3Qe^~3WRbw;T%GoN}m@Qb01HW1S{1YB7ghi}lOSWxMHMO<1rP;dMdfO7P zc?`4-vyHM%v`yy~<=4{!|EuA<);Tus{_mMgd@Awo7b5vH(=xe}8iD-Hl~qXDVA}@Q z)2%1ZC&d5Af7<@Mp}+D^g>C5Hvj6>SLf?IQrMbjSzq3dEYmNTd(is2t|Dgab{}tb# zmJ;2+6278b_++M{VYfrQ{_;23D_!Av_r?PkbH@83i zYW;t$JD;Em!TX|mk7IIa!)3=zN`4$Og)aQ;NFhVGGtfQpiX%zk-uk^msh~|iI3Cmb zs}2_($g_zQbImcCht%%UYmQS&8vmnXlKZD09i0_)pru`;mbV=7l+nhnrZKl1X>v*W z;FjYy6?SokQo&4{g}%P+I6%L&vnNyAJC2rgp}tc`i|;rx=*}Iqjc6cc+;xOfMxwJT zuVJEv<7_q(e|99$g-pASz8;6PJL7CYl=ZV?6-C~4^rzG-4w0tbbqrbjoV~fH+q_>K zaa8))5wxffO)mb`5kZl^I_gmRua0pv$B48m_Z%j=@T()1X9Q9FJx4etb#fXgHOVQ` zwO<{O0&9*g0z$x&M;m>qAjEC(Nth@hEVb&)Ic1*u3VQ7LfevIqdt1`&rbUvo z4i(&Ss43OxjOK%~$k9cspcqtw#0>35D4cl4SLu{UQaTeU?-4YyLh0O1+wyFov?ajV zmg1+wbVH^>i#J|?=|V*(EPI?6M2?BBRdI%M^Xs^bI@;OY-jd>`+a#W5qUmb1a6^rr zejaUWLr!bR3C);Vny|0`rX5a^8XB{_Y8CwVbk;wrxMWKT06Tb*j^t3zAy z$?V3#$El&?PN$Pk z8Mzq~tz^!4imUImP~-zX$L?a>PeM&4X9gEro|!soTGc7J*Hv|%QP6wUoXsgT)-x*6 zeI?czs&GffIVFXAW({Xckvb+iYk7KXP}dnuu1WS@R9GAH6N_0SLmg)n)vk*f_evcn zqic1X)hW2Hvo7_n3!D8=7Yf~w?2M$F4;@%8jrp4K8ZD51Npeo6Mlaf9JPIvrgy~~3 zV7^!~?V+?O+1b}WL2Uj|1f{G-zwH}1r;x7(#(Wn>JH|&ZJ0Eiu6d17fQxcIDU*Bo+ zE5opO4A#QrhR$zzeJ8DG3@fLYAtUq?>OS7Yc_3iT@fI-Dv6kqA?_loKR?Z~RUE0oB zsBpLJ;4D?rfdE)rR_KlAuocRyS)Gb$hVqzK-ery*)B;T*7Xz@MGnh1t&tDx4Nr5h~ z&sE_&V=_spP8;TW2v<*pVkcdE!B&@tZ9F@chvelP%eAhf1J#`^`QkHBgHDhG8(ffQ zrl&+h;i;)uyBT=q+3%<+C)H`ez^i!F?<=9B8L2ScmIs*LDM6lXBZN|V!w@+sSXPiv zE$de76w)b#4m@@w(v-(g^}bZ-c8=CJa(VlLj3$y-`GL_mJ0cS?^$`l?H7sqUUX4rT}9A$KZxOrS(zvHNBTqjsCz7Evq>&-ydw%Y<}TW7wo?&4TMhP>xM2c4kx z*86dA$!Rw`!SJ#rHVslC3JKD<>PFjtGfJF6y!rTgFu>;> z>rJ1Nei+&3wDN3*!3u;7#ZG@26mc!w#_TgF|Sme^x${7|ey-8&;RxHD{77yu!USkd{G z&Nyb)b;hm+(QrmEryAdXchT?h_o~vHp5t9;KZl4&oKY)AX1o8p8U~- z3Tir(&Q+2QnV&dUARq1HCoBvQ%6r5Kmy89mq7mf5rexr0k^Y4p&9^6cu_p6wR`Hy+CHD%(KL`3YGur%{@tA8o-K!8^y%g-Bz1S^D6v6Gy$UqG zyR$uQ?T$6U9sTmKqOjFrYr{5%y+xVX_Humo$Qy-@+Vb53vdUXaBn7sIB2Mv&7v?}= zSGps5yE_W+>kMl_U|D~tW`z7W$dY}fj(kdRS;@b7eB*ex&+8#+4 zc)1JF&P2oNl=0=;mP@X-Aw?nhwH8W=y-;AvOq(?zd>>R?i3@FaP!!P3T_-phH2 z3jU5W#&>e!6uE-y=fX#D@+^EKN#2g*F&)As z*a@eSyr!Nspr)C8bGgt3Vn9ctJEONVMWo~HQ1C)KRQX3vS`%laLP>8;w>cN1ve|pwH50>xb!c@x|W}c&pq7iClZ&sk!1ZV>Iz}D!S;6Y#> z+NYl?P8E6RbNzM2b$sz$E1{im)wmnq6xd4mN^#Y6)ucvfjV|0!$q-HNt64=?2SY7$ zEi*6hp%A7BlPkFlx3st9CifWj<0tZX?i<3-_7}>l5Xx6<3V1`%DduS#moK)?)2{bw zRj05D7wtv*K$N+uK5Y2VaLmv|{fR-Rn53wzT@rFmU1I7XCTJ%qM7hM5$eGz!G1g)= z%#@S9Qd~k(E1{l4Fh3Iz=xb%Fs*TVmvY^j7^X-Nb!cHv3NOf zkSuzHagA}DJl=Z7Ol>9|)G&LEgW3VcgIWtJ%`+}E_R*7Zsd2fn5Fap?7}pv%7&jZY z8n+vDio?ou)dcehQUo%4%skzefbD`6m5v)fHGXdV(s&LZwtr*%)_BEu)p)~r%XkML zyWcZDG*W{==FE&R))Hz7T9p4%`K>a+RNItfs&8s!(kULOE}O@ODh!KECspsM4h4TD zaE10T)m9b<@hS18a$3Mx(|A)YrB3mx{c=!yF+o&mU$t+ONA#g^E1+)hx^*+?U?7{V zSVbMQtOCB6I9to2T88Qy=*Q_7;7R6#`Y-i2^??S5p`IbtFvKv`@SISDM-BEHP8!Y` zzBAl3+%<^CC}RU-SK|odPNQH7Gc_^wHcc|ETjxHmWeXLmSy4jjYRcBL3fadI{0y7{ z=Rq0x9^3%G0wG#RwSq8E8N`5^paEzCT7q^U4U7bf!5d%`cpDr73jFkfmTu`;jWz{3 zAu=$d5Zc2(H|RXPg|H}O6wW|m-^ry>f-pgd7x+&`qzl>jmgeV?pCH8HHz?wSMA@w; z)OBYYn9Al}7QyxyT+ON}Am^kQ?xt4a?!0vFs(W+yA>6&ef1k#~Ul%EasF1^}xw`^x zw2&FgT~lO$&>*~V_ylE3#SU?Y7=ZkG;d_IliboapT*d2e>B8NusIxaXp_scfHh4?n zH(=HuEmmw$dny{Vt9-F@#U+KaupfI$?pjr@=o7!VbJk2NTDiuT*J19|+y?XHmR)AeW3J%YYcH-$ zlpDFXhBtEFuTXPViy7-vF~Wc>hLUV%ElMrHlMU-k!aD$bh-NypvrFj-GOt z!)5o*CMD`lP;SrYg|A@U8{A_hcb6CW%KtsHQpVduc$&$t3Cr}0nTu!pO6=Lt$W_v2 zBQK(o7e}b<)+l<``d@9VyypJKYT`ge7yoKFKV(Sza-)3>H7lN3SWT{5vp;X`hP=oI z%L0jcJS9PPW7qj=OzG3wv7k?Y;PTAYGppAXH7NCE*30Tuw_}zs)}p^6uDsuRr{64I z(oa@-l`P({evq$R(wh231LU+;ejPMhmtMR?Hm*Vz>7-m!@SC`oYu(tDBmGj@R((}? zLmo$(Ul?VHyJ)a%-R&)ThwsYn40&vm{iULYmb9-in&)@+ciwH&!qPE*V@}(cRZ`?P z^gHWbFaBt~fBcPByXuaUWq+|TZ{*b)+bnMal7+3N9!cP88V`bL)maoZ{+9eB6 zcc`zRJL`JO)&8~ca`Cdlf&N;T*IJ9SWF>d-Pqez5i#GItkK% zs+Gm-@C|T#gHOm=@A=i%e@(-ckNhjSc+#i6=Dq9_qeuUwxayg_sq&q;J62ZtF%|-Iwg$v<-OQHAZ5T%UjA+W2tQr7w)nDN(Vv$dT6q=Yg~;-7cgxf9 z=d5sF6KN&C6e<0quCQV3>Yp~a2Pd$B3fBm;kU9#C1>?aaFa=BlGr%ig4wwt(gGE4$ z5Hf~ogp6j*gp6f~7lRV87Hj~U!4B{)I08<9ufbLD3s6~vR0FVE1XpSp0#QH$H9#HE z5VQrIKzGm&WP#ye6qo=egBQU}FdNJVi@@vPO;7?hf^EPJc7uc91Mmqr2|ly9gw)dr zoCn{4@4-#*6SxO(L7N%~^uPq{AOw^Lk)Se&0X0D)s0)%oE6@>i0o_3_&=+KafnX5G z0i#`TCW2{T7I+mD00K)v5m*J*fOX(4uoJuk4uQXc55Q6IG58Fe2Is+d;5xVi?t**Z zArNgC5U>GPFq}|O2}FacARg2O$)F)<4%&e<&;|4c{Xl>4JQxOYK|Xi^OaU*0S>RPr z02YA7Ux4~|(7rY0Kf|KAga1LAo-+}MJHSiP2EEF>8tP(O> z1O64+f%wMTAxN7+%j>Wjp}+PN1P=e>KZM7_{6f-QR)?))eImsqv4JSy$Ge*0ic%0d z2t8!K3*2UMyoJDPKPPzn&bU(N<+^#}Y4TO5AcTwY_=j6TXsK?kZlM;0rs}%tn(lyp zte27oXR?8sCc;o5U&y2nGg)z9w3s3`6O%=n+@HnJ*8VJrj`wE?j#$)|)C~1&pp`^* zQ-qozUK8np&|KY8T|?cH*Z}rDg$-m0)>K^o<_n`B&-;*L6q@fmkk!_-P}f4$x-@qn zi=y2FS){vcAe*cR&O?!YxNPSGNafPttI9KJY!;h9kFr?0wgXazf?RrT5Nk&zgIKzz zIerK(Qy50Z!K|V@2n>U24rU{Q+o8)L5MT^i<3AV2FUB+JGB5W$qFkECgV~!cBy}>x zW&ndhso}y!AqRDuqTL)wkd1INgi!%9VVLj-;FakO59Kn^(QHs*TmQ z(k6g7dS?hSz8S*WYK94u71@xE4P_mwWeX$G!f3R?O*9034n(-KkSk;f*X6c7HxPNk zXmSr_8#S$=wC3v8G;|oN(5H#|7?iyhNnGtry%`4J;T8zjLOM4`YuPZh;0nT8l;=ij zg0Nkir0oFV+ToTZOxs9X4xuE3!?khR*4kigBf39~Rjec-D-H-k42s9g1qC4%#hnN{ zsqS#rK~)<;i6#wa#T1vrLiO1~bxg&P_+h?WYL>%B(#aeaUY@6NYj|wIW9>0c*n_U- zux@g8Yb1=3Rlu{mK>gJawmi0zPUo?c`ZSd0h8iv8 z(1{W3P2DiG&FzI!!}3{#o?DEkj1-2_%lWL5JdqHA*^2U+-Cz-$V3EaR(#MOmHJ>HZ zy?hon9vhlK20jmYJM{Hv7Dr)YSVV^$$O7q6qaA!BW(gk;U+uYEXx=Ge zX^8Q@cx66SvZ1dW#9u(nf`6%x7Zb&HVhSx7!#<;>qcMWPV_7V%9LvHSu`n_>bS2rM z+^z|*sxQ_G_HC?DE}*f|`%RNJouh(X@{M>&a$qNN#6$$C}ZJRX3->Ql~|zd=#2?%8YNF;_zZ9&o8P8A`bNJPnt(Q|V>8Hyq#h}GyfgBL z$=iS@KV2RVm%tO}Q=E@*4Aq;&n5!#_4@3jwz1c0WviYp!Zwc_`I>615&FhK#HcLKn zcz#nf#dir``4(tv06ODJQW8AHt##$wfG^CsHL z!{U32XJ~EV^HrWLFBs4MJs1r>j}*_+;?sps#QvCE-=hg5mx9kYzL}4v@>AFX+B1a} z8k?b4t}&jTOFdphQC^HMM80e1(c5eS-5iS4F16GYlT*>KTa^d>wOts6XBb zbv^B63M0IRvL8Rk#n@mzE~ z7C?OJF%#zGgXa4HUw>To=j1uc$HE8A_q(CU%R@8#Q0J2>Tb^RFeDumpR*R0!WK)b* zu|9UfhGJ7(IiVEO!u#U|JRX-)9W z6^-c2Sy&2&*(`zj&Sq6;;cRB3soXg-o7JHbo@SfFYtCitGg4+TEGd!qUv+06av7VqKEtE^5{e!zOSPH#EBxSkv* zp5=*cfm*!AD(O8F)^m>ad5u-0rLRE~GvQR^S$x~$w)X7=x$-s&+tb{$lf`tm}cxpP^0EX7Pn=ACfVDc@?RM{`*S zISZJnR%c}9$dfD|(~fUFU9jB_mb;f%rB|e8kidKXkg-74dp26-%VaRsEMUyYH91^1 z1hx-)rGQn}<1-k!42(dV3s|tVDH8Y=;9D~SWu{5?C@w^>ew zW{)wr?X$7345r5O7^7M9*f5Hi2b%}ZXRRpqPc==BxY9rz~27d-4qAHB&c_Gu!^&V}NM9znanQ2emuM;A})3~}S2wf0CG z;7#KK_)ewEDCN@#-|_jrDew5CFJ#pmyl7Wc8;0a;G~pW)@0xF~`FymLTgWOH`IQ*v zB8uU9lhz}N`WLbw<1^EX=3O+}pXVKR7A~PaHzz-E_*v>(@%#eAbDsGIT7td+O~Oo*spqn&t2j&84HK~}D=CKwFg zhWRi?Qn_L_A=vk!O)Vh_^47(NW;nH|({-nvJ}zeCY^~($4t_Pq_a;7@sGyjI;I~{4 z9%FWzx{3|7HAQoyF<1C$&aaKIP9s-i@A_^PYhdLH;>RPep3i4G)mqI4xi_t5p$gk? zdruJPy%Ls2qvkUUK2@`?VLwq=DGS&7#H&dYN^zU4Tgy`2Icr&|q76UHD&feJ)9aMR9VuIVFSytwvjcRgL%MbH+DRly@Ac6_>Hhy z_l<0v*>gr!m!}ETPe(VRe$P#84t3qnOcc18m6{vjgl>W_0!xu^x|-7Z&1^39--1i= zty|bYig}9_P{?{_vGQ9LK9peGOeZ0nL}%Y(jU5RH;&;$7wi>vr36~Fao^3~J416uW z!KJ$ESv7alt*n0l*>*tj(JQPrD%{S(=)3KR+J2U7c5Z)u@_6n+q+<^hayD^JyAUD`^{zS@`;{NGK7tdmnr0zg3q8m-D;7&ewj_`^z z5i+-y=fp_4+o71X8{O#eXI>_HC!CIO%zVA_ZGx|4%rEM*6PGwiJ8^iH?u4ofc)^q0 zNw|%tEAH(?e^+=kXcwFmIPyut7m$2?feYN4v8HmAx(hdkQ+Kf~lz$BMdhTZ3DQ-8a zY~9V4(zth!(f=Jp)3;bGl(dHx(v3YV*3PG^=V<10onItoQm0xbJH_n9HB$aw)Q#SU za^+wv{;ohJ{^kdK7>Y9Y;avE9ACvHg5Z{0J{u?R3?=gUW-N$P3d2yHw`*4RT9bl`d z<399%>;T(AhxTEG=HZ}=#FoZaC*R}+suWbU9GyDIw%9!u@La|7%^oKXZ9IfcBxOGf zai2THB1N*j&w9G2zRx-;D6QBU6ab6U!Ef*YYuN`-Mf`^_Zs>(s}RC-YWhg#!(QV`fM9X;S_D!cvC2wS8{R&bwKZeB6V<9Hmo&Hspvrz#&~RT(};+P06` zP1^GbLf5#Hc$}T4DkoU$;3m*8zZw`R?~47QZGP91eF7)LYr#xSD^IX|I>qY*orKf; zBx_40JfuF3{&b(>DkbhX!}G?UvN7(%pRz0kHUEswS2Uv$0aCDA{G3^o6nh#KMxDmI z*>{>{P{%LX8ESe4D!WjICxLqN(84pA&Nl+8;(6{fOr%X`SSmGri1BBfMKtXJ%Gu7M z+`zLacRQ*A>~I!WK$CfN>sg4h^ehYAagHS_sN+{GOtyKa@z!$m17bAzE7*1icf_v| zUB=VWzGllP;%lVc_?jK3JA)((6<)?r3>Vm78g&v^H7hPKo%_%Qc0)n?&ZA1`CFE?n zja`2@O}fNhrZE>-DDD*bm1T}+W2f_<;JuxFy#RUll(F`de$^T3PX3lPP`cl{ z%=Rg1*$-&#_z∋wnO0zF}32<>bZF%JcRdoxg`>&V2)M(yu~!W#6FKu&anNwZ&eAFWI?}%58L#os;pVSWJz`6 zuv~+&bd%)Mq8)Zo9;&2G!HrUN+)=d`s|!)Mui~Ku`JJXl*tsd=CVNEr-x`Bx-7U6| zVs5fF%kNBqbG!=>-83w6PNs(qLg)X4DJHsp;QqoMD6iw+ZO<~l) zCbf63vq{tOTwgh9CLNe3g_12)8bjMIVFq0Yl|G=Ep;Bu)R$e+yAB0J#-S1V9<|y2w zDoWu>DlIQnp>36<-LyLrO%92a+SB4-%*32dl8Np`O5^E3lvE~9=ly|FIVy{m5~#Ti z3nR6%be!(-Q+jfg6i&SdOMxU+fhHPMM`&dfLc^-S02x&zlSr$gB|KNz3yE_iWQSCi zobH8^v`(a~>QYC~uz#p7O;xzdYDkd*?(|wxKDN*6u=L<)C@1D3MsqVs3Zt7-jUg0Y z8xl;f24`w*X&)U$Nh;+BDuJo~jP7jyD-OhT_sQ`H(bMHHY z*EDD-1-J*NNTS;PdP}LVf^OzZB1x?!1C=#~m_N6I_7hu6n6MKgFuijkn8|HvE1eO! z7@|A;IY|njlljov;xy>$RGO4W$FiWh!7o9ltvgHCXkfY&?|v^`S{O(>Zem4#&=*hP zor^^2yd<O?sibzFSu8EYid`W!q7BQXZzyLuLR>;>`-T+j4ti7C zf=zY~>g1Im(LW+uJW;CRzEUWO_(zvgDUN>LgffL=C4+m)N+}K&&cb9xyLh|gC2lqp zr#sW6M7r4x^D1(clusBQ{z+mi>IJTbJ-=Iwa+Z~tuyT#EZm1DETdG6HS4*4R$4aE# zm>pFiMBYYB9`)-|D6Ei;MbF=B9f4~pekIQD1|Gj5Ioud$cMZ+RH7})tEt1N$Ym$K7 zPI$?S1YZ<(O==F`^JrHWSaB%eZ$k2W58vgp=fSSpxKrTIe?|*agSor7DtD)8xZCbI z?*4?I_>LAfW^*_FdG1z|AN6W1hh4Gq6JMQjct#YS0g4s|%VC%7?wrI^%FAVjw&UR` z^|@O;k-N?1C&$jpDdn2;6wmWxVk8fbmdn(|FaAag!|{|rv~a@AU2_A4FhN;g7J9c) z?qHzY&^$90z9pS@`aVVPg|7hSpQPvF6ZLxKgp8)Z_hIItNwi|CRJT%ZldQh|_>_^e zS5{wd(|mlYDSx1OXREYNm=qD-&?4&{JO|24r{LK%Pv{5pkLCc>Vn7A!T{3*(~G78(*n~n?@(r0zw_39 z#rmzkd>_*jL0sF!N8Tc_qS@Ph4@J1rBT|SuT>WX}2Y5wI7h}9ikGC8}$z0QPZ_SNXr(E(2xvTx&)Y_I$yrH+P??XJ7$4dDo zZV}$_9(gV__l^M%Qpl-oyz#l#j&h?HWKkygRXWVH%X&;sJL_#;t1x>_C@S>c&|^V^ zsXam2$J^Qo^Ldvn-BsDm^%`QowZGg6e~N5^a*!Mz=B+Zqa#>CtWAUjr+w{b6QI>bT z-FLQJ^tQIs{3b%4NxVxI(c}Iomvng^()3vIGv!a->VLCNkh@KgNB>yv@~-T5vvQ%< z$PE>HyO?5`3{o7uJokIIgX- zS68-64Y`P0PO*DMI&7&Xr|$7K$(N>2^)H*AELpp)27aHMuZ7BHCf6t@yUk>`vA4CI z3jWkMFLhp7#zo`fuWSB7F4RhP>w61)ZoVWdyplKmmG!7sgiF@r-q82f&wL?EH@S8% z*?rDi=NC&qZ|HkvJ8!7W(pfHZUakrI&sN+(kWY|VrpmG&e)7gAn_S*8{oVRd*2)06 zs?wW!->UJ3hFahDuZ1Nh9^myZlRIuLyJ@ofhPPBtagle5RkLM!%h$AJc|)7c zFZhSnOcV-YV?`kYy=3^t`yLW|BEIXXw3k#u!F?Qf2`_g#D1oZ(P6uOt?Dl^EIMK7% diff --git a/deps/icu-small/source/i18n/alphaindex.cpp b/deps/icu-small/source/i18n/alphaindex.cpp index f4a082c5b20e5e..99f70114cbdb15 100644 --- a/deps/icu-small/source/i18n/alphaindex.cpp +++ b/deps/icu-small/source/i18n/alphaindex.cpp @@ -511,8 +511,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const { ces, errorCode) && current.charAt(current.length() - 1) != 0xFFFF /* !current.endsWith("\uffff") */) { // "AE-ligature" or "Sch" etc. - for (int32_t i = bucketList->size() - 2;; --i) { - Bucket *singleBucket = getBucket(*bucketList, i); + for (int32_t j = bucketList->size() - 2;; --j) { + Bucket *singleBucket = getBucket(*bucketList, j); if (singleBucket->labelType_ != U_ALPHAINDEX_NORMAL) { // There is no single-character bucket since the last // underflow or inflow label. @@ -608,8 +608,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const { } // Do not call publicBucketList->setDeleter(): // This vector shares its objects with the bucketList. - for (int32_t i = 0; i < bucketList->size(); ++i) { - bucket = getBucket(*bucketList, i); + for (int32_t j = 0; j < bucketList->size(); ++j) { + bucket = getBucket(*bucketList, j); if (bucket->displayBucket_ == NULL) { publicBucketList->addElement(bucket, errorCode); } diff --git a/deps/icu-small/source/i18n/anytrans.cpp b/deps/icu-small/source/i18n/anytrans.cpp index d06469e2ae2746..6e382b824b95b7 100644 --- a/deps/icu-small/source/i18n/anytrans.cpp +++ b/deps/icu-small/source/i18n/anytrans.cpp @@ -391,12 +391,12 @@ void AnyTransliterator::registerIDs() { UnicodeString id; TransliteratorIDParser::STVtoID(UnicodeString(TRUE, ANY, 3), target, variant, id); ec = U_ZERO_ERROR; - AnyTransliterator* t = new AnyTransliterator(id, target, variant, + AnyTransliterator* tl = new AnyTransliterator(id, target, variant, targetScript, ec); if (U_FAILURE(ec)) { - delete t; + delete tl; } else { - Transliterator::_registerInstance(t); + Transliterator::_registerInstance(tl); Transliterator::_registerSpecialInverse(target, UnicodeString(TRUE, NULL_ID, 4), FALSE); } } diff --git a/deps/icu-small/source/i18n/calendar.cpp b/deps/icu-small/source/i18n/calendar.cpp index 61757cb250f77d..24c2fb964e91a1 100644 --- a/deps/icu-small/source/i18n/calendar.cpp +++ b/deps/icu-small/source/i18n/calendar.cpp @@ -3797,7 +3797,7 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode& Locale max = Locale::createFromName(maxLocaleID); useLocale = Locale(max.getLanguage(),max.getCountry()); } else { - useLocale = Locale(desiredLocale); + useLocale = desiredLocale; } /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to diff --git a/deps/icu-small/source/i18n/coll.cpp b/deps/icu-small/source/i18n/coll.cpp index b7348a1d16f1e1..2a614fac5dcfbc 100644 --- a/deps/icu-small/source/i18n/coll.cpp +++ b/deps/icu-small/source/i18n/coll.cpp @@ -448,6 +448,13 @@ Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale, #endif { coll = makeInstance(desiredLocale, status); + // Either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status) + } + // The use of *coll in setAttributesFromKeywords can cause the NULL check to be + // optimized out of the delete even though setAttributesFromKeywords returns + // immediately if U_FAILURE(status), so we add a check here. + if (U_FAILURE(status)) { + return NULL; } setAttributesFromKeywords(desiredLocale, *coll, status); if (U_FAILURE(status)) { @@ -986,8 +993,8 @@ Collator::internalCompareUTF8(const char *left, int32_t leftLength, return UCOL_EQUAL; } return compareUTF8( - StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength), - StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength), + StringPiece(left, (leftLength < 0) ? static_cast(uprv_strlen(left)) : leftLength), + StringPiece(right, (rightLength < 0) ? static_cast(uprv_strlen(right)) : rightLength), errorCode); } diff --git a/deps/icu-small/source/i18n/collationkeys.cpp b/deps/icu-small/source/i18n/collationkeys.cpp index 4b9e6b59075e1d..b5c322fb44679b 100644 --- a/deps/icu-small/source/i18n/collationkeys.cpp +++ b/deps/icu-small/source/i18n/collationkeys.cpp @@ -403,13 +403,13 @@ CollationKeys::writeSortKeyUpToQuaternary(CollationIterator &iter, uint8_t *secs = secondaries.data(); int32_t last = secondaries.length() - 1; if(secSegmentStart < last) { - uint8_t *p = secs + secSegmentStart; - uint8_t *q = secs + last; + uint8_t *q = secs + secSegmentStart; + uint8_t *r = secs + last; do { - uint8_t b = *p; - *p++ = *q; - *q-- = b; - } while(p < q); + uint8_t b = *q; + *q++ = *r; + *r-- = b; + } while(q < r); } secondaries.appendByte(p == Collation::NO_CE_PRIMARY ? Collation::LEVEL_SEPARATOR_BYTE : Collation::MERGE_SEPARATOR_BYTE); diff --git a/deps/icu-small/source/i18n/csrmbcs.cpp b/deps/icu-small/source/i18n/csrmbcs.cpp index 0c2df594d56a75..46d626bb3f4ffe 100644 --- a/deps/icu-small/source/i18n/csrmbcs.cpp +++ b/deps/icu-small/source/i18n/csrmbcs.cpp @@ -166,7 +166,7 @@ int32_t CharsetRecog_mbcs::match_mbcs(InputText *det, const uint16_t commonChars doubleByteCharCount++; if (commonChars != 0) { - if (binarySearch(commonChars, commonCharsLen, iter.charValue) >= 0){ + if (binarySearch(commonChars, commonCharsLen, static_cast(iter.charValue)) >= 0){ commonCharCount += 1; } } diff --git a/deps/icu-small/source/i18n/currpinf.cpp b/deps/icu-small/source/i18n/currpinf.cpp index 6b1efd5f4da721..f5d27e28d8ebfa 100644 --- a/deps/icu-small/source/i18n/currpinf.cpp +++ b/deps/icu-small/source/i18n/currpinf.cpp @@ -17,7 +17,6 @@ #include #endif - #include "unicode/locid.h" #include "unicode/plurrule.h" #include "unicode/strenum.h" @@ -30,7 +29,6 @@ U_NAMESPACE_BEGIN - static const UChar gNumberPatternSeparator = 0x3B; // ; U_CDECL_BEGIN @@ -65,66 +63,86 @@ static const char gDecimalFormatTag[]="decimalFormat"; static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns"; CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status) -: fPluralCountToCurrencyUnitPattern(NULL), - fPluralRules(NULL), - fLocale(NULL) { +: fPluralCountToCurrencyUnitPattern(nullptr), + fPluralRules(nullptr), + fLocale(nullptr), + fInternalStatus(U_ZERO_ERROR) { initialize(Locale::getDefault(), status); } CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status) -: fPluralCountToCurrencyUnitPattern(NULL), - fPluralRules(NULL), - fLocale(NULL) { +: fPluralCountToCurrencyUnitPattern(nullptr), + fPluralRules(nullptr), + fLocale(nullptr), + fInternalStatus(U_ZERO_ERROR) { initialize(locale, status); } CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info) : UObject(info), - fPluralCountToCurrencyUnitPattern(NULL), - fPluralRules(NULL), - fLocale(NULL) { + fPluralCountToCurrencyUnitPattern(nullptr), + fPluralRules(nullptr), + fLocale(nullptr), + fInternalStatus(U_ZERO_ERROR) { *this = info; } - CurrencyPluralInfo& CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) { if (this == &info) { return *this; } + fInternalStatus = info.fInternalStatus; + if (U_FAILURE(fInternalStatus)) { + // bail out early if the object we were copying from was already 'invalid'. + return *this; + } + deleteHash(fPluralCountToCurrencyUnitPattern); - UErrorCode status = U_ZERO_ERROR; - fPluralCountToCurrencyUnitPattern = initHash(status); + fPluralCountToCurrencyUnitPattern = initHash(fInternalStatus); copyHash(info.fPluralCountToCurrencyUnitPattern, - fPluralCountToCurrencyUnitPattern, status); - if ( U_FAILURE(status) ) { + fPluralCountToCurrencyUnitPattern, fInternalStatus); + if ( U_FAILURE(fInternalStatus) ) { return *this; } delete fPluralRules; + fPluralRules = nullptr; delete fLocale; - if (info.fPluralRules) { + fLocale = nullptr; + + if (info.fPluralRules != nullptr) { fPluralRules = info.fPluralRules->clone(); - } else { - fPluralRules = NULL; + if (fPluralRules == nullptr) { + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + return *this; + } } - if (info.fLocale) { + if (info.fLocale != nullptr) { fLocale = info.fLocale->clone(); - } else { - fLocale = NULL; + if (fLocale == nullptr) { + // Note: If clone had an error parameter, then we could check/set that instead. + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + return *this; + } + // If the other locale wasn't bogus, but our clone'd locale is bogus, then OOM happened + // during the call to clone(). + if (!info.fLocale->isBogus() && fLocale->isBogus()) { + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + return *this; + } } return *this; } - CurrencyPluralInfo::~CurrencyPluralInfo() { deleteHash(fPluralCountToCurrencyUnitPattern); - fPluralCountToCurrencyUnitPattern = NULL; + fPluralCountToCurrencyUnitPattern = nullptr; delete fPluralRules; delete fLocale; - fPluralRules = NULL; - fLocale = NULL; + fPluralRules = nullptr; + fLocale = nullptr; } UBool @@ -148,7 +166,14 @@ CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const { CurrencyPluralInfo* CurrencyPluralInfo::clone() const { - return new CurrencyPluralInfo(*this); + CurrencyPluralInfo* newObj = new CurrencyPluralInfo(*this); + // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr + // if the new object was not full constructed properly (an error occurred). + if (newObj != nullptr && U_FAILURE(newObj->fInternalStatus)) { + delete newObj; + newObj = nullptr; + } + return newObj; } const PluralRules* @@ -161,15 +186,15 @@ CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount, UnicodeString& result) const { const UnicodeString* currencyPluralPattern = (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount); - if (currencyPluralPattern == NULL) { + if (currencyPluralPattern == nullptr) { // fall back to "other" if (pluralCount.compare(gPluralCountOther, 5)) { currencyPluralPattern = (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5)); } - if (currencyPluralPattern == NULL) { + if (currencyPluralPattern == nullptr) { // no currencyUnitPatterns defined, - // fallback to predefined defult. + // fallback to predefined default. // This should never happen when ICU resource files are // available, since currencyUnitPattern of "other" is always // defined in root. @@ -190,14 +215,11 @@ void CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription, UErrorCode& status) { if (U_SUCCESS(status)) { - if (fPluralRules) { - delete fPluralRules; - } + delete fPluralRules; fPluralRules = PluralRules::createRules(ruleDescription, status); } } - void CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, const UnicodeString& pattern, @@ -206,63 +228,77 @@ CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, UnicodeString* oldValue = static_cast( fPluralCountToCurrencyUnitPattern->get(pluralCount)); delete oldValue; - fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status); + LocalPointer p(new UnicodeString(pattern), status); + if (U_SUCCESS(status)) { + // the p object allocated above will be owned by fPluralCountToCurrencyUnitPattern + // after the call to put(), even if the method returns failure. + fPluralCountToCurrencyUnitPattern->put(pluralCount, p.orphan(), status); + } } } - void CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) { initialize(loc, status); } - void CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) { if (U_FAILURE(status)) { return; } delete fLocale; + fLocale = nullptr; + delete fPluralRules; + fPluralRules = nullptr; + fLocale = loc.clone(); - if (fPluralRules) { - delete fPluralRules; + if (fLocale == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + // If the locale passed in wasn't bogus, but our clone'd locale is bogus, then OOM happened + // during the call to loc.clone(). + if (!loc.isBogus() && fLocale->isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + return; } fPluralRules = PluralRules::forLocale(loc, status); setupCurrencyPluralPattern(loc, status); } - void CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) { if (U_FAILURE(status)) { return; } - if (fPluralCountToCurrencyUnitPattern) { - deleteHash(fPluralCountToCurrencyUnitPattern); - } + deleteHash(fPluralCountToCurrencyUnitPattern); fPluralCountToCurrencyUnitPattern = initHash(status); if (U_FAILURE(status)) { return; } - NumberingSystem *ns = NumberingSystem::createInstance(loc,status); + LocalPointer ns(NumberingSystem::createInstance(loc, status), status); + if (U_FAILURE(status)) { + return; + } UErrorCode ec = U_ZERO_ERROR; - UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec); - UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec); - rb = ures_getByKeyWithFallback(numElements, ns->getName(), rb, &ec); - rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec); + LocalUResourceBundlePointer rb(ures_open(nullptr, loc.getName(), &ec)); + LocalUResourceBundlePointer numElements(ures_getByKeyWithFallback(rb.getAlias(), gNumberElementsTag, nullptr, &ec)); + ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.getAlias(), &ec); + ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec); int32_t ptnLen; - const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec); + const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec); // Fall back to "latn" if num sys specific pattern isn't there. - if ( ec == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),gLatnTag)) { + if ( ec == U_MISSING_RESOURCE_ERROR && (uprv_strcmp(ns->getName(), gLatnTag) != 0)) { ec = U_ZERO_ERROR; - rb = ures_getByKeyWithFallback(numElements, gLatnTag, rb, &ec); - rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec); - numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec); + ures_getByKeyWithFallback(numElements.getAlias(), gLatnTag, rb.getAlias(), &ec); + ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec); + numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec); } int32_t numberStylePatternLen = ptnLen; - const UChar* negNumberStylePattern = NULL; + const UChar* negNumberStylePattern = nullptr; int32_t negNumberStylePatternLen = 0; // TODO: Java // parse to check whether there is ";" separator in the numberStylePattern @@ -279,127 +315,127 @@ CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& st } } - ures_close(numElements); - ures_close(rb); - delete ns; - if (U_FAILURE(ec)) { + // If OOM occurred during the above code, then we want to report that back to the caller. + if (ec == U_MEMORY_ALLOCATION_ERROR) { + status = ec; + } return; } - UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec); - UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec); + LocalUResourceBundlePointer currRb(ures_open(U_ICUDATA_CURR, loc.getName(), &ec)); + LocalUResourceBundlePointer currencyRes(ures_getByKeyWithFallback(currRb.getAlias(), gCurrUnitPtnTag, nullptr, &ec)); #ifdef CURRENCY_PLURAL_INFO_DEBUG std::cout << "in set up\n"; #endif - StringEnumeration* keywords = fPluralRules->getKeywords(ec); + LocalPointer keywords(fPluralRules->getKeywords(ec), ec); if (U_SUCCESS(ec)) { const char* pluralCount; - while ((pluralCount = keywords->next(NULL, ec)) != NULL) { - if ( U_SUCCESS(ec) ) { - int32_t ptnLen; - UErrorCode err = U_ZERO_ERROR; - const UChar* patternChars = ures_getStringByKeyWithFallback( - currencyRes, pluralCount, &ptnLen, &err); - if (U_SUCCESS(err) && ptnLen > 0) { - UnicodeString* pattern = new UnicodeString(patternChars, ptnLen); + while (((pluralCount = keywords->next(nullptr, ec)) != nullptr) && U_SUCCESS(ec)) { + int32_t ptnLength; + UErrorCode err = U_ZERO_ERROR; + const UChar* patternChars = ures_getStringByKeyWithFallback(currencyRes.getAlias(), pluralCount, &ptnLength, &err); + if (err == U_MEMORY_ALLOCATION_ERROR || patternChars == nullptr) { + ec = err; + break; + } + if (U_SUCCESS(err) && ptnLength > 0) { + UnicodeString* pattern = new UnicodeString(patternChars, ptnLength); + if (pattern == nullptr) { + ec = U_MEMORY_ALLOCATION_ERROR; + break; + } #ifdef CURRENCY_PLURAL_INFO_DEBUG - char result_1[1000]; - pattern->extract(0, pattern->length(), result_1, "UTF-8"); - std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; + char result_1[1000]; + pattern->extract(0, pattern->length(), result_1, "UTF-8"); + std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; #endif - pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3), - UnicodeString(numberStylePattern, numberStylePatternLen)); - pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); - - if (hasSeparator) { - UnicodeString negPattern(patternChars, ptnLen); - negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3), - UnicodeString(negNumberStylePattern, negNumberStylePatternLen)); - negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); - pattern->append(gNumberPatternSeparator); - pattern->append(negPattern); - } + pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3), + UnicodeString(numberStylePattern, numberStylePatternLen)); + pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); + + if (hasSeparator) { + UnicodeString negPattern(patternChars, ptnLength); + negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3), + UnicodeString(negNumberStylePattern, negNumberStylePatternLen)); + negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); + pattern->append(gNumberPatternSeparator); + pattern->append(negPattern); + } #ifdef CURRENCY_PLURAL_INFO_DEBUG - pattern->extract(0, pattern->length(), result_1, "UTF-8"); - std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; + pattern->extract(0, pattern->length(), result_1, "UTF-8"); + std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; #endif - - fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status); - } + // the 'pattern' object allocated above will be owned by the fPluralCountToCurrencyUnitPattern after the call to + // put(), even if the method returns failure. + fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status); } } } - delete keywords; - ures_close(currencyRes); - ures_close(currRb); + // If OOM occurred during the above code, then we want to report that back to the caller. + if (ec == U_MEMORY_ALLOCATION_ERROR) { + status = ec; + } } - - void -CurrencyPluralInfo::deleteHash(Hashtable* hTable) -{ - if ( hTable == NULL ) { +CurrencyPluralInfo::deleteHash(Hashtable* hTable) { + if ( hTable == nullptr ) { return; } int32_t pos = UHASH_FIRST; - const UHashElement* element = NULL; - while ( (element = hTable->nextElement(pos)) != NULL ) { + const UHashElement* element = nullptr; + while ( (element = hTable->nextElement(pos)) != nullptr ) { const UHashTok valueTok = element->value; const UnicodeString* value = (UnicodeString*)valueTok.pointer; delete value; } delete hTable; - hTable = NULL; + hTable = nullptr; } - Hashtable* CurrencyPluralInfo::initHash(UErrorCode& status) { - if ( U_FAILURE(status) ) { - return NULL; - } - Hashtable* hTable; - if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; + if (U_FAILURE(status)) { + return nullptr; } - if ( U_FAILURE(status) ) { - delete hTable; - return NULL; + LocalPointer hTable(new Hashtable(TRUE, status), status); + if (U_FAILURE(status)) { + return nullptr; } hTable->setValueComparator(ValueComparator); - return hTable; + return hTable.orphan(); } - void CurrencyPluralInfo::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) { - if ( U_FAILURE(status) ) { + if (U_FAILURE(status)) { return; } int32_t pos = UHASH_FIRST; - const UHashElement* element = NULL; - if ( source ) { - while ( (element = source->nextElement(pos)) != NULL ) { + const UHashElement* element = nullptr; + if (source) { + while ( (element = source->nextElement(pos)) != nullptr ) { const UHashTok keyTok = element->key; const UnicodeString* key = (UnicodeString*)keyTok.pointer; const UHashTok valueTok = element->value; const UnicodeString* value = (UnicodeString*)valueTok.pointer; - UnicodeString* copy = new UnicodeString(*value); - target->put(UnicodeString(*key), copy, status); - if ( U_FAILURE(status) ) { + LocalPointer copy(new UnicodeString(*value), status); + if (U_FAILURE(status)) { + return; + } + // The HashTable owns the 'copy' object after the call to put(). + target->put(UnicodeString(*key), copy.orphan(), status); + if (U_FAILURE(status)) { return; } } } } - U_NAMESPACE_END #endif diff --git a/deps/icu-small/source/i18n/currunit.cpp b/deps/icu-small/source/i18n/currunit.cpp index 6d8d1cd6c6f97f..2ece508751bcec 100644 --- a/deps/icu-small/source/i18n/currunit.cpp +++ b/deps/icu-small/source/i18n/currunit.cpp @@ -27,9 +27,14 @@ CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) { // The constructor always leaves the CurrencyUnit in a valid state (with a 3-character currency code). // Note: in ICU4J Currency.getInstance(), we check string length for 3, but in ICU4C we allow a // non-NUL-terminated string to be passed as an argument, so it is not possible to check length. + // However, we allow a NUL-terminated empty string, which should have the same behavior as nullptr. + // Consider NUL-terminated strings of length 1 or 2 as invalid. const char16_t* isoCodeToUse; - if (U_FAILURE(ec) || _isoCode == nullptr) { + if (U_FAILURE(ec) || _isoCode == nullptr || _isoCode[0] == 0) { isoCodeToUse = kDefaultCurrency; + } else if (_isoCode[1] == 0 || _isoCode[2] == 0) { + isoCodeToUse = kDefaultCurrency; + ec = U_ILLEGAL_ARGUMENT_ERROR; } else if (!uprv_isInvariantUString(_isoCode, 3)) { // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code? isoCodeToUse = kDefaultCurrency; diff --git a/deps/icu-small/source/i18n/dcfmtsym.cpp b/deps/icu-small/source/i18n/dcfmtsym.cpp index 5a432aec8e4df0..04113785f27308 100644 --- a/deps/icu-small/source/i18n/dcfmtsym.cpp +++ b/deps/icu-small/source/i18n/dcfmtsym.cpp @@ -436,7 +436,7 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, sink.resolveMissingMonetarySeparators(fSymbols); // Resolve codePointZero - UChar32 tempCodePointZero; + UChar32 tempCodePointZero = -1; for (int32_t i=0; i<=9; i++) { const UnicodeString& stringDigit = getConstDigitSymbol(i); if (stringDigit.countChar32() != 1) { diff --git a/deps/icu-small/source/i18n/decimfmt.cpp b/deps/icu-small/source/i18n/decimfmt.cpp index a2638bb74298e3..edd8910d9d4fd6 100644 --- a/deps/icu-small/source/i18n/decimfmt.cpp +++ b/deps/icu-small/source/i18n/decimfmt.cpp @@ -1057,12 +1057,19 @@ UBool DecimalFormat::areSignificantDigitsUsed() const { void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { // These are the default values from the old implementation. + if (useSignificantDigits) { + if (fields->properties->minimumSignificantDigits != -1 || + fields->properties->maximumSignificantDigits != -1) { + return; + } + } else { + if (fields->properties->minimumSignificantDigits == -1 && + fields->properties->maximumSignificantDigits == -1) { + return; + } + } int32_t minSig = useSignificantDigits ? 1 : -1; int32_t maxSig = useSignificantDigits ? 6 : -1; - if (fields->properties->minimumSignificantDigits == minSig && - fields->properties->maximumSignificantDigits == maxSig) { - return; - } fields->properties->minimumSignificantDigits = minSig; fields->properties->maximumSignificantDigits = maxSig; touchNoError(); @@ -1175,7 +1182,12 @@ void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32 } const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const { - if (U_FAILURE(status)) { return nullptr; } + // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp) + // See ICU-20146 + + if (U_FAILURE(status)) { + return nullptr; + } // First try to get the pre-computed parser auto* ptr = fields->atomicParser.load(); @@ -1185,13 +1197,17 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta // Try computing the parser on our own auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status); + if (U_FAILURE(status)) { + return nullptr; + } if (temp == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; - // although we may still dereference, call sites should be guarded + return nullptr; } - // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the - // atomic if another thread beat us to computing the parser object. + // Note: ptr starts as nullptr; during compare_exchange, + // it is set to what is actually stored in the atomic + // if another thread beat us to computing the parser object. auto* nonConstThis = const_cast(this); if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) { // Another thread beat us to computing the parser diff --git a/deps/icu-small/source/i18n/dtfmtsym.cpp b/deps/icu-small/source/i18n/dtfmtsym.cpp index af421d41c72e61..c9dfa045831d60 100644 --- a/deps/icu-small/source/i18n/dtfmtsym.cpp +++ b/deps/icu-small/source/i18n/dtfmtsym.cpp @@ -1311,7 +1311,7 @@ DateFormatSymbols::initZoneStringsArray(void) { UDate now = Calendar::getNow(); UnicodeString tzDispName; - while ((tzid = tzids->snext(status))) { + while ((tzid = tzids->snext(status)) != 0) { if (U_FAILURE(status)) { break; } @@ -2224,8 +2224,8 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError ++typeMapPtr; } if (typeMapPtr->usageTypeName != NULL && compResult == 0) { - fCapitalization[typeMapPtr->usageTypeEnumValue][0] = intVector[0]; - fCapitalization[typeMapPtr->usageTypeEnumValue][1] = intVector[1]; + fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast(intVector[0]); + fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast(intVector[1]); } } } diff --git a/deps/icu-small/source/i18n/dtitvfmt.cpp b/deps/icu-small/source/i18n/dtitvfmt.cpp index 743b534fc8f9cf..d952cbf509dc40 100644 --- a/deps/icu-small/source/i18n/dtitvfmt.cpp +++ b/deps/icu-small/source/i18n/dtitvfmt.cpp @@ -877,8 +877,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton, if ( MCount < 3 ) { normalizedDateSkeleton.append(CAP_M); } else { - int32_t i; - for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) { + for ( int32_t j = 0; j < MCount && j < MAX_M_COUNT; ++j) { normalizedDateSkeleton.append(CAP_M); } } @@ -887,8 +886,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton, if ( ECount <= 3 ) { normalizedDateSkeleton.append(CAP_E); } else { - int32_t i; - for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) { + for ( int32_t j = 0; j < ECount && j < MAX_E_COUNT; ++j ) { normalizedDateSkeleton.append(CAP_E); } } diff --git a/deps/icu-small/source/i18n/dtitvinf.cpp b/deps/icu-small/source/i18n/dtitvinf.cpp index c863a683a5c2f8..a289fc79c8da0e 100644 --- a/deps/icu-small/source/i18n/dtitvinf.cpp +++ b/deps/icu-small/source/i18n/dtitvinf.cpp @@ -594,7 +594,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, const UHashElement* elem = NULL; while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) { const UHashTok keyTok = elem->key; - UnicodeString* skeleton = (UnicodeString*)keyTok.pointer; + UnicodeString* newSkeleton = (UnicodeString*)keyTok.pointer; #ifdef DTITVINF_DEBUG skeleton->extract(0, skeleton->length(), result, "UTF-8"); sprintf(mesg, "available skeletons: skeleton: %s; \n", result); @@ -606,7 +606,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, for ( i = 0; i < fieldLength; ++i ) { skeletonFieldWidth[i] = 0; } - parseSkeleton(*skeleton, skeletonFieldWidth); + parseSkeleton(*newSkeleton, skeletonFieldWidth); // calculate distance int32_t distance = 0; int8_t fieldDifference = 1; @@ -632,7 +632,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, } } if ( distance < bestDistance ) { - bestSkeleton = skeleton; + bestSkeleton = newSkeleton; bestDistance = distance; bestMatchDistanceInfo = fieldDifference; } diff --git a/deps/icu-small/source/i18n/dtptngen.cpp b/deps/icu-small/source/i18n/dtptngen.cpp index aefd70464eb2d8..b44daf37bf5802 100644 --- a/deps/icu-small/source/i18n/dtptngen.cpp +++ b/deps/icu-small/source/i18n/dtptngen.cpp @@ -18,6 +18,7 @@ #include "unicode/decimfmt.h" #include "unicode/dtfmtsym.h" #include "unicode/dtptngen.h" +#include "unicode/localpointer.h" #include "unicode/simpleformatter.h" #include "unicode/smpdtfmt.h" #include "unicode/udat.h" @@ -88,17 +89,17 @@ static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, aiter->num = ures_getSize(aiter->bund); aiter->cursor = 0; #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR) - aiter->entries = NULL; + aiter->entries = nullptr; #else aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num); for(int i=0;inum;i++) { - aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status); + aiter->entries[i].item = ures_getByIndex(aiter->bund, i, nullptr, status); const char *akey = ures_getKey(aiter->entries[i].item); int32_t len = uprv_strlen(akey)+1; aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar)); u_charsToUChars(akey, aiter->entries[i].key, len); } - uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status); + uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, nullptr, TRUE, status); #endif } @@ -115,7 +116,7 @@ static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_ #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR) return ures_getNextString(aiter->bund, len, key, err); #else - if(U_FAILURE(*err)) return NULL; + if(U_FAILURE(*err)) return nullptr; UResourceBundle *item = aiter->entries[aiter->cursor].item; const UChar* ret = ures_getString(item, len, err); *key = ures_getKey(item); @@ -302,49 +303,48 @@ DateTimePatternGenerator::createInstance(UErrorCode& status) { DateTimePatternGenerator* U_EXPORT2 DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } LocalPointer result( new DateTimePatternGenerator(locale, status), status); - return U_SUCCESS(status) ? result.orphan() : NULL; + return U_SUCCESS(status) ? result.orphan() : nullptr; } DateTimePatternGenerator* U_EXPORT2 DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) { - DateTimePatternGenerator *result = new DateTimePatternGenerator(status); - if (result == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } if (U_FAILURE(status)) { - delete result; - result = NULL; + return nullptr; } - return result; + LocalPointer result( + new DateTimePatternGenerator(status), status); + return U_SUCCESS(status) ? result.orphan() : nullptr; } DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) : - skipMatcher(NULL), - fAvailableFormatKeyHash(NULL) + skipMatcher(nullptr), + fAvailableFormatKeyHash(nullptr), + internalErrorCode(U_ZERO_ERROR) { fp = new FormatParser(); dtMatcher = new DateTimeMatcher(); distanceInfo = new DistanceInfo(); patternMap = new PatternMap(); - if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; + if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { + internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR; } } DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) : - skipMatcher(NULL), - fAvailableFormatKeyHash(NULL) + skipMatcher(nullptr), + fAvailableFormatKeyHash(nullptr), + internalErrorCode(U_ZERO_ERROR) { fp = new FormatParser(); dtMatcher = new DateTimeMatcher(); distanceInfo = new DistanceInfo(); patternMap = new PatternMap(); - if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; + if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { + internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR; } else { initData(locale, status); @@ -353,13 +353,17 @@ DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorC DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) : UObject(), - skipMatcher(NULL), - fAvailableFormatKeyHash(NULL) + skipMatcher(nullptr), + fAvailableFormatKeyHash(nullptr), + internalErrorCode(U_ZERO_ERROR) { fp = new FormatParser(); dtMatcher = new DateTimeMatcher(); distanceInfo = new DistanceInfo(); patternMap = new PatternMap(); + if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { + internalErrorCode = U_MEMORY_ALLOCATION_ERROR; + } *this=other; } @@ -369,6 +373,7 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) { if (&other == this) { return *this; } + internalErrorCode = other.internalErrorCode; pLocale = other.pLocale; fDefaultHourFormatChar = other.fDefaultHourFormatChar; *fp = *(other.fp); @@ -380,11 +385,16 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) { dateTimeFormat.getTerminatedBuffer(); decimal.getTerminatedBuffer(); delete skipMatcher; - if ( other.skipMatcher == NULL ) { - skipMatcher = NULL; + if ( other.skipMatcher == nullptr ) { + skipMatcher = nullptr; } else { skipMatcher = new DateTimeMatcher(*other.skipMatcher); + if (skipMatcher == nullptr) + { + internalErrorCode = U_MEMORY_ALLOCATION_ERROR; + return *this; + } } for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) { appendItemFormats[i] = other.appendItemFormats[i]; @@ -394,9 +404,8 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) { fieldDisplayNames[i][j].getTerminatedBuffer(); // NUL-terminate for the C API. } } - UErrorCode status = U_ZERO_ERROR; - patternMap->copyFrom(*other.patternMap, status); - copyHashtable(other.fAvailableFormatKeyHash, status); + patternMap->copyFrom(*other.patternMap, internalErrorCode); + copyHashtable(other.fAvailableFormatKeyHash, internalErrorCode); return *this; } @@ -431,21 +440,21 @@ DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) cons } DateTimePatternGenerator::~DateTimePatternGenerator() { - if (fAvailableFormatKeyHash!=NULL) { + if (fAvailableFormatKeyHash!=nullptr) { delete fAvailableFormatKeyHash; } - if (fp != NULL) delete fp; - if (dtMatcher != NULL) delete dtMatcher; - if (distanceInfo != NULL) delete distanceInfo; - if (patternMap != NULL) delete patternMap; - if (skipMatcher != NULL) delete skipMatcher; + if (fp != nullptr) delete fp; + if (dtMatcher != nullptr) delete dtMatcher; + if (distanceInfo != nullptr) delete distanceInfo; + if (patternMap != nullptr) delete patternMap; + if (skipMatcher != nullptr) delete skipMatcher; } namespace { UInitOnce initOnce = U_INITONCE_INITIALIZER; -UHashtable *localeToAllowedHourFormatsMap = NULL; +UHashtable *localeToAllowedHourFormatsMap = nullptr; // Value deleter for hashmap. U_CFUNC void U_CALLCONV deleteAllowedHourFormats(void *ptr) { @@ -474,8 +483,8 @@ void DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) { //const char *baseLangName = locale.getBaseName(); // unused - skipMatcher = NULL; - fAvailableFormatKeyHash=NULL; + skipMatcher = nullptr; + fAvailableFormatKeyHash=nullptr; addCanonicalItems(status); addICUPatterns(locale, status); addCLDRData(locale, status); @@ -483,6 +492,8 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) { setDecimalSymbols(locale, status); umtx_initOnce(initOnce, loadAllowedHourFormatsData, status); getAllowedHourFormats(locale, status); + // If any of the above methods failed then the object is in an invalid state. + internalErrorCode = status; } // DateTimePatternGenerator::initData namespace { @@ -505,7 +516,7 @@ struct AllowedHourFormatsSink : public ResourceSink { LocalMemory list; int32_t length; if (value.getType() == URES_STRING) { - if (list.allocateInsteadAndReset(2) == NULL) { + if (list.allocateInsteadAndReset(2) == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; return; } @@ -515,7 +526,7 @@ struct AllowedHourFormatsSink : public ResourceSink { else { ResourceArray allowedFormats = value.getArray(errorCode); length = allowedFormats.getSize(); - if (list.allocateInsteadAndReset(length + 1) == NULL) { + if (list.allocateInsteadAndReset(length + 1) == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; return; } @@ -555,9 +566,14 @@ AllowedHourFormatsSink::~AllowedHourFormatsSink() {} U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) { if (U_FAILURE(status)) { return; } localeToAllowedHourFormatsMap = uhash_open( - uhash_hashChars, uhash_compareChars, NULL, &status); + uhash_hashChars, uhash_compareChars, nullptr, &status); + if (U_FAILURE(status)) { return; } + uhash_setValueDeleter(localeToAllowedHourFormatsMap, deleteAllowedHourFormats); - LocalUResourceBundlePointer rb(ures_openDirect(NULL, "supplementalData", &status)); + ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup); + + LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status)); + if (U_FAILURE(status)) { return; } AllowedHourFormatsSink sink; // TODO: Currently in the enumeration each table allocates a new array. @@ -567,8 +583,6 @@ U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UEr // vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime // object. Remember to clean up the vector, too. ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status); - - ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup); } void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErrorCode &status) { @@ -589,17 +603,17 @@ void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErro const char *language = maxLocale.getLanguage(); CharString langCountry; - langCountry.append(language, uprv_strlen(language), status); + langCountry.append(language, static_cast(uprv_strlen(language)), status); langCountry.append('_', status); - langCountry.append(country, uprv_strlen(country), status); + langCountry.append(country, static_cast(uprv_strlen(country)), status); int32_t *allowedFormats; allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data()); - if (allowedFormats == NULL) { + if (allowedFormats == nullptr) { allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast(country)); } - if (allowedFormats != NULL) { // Lookup is successful + if (allowedFormats != nullptr) { // Lookup is successful for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) { fAllowedHourFormats[i] = allowedFormats[i]; if (allowedFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) { @@ -615,10 +629,10 @@ void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErro UnicodeString DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { - FormatParser fp; + FormatParser fp2; DateTimeMatcher matcher; PtnSkeleton localSkeleton; - matcher.set(pattern, &fp, localSkeleton); + matcher.set(pattern, &fp2, localSkeleton); return localSkeleton.getSkeleton(); } @@ -634,10 +648,10 @@ DateTimePatternGenerator::staticGetSkeleton( UnicodeString DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { - FormatParser fp; + FormatParser fp2; DateTimeMatcher matcher; PtnSkeleton localSkeleton; - matcher.set(pattern, &fp, localSkeleton); + matcher.set(pattern, &fp2, localSkeleton); return localSkeleton.getBaseSkeleton(); } @@ -663,7 +677,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu DateFormat::EStyle style = (DateFormat::EStyle)i; df = DateFormat::createDateInstance(style, locale); SimpleDateFormat* sdf; - if (df != NULL && (sdf = dynamic_cast(df)) != NULL) { + if (df != nullptr && (sdf = dynamic_cast(df)) != nullptr) { sdf->toPattern(dfPattern); addPattern(dfPattern, FALSE, conflictingString, status); } @@ -672,7 +686,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu if (U_FAILURE(status)) { return; } df = DateFormat::createTimeInstance(style, locale); - if (df != NULL && (sdf = dynamic_cast(df)) != NULL) { + if (df != nullptr && (sdf = dynamic_cast(df)) != nullptr) { sdf->toPattern(dfPattern); addPattern(dfPattern, FALSE, conflictingString, status); @@ -747,13 +761,14 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& ures_getFunctionalEquivalent( localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, - NULL, + nullptr, "calendar", "calendar", locale.getName(), - NULL, + nullptr, FALSE, &err); + if (U_FAILURE(err)) { return; } localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination // now get the calendar key value from that locale char calendarType[ULOC_KEYWORDS_CAPACITY]; @@ -763,7 +778,8 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& calendarType, ULOC_KEYWORDS_CAPACITY, &err); - if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { + if (U_FAILURE(err)) { return; } + if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { destination.clear().append(calendarType, -1, err); if (U_FAILURE(err)) { return; } } @@ -774,7 +790,7 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& void DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTimePattern, UErrorCode& status) { - + if (U_FAILURE(status)) { return; } // set fDefaultHourFormatChar to the hour format character from this pattern int32_t tfIdx, tfLen = shortTimePattern.length(); UBool ignoreChars = FALSE; @@ -782,7 +798,7 @@ DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTime UChar tfChar = shortTimePattern.charAt(tfIdx); if ( tfChar == SINGLE_QUOTE ) { ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote) - } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) { + } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != nullptr ) { fDefaultHourFormatChar = tfChar; break; } @@ -872,9 +888,9 @@ struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink { valueStr.getTerminatedBuffer(); } for (int32_t j = 1; j < UDATPG_WIDTH_COUNT; j++) { - UnicodeString& valueStr = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j); - if (valueStr.isEmpty()) { - valueStr = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1)); + UnicodeString& valueStr2 = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j); + if (valueStr2.isEmpty()) { + valueStr2 = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1)); } } } @@ -921,7 +937,7 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod UnicodeString rbPattern, value, field; CharString path; - LocalUResourceBundlePointer rb(ures_open(NULL, locale.getName(), &errorCode)); + LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode)); if (U_FAILURE(errorCode)) { return; } CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well @@ -966,12 +982,13 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod void DateTimePatternGenerator::initHashtable(UErrorCode& err) { - if (fAvailableFormatKeyHash!=NULL) { + if (U_FAILURE(err)) { return; } + if (fAvailableFormatKeyHash!=nullptr) { return; } - if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) { - err=U_MEMORY_ALLOCATION_ERROR; - return; + LocalPointer hash(new Hashtable(FALSE, err), err); + if (U_SUCCESS(err)) { + fAvailableFormatKeyHash = hash.orphan(); } } @@ -1028,7 +1045,14 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErro UnicodeString DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) { - const UnicodeString *bestPattern=NULL; + if (U_FAILURE(status)) { + return UnicodeString(); + } + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return UnicodeString(); + } + const UnicodeString *bestPattern = nullptr; UnicodeString dtFormat; UnicodeString resultPattern; int32_t flags = kDTPGNoFlags; @@ -1044,16 +1068,23 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate resultPattern.remove(); dtMatcher->set(patternFormMapped, fp); - const PtnSkeleton* specifiedSkeleton=NULL; - bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton); + const PtnSkeleton* specifiedSkeleton = nullptr; + bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, status, &specifiedSkeleton); + if (U_FAILURE(status)) { + return UnicodeString(); + } + if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) { resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options); return resultPattern; } int32_t neededFields = dtMatcher->getFieldMask(); - UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options); - UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options); + UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, status, options); + UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, status, options); + if (U_FAILURE(status)) { + return UnicodeString(); + } if (datePattern.length()==0) { if (timePattern.length()==0) { resultPattern.remove(); @@ -1074,7 +1105,7 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate /* * Map a skeleton that may have metacharacters jJC to one without, by replacing - * the metacharacters with locale-appropriate fields of of h/H/k/K and of a/b/B + * the metacharacters with locale-appropriate fields of h/H/k/K and of a/b/B * (depends on fDefaultHourFormatChar and fAllowedHourFormats being set, which in * turn depends on initData having been run). This method also updates the flags * as necessary. Returns the updated skeleton. @@ -1159,9 +1190,16 @@ UnicodeString DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern, const UnicodeString& skeleton, UDateTimePatternMatchOptions options, - UErrorCode& /*status*/) { + UErrorCode& status) { + if (U_FAILURE(status)) { + return UnicodeString(); + } + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return UnicodeString(); + } dtMatcher->set(skeleton, fp); - UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options); + UnicodeString result = adjustFieldTypes(pattern, nullptr, kDTPGNoFlags, options); return result; } @@ -1204,20 +1242,24 @@ DateTimePatternGenerator::getDateTimeFormat() const { void DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) { + if (U_FAILURE(status)) { return; } + const UChar *resStr; int32_t resStrLen = 0; - Calendar* fCalendar = Calendar::createInstance(locale, status); + LocalPointer fCalendar(Calendar::createInstance(locale, status), status); if (U_FAILURE(status)) { return; } - LocalUResourceBundlePointer calData(ures_open(NULL, locale.getBaseName(), &status)); + LocalUResourceBundlePointer calData(ures_open(nullptr, locale.getBaseName(), &status)); + if (U_FAILURE(status)) { return; } ures_getByKey(calData.getAlias(), DT_DateTimeCalendarTag, calData.getAlias(), &status); + if (U_FAILURE(status)) { return; } LocalUResourceBundlePointer dateTimePatterns; - if (fCalendar != NULL && fCalendar->getType() != NULL && *fCalendar->getType() != '\0' + if (fCalendar->getType() != nullptr && *fCalendar->getType() != '\0' && uprv_strcmp(fCalendar->getType(), DT_DateTimeGregorianTag) != 0) { dateTimePatterns.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), fCalendar->getType(), - NULL, &status)); + nullptr, &status)); ures_getByKeyWithFallback(dateTimePatterns.getAlias(), DT_DateTimePatternsTag, dateTimePatterns.getAlias(), &status); } @@ -1238,8 +1280,6 @@ DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCo } resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), (int32_t)DateFormat::kDateTime, &resStrLen, &status); setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen)); - - delete fCalendar; } void @@ -1259,7 +1299,12 @@ DateTimePatternGenerator::addPattern( UnicodeString &conflictingPattern, UErrorCode& status) { - return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status); + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return UDATPG_NO_CONFLICT; + } + + return addPatternWithSkeleton(pattern, nullptr, override, conflictingPattern, status); } // For DateTimePatternGenerator::addPatternWithSkeleton - @@ -1280,13 +1325,17 @@ DateTimePatternGenerator::addPatternWithSkeleton( UnicodeString& conflictingPattern, UErrorCode& status) { + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return UDATPG_NO_CONFLICT; + } UnicodeString basePattern; PtnSkeleton skeleton; UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT; DateTimeMatcher matcher; - if ( skeletonToUse == NULL ) { + if ( skeletonToUse == nullptr ) { matcher.set(pattern, fp, skeleton); matcher.getBasePattern(basePattern); } else { @@ -1302,7 +1351,7 @@ DateTimePatternGenerator::addPatternWithSkeleton( // availableFormats items from root, which should not override any previous entry with the same base. UBool entryHadSpecifiedSkeleton; const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton); - if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) { + if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) { conflictingStatus = UDATPG_BASE_CONFLICT; conflictingPattern = *duplicatePattern; if (!override) { @@ -1313,16 +1362,16 @@ DateTimePatternGenerator::addPatternWithSkeleton( // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for // the previously-specified conflicting item. - const PtnSkeleton* entrySpecifiedSkeleton = NULL; + const PtnSkeleton* entrySpecifiedSkeleton = nullptr; duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton); - if (duplicatePattern != NULL ) { + if (duplicatePattern != nullptr ) { conflictingStatus = UDATPG_CONFLICT; conflictingPattern = *duplicatePattern; - if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) { + if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) { return conflictingStatus; } } - patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status); + patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status); if(U_FAILURE(status)) { return conflictingStatus; } @@ -1369,13 +1418,16 @@ const UnicodeString* DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields, + UErrorCode &status, const PtnSkeleton** specifiedSkeletonPtr) { int32_t bestDistance = 0x7fffffff; DistanceInfo tempInfo; - const UnicodeString *bestPattern=NULL; - const PtnSkeleton* specifiedSkeleton=NULL; + const UnicodeString *bestPattern=nullptr; + const PtnSkeleton* specifiedSkeleton=nullptr; + + PatternMapIterator it(status); + if (U_FAILURE(status)) { return nullptr; } - PatternMapIterator it; for (it.set(*patternMap); it.hasNext(); ) { DateTimeMatcher trial = it.next(); if (trial.equals(skipMatcher)) { @@ -1485,8 +1537,8 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern, c = fDefaultHourFormatChar; } field.remove(); - for (int32_t i=adjFieldLen; i>0; --i) { - field+=c; + for (int32_t j=adjFieldLen; j>0; --j) { + field += c; } } newPattern+=field; @@ -1496,14 +1548,21 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern, } UnicodeString -DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) { +DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UErrorCode &status, UDateTimePatternMatchOptions options) { + if (U_FAILURE(status)) { + return UnicodeString(); + } UnicodeString resultPattern, tempPattern; - UErrorCode err=U_ZERO_ERROR; + const UnicodeString* tempPatternPtr; int32_t lastMissingFieldMask=0; if (missingFields!=0) { resultPattern=UnicodeString(); - const PtnSkeleton* specifiedSkeleton=NULL; - tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton); + const PtnSkeleton* specifiedSkeleton=nullptr; + tempPatternPtr = getBestRaw(*dtMatcher, missingFields, distanceInfo, status, &specifiedSkeleton); + if (U_FAILURE(status)) { + return UnicodeString(); + } + tempPattern = *tempPatternPtr; resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); if ( distanceInfo->missingFieldMask==0 ) { return resultPattern; @@ -1519,19 +1578,26 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, continue; } int32_t startingMask = distanceInfo->missingFieldMask; - tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton); + tempPatternPtr = getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, status, &specifiedSkeleton); + if (U_FAILURE(status)) { + return UnicodeString(); + } + tempPattern = *tempPatternPtr; tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask; int32_t topField=getTopBitNumber(foundMask); - UnicodeString appendName; - getAppendName((UDateTimePatternField)topField, appendName); - const UnicodeString *values[3] = { - &resultPattern, - &tempPattern, - &appendName - }; - SimpleFormatter(appendItemFormats[topField], 2, 3, err). - formatAndReplace(values, 3, resultPattern, NULL, 0, err); + + if (appendItemFormats[topField].length() != 0) { + UnicodeString appendName; + getAppendName((UDateTimePatternField)topField, appendName); + const UnicodeString *values[3] = { + &resultPattern, + &tempPattern, + &appendName + }; + SimpleFormatter(appendItemFormats[topField], 2, 3, status). + formatAndReplace(values, 3, resultPattern, nullptr, 0, status); + } lastMissingFieldMask = distanceInfo->missingFieldMask; } } @@ -1539,7 +1605,7 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, } int32_t -DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) { +DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) const { if ( foundMask==0 ) { return 0; } @@ -1568,22 +1634,21 @@ DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const { void DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) { - - if (other == NULL) { + if (other == nullptr || U_FAILURE(status)) { return; } - if (fAvailableFormatKeyHash != NULL) { + if (fAvailableFormatKeyHash != nullptr) { delete fAvailableFormatKeyHash; - fAvailableFormatKeyHash = NULL; + fAvailableFormatKeyHash = nullptr; } initHashtable(status); if(U_FAILURE(status)){ return; } int32_t pos = UHASH_FIRST; - const UHashElement* elem = NULL; + const UHashElement* elem = nullptr; // walk through the hash table and create a deep clone - while((elem = other->nextElement(pos))!= NULL){ + while((elem = other->nextElement(pos))!= nullptr){ const UHashTok otherKeyTok = elem->key; UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer; fAvailableFormatKeyHash->puti(*otherKey, 1, status); @@ -1595,8 +1660,17 @@ DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) { StringEnumeration* DateTimePatternGenerator::getSkeletons(UErrorCode& status) const { - StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status); - return skeletonEnumerator; + if (U_FAILURE(status)) { + return nullptr; + } + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return nullptr; + } + LocalPointer skeletonEnumerator( + new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status), status); + + return U_SUCCESS(status) ? skeletonEnumerator.orphan() : nullptr; } const UnicodeString& @@ -1607,47 +1681,70 @@ DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) c return emptyString; } curElem = patternMap->getHeader(skeleton.charAt(0)); - while ( curElem != NULL ) { + while ( curElem != nullptr ) { if ( curElem->skeleton->getSkeleton()==skeleton ) { return curElem->pattern; } - curElem=curElem->next; + curElem = curElem->next.getAlias(); } return emptyString; } StringEnumeration* DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const { - StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status); - return baseSkeletonEnumerator; + if (U_FAILURE(status)) { + return nullptr; + } + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return nullptr; + } + LocalPointer baseSkeletonEnumerator( + new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status), status); + + return U_SUCCESS(status) ? baseSkeletonEnumerator.orphan() : nullptr; } StringEnumeration* DateTimePatternGenerator::getRedundants(UErrorCode& status) { - StringEnumeration* output = new DTRedundantEnumeration(); + if (U_FAILURE(status)) { return nullptr; } + if (U_FAILURE(internalErrorCode)) { + status = internalErrorCode; + return nullptr; + } + LocalPointer output(new DTRedundantEnumeration(), status); + if (U_FAILURE(status)) { return nullptr; } const UnicodeString *pattern; - PatternMapIterator it; + PatternMapIterator it(status); + if (U_FAILURE(status)) { return nullptr; } + for (it.set(*patternMap); it.hasNext(); ) { DateTimeMatcher current = it.next(); pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton())); if ( isCanonicalItem(*pattern) ) { continue; } - if ( skipMatcher == NULL ) { + if ( skipMatcher == nullptr ) { skipMatcher = new DateTimeMatcher(current); + if (skipMatcher == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } } else { *skipMatcher = current; } UnicodeString trial = getBestPattern(current.getPattern(), status); + if (U_FAILURE(status)) { return nullptr; } if (trial == *pattern) { - ((DTRedundantEnumeration *)output)->add(*pattern, status); + ((DTRedundantEnumeration *)output.getAlias())->add(*pattern, status); + if (U_FAILURE(status)) { return nullptr; } } if (current.equals(skipMatcher)) { continue; } } - return output; + return output.orphan(); } UBool @@ -1671,45 +1768,54 @@ DateTimePatternGenerator::clone() const { PatternMap::PatternMap() { for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { - boot[i]=NULL; + boot[i] = nullptr; } isDupAllowed = TRUE; } void PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } this->isDupAllowed = other.isDupAllowed; - for (int32_t bootIndex=0; bootIndexbasePattern, otherElem->pattern))==NULL) { - // out of memory - status = U_MEMORY_ALLOCATION_ERROR; - return; + while (otherElem != nullptr) { + LocalPointer newElem(new PtnElem(otherElem->basePattern, otherElem->pattern), status); + if (U_FAILURE(status)) { + return; // out of memory } - if ( this->boot[bootIndex]== NULL ) { - this->boot[bootIndex] = curElem; + newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(*(otherElem->skeleton)), status); + if (U_FAILURE(status)) { + return; // out of memory } - if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) { - // out of memory - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - curElem->skeletonWasSpecified = otherElem->skeletonWasSpecified; - if (prevElem!=NULL) { - prevElem->next=curElem; + newElem->skeletonWasSpecified = otherElem->skeletonWasSpecified; + + // Release ownership from the LocalPointer of the PtnElem object. + // The PtnElem will now be owned by either the boot (for the first entry in the linked-list) + // or owned by the previous PtnElem object in the linked-list. + curElem = newElem.orphan(); + + if (this->boot[bootIndex] == nullptr) { + this->boot[bootIndex] = curElem; + } else { + if (prevElem != nullptr) { + prevElem->next.adoptInstead(curElem); + } else { + U_ASSERT(false); + } } - curElem->next=NULL; prevElem = curElem; - otherElem = otherElem->next; + otherElem = otherElem->next.getAlias(); } } } PtnElem* -PatternMap::getHeader(UChar baseChar) { +PatternMap::getHeader(UChar baseChar) const { PtnElem* curElem; if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) { @@ -1720,7 +1826,7 @@ PatternMap::getHeader(UChar baseChar) { curElem = boot[26+baseChar-LOW_A]; } else { - return NULL; + return nullptr; } } return curElem; @@ -1728,9 +1834,9 @@ PatternMap::getHeader(UChar baseChar) { PatternMap::~PatternMap() { for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { - if (boot[i]!=NULL ) { + if (boot[i] != nullptr ) { delete boot[i]; - boot[i]=NULL; + boot[i] = nullptr; } } } // PatternMap destructor @@ -1759,39 +1865,45 @@ PatternMap::add(const UnicodeString& basePattern, } } - if (baseElem == NULL) { - if ((curElem = new PtnElem(basePattern, value)) == NULL ) { - // out of memory - status = U_MEMORY_ALLOCATION_ERROR; - return; + if (baseElem == nullptr) { + LocalPointer newElem(new PtnElem(basePattern, value), status); + if (U_FAILURE(status)) { + return; // out of memory } + newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status); + if (U_FAILURE(status)) { + return; // out of memory + } + newElem->skeletonWasSpecified = skeletonWasSpecified; if (baseChar >= LOW_A) { - boot[26 + (baseChar-LOW_A)] = curElem; + boot[26 + (baseChar - LOW_A)] = newElem.orphan(); // the boot array now owns the PtnElem. } else { - boot[baseChar-CAP_A] = curElem; + boot[baseChar - CAP_A] = newElem.orphan(); // the boot array now owns the PtnElem. } - curElem->skeleton = new PtnSkeleton(skeleton); - curElem->skeletonWasSpecified = skeletonWasSpecified; } - if ( baseElem != NULL ) { + if ( baseElem != nullptr ) { curElem = getDuplicateElem(basePattern, skeleton, baseElem); - if (curElem == NULL) { + if (curElem == nullptr) { // add new element to the list. curElem = baseElem; - while( curElem -> next != NULL ) + while( curElem -> next != nullptr ) { - curElem = curElem->next; + curElem = curElem->next.getAlias(); } - if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) { - // out of memory - status = U_MEMORY_ALLOCATION_ERROR; - return; + + LocalPointer newElem(new PtnElem(basePattern, value), status); + if (U_FAILURE(status)) { + return; // out of memory } - curElem=curElem->next; - curElem->skeleton = new PtnSkeleton(skeleton); - curElem->skeletonWasSpecified = skeletonWasSpecified; + newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status); + if (U_FAILURE(status)) { + return; // out of memory + } + newElem->skeletonWasSpecified = skeletonWasSpecified; + curElem->next.adoptInstead(newElem.orphan()); + curElem = curElem->next.getAlias(); } else { // Pattern exists in the list already. @@ -1809,11 +1921,11 @@ PatternMap::add(const UnicodeString& basePattern, // Find the pattern from the given basePattern string. const UnicodeString * -PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for +PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const { // key to search for PtnElem *curElem; - if ((curElem=getHeader(basePattern.charAt(0)))==NULL) { - return NULL; // no match + if ((curElem=getHeader(basePattern.charAt(0)))==nullptr) { + return nullptr; // no match } do { @@ -1821,10 +1933,10 @@ PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeleto skeletonWasSpecified = curElem->skeletonWasSpecified; return &(curElem->pattern); } - curElem=curElem->next; - }while (curElem != NULL); + curElem = curElem->next.getAlias(); + } while (curElem != nullptr); - return NULL; + return nullptr; } // PatternMap::getFromBasePattern @@ -1835,69 +1947,69 @@ PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeleto // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL), // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily. const UnicodeString * -PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for +PatternMap::getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) const { // key to search for PtnElem *curElem; if (specifiedSkeletonPtr) { - *specifiedSkeletonPtr = NULL; + *specifiedSkeletonPtr = nullptr; } // find boot entry UChar baseChar = skeleton.getFirstChar(); - if ((curElem=getHeader(baseChar))==NULL) { - return NULL; // no match + if ((curElem=getHeader(baseChar))==nullptr) { + return nullptr; // no match } do { UBool equal; - if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original + if (specifiedSkeletonPtr != nullptr) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original equal = curElem->skeleton->original == skeleton.original; } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal equal = curElem->skeleton->baseOriginal == skeleton.baseOriginal; } if (equal) { if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) { - *specifiedSkeletonPtr = curElem->skeleton; + *specifiedSkeletonPtr = curElem->skeleton.getAlias(); } return &(curElem->pattern); } - curElem=curElem->next; - }while (curElem != NULL); + curElem = curElem->next.getAlias(); + } while (curElem != nullptr); - return NULL; + return nullptr; } UBool -PatternMap::equals(const PatternMap& other) { +PatternMap::equals(const PatternMap& other) const { if ( this==&other ) { return TRUE; } - for (int32_t bootIndex=0; bootIndexbasePattern != otherElem->basePattern) || (myElem->pattern != otherElem->pattern) ) { return FALSE; } - if ((myElem->skeleton!=otherElem->skeleton)&& + if ((myElem->skeleton.getAlias() != otherElem->skeleton.getAlias()) && !myElem->skeleton->equals(*(otherElem->skeleton))) { return FALSE; } - myElem = myElem->next; - otherElem=otherElem->next; + myElem = myElem->next.getAlias(); + otherElem = otherElem->next.getAlias(); } } return TRUE; @@ -1909,21 +2021,21 @@ PtnElem* PatternMap::getDuplicateElem( const UnicodeString &basePattern, const PtnSkeleton &skeleton, - PtnElem *baseElem) { + PtnElem *baseElem) { PtnElem *curElem; - if ( baseElem == (PtnElem *)NULL ) { - return (PtnElem*)NULL; + if ( baseElem == nullptr ) { + return nullptr; } else { curElem = baseElem; } do { if ( basePattern.compare(curElem->basePattern)==0 ) { - UBool isEqual=TRUE; - for (int32_t i=0; iskeleton->type[i] != skeleton.type[i] ) { - isEqual=FALSE; + isEqual = FALSE; break; } } @@ -1931,11 +2043,11 @@ PatternMap::getDuplicateElem( return curElem; } } - curElem = curElem->next; - } while( curElem != (PtnElem *)NULL ); + curElem = curElem->next.getAlias(); + } while( curElem != nullptr ); // end of the list - return (PtnElem*)NULL; + return nullptr; } // PatternMap::getDuplicateElem @@ -1976,7 +2088,7 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton continue; } int32_t canonicalIndex = fp->getCanonicalIndex(value); - if (canonicalIndex < 0 ) { + if (canonicalIndex < 0) { continue; } const dtTypeElem *row = &dtTypes[canonicalIndex]; @@ -1986,8 +2098,9 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton int32_t repeatCount = row->minLen; skeletonResult.baseOriginal.populate(field, repeatChar, repeatCount); int16_t subField = row->type; - if ( row->type > 0) { - subField += value.length(); + if (row->type > 0) { + U_ASSERT(value.length() < INT16_MAX); + subField += static_cast(value.length()); } skeletonResult.type[field] = subField; } @@ -2031,8 +2144,8 @@ DateTimeMatcher::getPattern() { } int32_t -DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) { - int32_t result=0; +DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const { + int32_t result = 0; distanceInfo.clear(); for (int32_t i=0; iskeleton.original; } int32_t -DateTimeMatcher::getFieldMask() { - int32_t result=0; +DateTimeMatcher::getFieldMask() const { + int32_t result = 0; for (int32_t i=0; i= pattern.length()) { return DONE; } @@ -2132,10 +2245,10 @@ FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t void FormatParser::set(const UnicodeString& pattern) { - int32_t startPos=0; - TokenStatus result=START; - int32_t len=0; - itemNumber =0; + int32_t startPos = 0; + TokenStatus result = START; + int32_t len = 0; + itemNumber = 0; do { result = setTokens( pattern, startPos, &len ); @@ -2186,14 +2299,14 @@ FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) { UBool FormatParser::isQuoteLiteral(const UnicodeString& s) { - return (UBool)(s.charAt(0)==SINGLE_QUOTE); + return (UBool)(s.charAt(0) == SINGLE_QUOTE); } -// This function aussumes the current itemIndex points to the quote literal. +// This function assumes the current itemIndex points to the quote literal. // Please call isQuoteLiteral prior to this function. void FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) { - int32_t i=*itemIndex; + int32_t i = *itemIndex; quote.remove(); if (items[i].charAt(0)==SINGLE_QUOTE) { @@ -2222,7 +2335,7 @@ FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) { } UBool -FormatParser::isPatternSeparator(UnicodeString& field) { +FormatParser::isPatternSeparator(const UnicodeString& field) const { for (int32_t i=0; iskeleton; + return nodePtr->skeleton.getAlias(); } } UBool -PatternMapIterator::hasNext() { - int32_t headIndex=bootIndex; - PtnElem *curPtr=nodePtr; +PatternMapIterator::hasNext() const { + int32_t headIndex = bootIndex; + PtnElem *curPtr = nodePtr; - if (patternMap==NULL) { + if (patternMap==nullptr) { return FALSE; } while ( headIndex < MAX_PATTERN_ENTRIES ) { - if ( curPtr != NULL ) { - if ( curPtr->next != NULL ) { + if ( curPtr != nullptr ) { + if ( curPtr->next != nullptr ) { return TRUE; } else { headIndex++; - curPtr=NULL; + curPtr=nullptr; continue; } } else { - if ( patternMap->boot[headIndex] != NULL ) { + if ( patternMap->boot[headIndex] != nullptr ) { return TRUE; } else { @@ -2299,7 +2410,6 @@ PatternMapIterator::hasNext() { continue; } } - } return FALSE; } @@ -2307,19 +2417,19 @@ PatternMapIterator::hasNext() { DateTimeMatcher& PatternMapIterator::next() { while ( bootIndex < MAX_PATTERN_ENTRIES ) { - if ( nodePtr != NULL ) { - if ( nodePtr->next != NULL ) { - nodePtr = nodePtr->next; + if ( nodePtr != nullptr ) { + if ( nodePtr->next != nullptr ) { + nodePtr = nodePtr->next.getAlias(); break; } else { bootIndex++; - nodePtr=NULL; + nodePtr=nullptr; continue; } } else { - if ( patternMap->boot[bootIndex] != NULL ) { + if ( patternMap->boot[bootIndex] != nullptr ) { nodePtr = patternMap->boot[bootIndex]; break; } @@ -2329,7 +2439,7 @@ PatternMapIterator::next() { } } } - if (nodePtr!=NULL) { + if (nodePtr!=nullptr) { matcher->copyFrom(*nodePtr->skeleton); } else { @@ -2468,36 +2578,28 @@ PtnSkeleton::~PtnSkeleton() { } PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) : -basePattern(basePat), -skeleton(NULL), -pattern(pat), -next(NULL) + basePattern(basePat), skeleton(nullptr), pattern(pat), next(nullptr) { } PtnElem::~PtnElem() { - - if (next!=NULL) { - delete next; - } - delete skeleton; } -DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) { +DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status) : fSkeletons(nullptr) { PtnElem *curElem; PtnSkeleton *curSkeleton; UnicodeString s; int32_t bootIndex; pos=0; - fSkeletons = new UVector(status); + fSkeletons.adoptInsteadAndCheckErrorCode(new UVector(status), status); if (U_FAILURE(status)) { - delete fSkeletons; return; } + for (bootIndex=0; bootIndexbasePattern; @@ -2506,32 +2608,36 @@ DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum t s=curElem->pattern; break; case DT_SKELETON: - curSkeleton=curElem->skeleton; + curSkeleton=curElem->skeleton.getAlias(); s=curSkeleton->getSkeleton(); break; } if ( !isCanonicalItem(s) ) { - fSkeletons->addElement(new UnicodeString(s), status); + LocalPointer newElem(new UnicodeString(s), status); if (U_FAILURE(status)) { - delete fSkeletons; - fSkeletons = NULL; return; } + fSkeletons->addElement(newElem.getAlias(), status); + if (U_FAILURE(status)) { + fSkeletons.adoptInstead(nullptr); + return; + } + newElem.orphan(); // fSkeletons vector now owns the UnicodeString. } - curElem = curElem->next; + curElem = curElem->next.getAlias(); } } - if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) { + if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=nullptr) ) { status = U_BUFFER_OVERFLOW_ERROR; } } const UnicodeString* DTSkeletonEnumeration::snext(UErrorCode& status) { - if (U_SUCCESS(status) && pos < fSkeletons->size()) { + if (U_SUCCESS(status) && fSkeletons.isValid() && pos < fSkeletons->size()) { return (const UnicodeString*)fSkeletons->elementAt(pos++); } - return NULL; + return nullptr; } void @@ -2541,7 +2647,7 @@ DTSkeletonEnumeration::reset(UErrorCode& /*status*/) { int32_t DTSkeletonEnumeration::count(UErrorCode& /*status*/) const { - return (fSkeletons==NULL) ? 0 : fSkeletons->size(); + return (fSkeletons.isNull()) ? 0 : fSkeletons->size(); } UBool @@ -2559,44 +2665,45 @@ DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) { DTSkeletonEnumeration::~DTSkeletonEnumeration() { UnicodeString *s; - for (int32_t i=0; isize(); ++i) { - if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) { - delete s; + if (fSkeletons.isValid()) { + for (int32_t i = 0; i < fSkeletons->size(); ++i) { + if ((s = (UnicodeString *)fSkeletons->elementAt(i)) != nullptr) { + delete s; + } } } - delete fSkeletons; } -DTRedundantEnumeration::DTRedundantEnumeration() { - pos=0; - fPatterns = NULL; +DTRedundantEnumeration::DTRedundantEnumeration() : pos(0), fPatterns(nullptr) { } void DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) { - if (U_FAILURE(status)) return; - if (fPatterns == NULL) { - fPatterns = new UVector(status); + if (U_FAILURE(status)) { return; } + if (fPatterns.isNull()) { + fPatterns.adoptInsteadAndCheckErrorCode(new UVector(status), status); if (U_FAILURE(status)) { - delete fPatterns; - fPatterns = NULL; return; } } - fPatterns->addElement(new UnicodeString(pattern), status); + LocalPointer newElem(new UnicodeString(pattern), status); + if (U_FAILURE(status)) { + return; + } + fPatterns->addElement(newElem.getAlias(), status); if (U_FAILURE(status)) { - delete fPatterns; - fPatterns = NULL; + fPatterns.adoptInstead(nullptr); return; } + newElem.orphan(); // fPatterns now owns the string. } const UnicodeString* DTRedundantEnumeration::snext(UErrorCode& status) { - if (U_SUCCESS(status) && pos < fPatterns->size()) { + if (U_SUCCESS(status) && fPatterns.isValid() && pos < fPatterns->size()) { return (const UnicodeString*)fPatterns->elementAt(pos++); } - return NULL; + return nullptr; } void @@ -2606,11 +2713,11 @@ DTRedundantEnumeration::reset(UErrorCode& /*status*/) { int32_t DTRedundantEnumeration::count(UErrorCode& /*status*/) const { - return (fPatterns==NULL) ? 0 : fPatterns->size(); + return (fPatterns.isNull()) ? 0 : fPatterns->size(); } UBool -DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) { +DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const { if ( item.length() != 1 ) { return FALSE; } @@ -2624,12 +2731,13 @@ DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) { DTRedundantEnumeration::~DTRedundantEnumeration() { UnicodeString *s; - for (int32_t i=0; isize(); ++i) { - if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) { - delete s; + if (fPatterns.isValid()) { + for (int32_t i = 0; i < fPatterns->size(); ++i) { + if ((s = (UnicodeString *)fPatterns->elementAt(i)) != nullptr) { + delete s; + } } } - delete fPatterns; } U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/dtptngen_impl.h b/deps/icu-small/source/i18n/dtptngen_impl.h index 2ea31a75c488fa..95219f0ba257f5 100644 --- a/deps/icu-small/source/i18n/dtptngen_impl.h +++ b/deps/icu-small/source/i18n/dtptngen_impl.h @@ -116,7 +116,7 @@ typedef struct dtTypeElem { int16_t type; int16_t minLen; int16_t weight; -}dtTypeElem; +} dtTypeElem; // A compact storage mechanism for skeleton field strings. Several dozen of these will be created // for a typical DateTimePatternGenerator instance. @@ -172,30 +172,28 @@ class PtnSkeleton : public UMemory { virtual ~PtnSkeleton(); }; - class PtnElem : public UMemory { public: UnicodeString basePattern; - PtnSkeleton *skeleton; + LocalPointer skeleton; UnicodeString pattern; UBool skeletonWasSpecified; // if specified in availableFormats, not derived - PtnElem *next; + LocalPointer next; PtnElem(const UnicodeString &basePattern, const UnicodeString &pattern); virtual ~PtnElem(); - }; class FormatParser : public UMemory { public: UnicodeString items[MAX_DT_TOKEN]; - int32_t itemNumber; + int32_t itemNumber; FormatParser(); virtual ~FormatParser(); void set(const UnicodeString& patternString); void getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex); - UBool isPatternSeparator(UnicodeString& field); + UBool isPatternSeparator(const UnicodeString& field) const; static UBool isQuoteLiteral(const UnicodeString& s); static int32_t getCanonicalIndex(const UnicodeString& s) { return getCanonicalIndex(s, TRUE); } static int32_t getCanonicalIndex(const UnicodeString& s, UBool strict); @@ -206,7 +204,7 @@ class FormatParser : public UMemory { ADD_TOKEN, SYNTAX_ERROR, DONE - } ToeknStatus; + } TokenStatus; TokenStatus status; virtual TokenStatus setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len); @@ -220,7 +218,7 @@ class DistanceInfo : public UMemory { DistanceInfo() {} virtual ~DistanceInfo(); void clear() { missingFieldMask = extraFieldMask = 0; } - void setTo(DistanceInfo& other); + void setTo(const DistanceInfo& other); void addMissing(int32_t field) { missingFieldMask |= (1< matcher; PatternMap *patternMap; }; class DTSkeletonEnumeration : public StringEnumeration { public: - DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status); + DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status); virtual ~DTSkeletonEnumeration(); static UClassID U_EXPORT2 getStaticClassID(void); virtual UClassID getDynamicClassID(void) const; @@ -287,7 +285,7 @@ class DTSkeletonEnumeration : public StringEnumeration { private: int32_t pos; UBool isCanonicalItem(const UnicodeString& item); - UVector *fSkeletons; + LocalPointer fSkeletons; }; class DTRedundantEnumeration : public StringEnumeration { @@ -302,8 +300,8 @@ class DTRedundantEnumeration : public StringEnumeration { void add(const UnicodeString &pattern, UErrorCode& status); private: int32_t pos; - UBool isCanonicalItem(const UnicodeString& item); - UVector *fPatterns; + UBool isCanonicalItem(const UnicodeString& item) const; + LocalPointer fPatterns; }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/erarules.cpp b/deps/icu-small/source/i18n/erarules.cpp new file mode 100644 index 00000000000000..669f84423046fd --- /dev/null +++ b/deps/icu-small/source/i18n/erarules.cpp @@ -0,0 +1,307 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include +#include "unicode/ucal.h" +#include "unicode/ures.h" +#include "unicode/ustring.h" +#include "cmemory.h" +#include "cstring.h" +#include "erarules.h" +#include "gregoimp.h" +#include "uassert.h" + +U_NAMESPACE_BEGIN + +static const int32_t MAX_ENCODED_START_YEAR = 32767; +static const int32_t MIN_ENCODED_START_YEAR = -32768; +static const int32_t MIN_ENCODED_START = -2147483391; // encodeDate(MIN_ENCODED_START_YEAR, 1, 1, ...); + +static const int32_t YEAR_MASK = 0xFFFF0000; +static const int32_t MONTH_MASK = 0x0000FF00; +static const int32_t DAY_MASK = 0x000000FF; + +static const int32_t MAX_INT32 = 0x7FFFFFFF; +static const int32_t MIN_INT32 = 0xFFFFFFFF; + +static const UChar VAL_FALSE[] = {0x66, 0x61, 0x6c, 0x73, 0x65}; // "false" +static const UChar VAL_FALSE_LEN = 5; + +static UBool isSet(int startDate) { + return startDate != 0; +} + +static UBool isValidRuleStartDate(int32_t year, int32_t month, int32_t day) { + return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR + && month >= 1 && month <= 12 && day >=1 && day <= 31; +} + +/** + * Encode year/month/date to a single integer. + * year is high 16 bits (-32768 to 32767), month is + * next 8 bits and day of month is last 8 bits. + * + * @param year year + * @param month month (1-base) + * @param day day of month + * @return an encoded date. + */ +static int32_t encodeDate(int32_t year, int32_t month, int32_t day) { + return year << 16 | month << 8 | day; +} + +static void decodeDate(int32_t encodedDate, int32_t (&fields)[3]) { + if (encodedDate == MIN_ENCODED_START) { + fields[0] = MIN_INT32; + fields[1] = 1; + fields[2] = 1; + } else { + fields[0] = (encodedDate & YEAR_MASK) >> 16; + fields[1] = (encodedDate & MONTH_MASK) >> 8; + fields[2] = encodedDate & DAY_MASK; + } +} + +/** + * Compare an encoded date with another date specified by year/month/day. + * @param encoded An encoded date + * @param year Year of another date + * @param month Month of another date + * @param day Day of another date + * @return -1 when encoded date is earlier, 0 when two dates are same, + * and 1 when encoded date is later. + */ +static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int day) { + if (year < MIN_ENCODED_START_YEAR) { + if (encoded == MIN_ENCODED_START) { + if (year > MIN_INT32 || month > 1 || day > 1) { + return -1; + } + return 0; + } else { + return 1; + } + } else if (year > MAX_ENCODED_START_YEAR) { + return -1; + } else { + int tmp = encodeDate(year, month, day); + if (encoded < tmp) { + return -1; + } else if (encoded == tmp) { + return 0; + } else { + return 1; + } + } +} + +EraRules::EraRules(LocalMemory& eraStartDates, int32_t numEras) + : numEras(numEras) { + startDates.moveFrom(eraStartDates); + initCurrentEra(); +} + +EraRules::~EraRules() { +} + +EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) { + if(U_FAILURE(status)) { + return nullptr; + } + LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status)); + ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status); + ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status); + ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status); + + if (U_FAILURE(status)) { + return nullptr; + } + + int32_t numEras = ures_getSize(rb.getAlias()); + int32_t firstTentativeIdx = MAX_INT32; + + LocalMemory startDates(static_cast(uprv_malloc(numEras * sizeof(int32_t)))); + if (startDates.isNull()) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t)); + + while (ures_hasNext(rb.getAlias())) { + LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status)); + if (U_FAILURE(status)) { + return nullptr; + } + const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias()); + char *endp; + int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10); + if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + if (eraIdx < 0 || eraIdx >= numEras) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + if (isSet(startDates[eraIdx])) { + // start date of the index was already set + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + + UBool hasName = TRUE; + UBool hasEnd = TRUE; + int32_t len; + while (ures_hasNext(eraRuleRes.getAlias())) { + LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status)); + if (U_FAILURE(status)) { + return nullptr; + } + const char *key = ures_getKey(res.getAlias()); + if (uprv_strcmp(key, "start") == 0) { + const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status); + if (U_FAILURE(status)) { + return nullptr; + } + if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]); + } else if (uprv_strcmp(key, "named") == 0) { + const UChar *val = ures_getString(res.getAlias(), &len, &status); + if (u_strncmp(val, VAL_FALSE, VAL_FALSE_LEN) == 0) { + hasName = FALSE; + } + } else if (uprv_strcmp(key, "end") == 0) { + hasEnd = TRUE; + } + } + + if (isSet(startDates[eraIdx])) { + if (hasEnd) { + // This implementation assumes either start or end is available, not both. + // For now, just ignore the end rule. + } + } else { + if (hasEnd) { + if (eraIdx != 0) { + // This implementation does not support end only rule for eras other than + // the first one. + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + U_ASSERT(eraIdx == 0); + startDates[eraIdx] = MIN_ENCODED_START; + } else { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + } + + if (hasName) { + if (eraIdx >= firstTentativeIdx) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + } else { + if (eraIdx < firstTentativeIdx) { + firstTentativeIdx = eraIdx; + } + } + } + + EraRules *result; + if (firstTentativeIdx < MAX_INT32 && !includeTentativeEra) { + result = new EraRules(startDates, firstTentativeIdx); + } else { + result = new EraRules(startDates, numEras); + } + + if (result == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + +void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const { + if(U_FAILURE(status)) { + return; + } + if (eraIdx < 0 || eraIdx >= numEras) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + decodeDate(startDates[eraIdx], fields); +} + +int32_t EraRules::getStartYear(int32_t eraIdx, UErrorCode& status) const { + int year = MAX_INT32; // bogus value + if(U_FAILURE(status)) { + return year; + } + if (eraIdx < 0 || eraIdx >= numEras) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return year; + } + int fields[3]; + decodeDate(startDates[eraIdx], fields); + year = fields[0]; + + return year; +} + +int32_t EraRules::getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const { + if(U_FAILURE(status)) { + return -1; + } + + if (month < 1 || month > 12 || day < 1 || day > 31) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + int32_t high = numEras; // last index + 1 + int32_t low; + + // Short circuit for recent years. Most modern computations will + // occur in the last few eras. + if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) { + low = getCurrentEraIndex(); + } else { + low = 0; + } + + // Do binary search + while (low < high - 1) { + int i = (low + high) / 2; + if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) { + low = i; + } else { + high = i; + } + } + return low; +} + +void EraRules::initCurrentEra() { + UDate now = ucal_getNow(); + int year, month0, dom, dow, doy, mid; + Grego::timeToFields(now, year, month0, dom, dow, doy, mid); + int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom); + int eraIdx = numEras - 1; + while (eraIdx > 0) { + if (currentEncodedDate >= startDates[eraIdx]) { + break; + } + eraIdx--; + } + // Note: current era could be before the first era. + // In this case, this implementation returns the first era index (0). + currentEra = eraIdx;} + +U_NAMESPACE_END +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/erarules.h b/deps/icu-small/source/i18n/erarules.h new file mode 100644 index 00000000000000..4ed86408325ed7 --- /dev/null +++ b/deps/icu-small/source/i18n/erarules.h @@ -0,0 +1,92 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#ifndef ERARULES_H_ +#define ERARULES_H_ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/localpointer.h" +#include "unicode/uobject.h" +#include "cmemory.h" + +U_NAMESPACE_BEGIN + +// Export an explicit template instantiation of LocalMemory used as a data member of EraRules. +// When building DLLs for Windows this is required even though no direct access leaks out of the i18n library. +// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples. +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!= +#pragma warning(suppress: 4661) +template class U_I18N_API LocalPointerBase; +template class U_I18N_API LocalMemory; +#endif + +class U_I18N_API EraRules : public UMemory { +public: + ~EraRules(); + + static EraRules* createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status); + + /** + * Gets number of effective eras + * @return number of effective eras + */ + inline int32_t getNumberOfEras() const { + return numEras; + } + + /** + * Gets start date of an era + * @param eraIdx Era index + * @param fields Receives date fields. The result includes values of year, month, + * day of month in this order. When an era has no start date, the result + * will be January 1st in year whose value is minimum integer. + * @param status Receives status. + */ + void getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const; + + /** + * Gets start year of an era + * @param eraIdx Era index + * @param status Receives status. + * @return The first year of an era. When a era has no start date, minimum int32 + * value is returned. + */ + int32_t getStartYear(int32_t eraIdx, UErrorCode& status) const; + + /** + * Returns era index for the specified year/month/day. + * @param year Year + * @param month Month (1-base) + * @param day Day of month + * @param status Receives status + * @return era index (or 0, when the specified date is before the first era) + */ + int32_t getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const; + + /** + * Gets the current era index. This is calculated only once for an instance of + * EraRules. + * + * @return era index of current era (or 0, when current date is before the first era) + */ + inline int32_t getCurrentEraIndex() const { + return currentEra; + } + +private: + EraRules(LocalMemory& eraStartDates, int32_t numEra); + + void initCurrentEra(); + + LocalMemory startDates; + int32_t numEras; + int32_t currentEra; +}; + +U_NAMESPACE_END +#endif /* #if !UCONFIG_NO_FORMATTING */ +#endif /* ERARULES_H_ */ diff --git a/deps/icu-small/source/i18n/fphdlimp.h b/deps/icu-small/source/i18n/fphdlimp.h index 2e9d5622b1b5b0..a6827e01e98b4b 100644 --- a/deps/icu-small/source/i18n/fphdlimp.h +++ b/deps/icu-small/source/i18n/fphdlimp.h @@ -10,9 +10,10 @@ #ifndef FPHDLIMP_H #define FPHDLIMP_H +#include "unicode/utypes.h" + #if !UCONFIG_NO_FORMATTING -#include "unicode/utypes.h" #include "unicode/fieldpos.h" #include "unicode/fpositer.h" diff --git a/deps/icu-small/source/i18n/gregocal.cpp b/deps/icu-small/source/i18n/gregocal.cpp index 49c4226049d9c8..4db66758df1f1f 100644 --- a/deps/icu-small/source/i18n/gregocal.cpp +++ b/deps/icu-small/source/i18n/gregocal.cpp @@ -541,8 +541,8 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, } UBool isLeap = eyear%4 == 0; - int32_t y = eyear-1; - int32_t julianDay = 365*y + ClockMath::floorDivide(y, 4) + (kJan1_1JulianDay - 3); + int64_t y = (int64_t)eyear-1; + int64_t julianDay = 365*y + ClockMath::floorDivide(y, (int64_t)4) + (kJan1_1JulianDay - 3); nonConstThis->fIsGregorian = (eyear >= fGregorianCutoverYear); #if defined (U_DEBUG_CAL) @@ -572,7 +572,7 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, julianDay += isLeap?kLeapNumDays[month]:kNumDays[month]; } - return julianDay; + return static_cast(julianDay); } int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const diff --git a/deps/icu-small/source/i18n/gregoimp.h b/deps/icu-small/source/i18n/gregoimp.h index 55922a6b40aa52..eb3844f8523eeb 100644 --- a/deps/icu-small/source/i18n/gregoimp.h +++ b/deps/icu-small/source/i18n/gregoimp.h @@ -299,8 +299,8 @@ inline int32_t Grego::millisToJulianDay(double millis) { } inline int32_t Grego::gregorianShift(int32_t eyear) { - int32_t y = eyear-1; - int32_t gregShift = ClockMath::floorDivide(y, 400) - ClockMath::floorDivide(y, 100) + 2; + int64_t y = (int64_t)eyear-1; + int32_t gregShift = static_cast(ClockMath::floorDivide(y, (int64_t)400) - ClockMath::floorDivide(y, (int64_t)100) + 2); return gregShift; } diff --git a/deps/icu-small/source/i18n/indiancal.cpp b/deps/icu-small/source/i18n/indiancal.cpp index a2a7f2dcdd3e9e..667b6f2d7a32c5 100644 --- a/deps/icu-small/source/i18n/indiancal.cpp +++ b/deps/icu-small/source/i18n/indiancal.cpp @@ -347,12 +347,15 @@ IndianCalendar::inDaylightTime(UErrorCode& status) const return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE); } -// default century -const UDate IndianCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t IndianCalendar::fgSystemDefaultCenturyYear = -1; -UDate IndianCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t IndianCalendar::fgSystemDefaultCenturyStartYear = -1; +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static icu::UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool IndianCalendar::haveDefaultCentury() const @@ -360,87 +363,45 @@ UBool IndianCalendar::haveDefaultCentury() const return TRUE; } -UDate IndianCalendar::defaultCenturyStart() const +static void U_CALLCONV +initializeSystemDefaultCentury() { - return internalGetDefaultCenturyStart(); -} + // initialize systemDefaultCentury and systemDefaultCenturyYear based + // on the current time. They'll be set to 80 years before + // the current time. + UErrorCode status = U_ZERO_ERROR; -int32_t IndianCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} + IndianCalendar calendar ( Locale ( "@calendar=Indian" ), status); + if ( U_SUCCESS ( status ) ) { + calendar.setTime ( Calendar::getNow(), status ); + calendar.add ( UCAL_YEAR, -80, status ); -UDate -IndianCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - { - Mutex m; - needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury); - } + UDate newStart = calendar.getTime ( status ); + int32_t newYear = calendar.get ( UCAL_YEAR, status ); - if (needsUpdate) { - initializeSystemDefaultCentury(); + gSystemDefaultCenturyStart = newStart; + gSystemDefaultCenturyStartYear = newYear; } + // We have no recourse upon failure. +} - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - return fgSystemDefaultCenturyStart; +UDate +IndianCalendar::defaultCenturyStart() const +{ + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; } int32_t -IndianCalendar::internalGetDefaultCenturyStartYear() const +IndianCalendar::defaultCenturyStartYear() const { // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - { - Mutex m; - - needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury); - } - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; } -void -IndianCalendar::initializeSystemDefaultCentury() -{ - // initialize systemDefaultCentury and systemDefaultCenturyYear based - // on the current time. They'll be set to 80 years before - // the current time. - // No point in locking as it should be idempotent. - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) { - UErrorCode status = U_ZERO_ERROR; - - IndianCalendar calendar(Locale("@calendar=Indian"),status); - if (U_SUCCESS(status)) { - calendar.setTime(Calendar::getNow(), status); - calendar.add(UCAL_YEAR, -80, status); - - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - - { - Mutex m; - - fgSystemDefaultCenturyStart = newStart; - fgSystemDefaultCenturyStartYear = newYear; - } - } - - // We have no recourse upon failure unless we want to propagate the failure - // out. - } -} UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndianCalendar) diff --git a/deps/icu-small/source/i18n/indiancal.h b/deps/icu-small/source/i18n/indiancal.h index d40af5ad450c9e..ffd4ae8b8a40cd 100644 --- a/deps/icu-small/source/i18n/indiancal.h +++ b/deps/icu-small/source/i18n/indiancal.h @@ -68,7 +68,7 @@ U_NAMESPACE_BEGIN */ -class IndianCalendar : public Calendar { +class U_I18N_API IndianCalendar : public Calendar { public: /** * Useful constants for IndianCalendar. @@ -274,10 +274,10 @@ class IndianCalendar : public Calendar { * @return The class ID for all objects of this class. * @internal */ - U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void); + static UClassID U_EXPORT2 getStaticClassID(void); /** - * return the calendar type, "buddhist". + * return the calendar type, "indian". * * @return calendar type * @internal @@ -320,49 +320,6 @@ class IndianCalendar : public Calendar { * @internal */ virtual int32_t defaultCenturyStartYear() const; - - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/japancal.cpp b/deps/icu-small/source/i18n/japancal.cpp index a2738e86a91edb..056781617d6d9d 100644 --- a/deps/icu-small/source/i18n/japancal.cpp +++ b/deps/icu-small/source/i18n/japancal.cpp @@ -16,286 +16,88 @@ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING - +#if U_PLATFORM_HAS_WINUWP_API == 0 +#include // getenv() is not available in UWP env +#endif #include "cmemory.h" +#include "erarules.h" #include "japancal.h" #include "unicode/gregocal.h" #include "umutex.h" #include "uassert.h" - -//#define U_DEBUG_JCAL - -#ifdef U_DEBUG_JCAL -#include -#endif +#include "ucln_in.h" +#include "cstring.h" + +static icu::EraRules * gJapaneseEraRules = nullptr; +static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER; +static int32_t gCurrentEra = 0; + +U_CDECL_BEGIN +static UBool japanese_calendar_cleanup(void) { + if (gJapaneseEraRules) { + delete gJapaneseEraRules; + gJapaneseEraRules = nullptr; + } + gCurrentEra = 0; + gJapaneseEraRulesInitOnce.reset(); + return TRUE; +} +U_CDECL_END U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar) -// Gregorian date of each emperor's ascension -// Years are AD, months are 1-based. -static const struct { - int16_t year; - int8_t month; - int8_t day; -} kEraInfo[] = { - // Year Month Day - { 645, 6, 19 }, // Taika 0 - { 650, 2, 15 }, // Hakuchi 1 - { 672, 1, 1 }, // Hakuho 2 - { 686, 7, 20 }, // Shucho 3 - { 701, 3, 21 }, // Taiho 4 - { 704, 5, 10 }, // Keiun 5 - { 708, 1, 11 }, // Wado 6 - { 715, 9, 2 }, // Reiki 7 - { 717, 11, 17 }, // Yoro 8 - { 724, 2, 4 }, // Jinki 9 - { 729, 8, 5 }, // Tempyo 10 - { 749, 4, 14 }, // Tempyo-kampo 11 - { 749, 7, 2 }, // Tempyo-shoho 12 - { 757, 8, 18 }, // Tempyo-hoji 13 - { 765, 1, 7 }, // Tempho-jingo 14 - { 767, 8, 16 }, // Jingo-keiun 15 - { 770, 10, 1 }, // Hoki 16 - { 781, 1, 1 }, // Ten-o 17 - { 782, 8, 19 }, // Enryaku 18 - { 806, 5, 18 }, // Daido 19 - { 810, 9, 19 }, // Konin 20 - { 824, 1, 5 }, // Tencho - { 834, 1, 3 }, // Showa - { 848, 6, 13 }, // Kajo - { 851, 4, 28 }, // Ninju - { 854, 11, 30 }, // Saiko - { 857, 2, 21 }, // Tennan - { 859, 4, 15 }, // Jogan - { 877, 4, 16 }, // Genkei - { 885, 2, 21 }, // Ninna - { 889, 4, 27 }, // Kampyo 30 - { 898, 4, 26 }, // Shotai - { 901, 7, 15 }, // Engi - { 923, 4, 11 }, // Encho - { 931, 4, 26 }, // Shohei - { 938, 5, 22 }, // Tengyo - { 947, 4, 22 }, // Tenryaku - { 957, 10, 27 }, // Tentoku - { 961, 2, 16 }, // Owa - { 964, 7, 10 }, // Koho - { 968, 8, 13 }, // Anna 40 - { 970, 3, 25 }, // Tenroku - { 973, 12, 20 }, // Ten-en - { 976, 7, 13 }, // Jogen - { 978, 11, 29 }, // Tengen - { 983, 4, 15 }, // Eikan - { 985, 4, 27 }, // Kanna - { 987, 4, 5 }, // Ei-en - { 989, 8, 8 }, // Eiso - { 990, 11, 7 }, // Shoryaku - { 995, 2, 22 }, // Chotoku 50 - { 999, 1, 13 }, // Choho - { 1004, 7, 20 }, // Kanko - { 1012, 12, 25 }, // Chowa - { 1017, 4, 23 }, // Kannin - { 1021, 2, 2 }, // Jian - { 1024, 7, 13 }, // Manju - { 1028, 7, 25 }, // Chogen - { 1037, 4, 21 }, // Choryaku - { 1040, 11, 10 }, // Chokyu - { 1044, 11, 24 }, // Kantoku 60 - { 1046, 4, 14 }, // Eisho - { 1053, 1, 11 }, // Tengi - { 1058, 8, 29 }, // Kohei - { 1065, 8, 2 }, // Jiryaku - { 1069, 4, 13 }, // Enkyu - { 1074, 8, 23 }, // Shoho - { 1077, 11, 17 }, // Shoryaku - { 1081, 2, 10 }, // Eiho - { 1084, 2, 7 }, // Otoku - { 1087, 4, 7 }, // Kanji 70 - { 1094, 12, 15 }, // Kaho - { 1096, 12, 17 }, // Eicho - { 1097, 11, 21 }, // Shotoku - { 1099, 8, 28 }, // Kowa - { 1104, 2, 10 }, // Choji - { 1106, 4, 9 }, // Kasho - { 1108, 8, 3 }, // Tennin - { 1110, 7, 13 }, // Ten-ei - { 1113, 7, 13 }, // Eikyu - { 1118, 4, 3 }, // Gen-ei 80 - { 1120, 4, 10 }, // Hoan - { 1124, 4, 3 }, // Tenji - { 1126, 1, 22 }, // Daiji - { 1131, 1, 29 }, // Tensho - { 1132, 8, 11 }, // Chosho - { 1135, 4, 27 }, // Hoen - { 1141, 7, 10 }, // Eiji - { 1142, 4, 28 }, // Koji - { 1144, 2, 23 }, // Tenyo - { 1145, 7, 22 }, // Kyuan 90 - { 1151, 1, 26 }, // Ninpei - { 1154, 10, 28 }, // Kyuju - { 1156, 4, 27 }, // Hogen - { 1159, 4, 20 }, // Heiji - { 1160, 1, 10 }, // Eiryaku - { 1161, 9, 4 }, // Oho - { 1163, 3, 29 }, // Chokan - { 1165, 6, 5 }, // Eiman - { 1166, 8, 27 }, // Nin-an - { 1169, 4, 8 }, // Kao 100 - { 1171, 4, 21 }, // Shoan - { 1175, 7, 28 }, // Angen - { 1177, 8, 4 }, // Jisho - { 1181, 7, 14 }, // Yowa - { 1182, 5, 27 }, // Juei - { 1184, 4, 16 }, // Genryuku - { 1185, 8, 14 }, // Bunji - { 1190, 4, 11 }, // Kenkyu - { 1199, 4, 27 }, // Shoji - { 1201, 2, 13 }, // Kennin 110 - { 1204, 2, 20 }, // Genkyu - { 1206, 4, 27 }, // Ken-ei - { 1207, 10, 25 }, // Shogen - { 1211, 3, 9 }, // Kenryaku - { 1213, 12, 6 }, // Kenpo - { 1219, 4, 12 }, // Shokyu - { 1222, 4, 13 }, // Joo - { 1224, 11, 20 }, // Gennin - { 1225, 4, 20 }, // Karoku - { 1227, 12, 10 }, // Antei 120 - { 1229, 3, 5 }, // Kanki - { 1232, 4, 2 }, // Joei - { 1233, 4, 15 }, // Tempuku - { 1234, 11, 5 }, // Bunryaku - { 1235, 9, 19 }, // Katei - { 1238, 11, 23 }, // Ryakunin - { 1239, 2, 7 }, // En-o - { 1240, 7, 16 }, // Ninji - { 1243, 2, 26 }, // Kangen - { 1247, 2, 28 }, // Hoji 130 - { 1249, 3, 18 }, // Kencho - { 1256, 10, 5 }, // Kogen - { 1257, 3, 14 }, // Shoka - { 1259, 3, 26 }, // Shogen - { 1260, 4, 13 }, // Bun-o - { 1261, 2, 20 }, // Kocho - { 1264, 2, 28 }, // Bun-ei - { 1275, 4, 25 }, // Kenji - { 1278, 2, 29 }, // Koan - { 1288, 4, 28 }, // Shoo 140 - { 1293, 8, 55 }, // Einin - { 1299, 4, 25 }, // Shoan - { 1302, 11, 21 }, // Kengen - { 1303, 8, 5 }, // Kagen - { 1306, 12, 14 }, // Tokuji - { 1308, 10, 9 }, // Enkei - { 1311, 4, 28 }, // Ocho - { 1312, 3, 20 }, // Showa - { 1317, 2, 3 }, // Bunpo - { 1319, 4, 28 }, // Geno 150 - { 1321, 2, 23 }, // Genkyo - { 1324, 12, 9 }, // Shochu - { 1326, 4, 26 }, // Kareki - { 1329, 8, 29 }, // Gentoku - { 1331, 8, 9 }, // Genko - { 1334, 1, 29 }, // Kemmu - { 1336, 2, 29 }, // Engen - { 1340, 4, 28 }, // Kokoku - { 1346, 12, 8 }, // Shohei - { 1370, 7, 24 }, // Kentoku 160 - { 1372, 4, 1 }, // Bunch\u0169 - { 1375, 5, 27 }, // Tenju - { 1379, 3, 22 }, // Koryaku - { 1381, 2, 10 }, // Kowa - { 1384, 4, 28 }, // Gench\u0169 - { 1384, 2, 27 }, // Meitoku - { 1387, 8, 23 }, // Kakei - { 1389, 2, 9 }, // Koo - { 1390, 3, 26 }, // Meitoku - { 1394, 7, 5 }, // Oei 170 - { 1428, 4, 27 }, // Shocho - { 1429, 9, 5 }, // Eikyo - { 1441, 2, 17 }, // Kakitsu - { 1444, 2, 5 }, // Bun-an - { 1449, 7, 28 }, // Hotoku - { 1452, 7, 25 }, // Kyotoku - { 1455, 7, 25 }, // Kosho - { 1457, 9, 28 }, // Choroku - { 1460, 12, 21 }, // Kansho - { 1466, 2, 28 }, // Bunsho 180 - { 1467, 3, 3 }, // Onin - { 1469, 4, 28 }, // Bunmei - { 1487, 7, 29 }, // Chokyo - { 1489, 8, 21 }, // Entoku - { 1492, 7, 19 }, // Meio - { 1501, 2, 29 }, // Bunki - { 1504, 2, 30 }, // Eisho - { 1521, 8, 23 }, // Taiei - { 1528, 8, 20 }, // Kyoroku - { 1532, 7, 29 }, // Tenmon 190 - { 1555, 10, 23 }, // Koji - { 1558, 2, 28 }, // Eiroku - { 1570, 4, 23 }, // Genki - { 1573, 7, 28 }, // Tensho - { 1592, 12, 8 }, // Bunroku - { 1596, 10, 27 }, // Keicho - { 1615, 7, 13 }, // Genwa - { 1624, 2, 30 }, // Kan-ei - { 1644, 12, 16 }, // Shoho - { 1648, 2, 15 }, // Keian 200 - { 1652, 9, 18 }, // Shoo - { 1655, 4, 13 }, // Meiryaku - { 1658, 7, 23 }, // Manji - { 1661, 4, 25 }, // Kanbun - { 1673, 9, 21 }, // Enpo - { 1681, 9, 29 }, // Tenwa - { 1684, 2, 21 }, // Jokyo - { 1688, 9, 30 }, // Genroku - { 1704, 3, 13 }, // Hoei - { 1711, 4, 25 }, // Shotoku 210 - { 1716, 6, 22 }, // Kyoho - { 1736, 4, 28 }, // Genbun - { 1741, 2, 27 }, // Kanpo - { 1744, 2, 21 }, // Enkyo - { 1748, 7, 12 }, // Kan-en - { 1751, 10, 27 }, // Horyaku - { 1764, 6, 2 }, // Meiwa - { 1772, 11, 16 }, // An-ei - { 1781, 4, 2 }, // Tenmei - { 1789, 1, 25 }, // Kansei 220 - { 1801, 2, 5 }, // Kyowa - { 1804, 2, 11 }, // Bunka - { 1818, 4, 22 }, // Bunsei - { 1830, 12, 10 }, // Tenpo - { 1844, 12, 2 }, // Koka - { 1848, 2, 28 }, // Kaei - { 1854, 11, 27 }, // Ansei - { 1860, 3, 18 }, // Man-en - { 1861, 2, 19 }, // Bunkyu - { 1864, 2, 20 }, // Genji 230 - { 1865, 4, 7 }, // Keio 231 - { 1868, 9, 8 }, // Meiji 232 - { 1912, 7, 30 }, // Taisho 233 - { 1926, 12, 25 }, // Showa 234 - { 1989, 1, 8 } // Heisei 235 -}; - -#define kEraCount UPRV_LENGTHOF(kEraInfo) - -/** - * The current era, for reference. - */ -static const int32_t kCurrentEra = (kEraCount-1); // int32_t to match the calendar field type - static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR +static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA"; + +// Initialize global Japanese era data +static void U_CALLCONV initializeEras(UErrorCode &status) { + // Although start date of next Japanese era is planned ahead, a name of + // new era might not be available. This implementation allows tester to + // check a new era without era names by settings below (in priority order). + // By default, such tentative era is disabled. + + // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false + + UBool includeTentativeEra = FALSE; + +#if U_PLATFORM_HAS_WINUWP_API == 1 + // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing. + UChar varName[26] = {}; + u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast(uprv_strlen(TENTATIVE_ERA_VAR_NAME))); + WCHAR varValue[5] = {}; + DWORD ret = GetEnvironmentVariableW(reinterpret_cast(varName), varValue, UPRV_LENGTHOF(varValue)); + if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) { + includeTentativeEra = TRUE; + } +#else + char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); + if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) { + includeTentativeEra = TRUE; + } +#endif + gJapaneseEraRules = EraRules::createInstance("japanese", includeTentativeEra, status); + if (U_FAILURE(status)) { + return; + } + gCurrentEra = gJapaneseEraRules->getCurrentEraIndex(); +} + +static void init(UErrorCode &status) { + umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status); + ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup); +} /* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */ uint32_t JapaneseCalendar::getCurrentEra() { - return kCurrentEra; + return gCurrentEra; } JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success) : GregorianCalendar(aLocale, success) { + init(success); setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. } @@ -306,6 +108,9 @@ JapaneseCalendar::~JapaneseCalendar() JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source) : GregorianCalendar(source) { + UErrorCode status = U_ZERO_ERROR; + init(status); + U_ASSERT(U_SUCCESS(status)); } JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right) @@ -332,10 +137,14 @@ int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear) int32_t month = 0; // Find out if we are at the edge of an era - - if(eyear == kEraInfo[era].year) { + int32_t eraStart[3] = { 0,0,0 }; + UErrorCode status = U_ZERO_ERROR; + gJapaneseEraRules->getStartDate(era, eraStart, status); + U_ASSERT(U_SUCCESS(status)); + if(eyear == eraStart[0]) { // Yes, we're in the first year of this era. - return kEraInfo[era].month-1; + return eraStart[1] // month + -1; // return 0-based month } return month; @@ -346,9 +155,13 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month) int32_t era = internalGetEra(); int32_t day = 1; - if(eyear == kEraInfo[era].year) { - if(month == (kEraInfo[era].month-1)) { - return kEraInfo[era].day; + int32_t eraStart[3] = { 0,0,0 }; + UErrorCode status = U_ZERO_ERROR; + gJapaneseEraRules->getStartDate(era, eraStart, status); + U_ASSERT(U_SUCCESS(status)); + if(eyear == eraStart[0]) { + if(month == eraStart[1] - 1) { + return eraStart[2]; } } @@ -358,7 +171,7 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month) int32_t JapaneseCalendar::internalGetEra() const { - return internalGet(UCAL_ERA, kCurrentEra); + return internalGet(UCAL_ERA, gCurrentEra); } int32_t JapaneseCalendar::handleGetExtendedYear() @@ -369,12 +182,18 @@ int32_t JapaneseCalendar::handleGetExtendedYear() if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR && newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) { - year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); - } else { - // Subtract one because year starts at 1 - year = internalGet(UCAL_YEAR) + kEraInfo[internalGetEra()].year - 1; - } - return year; + year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); + } else { + UErrorCode status = U_ZERO_ERROR; + int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status); + U_ASSERT(U_SUCCESS(status)); + + // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc + year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year) + + eraStartYear // add gregorian starting year + - 1; // Subtract one because year starts at 1 + } + return year; } @@ -383,79 +202,10 @@ void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status //Calendar::timeToFields(theTime, quick, status); GregorianCalendar::handleComputeFields(julianDay, status); int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year + int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status); - int32_t low = 0; - - // Short circuit for recent years. Most modern computations will - // occur in the current era and won't require the binary search. - // Note that if the year is == the current era year, then we use - // the binary search to handle the month/dom comparison. -#ifdef U_DEBUG_JCAL - fprintf(stderr, "== %d \n", year); -#endif - - if (year > kEraInfo[kCurrentEra].year) { - low = kCurrentEra; -#ifdef U_DEBUG_JCAL - fprintf(stderr, " low=%d (special)\n", low); -#endif - } else { - // Binary search - int32_t high = kEraCount; - -#ifdef U_DEBUG_JCAL - fprintf(stderr, " high=%d\n", high); -#endif - while (low < high - 1) { - int32_t i = (low + high) / 2; - int32_t diff = year - kEraInfo[i].year; - -#ifdef U_DEBUG_JCAL - fprintf(stderr, " d=%d low=%d, high=%d. Considering %d:M%d D%d Y%d. { we are ?:M%d D%d Y%d }\n", - diff,low, high, i, kEraInfo[i].month-1, kEraInfo[i].day, kEraInfo[i].year, internalGet(UCAL_MONTH), internalGet(UCAL_DATE),year); -#endif - - // If years are the same, then compare the months, and if those - // are the same, compare days of month. In the ERAS array - // months are 1-based for easier maintenance. - if (diff == 0) { - diff = internalGet(UCAL_MONTH) - (kEraInfo[i].month - 1); -#ifdef U_DEBUG_JCAL - fprintf(stderr, "diff now %d (M) = %d - %d - 1\n", diff, internalGet(UCAL_MONTH), kEraInfo[i].month); -#endif - if (diff == 0) { - diff = internalGet(UCAL_DATE) - kEraInfo[i].day; -#ifdef U_DEBUG_JCAL - fprintf(stderr, "diff now %d (D)\n", diff); -#endif - } - } - if (diff >= 0) { - low = i; - } else { - high = i; - } -#ifdef U_DEBUG_JCAL - fprintf(stderr, ". low=%d, high=%d, i=%d, diff=%d.. %d\n", low, high, i, diff, year); -#endif - - } - } - -#ifdef U_DEBUG_JCAL - fprintf(stderr, " low[era]=%d,.. %d\n", low, year); -#endif - // Now we've found the last era that starts before this date, so - // adjust the year to count from the start of that era. Note that - // all dates before the first era will fall into the first era by - // the algorithm. - - internalSet(UCAL_ERA, low); - internalSet(UCAL_YEAR, year - kEraInfo[low].year + 1); -#ifdef U_DEBUG_JCAL - fprintf(stderr, " Set ERA=%d, year=%d\n", low, year-kEraInfo[low].year+1); -#endif - + internalSet(UCAL_ERA, eraIdx); + internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1); } /* @@ -483,7 +233,7 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) { return 0; } - return kCurrentEra; + return gCurrentEra; case UCAL_YEAR: { switch (limitType) { @@ -494,7 +244,12 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l return 1; case UCAL_LIMIT_COUNT: //added to avoid warning case UCAL_LIMIT_MAXIMUM: - return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - kEraInfo[kCurrentEra].year; + { + UErrorCode status = U_ZERO_ERROR; + int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status); + U_ASSERT(U_SUCCESS(status)); + return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear; + } default: return 1; // Error condition, invalid limitType } @@ -510,15 +265,18 @@ int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode if (U_FAILURE(status)) { return 0; // error case... any value } - if (era == kCurrentEra) { + if (era == gCurrentEra) { // TODO: Investigate what value should be used here - revisit after 4.0. return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM); } else { - int32_t nextEraYear = kEraInfo[era + 1].year; - int32_t nextEraMonth = kEraInfo[era + 1].month; - int32_t nextEraDate = kEraInfo[era + 1].day; - - int32_t maxYear = nextEraYear - kEraInfo[era].year + 1; // 1-base + int32_t nextEraStart[3] = { 0,0,0 }; + gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status); + int32_t nextEraYear = nextEraStart[0]; + int32_t nextEraMonth = nextEraStart[1]; // 1-base + int32_t nextEraDate = nextEraStart[2]; + + int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status); + int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base if (nextEraMonth == 1 && nextEraDate == 1) { // Subtract 1, because the next era starts at Jan 1 maxYear--; diff --git a/deps/icu-small/source/i18n/japancal.h b/deps/icu-small/source/i18n/japancal.h index 356351d28dd28a..67d2d7031526a2 100644 --- a/deps/icu-small/source/i18n/japancal.h +++ b/deps/icu-small/source/i18n/japancal.h @@ -49,10 +49,18 @@ U_NAMESPACE_BEGIN * July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants * for these eras, suitable for use in the UCAL_ERA field, are provided * in this class. Note that the number used for each era is more or - * less arbitrary. Currently, the era starting in 1053 AD is era #0; however this - * may change in the future as we add more historical data. Use the predefined - * constants rather than using actual, absolute numbers. + * less arbitrary. Currently, the era starting in 645 AD is era #0; however this + * may change in the future. Use the predefined constants rather than using actual, + * absolute numbers. *

+ * Since ICU4C 63, start date of each era is imported from CLDR. CLDR era data + * may contain tentative era in near future with placeholder names. By default, + * such era data is not enabled. ICU4C users who want to test the behavior of + * the future era can enable this one of following settings (in the priority + * order): + *

    + *
  1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true.
  2. + * * @internal */ class JapaneseCalendar : public GregorianCalendar { diff --git a/deps/icu-small/source/common/listformatter.cpp b/deps/icu-small/source/i18n/listformatter.cpp similarity index 71% rename from deps/icu-small/source/common/listformatter.cpp rename to deps/icu-small/source/i18n/listformatter.cpp index 33a8ac28671fc6..d9195348529c57 100644 --- a/deps/icu-small/source/common/listformatter.cpp +++ b/deps/icu-small/source/i18n/listformatter.cpp @@ -16,14 +16,19 @@ * created by: Umesh P. Nair */ +#include "cmemory.h" +#include "unicode/fpositer.h" // FieldPositionIterator #include "unicode/listformatter.h" #include "unicode/simpleformatter.h" +#include "unicode/ulistformatter.h" +#include "fphdlimp.h" #include "mutex.h" #include "hash.h" #include "cstring.h" +#include "uarrsort.h" #include "ulocimp.h" #include "charstr.h" -#include "ucln_cmn.h" +#include "ucln_in.h" #include "uresimp.h" #include "resource.h" @@ -61,14 +66,14 @@ ListFormatInternal(const ListFormatInternal &other) : -static Hashtable* listPatternHash = NULL; +static Hashtable* listPatternHash = nullptr; static UMutex listFormatterMutex = U_MUTEX_INITIALIZER; static const char STANDARD_STYLE[] = "standard"; U_CDECL_BEGIN static UBool U_CALLCONV uprv_listformatter_cleanup() { delete listPatternHash; - listPatternHash = NULL; + listPatternHash = nullptr; return TRUE; } @@ -81,7 +86,7 @@ U_CDECL_END ListFormatter::ListFormatter(const ListFormatter& other) : owned(other.owned), data(other.data) { - if (other.owned != NULL) { + if (other.owned != nullptr) { owned = new ListFormatInternal(*other.owned); data = owned; } @@ -96,7 +101,7 @@ ListFormatter& ListFormatter::operator=(const ListFormatter& other) { owned = new ListFormatInternal(*other.owned); data = owned; } else { - owned = NULL; + owned = nullptr; data = other.data; } return *this; @@ -108,53 +113,53 @@ void ListFormatter::initializeHash(UErrorCode& errorCode) { } listPatternHash = new Hashtable(); - if (listPatternHash == NULL) { + if (listPatternHash == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; return; } listPatternHash->setValueDeleter(uprv_deleteListFormatInternal); - ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup); + ucln_i18n_registerCleanup(UCLN_I18N_LIST_FORMATTER, uprv_listformatter_cleanup); } const ListFormatInternal* ListFormatter::getListFormatInternal( const Locale& locale, const char *style, UErrorCode& errorCode) { if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } CharString keyBuffer(locale.getName(), errorCode); keyBuffer.append(':', errorCode).append(style, errorCode); UnicodeString key(keyBuffer.data(), -1, US_INV); - ListFormatInternal* result = NULL; + ListFormatInternal* result = nullptr; { Mutex m(&listFormatterMutex); - if (listPatternHash == NULL) { + if (listPatternHash == nullptr) { initializeHash(errorCode); if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } } result = static_cast(listPatternHash->get(key)); } - if (result != NULL) { + if (result != nullptr) { return result; } result = loadListFormatInternal(locale, style, errorCode); if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } { Mutex m(&listFormatterMutex); ListFormatInternal* temp = static_cast(listPatternHash->get(key)); - if (temp != NULL) { + if (temp != nullptr) { delete result; result = temp; } else { listPatternHash->put(key, result, errorCode); if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } } } @@ -235,11 +240,11 @@ ListFormatter::ListPatternsSink::~ListPatternsSink() {} ListFormatInternal* ListFormatter::loadListFormatInternal( const Locale& locale, const char * style, UErrorCode& errorCode) { - UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode); + UResourceBundle* rb = ures_open(nullptr, locale.getName(), &errorCode); rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode); if (U_FAILURE(errorCode)) { ures_close(rb); - return NULL; + return nullptr; } ListFormatter::ListPatternsSink sink; char currentStyle[kStyleLenMax+1]; @@ -255,20 +260,20 @@ ListFormatInternal* ListFormatter::loadListFormatInternal( } ures_close(rb); if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) { errorCode = U_MISSING_RESOURCE_ERROR; - return NULL; + return nullptr; } ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, errorCode); - if (result == NULL) { + if (result == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; - return NULL; + return nullptr; } if (U_FAILURE(errorCode)) { delete result; - return NULL; + return nullptr; } return result; } @@ -283,15 +288,14 @@ ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& e } ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) { - Locale tempLocale = locale; - const ListFormatInternal* listFormatInternal = getListFormatInternal(tempLocale, style, errorCode); + const ListFormatInternal* listFormatInternal = getListFormatInternal(locale, style, errorCode); if (U_FAILURE(errorCode)) { - return NULL; + return nullptr; } ListFormatter* p = new ListFormatter(listFormatInternal); - if (p == NULL) { + if (p == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; - return NULL; + return nullptr; } return p; } @@ -301,7 +305,7 @@ ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &e data = owned; } -ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(NULL), data(listFormatterInternal) { +ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(nullptr), data(listFormatterInternal) { } ListFormatter::~ListFormatter() { @@ -323,6 +327,8 @@ static void joinStringsAndReplace( UnicodeString &result, UBool recordOffset, int32_t &offset, + int32_t *offsetFirst, + int32_t *offsetSecond, UErrorCode& errorCode) { if (U_FAILURE(errorCode)) { return; @@ -348,6 +354,8 @@ static void joinStringsAndReplace( } else if (offset >= 0) { offset += offsets[0]; } + if (offsetFirst != nullptr) *offsetFirst = offsets[0]; + if (offsetSecond != nullptr) *offsetSecond = offsets[1]; } UnicodeString& ListFormatter::format( @@ -359,6 +367,19 @@ UnicodeString& ListFormatter::format( return format(items, nItems, appendTo, -1, offset, errorCode); } +#if !UCONFIG_NO_FORMATTING +UnicodeString& ListFormatter::format( + const UnicodeString items[], + int32_t nItems, + UnicodeString & appendTo, + FieldPositionIterator* posIter, + UErrorCode& errorCode) const { + int32_t offset; + FieldPositionIteratorHandler handler(posIter, errorCode); + return format_(items, nItems, appendTo, -1, offset, &handler, errorCode); +}; +#endif + UnicodeString& ListFormatter::format( const UnicodeString items[], int32_t nItems, @@ -366,11 +387,23 @@ UnicodeString& ListFormatter::format( int32_t index, int32_t &offset, UErrorCode& errorCode) const { + return format_(items, nItems, appendTo, index, offset, nullptr, errorCode); +} + +UnicodeString& ListFormatter::format_( + const UnicodeString items[], + int32_t nItems, + UnicodeString& appendTo, + int32_t index, + int32_t &offset, + FieldPositionHandler* handler, + UErrorCode& errorCode) const { +#if !UCONFIG_NO_FORMATTING offset = -1; if (U_FAILURE(errorCode)) { return appendTo; } - if (data == NULL) { + if (data == nullptr) { errorCode = U_INVALID_STATE_ERROR; return appendTo; } @@ -382,6 +415,11 @@ UnicodeString& ListFormatter::format( if (index == 0) { offset = appendTo.length(); } + if (handler != nullptr) { + handler->addAttribute(ULISTFMT_ELEMENT_FIELD, + appendTo.length(), + appendTo.length() + items[0].length()); + } appendTo.append(items[0]); return appendTo; } @@ -389,6 +427,12 @@ UnicodeString& ListFormatter::format( if (index == 0) { offset = 0; } + int32_t offsetFirst; + int32_t offsetSecond; + int32_t prefixLength = 0; + // for n items, there are 2 * (n + 1) boundary including 0 and the upper + // edge. + MaybeStackArray offsets((handler != nullptr) ? 2 * (nItems + 1): 0); joinStringsAndReplace( nItems == 2 ? data->twoPattern : data->startPattern, result, @@ -396,7 +440,14 @@ UnicodeString& ListFormatter::format( result, index == 1, offset, + &offsetFirst, + &offsetSecond, errorCode); + if (handler != nullptr) { + offsets[0] = 0; + prefixLength += offsetFirst; + offsets[1] = offsetSecond - prefixLength; + } if (nItems > 2) { for (int32_t i = 2; i < nItems - 1; ++i) { joinStringsAndReplace( @@ -406,7 +457,13 @@ UnicodeString& ListFormatter::format( result, index == i, offset, + &offsetFirst, + &offsetSecond, errorCode); + if (handler != nullptr) { + prefixLength += offsetFirst; + offsets[i] = offsetSecond - prefixLength; + } } joinStringsAndReplace( data->endPattern, @@ -415,7 +472,45 @@ UnicodeString& ListFormatter::format( result, index == nItems - 1, offset, + &offsetFirst, + &offsetSecond, errorCode); + if (handler != nullptr) { + prefixLength += offsetFirst; + offsets[nItems - 1] = offsetSecond - prefixLength; + } + } + if (handler != nullptr) { + // If there are already some data in appendTo, we need to adjust the index + // by shifting that lenght while insert into handler. + int32_t shift = appendTo.length() + prefixLength; + // Output the ULISTFMT_ELEMENT_FIELD in the order of the input elements + for (int32_t i = 0; i < nItems; ++i) { + offsets[i + nItems] = offsets[i] + items[i].length() + shift; + offsets[i] += shift; + handler->addAttribute( + ULISTFMT_ELEMENT_FIELD, // id + offsets[i], // index + offsets[i + nItems]); // limit + } + // The locale pattern may reorder the items (such as in ur-IN locale), + // so we cannot assume the array is in accendning order. + // To handle the edging case, just insert the two ends into the array + // and sort. Then we output ULISTFMT_LITERAL_FIELD if the indecies + // between the even and odd position are not the same in the sorted array. + offsets[2 * nItems] = shift - prefixLength; + offsets[2 * nItems + 1] = result.length() + shift - prefixLength; + uprv_sortArray(offsets.getAlias(), 2 * (nItems + 1), sizeof(int32_t), + uprv_int32Comparator, nullptr, + false, &errorCode); + for (int32_t i = 0; i <= nItems; ++i) { + if (offsets[i * 2] != offsets[i * 2 + 1]) { + handler->addAttribute( + ULISTFMT_LITERAL_FIELD, // id + offsets[i * 2], // index + offsets[i * 2 + 1]); // limit + } + } } if (U_SUCCESS(errorCode)) { if (offset >= 0) { @@ -423,6 +518,7 @@ UnicodeString& ListFormatter::format( } appendTo += result; } +#endif return appendTo; } diff --git a/deps/icu-small/source/i18n/measfmt.cpp b/deps/icu-small/source/i18n/measfmt.cpp index 996a20c2e043e8..03974ff4b74048 100644 --- a/deps/icu-small/source/i18n/measfmt.cpp +++ b/deps/icu-small/source/i18n/measfmt.cpp @@ -47,7 +47,7 @@ U_NAMESPACE_BEGIN static constexpr int32_t PER_UNIT_INDEX = StandardPlural::COUNT; static constexpr int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1; -static constexpr int32_t MEAS_UNIT_COUNT = 138; // see assertion in MeasureFormatCacheData constructor +static constexpr int32_t MEAS_UNIT_COUNT = 142; // see assertion in MeasureFormatCacheData constructor static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat) @@ -618,7 +618,7 @@ MeasureFormat::MeasureFormat( : cache(NULL), numberFormat(NULL), pluralRules(NULL), - width(w), + fWidth(w), listFormatter(NULL) { initMeasureFormat(locale, w, NULL, status); } @@ -631,7 +631,7 @@ MeasureFormat::MeasureFormat( : cache(NULL), numberFormat(NULL), pluralRules(NULL), - width(w), + fWidth(w), listFormatter(NULL) { initMeasureFormat(locale, w, nfToAdopt, status); } @@ -641,7 +641,7 @@ MeasureFormat::MeasureFormat(const MeasureFormat &other) : cache(other.cache), numberFormat(other.numberFormat), pluralRules(other.pluralRules), - width(other.width), + fWidth(other.fWidth), listFormatter(NULL) { cache->addRef(); numberFormat->addRef(); @@ -659,7 +659,7 @@ MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) { SharedObject::copyPtr(other.cache, cache); SharedObject::copyPtr(other.numberFormat, numberFormat); SharedObject::copyPtr(other.pluralRules, pluralRules); - width = other.width; + fWidth = other.fWidth; delete listFormatter; if (other.listFormatter != NULL) { listFormatter = new ListFormatter(*other.listFormatter); @@ -673,7 +673,7 @@ MeasureFormat::MeasureFormat() : cache(NULL), numberFormat(NULL), pluralRules(NULL), - width(UMEASFMT_WIDTH_SHORT), + fWidth(UMEASFMT_WIDTH_SHORT), listFormatter(NULL) { } @@ -703,7 +703,7 @@ UBool MeasureFormat::operator==(const Format &other) const { // don't have to check it here. // differing widths aren't equivalent - if (width != rhs.width) { + if (fWidth != rhs.fWidth) { return FALSE; } // Width the same check locales. @@ -805,7 +805,7 @@ UnicodeString &MeasureFormat::formatMeasures( if (measureCount == 1) { return formatMeasure(measures[0], **numberFormat, appendTo, pos, status); } - if (width == UMEASFMT_WIDTH_NUMERIC) { + if (fWidth == UMEASFMT_WIDTH_NUMERIC) { Formattable hms[3]; int32_t bitMap = toHMS(measures, measureCount, hms, status); if (bitMap > 0) { @@ -839,7 +839,7 @@ UnicodeString &MeasureFormat::formatMeasures( } UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& /*status*/) const { - UMeasureFormatWidth width = getRegularWidth(this->width); + UMeasureFormatWidth width = getRegularWidth(fWidth); const UChar* const* styleToDnam = cache->dnams[unit.getIndex()]; const UChar* dnam = styleToDnam[width]; if (dnam == NULL) { @@ -895,11 +895,11 @@ void MeasureFormat::initMeasureFormat( return; } } - width = w; + fWidth = w; delete listFormatter; listFormatter = ListFormatter::createInstance( locale, - listStyles[getRegularWidth(width)], + listStyles[getRegularWidth(fWidth)], status); } @@ -922,7 +922,7 @@ UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &st if (U_FAILURE(status) || locale == getLocale(status)) { return FALSE; } - initMeasureFormat(locale, width, NULL, status); + initMeasureFormat(locale, fWidth, NULL, status); return U_SUCCESS(status); } @@ -956,7 +956,7 @@ UnicodeString &MeasureFormat::formatMeasure( if (isCurrency(amtUnit)) { UChar isoCode[4]; u_charsToUChars(amtUnit.getSubtype(), isoCode, 4); - return cache->getCurrencyFormat(width)->format( + return cache->getCurrencyFormat(fWidth)->format( new CurrencyAmount(amtNumber, isoCode, status), appendTo, pos, @@ -965,7 +965,7 @@ UnicodeString &MeasureFormat::formatMeasure( UnicodeString formattedNumber; StandardPlural::Form pluralForm = QuantityFormatter::selectPlural( amtNumber, nf, **pluralRules, formattedNumber, pos, status); - const SimpleFormatter *formatter = getPluralFormatter(amtUnit, width, pluralForm, status); + const SimpleFormatter *formatter = getPluralFormatter(amtUnit, fWidth, pluralForm, status); return QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos, status); } @@ -1016,7 +1016,6 @@ UnicodeString &MeasureFormat::formatNumeric( return appendTo; break; } - return appendTo; } static void appendRange( @@ -1173,7 +1172,7 @@ int32_t MeasureFormat::withPerUnitAndAppend( if (U_FAILURE(status)) { return offset; } - const SimpleFormatter *perUnitFormatter = getFormatterOrNull(perUnit, width, PER_UNIT_INDEX); + const SimpleFormatter *perUnitFormatter = getFormatterOrNull(perUnit, fWidth, PER_UNIT_INDEX); if (perUnitFormatter != NULL) { const UnicodeString *params[] = {&formatted}; perUnitFormatter->formatAndAppend( @@ -1185,9 +1184,9 @@ int32_t MeasureFormat::withPerUnitAndAppend( status); return offset; } - const SimpleFormatter *perFormatter = getPerFormatter(width, status); + const SimpleFormatter *perFormatter = getPerFormatter(fWidth, status); const SimpleFormatter *pattern = - getPluralFormatter(perUnit, width, StandardPlural::ONE, status); + getPluralFormatter(perUnit, fWidth, StandardPlural::ONE, status); if (U_FAILURE(status)) { return offset; } diff --git a/deps/icu-small/source/i18n/measunit.cpp b/deps/icu-small/source/i18n/measunit.cpp index dc156aa720aae0..f6059f8c6dc808 100644 --- a/deps/icu-small/source/i18n/measunit.cpp +++ b/deps/icu-small/source/i18n/measunit.cpp @@ -39,23 +39,23 @@ static const int32_t gOffsets[] = { 2, 7, 16, - 20, - 24, - 321, - 331, - 342, - 346, - 352, - 356, - 376, - 377, - 388, - 391, - 397, + 22, + 26, + 325, + 336, + 347, + 351, + 357, + 361, + 381, + 382, + 393, + 396, 402, - 406, - 410, - 435 + 408, + 412, + 416, + 441 }; static const int32_t gIndexes[] = { @@ -63,23 +63,23 @@ static const int32_t gIndexes[] = { 2, 7, 16, - 20, - 24, - 24, - 34, - 45, - 49, - 55, - 59, - 79, - 80, - 91, + 22, + 26, + 26, + 37, + 48, + 52, + 58, + 62, + 82, + 83, 94, - 100, - 105, + 97, + 103, 109, 113, - 138 + 117, + 142 }; // Must be sorted alphabetically. @@ -128,6 +128,8 @@ static const char * const gSubTypes[] = { "milligram-per-deciliter", "millimole-per-liter", "part-per-million", + "percent", + "permille", "liter-per-100kilometers", "liter-per-kilometer", "mile-per-gallon", @@ -388,9 +390,11 @@ static const char * const gSubTypes[] = { "UYN", "UYP", "UYU", + "UYW", "UZS", "VEB", "VEF", + "VES", "VNC", "VND", "VUV", @@ -437,6 +441,7 @@ static const char * const gSubTypes[] = { "kilobyte", "megabit", "megabyte", + "petabyte", "terabit", "terabyte", "century", @@ -505,6 +510,7 @@ static const char * const gSubTypes[] = { "megawatt", "milliwatt", "watt", + "atmosphere", "hectopascal", "inch-hg", "millibar", @@ -547,14 +553,14 @@ static const char * const gSubTypes[] = { // Must be sorted by first value and then second value. static int32_t unitPerUnitToSingleUnit[][4] = { - {363, 333, 17, 0}, - {365, 339, 17, 2}, - {367, 333, 17, 3}, - {367, 424, 4, 2}, - {367, 425, 4, 3}, - {382, 422, 3, 1}, - {385, 11, 16, 4}, - {427, 363, 4, 1} + {368, 338, 17, 0}, + {370, 344, 17, 2}, + {372, 338, 17, 3}, + {372, 430, 4, 2}, + {372, 431, 4, 3}, + {387, 428, 3, 1}, + {390, 11, 16, 5}, + {433, 368, 4, 1} }; // Shortcuts to the base unit in order to make the default constructor fast @@ -641,6 +647,14 @@ MeasureUnit *MeasureUnit::createPartPerMillion(UErrorCode &status) { return MeasureUnit::create(3, 3, status); } +MeasureUnit *MeasureUnit::createPercent(UErrorCode &status) { + return MeasureUnit::create(3, 4, status); +} + +MeasureUnit *MeasureUnit::createPermille(UErrorCode &status) { + return MeasureUnit::create(3, 5, status); +} + MeasureUnit *MeasureUnit::createLiterPer100Kilometers(UErrorCode &status) { return MeasureUnit::create(4, 0, status); } @@ -689,14 +703,18 @@ MeasureUnit *MeasureUnit::createMegabyte(UErrorCode &status) { return MeasureUnit::create(6, 7, status); } -MeasureUnit *MeasureUnit::createTerabit(UErrorCode &status) { +MeasureUnit *MeasureUnit::createPetabyte(UErrorCode &status) { return MeasureUnit::create(6, 8, status); } -MeasureUnit *MeasureUnit::createTerabyte(UErrorCode &status) { +MeasureUnit *MeasureUnit::createTerabit(UErrorCode &status) { return MeasureUnit::create(6, 9, status); } +MeasureUnit *MeasureUnit::createTerabyte(UErrorCode &status) { + return MeasureUnit::create(6, 10, status); +} + MeasureUnit *MeasureUnit::createCentury(UErrorCode &status) { return MeasureUnit::create(7, 0, status); } @@ -949,26 +967,30 @@ MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) { return MeasureUnit::create(15, 5, status); } -MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) { +MeasureUnit *MeasureUnit::createAtmosphere(UErrorCode &status) { return MeasureUnit::create(16, 0, status); } -MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) { +MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) { return MeasureUnit::create(16, 1, status); } -MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) { +MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) { return MeasureUnit::create(16, 2, status); } -MeasureUnit *MeasureUnit::createMillimeterOfMercury(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) { return MeasureUnit::create(16, 3, status); } -MeasureUnit *MeasureUnit::createPoundPerSquareInch(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMillimeterOfMercury(UErrorCode &status) { return MeasureUnit::create(16, 4, status); } +MeasureUnit *MeasureUnit::createPoundPerSquareInch(UErrorCode &status) { + return MeasureUnit::create(16, 5, status); +} + MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) { return MeasureUnit::create(17, 0, status); } diff --git a/deps/icu-small/source/i18n/msgfmt.cpp b/deps/icu-small/source/i18n/msgfmt.cpp index 8b3807e67148a4..8ff86a2cacf018 100644 --- a/deps/icu-small/source/i18n/msgfmt.cpp +++ b/deps/icu-small/source/i18n/msgfmt.cpp @@ -1078,7 +1078,7 @@ void MessageFormat::format(int32_t msgStart, const void *plNumber, // that formats the number without subtracting the offset. appendTo.formatAndAppend(pluralNumber.formatter, *arg, success); } - } else if ((formatter = getCachedFormatter(i -2))) { + } else if ((formatter = getCachedFormatter(i -2)) != 0) { // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings. if (dynamic_cast(formatter) || dynamic_cast(formatter) || diff --git a/deps/icu-small/source/i18n/nfrule.cpp b/deps/icu-small/source/i18n/nfrule.cpp index 9f5deb31683291..b5e7892d5e68cb 100644 --- a/deps/icu-small/source/i18n/nfrule.cpp +++ b/deps/icu-small/source/i18n/nfrule.cpp @@ -39,14 +39,14 @@ NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleTex , radix(10) , exponent(0) , decimalPoint(0) - , ruleText(_ruleText) + , fRuleText(_ruleText) , sub1(NULL) , sub2(NULL) , formatter(_rbnf) , rulePatternFormat(NULL) { - if (!ruleText.isEmpty()) { - parseRuleDescriptor(ruleText, status); + if (!fRuleText.isEmpty()) { + parseRuleDescriptor(fRuleText, status); } } @@ -122,7 +122,7 @@ NFRule::makeRules(UnicodeString& description, status = U_MEMORY_ALLOCATION_ERROR; return; } - description = rule1->ruleText; + description = rule1->fRuleText; // check the description to see whether there's text enclosed // in brackets @@ -314,7 +314,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) if (c == gSlash) { val = 0; ++p; - int64_t ll_10 = 10; + ll_10 = 10; while (p < descriptorLength) { c = descriptor.charAt(p); if (c >= gZero && c <= gNine) { @@ -418,7 +418,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet, if (U_FAILURE(status)) { return; } - this->ruleText = ruleText; + fRuleText = ruleText; sub1 = extractSubstitution(ruleSet, predecessor, status); if (sub1 == NULL) { // Small optimization. There is no need to create a redundant NullSubstitution. @@ -427,15 +427,15 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet, else { sub2 = extractSubstitution(ruleSet, predecessor, status); } - int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1, 0); - int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1); + int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0); + int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1); if (pluralRuleEnd >= 0) { - int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart); + int32_t endType = fRuleText.indexOf(gComma, pluralRuleStart); if (endType < 0) { status = U_PARSE_ERROR; return; } - UnicodeString type(this->ruleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2)); + UnicodeString type(fRuleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2)); UPluralType pluralType; if (type.startsWith(UNICODE_STRING_SIMPLE("cardinal"))) { pluralType = UPLURAL_TYPE_CARDINAL; @@ -448,7 +448,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet, return; } rulePatternFormat = formatter->createPluralFormat(pluralType, - this->ruleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status); + fRuleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status); } } @@ -484,16 +484,16 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet, // special-case the ">>>" token, since searching for the > at the // end will actually find the > in the middle - if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { + if (fRuleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { subEnd = subStart + 2; // otherwise the substitution token ends with the same character // it began with } else { - UChar c = ruleText.charAt(subStart); - subEnd = ruleText.indexOf(c, subStart + 1); + UChar c = fRuleText.charAt(subStart); + subEnd = fRuleText.indexOf(c, subStart + 1); // special case for '<%foo<<' - if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) { + if (c == gLessThan && subEnd != -1 && subEnd < fRuleText.length() - 1 && fRuleText.charAt(subEnd+1) == c) { // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle // occurs because of the juxtaposition of two different rules. The check for '<' is a hack // to get around this. Having the duplicate at the front would cause problems with @@ -513,12 +513,12 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet, // some text bounded by substitution token characters). Use // makeSubstitution() to create the right kind of substitution UnicodeString subToken; - subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); + subToken.setTo(fRuleText, subStart, subEnd + 1 - subStart); result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleSet, this->formatter, subToken, status); // remove the substitution from the rule text - ruleText.removeBetween(subStart, subEnd+1); + fRuleText.removeBetween(subStart, subEnd+1); return result; } @@ -601,7 +601,7 @@ NFRule::indexOfAnyRulePrefix() const { int result = -1; for (int i = 0; RULE_PREFIXES[i]; i++) { - int32_t pos = ruleText.indexOf(*RULE_PREFIXES[i]); + int32_t pos = fRuleText.indexOf(*RULE_PREFIXES[i]); if (pos != -1 && (result == -1 || pos < result)) { result = pos; } @@ -637,7 +637,7 @@ NFRule::operator==(const NFRule& rhs) const return baseValue == rhs.baseValue && radix == rhs.radix && exponent == rhs.exponent - && ruleText == rhs.ruleText + && fRuleText == rhs.fRuleText && util_equalSubstitutions(sub1, rhs.sub1) && util_equalSubstitutions(sub2, rhs.sub2); } @@ -690,14 +690,14 @@ NFRule::_appendRuleText(UnicodeString& result) const // if the rule text begins with a space, write an apostrophe // (whitespace after the rule descriptor is ignored; the // apostrophe is used to make the whitespace significant) - if (ruleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) { + if (fRuleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) { result.append(gTick); } // now, write the rule's rule text, inserting appropriate // substitution tokens in the appropriate places UnicodeString ruleTextCopy; - ruleTextCopy.setTo(ruleText); + ruleTextCopy.setTo(fRuleText); UnicodeString temp; if (sub2 != NULL) { @@ -743,24 +743,24 @@ NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32 // into the right places in toInsertInto (notice we do the // substitutions in reverse order so that the offsets don't get // messed up) - int32_t pluralRuleStart = ruleText.length(); + int32_t pluralRuleStart = fRuleText.length(); int32_t lengthOffset = 0; if (!rulePatternFormat) { - toInsertInto.insert(pos, ruleText); + toInsertInto.insert(pos, fRuleText); } else { - pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); - int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart); + pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0); + int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart); int initialLength = toInsertInto.length(); - if (pluralRuleEnd < ruleText.length() - 1) { - toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); + if (pluralRuleEnd < fRuleText.length() - 1) { + toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2)); } toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(number/util64_pow(radix, exponent)), status)); if (pluralRuleStart > 0) { - toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)); + toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart)); } - lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength); + lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength); } if (sub2 != NULL) { @@ -789,17 +789,17 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_ // [again, we have two copies of this routine that do the same thing // so that we don't sacrifice precision in a long by casting it // to a double] - int32_t pluralRuleStart = ruleText.length(); + int32_t pluralRuleStart = fRuleText.length(); int32_t lengthOffset = 0; if (!rulePatternFormat) { - toInsertInto.insert(pos, ruleText); + toInsertInto.insert(pos, fRuleText); } else { - pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); - int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart); + pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0); + int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart); int initialLength = toInsertInto.length(); - if (pluralRuleEnd < ruleText.length() - 1) { - toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); + if (pluralRuleEnd < fRuleText.length() - 1) { + toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2)); } double pluralVal = number; if (0 <= pluralVal && pluralVal < 1) { @@ -812,9 +812,9 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_ } toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status)); if (pluralRuleStart > 0) { - toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)); + toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart)); } - lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength); + lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength); } if (sub2 != NULL) { @@ -908,15 +908,15 @@ NFRule::doParse(const UnicodeString& text, ParsePosition pp; UnicodeString workText(text); - int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : ruleText.length(); - int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : ruleText.length(); + int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : fRuleText.length(); + int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : fRuleText.length(); // check to see whether the text before the first substitution // matches the text at the beginning of the string being // parsed. If it does, strip that off the front of workText; // otherwise, dump out with a mismatch UnicodeString prefix; - prefix.setTo(ruleText, 0, sub1Pos); + prefix.setTo(fRuleText, 0, sub1Pos); #ifdef RBNF_DEBUG fprintf(stderr, "doParse %p ", this); @@ -1000,7 +1000,7 @@ NFRule::doParse(const UnicodeString& text, // the substitution, giving us a new partial parse result pp.setIndex(0); - temp.setTo(ruleText, sub1Pos, sub2Pos - sub1Pos); + temp.setTo(fRuleText, sub1Pos, sub2Pos - sub1Pos); double partialResult = matchToDelimiter(workText, start, tempBaseValue, temp, pp, sub1, nonNumericalExecutedRuleMask, @@ -1021,7 +1021,7 @@ NFRule::doParse(const UnicodeString& text, // partial result with whatever it gets back from its // substitution if there's a successful match, giving us // a real result - temp.setTo(ruleText, sub2Pos, ruleText.length() - sub2Pos); + temp.setTo(fRuleText, sub2Pos, fRuleText.length() - sub2Pos); partialResult = matchToDelimiter(workText2, 0, partialResult, temp, pp2, sub2, nonNumericalExecutedRuleMask, @@ -1039,18 +1039,18 @@ NFRule::doParse(const UnicodeString& text, else { // commented out because ParsePosition doesn't have error index in 1.1.x // restored for ICU4C port - int32_t temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex(); - if (temp> parsePosition.getErrorIndex()) { - parsePosition.setErrorIndex(temp); + int32_t i_temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex(); + if (i_temp> parsePosition.getErrorIndex()) { + parsePosition.setErrorIndex(i_temp); } } } else { // commented out because ParsePosition doesn't have error index in 1.1.x // restored for ICU4C port - int32_t temp = sub1Pos + pp.getErrorIndex(); - if (temp > parsePosition.getErrorIndex()) { - parsePosition.setErrorIndex(temp); + int32_t i_temp = sub1Pos + pp.getErrorIndex(); + if (i_temp > parsePosition.getErrorIndex()) { + parsePosition.setErrorIndex(i_temp); } } // keep trying to match things until the outer matchToDelimiter() @@ -1483,11 +1483,11 @@ NFRule::findText(const UnicodeString& str, rulePatternFormat->parseType(str, this, result, position); int start = position.getBeginIndex(); if (start >= 0) { - int32_t pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); - int32_t pluralRuleSuffix = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2; + int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0); + int32_t pluralRuleSuffix = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2; int32_t matchLen = position.getEndIndex() - start; - UnicodeString prefix(ruleText.tempSubString(0, pluralRuleStart)); - UnicodeString suffix(ruleText.tempSubString(pluralRuleSuffix)); + UnicodeString prefix(fRuleText.tempSubString(0, pluralRuleStart)); + UnicodeString suffix(fRuleText.tempSubString(pluralRuleSuffix)); if (str.compare(start - prefix.length(), prefix.length(), prefix, 0, prefix.length()) == 0 && str.compare(start + matchLen, suffix.length(), suffix, 0, suffix.length()) == 0) { diff --git a/deps/icu-small/source/i18n/nfrule.h b/deps/icu-small/source/i18n/nfrule.h index 843a4a0762bb01..2b030390ea7dcb 100644 --- a/deps/icu-small/source/i18n/nfrule.h +++ b/deps/icu-small/source/i18n/nfrule.h @@ -109,7 +109,7 @@ class NFRule : public UMemory { int32_t radix; int16_t exponent; UChar decimalPoint; - UnicodeString ruleText; + UnicodeString fRuleText; NFSubstitution* sub1; NFSubstitution* sub2; const RuleBasedNumberFormat* formatter; diff --git a/deps/icu-small/source/i18n/number_compact.cpp b/deps/icu-small/source/i18n/number_compact.cpp index 40278e1a012e54..10942c35f535df 100644 --- a/deps/icu-small/source/i18n/number_compact.cpp +++ b/deps/icu-small/source/i18n/number_compact.cpp @@ -273,13 +273,13 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr if (U_FAILURE(status)) { return; } // Treat zero as if it had magnitude 0 - int magnitude; + int32_t magnitude; if (quantity.isZero()) { magnitude = 0; micros.rounder.apply(quantity, status); } else { // TODO: Revisit chooseMultiplierAndApply - int multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status); + int32_t multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status); magnitude = quantity.isZero() ? 0 : quantity.getMagnitude(); magnitude -= multiplier; } diff --git a/deps/icu-small/source/i18n/number_decimalquantity.cpp b/deps/icu-small/source/i18n/number_decimalquantity.cpp index 9d80e3349cb8aa..2c4182b1c6ecda 100644 --- a/deps/icu-small/source/i18n/number_decimalquantity.cpp +++ b/deps/icu-small/source/i18n/number_decimalquantity.cpp @@ -1154,8 +1154,31 @@ const char16_t* DecimalQuantity::checkHealth() const { } bool DecimalQuantity::operator==(const DecimalQuantity& other) const { - // FIXME: Make a faster implementation. - return toString() == other.toString(); + bool basicEquals = + scale == other.scale + && precision == other.precision + && flags == other.flags + && lOptPos == other.lOptPos + && lReqPos == other.lReqPos + && rReqPos == other.rReqPos + && rOptPos == other.rOptPos + && isApproximate == other.isApproximate; + if (!basicEquals) { + return false; + } + + if (precision == 0) { + return true; + } else if (isApproximate) { + return origDouble == other.origDouble && origDelta == other.origDelta; + } else { + for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { + if (getDigit(m) != other.getDigit(m)) { + return false; + } + } + return true; + } } UnicodeString DecimalQuantity::toString() const { diff --git a/deps/icu-small/source/i18n/number_decimfmtprops.cpp b/deps/icu-small/source/i18n/number_decimfmtprops.cpp index 6754fe19eca56c..12fe7060e2d051 100644 --- a/deps/icu-small/source/i18n/number_decimfmtprops.cpp +++ b/deps/icu-small/source/i18n/number_decimfmtprops.cpp @@ -15,6 +15,7 @@ using namespace icu::number::impl; namespace { +alignas(DecimalFormatProperties) char kRawDefaultProperties[sizeof(DecimalFormatProperties)]; icu::UInitOnce gDefaultPropertiesInitOnce = U_INITONCE_INITIALIZER; diff --git a/deps/icu-small/source/i18n/number_fluent.cpp b/deps/icu-small/source/i18n/number_fluent.cpp index 687adb6b5babd2..a66e3bd0f23510 100644 --- a/deps/icu-small/source/i18n/number_fluent.cpp +++ b/deps/icu-small/source/i18n/number_fluent.cpp @@ -363,6 +363,7 @@ UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS& other) // No additional fields to assign } +// Make default copy constructor call the NumberFormatterSettings copy constructor. UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT : UNF(static_cast&&>(src)) {} @@ -383,6 +384,7 @@ UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_N return *this; } +// Make default copy constructor call the NumberFormatterSettings copy constructor. LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other) : LNF(static_cast&>(other)) {} @@ -405,7 +407,8 @@ LocalizedNumberFormatter::LocalizedNumberFormatter(NFS&& src) U_NOEXCEPT LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) { NFS::operator=(static_cast&>(other)); - // No additional fields to assign (let call count and compiled formatter reset to defaults) + // Reset to default values. + clear(); return *this; } @@ -417,20 +420,26 @@ LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXC // Formatter is compiled lnfMoveHelper(static_cast(src)); } else { - // Reset to default values. - auto* callCount = reinterpret_cast(fUnsafeCallCount); - umtx_storeRelease(*callCount, 0); - fCompiled = nullptr; + clear(); } return *this; } +void LocalizedNumberFormatter::clear() { + // Reset to default values. + auto* callCount = reinterpret_cast(fUnsafeCallCount); + umtx_storeRelease(*callCount, 0); + delete fCompiled; + fCompiled = nullptr; +} + void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) { // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled(). // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease. // The bits themselves appear to be platform-dependent, so copying them might not be safe. auto* callCount = reinterpret_cast(fUnsafeCallCount); umtx_storeRelease(*callCount, INT32_MIN); + delete fCompiled; fCompiled = src.fCompiled; // Reset the source object to leave it in a safe state. auto* srcCallCount = reinterpret_cast(src.fUnsafeCallCount); @@ -657,9 +666,9 @@ LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErro void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { if (computeCompiled(status)) { - fCompiled->apply(results->quantity, results->string, status); + fCompiled->format(results->quantity, results->string, status); } else { - NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status); + NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status); } } @@ -706,7 +715,11 @@ bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { if (currentCount == fMacros.threshold && fMacros.threshold > 0) { // Build the data structure and then use it (slow to fast path). - const NumberFormatterImpl* compiled = NumberFormatterImpl::fromMacros(fMacros, status); + const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status); + if (compiled == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return false; + } U_ASSERT(fCompiled == nullptr); const_cast(this)->fCompiled = compiled; umtx_storeRelease(*callCount, INT32_MIN); @@ -776,7 +789,7 @@ Appendable& FormattedNumber::appendTo(Appendable& appendable) { return appendTo(appendable, localStatus); } -Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) { +Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) const { if (U_FAILURE(status)) { return appendable; } diff --git a/deps/icu-small/source/i18n/number_formatimpl.cpp b/deps/icu-small/source/i18n/number_formatimpl.cpp index 3f887128bcc668..60c18ee284e238 100644 --- a/deps/icu-small/source/i18n/number_formatimpl.cpp +++ b/deps/icu-small/source/i18n/number_formatimpl.cpp @@ -67,14 +67,18 @@ getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& sta MicroPropsGenerator::~MicroPropsGenerator() = default; -NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, UErrorCode& status) { - return new NumberFormatterImpl(macros, true, status); +NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status) + : NumberFormatterImpl(macros, true, status) { } -void NumberFormatterImpl::applyStatic(const MacroProps& macros, DecimalQuantity& inValue, - NumberStringBuilder& outString, UErrorCode& status) { +int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue, + NumberStringBuilder& outString, UErrorCode& status) { NumberFormatterImpl impl(macros, false, status); - impl.applyUnsafe(inValue, outString, status); + MicroProps& micros = impl.preProcessUnsafe(inValue, status); + if (U_FAILURE(status)) { return 0; } + int32_t length = writeNumber(micros, inValue, outString, 0, status); + length += writeAffixes(micros, outString, 0, length, status); + return length; } int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum, @@ -89,22 +93,40 @@ int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int // The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation. // See MicroProps::processQuantity() for details. -void NumberFormatterImpl::apply(DecimalQuantity& inValue, NumberStringBuilder& outString, +int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const { - if (U_FAILURE(status)) { return; } MicroProps micros; - if (!fMicroPropsGenerator) { return; } - fMicroPropsGenerator->processQuantity(inValue, micros, status); - if (U_FAILURE(status)) { return; } - microsToString(micros, inValue, outString, status); + preProcess(inValue, micros, status); + if (U_FAILURE(status)) { return 0; } + int32_t length = writeNumber(micros, inValue, outString, 0, status); + length += writeAffixes(micros, outString, 0, length, status); + return length; } -void NumberFormatterImpl::applyUnsafe(DecimalQuantity& inValue, NumberStringBuilder& outString, - UErrorCode& status) { +void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut, + UErrorCode& status) const { if (U_FAILURE(status)) { return; } + if (fMicroPropsGenerator == nullptr) { + status = U_INTERNAL_PROGRAM_ERROR; + return; + } + fMicroPropsGenerator->processQuantity(inValue, microsOut, status); + microsOut.rounder.apply(inValue, status); + microsOut.integerWidth.apply(inValue, status); +} + +MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) { + if (U_FAILURE(status)) { + return fMicros; // must always return a value + } + if (fMicroPropsGenerator == nullptr) { + status = U_INTERNAL_PROGRAM_ERROR; + return fMicros; // must always return a value + } fMicroPropsGenerator->processQuantity(inValue, fMicros, status); - if (U_FAILURE(status)) { return; } - microsToString(fMicros, inValue, outString, status); + fMicros.rounder.apply(inValue, status); + fMicros.integerWidth.apply(inValue, status); + return fMicros; } int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural, @@ -115,7 +137,7 @@ int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form const Modifier* modifier = fImmutablePatternModifier->getModifier(signum, plural); modifier->apply(outString, 0, 0, status); if (U_FAILURE(status)) { return 0; } - return modifier->getPrefixLength(status); + return modifier->getPrefixLength(); } int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural, @@ -126,7 +148,7 @@ int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural fPatternModifier->setNumberProperties(signum, plural); fPatternModifier->apply(outString, 0, 0, status); if (U_FAILURE(status)) { return 0; } - return fPatternModifier->getPrefixLength(status); + return fPatternModifier->getPrefixLength(); } NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) { @@ -344,25 +366,23 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe, // Outer modifier (CLDR units and currency long names) if (isCldrUnit) { fLongNameHandler.adoptInstead( - new LongNameHandler( - LongNameHandler::forMeasureUnit( - macros.locale, - macros.unit, - macros.perUnit, - unitWidth, - resolvePluralRules(macros.rules, macros.locale, status), - chain, - status))); + LongNameHandler::forMeasureUnit( + macros.locale, + macros.unit, + macros.perUnit, + unitWidth, + resolvePluralRules(macros.rules, macros.locale, status), + chain, + status)); chain = fLongNameHandler.getAlias(); } else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) { fLongNameHandler.adoptInstead( - new LongNameHandler( - LongNameHandler::forCurrencyLongNames( - macros.locale, - currency, - resolvePluralRules(macros.rules, macros.locale, status), - chain, - status))); + LongNameHandler::forCurrencyLongNames( + macros.locale, + currency, + resolvePluralRules(macros.rules, macros.locale, status), + chain, + status)); chain = fLongNameHandler.getAlias(); } else { // No outer modifier required @@ -404,50 +424,46 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Local return fRules.getAlias(); } -int32_t NumberFormatterImpl::microsToString(const MicroProps& micros, DecimalQuantity& quantity, - NumberStringBuilder& string, UErrorCode& status) { - micros.rounder.apply(quantity, status); - micros.integerWidth.apply(quantity, status); - int32_t length = writeNumber(micros, quantity, string, status); - // NOTE: When range formatting is added, these modifiers can bubble up. - // For now, apply them all here at once. +int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberStringBuilder& string, + int32_t start, int32_t end, UErrorCode& status) { // Always apply the inner modifier (which is "strong"). - length += micros.modInner->apply(string, 0, length, status); + int32_t length = micros.modInner->apply(string, start, end, status); if (micros.padding.isValid()) { length += micros.padding - .padAndApply(*micros.modMiddle, *micros.modOuter, string, 0, length, status); + .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status); } else { - length += micros.modMiddle->apply(string, 0, length, status); - length += micros.modOuter->apply(string, 0, length, status); + length += micros.modMiddle->apply(string, start, length + end, status); + length += micros.modOuter->apply(string, start, length + end, status); } return length; } int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity, - NumberStringBuilder& string, UErrorCode& status) { + NumberStringBuilder& string, int32_t index, + UErrorCode& status) { int32_t length = 0; if (quantity.isInfinite()) { length += string.insert( - length, + length + index, micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol), UNUM_INTEGER_FIELD, status); } else if (quantity.isNaN()) { length += string.insert( - length, + length + index, micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol), UNUM_INTEGER_FIELD, status); } else { // Add the integer digits - length += writeIntegerDigits(micros, quantity, string, status); + length += writeIntegerDigits(micros, quantity, string, length + index, status); // Add the decimal point if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) { length += string.insert( - length, + length + index, micros.useCurrency ? micros.symbols->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros .symbols @@ -458,21 +474,22 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti } // Add the fraction digits - length += writeFractionDigits(micros, quantity, string, status); + length += writeFractionDigits(micros, quantity, string, length + index, status); } return length; } int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity, - NumberStringBuilder& string, UErrorCode& status) { + NumberStringBuilder& string, int32_t index, + UErrorCode& status) { int length = 0; int integerCount = quantity.getUpperDisplayMagnitude() + 1; for (int i = 0; i < integerCount; i++) { // Add grouping separator if (micros.grouping.groupAtPosition(i, quantity)) { length += string.insert( - 0, + index, micros.useCurrency ? micros.symbols->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol) : micros.symbols->getSymbol( @@ -484,20 +501,21 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima // Get and append the next digit value int8_t nextDigit = quantity.getDigit(i); length += utils::insertDigitFromSymbols( - string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status); + string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status); } return length; } int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity, - NumberStringBuilder& string, UErrorCode& status) { + NumberStringBuilder& string, int32_t index, + UErrorCode& status) { int length = 0; int fractionCount = -quantity.getLowerDisplayMagnitude(); for (int i = 0; i < fractionCount; i++) { // Get and append the next digit value int8_t nextDigit = quantity.getDigit(-i - 1); length += utils::insertDigitFromSymbols( - string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status); + string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status); } return length; } diff --git a/deps/icu-small/source/i18n/number_formatimpl.h b/deps/icu-small/source/i18n/number_formatimpl.h index 744fecec13f984..fda38c92845f87 100644 --- a/deps/icu-small/source/i18n/number_formatimpl.h +++ b/deps/icu-small/source/i18n/number_formatimpl.h @@ -29,14 +29,14 @@ class NumberFormatterImpl : public UMemory { * Builds a "safe" MicroPropsGenerator, which is thread-safe and can be used repeatedly. * The caller owns the returned NumberFormatterImpl. */ - static NumberFormatterImpl *fromMacros(const MacroProps ¯os, UErrorCode &status); + NumberFormatterImpl(const MacroProps ¯os, UErrorCode &status); /** * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once. */ - static void - applyStatic(const MacroProps ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString, - UErrorCode &status); + static int32_t + formatStatic(const MacroProps ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString, + UErrorCode &status); /** * Prints only the prefix and suffix; used for DecimalFormat getters. @@ -51,7 +51,12 @@ class NumberFormatterImpl : public UMemory { /** * Evaluates the "safe" MicroPropsGenerator created by "fromMacros". */ - void apply(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const; + int32_t format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const; + + /** + * Like format(), but saves the result into an output MicroProps without additional processing. + */ + void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const; /** * Like getPrefixSuffixStatic() but uses the safe compiled object. @@ -59,6 +64,19 @@ class NumberFormatterImpl : public UMemory { int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString, UErrorCode& status) const; + /** + * Synthesizes the output string from a MicroProps and DecimalQuantity. + * This method formats only the main number, not affixes. + */ + static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity, + NumberStringBuilder& string, int32_t index, UErrorCode& status); + + /** + * Adds the affixes. Intended to be called immediately after formatNumber. + */ + static int32_t writeAffixes(const MicroProps& micros, NumberStringBuilder& string, int32_t start, + int32_t end, UErrorCode& status); + private: // Head of the MicroPropsGenerator linked list: const MicroPropsGenerator *fMicroPropsGenerator = nullptr; @@ -85,7 +103,7 @@ class NumberFormatterImpl : public UMemory { NumberFormatterImpl(const MacroProps ¯os, bool safe, UErrorCode &status); - void applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status); + MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status); int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString, UErrorCode& status); @@ -113,31 +131,13 @@ class NumberFormatterImpl : public UMemory { const MicroPropsGenerator * macrosToMicroGenerator(const MacroProps ¯os, bool safe, UErrorCode &status); - /** - * Synthesizes the output string from a MicroProps and DecimalQuantity. - * - * @param micros - * The MicroProps after the quantity has been consumed. Will not be mutated. - * @param quantity - * The DecimalQuantity to be rendered. May be mutated. - * @param string - * The output string. Will be mutated. - */ - static int32_t - microsToString(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string, - UErrorCode &status); - - static int32_t - writeNumber(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string, - UErrorCode &status); - static int32_t writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string, - UErrorCode &status); + int32_t index, UErrorCode &status); static int32_t writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string, - UErrorCode &status); + int32_t index, UErrorCode &status); }; } // namespace impl diff --git a/deps/icu-small/source/i18n/number_grouping.cpp b/deps/icu-small/source/i18n/number_grouping.cpp index 4a1cceb49948b9..da32cca99a38df 100644 --- a/deps/icu-small/source/i18n/number_grouping.cpp +++ b/deps/icu-small/source/i18n/number_grouping.cpp @@ -80,7 +80,7 @@ void Grouper::setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Lo if (fMinGrouping == -2) { fMinGrouping = getMinGroupingForLocale(locale); } else if (fMinGrouping == -3) { - fMinGrouping = uprv_max(2, getMinGroupingForLocale(locale)); + fMinGrouping = static_cast(uprv_max(2, getMinGroupingForLocale(locale))); } else { // leave fMinGrouping alone } diff --git a/deps/icu-small/source/i18n/number_longnames.cpp b/deps/icu-small/source/i18n/number_longnames.cpp index 26f9af4c9bdbfe..fd8e8d381a1d76 100644 --- a/deps/icu-small/source/i18n/number_longnames.cpp +++ b/deps/icu-small/source/i18n/number_longnames.cpp @@ -39,7 +39,7 @@ static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) { static UnicodeString getWithPlural( const UnicodeString* strings, - int32_t plural, + StandardPlural::Form plural, UErrorCode& status) { UnicodeString result = strings[plural]; if (result.isBogus()) { @@ -156,7 +156,7 @@ UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &wid } // namespace -LongNameHandler +LongNameHandler* LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const MeasureUnit &perUnit, const UNumberUnitWidth &width, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status) { @@ -173,20 +173,28 @@ LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, c } } - LongNameHandler result(rules, parent); + auto* result = new LongNameHandler(rules, parent); + if (result == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } UnicodeString simpleFormats[ARRAY_LENGTH]; getMeasureData(loc, unit, width, simpleFormats, status); if (U_FAILURE(status)) { return result; } // TODO: What field to use for units? - simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, result.fModifiers, status); + result->simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, status); return result; } -LongNameHandler +LongNameHandler* LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit, const UNumberUnitWidth &width, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status) { - LongNameHandler result(rules, parent); + auto* result = new LongNameHandler(rules, parent); + if (result == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } UnicodeString primaryData[ARRAY_LENGTH]; getMeasureData(loc, unit, width, primaryData, status); if (U_FAILURE(status)) { return result; } @@ -213,46 +221,52 @@ LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con if (U_FAILURE(status)) { return result; } } // TODO: What field to use for units? - multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_FIELD_COUNT, result.fModifiers, status); + result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_FIELD_COUNT, status); return result; } -LongNameHandler LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, +LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status) { - LongNameHandler result(rules, parent); + auto* result = new LongNameHandler(rules, parent); + if (result == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } UnicodeString simpleFormats[ARRAY_LENGTH]; getCurrencyLongNameData(loc, currency, simpleFormats, status); - if (U_FAILURE(status)) { return result; } - simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, result.fModifiers, status); + if (U_FAILURE(status)) { return nullptr; } + result->simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, status); return result; } void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, - SimpleModifier *output, UErrorCode &status) { + UErrorCode &status) { for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { - UnicodeString simpleFormat = getWithPlural(simpleFormats, i, status); + StandardPlural::Form plural = static_cast(i); + UnicodeString simpleFormat = getWithPlural(simpleFormats, plural, status); if (U_FAILURE(status)) { return; } SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status); if (U_FAILURE(status)) { return; } - output[i] = SimpleModifier(compiledFormatter, field, false); + fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, 0, plural}); } } void LongNameHandler::multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat, - Field field, SimpleModifier *output, UErrorCode &status) { + Field field, UErrorCode &status) { SimpleFormatter trailCompiled(trailFormat, 1, 1, status); if (U_FAILURE(status)) { return; } for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { - UnicodeString leadFormat = getWithPlural(leadFormats, i, status); + StandardPlural::Form plural = static_cast(i); + UnicodeString leadFormat = getWithPlural(leadFormats, plural, status); if (U_FAILURE(status)) { return; } UnicodeString compoundFormat; trailCompiled.format(leadFormat, compoundFormat, status); if (U_FAILURE(status)) { return; } SimpleFormatter compoundCompiled(compoundFormat, 0, 1, status); if (U_FAILURE(status)) { return; } - output[i] = SimpleModifier(compoundCompiled, field, false); + fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, 0, plural}); } } @@ -265,4 +279,8 @@ void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic micros.modOuter = &fModifiers[utils::getStandardPlural(rules, copy)]; } +const Modifier* LongNameHandler::getModifier(int8_t /*signum*/, StandardPlural::Form plural) const { + return &fModifiers[plural]; +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_longnames.h b/deps/icu-small/source/i18n/number_longnames.h index 1d1e7dd3e864a6..a71d0caadf125c 100644 --- a/deps/icu-small/source/i18n/number_longnames.h +++ b/deps/icu-small/source/i18n/number_longnames.h @@ -14,13 +14,13 @@ U_NAMESPACE_BEGIN namespace number { namespace impl { -class LongNameHandler : public MicroPropsGenerator, public UMemory { +class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory { public: - static LongNameHandler + static LongNameHandler* forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status); - static LongNameHandler + static LongNameHandler* forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit, const UNumberUnitWidth &width, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status); @@ -28,6 +28,8 @@ class LongNameHandler : public MicroPropsGenerator, public UMemory { void processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const U_OVERRIDE; + const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE; + private: SimpleModifier fModifiers[StandardPlural::Form::COUNT]; const PluralRules *rules; @@ -36,15 +38,14 @@ class LongNameHandler : public MicroPropsGenerator, public UMemory { LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) : rules(rules), parent(parent) {} - static LongNameHandler + static LongNameHandler* forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit, const UNumberUnitWidth &width, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status); - static void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, - SimpleModifier *output, UErrorCode &status); - static void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat, - Field field, SimpleModifier *output, UErrorCode &status); + void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status); + void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat, + Field field, UErrorCode &status); }; } // namespace impl diff --git a/deps/icu-small/source/i18n/number_mapper.cpp b/deps/icu-small/source/i18n/number_mapper.cpp index d260632f93b0db..2c9a8e5178f35e 100644 --- a/deps/icu-small/source/i18n/number_mapper.cpp +++ b/deps/icu-small/source/i18n/number_mapper.cpp @@ -225,8 +225,8 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert // TODO: Overriding here is a bit of a hack. Should this logic go earlier? if (macros.precision.fType == Precision::PrecisionType::RND_FRACTION) { // For the purposes of rounding, get the original min/max int/frac, since the local - // variables - // have been manipulated for display purposes. + // variables have been manipulated for display purposes. + int maxInt_ = properties.maximumIntegerDigits; int minInt_ = properties.minimumIntegerDigits; int minFrac_ = properties.minimumFractionDigits; int maxFrac_ = properties.maximumFractionDigits; @@ -237,9 +237,15 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert // Patterns like "#.##E0" (no zeros in the mantissa), which mean round to maxFrac+1 macros.precision = Precision::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode); } else { - // All other scientific patterns, which mean round to minInt+maxFrac - macros.precision = Precision::constructSignificant( - minInt_ + minFrac_, minInt_ + maxFrac_).withMode(roundingMode); + int maxSig_ = minInt_ + maxFrac_; + // Bug #20058: if maxInt_ > minInt_ > 1, then minInt_ should be 1. + if (maxInt_ > minInt_ && minInt_ > 1) { + minInt_ = 1; + } + int minSig_ = minInt_ + minFrac_; + // To avoid regression, maxSig is not reset when minInt_ set to 1. + // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec. + macros.precision = Precision::constructSignificant(minSig_, maxSig_).withMode(roundingMode); } } } diff --git a/deps/icu-small/source/i18n/number_modifiers.cpp b/deps/icu-small/source/i18n/number_modifiers.cpp index 4385499b54f603..d92ec63b08da58 100644 --- a/deps/icu-small/source/i18n/number_modifiers.cpp +++ b/deps/icu-small/source/i18n/number_modifiers.cpp @@ -53,6 +53,21 @@ void U_CALLCONV initDefaultCurrencySpacing(UErrorCode &status) { Modifier::~Modifier() = default; +Modifier::Parameters::Parameters() + : obj(nullptr) {} + +Modifier::Parameters::Parameters( + const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural) + : obj(_obj), signum(_signum), plural(_plural) {} + +ModifierStore::~ModifierStore() = default; + +AdoptingModifierStore::~AdoptingModifierStore() { + for (const Modifier *mod : mods) { + delete mod; + } +} + int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const { @@ -62,13 +77,11 @@ int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, return length; } -int32_t ConstantAffixModifier::getPrefixLength(UErrorCode &status) const { - (void)status; +int32_t ConstantAffixModifier::getPrefixLength() const { return fPrefix.length(); } -int32_t ConstantAffixModifier::getCodePointCount(UErrorCode &status) const { - (void)status; +int32_t ConstantAffixModifier::getCodePointCount() const { return fPrefix.countChar32() + fSuffix.countChar32(); } @@ -76,8 +89,38 @@ bool ConstantAffixModifier::isStrong() const { return fStrong; } +bool ConstantAffixModifier::containsField(UNumberFormatFields field) const { + (void)field; + // This method is not currently used. + U_ASSERT(false); + return false; +} + +void ConstantAffixModifier::getParameters(Parameters& output) const { + (void)output; + // This method is not currently used. + U_ASSERT(false); +} + +bool ConstantAffixModifier::semanticallyEquivalent(const Modifier& other) const { + auto* _other = dynamic_cast(&other); + if (_other == nullptr) { + return false; + } + return fPrefix == _other->fPrefix + && fSuffix == _other->fSuffix + && fField == _other->fField + && fStrong == _other->fStrong; +} + + SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong) - : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong) { + : SimpleModifier(simpleFormatter, field, strong, {}) {} + +SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong, + const Modifier::Parameters parameters) + : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong), + fParameters(parameters) { int32_t argLimit = SimpleFormatter::getArgumentLimit( fCompiledPattern.getBuffer(), fCompiledPattern.length()); if (argLimit == 0) { @@ -90,15 +133,19 @@ SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field fie } else { U_ASSERT(argLimit == 1); if (fCompiledPattern.charAt(1) != 0) { + // Found prefix fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT; fSuffixOffset = 3 + fPrefixLength; } else { + // No prefix fPrefixLength = 0; fSuffixOffset = 2; } if (3 + fPrefixLength < fCompiledPattern.length()) { + // Found suffix fSuffixLength = fCompiledPattern.charAt(fSuffixOffset) - ARG_NUM_LIMIT; } else { + // No suffix fSuffixLength = 0; } } @@ -113,13 +160,11 @@ int32_t SimpleModifier::apply(NumberStringBuilder &output, int leftIndex, int ri return formatAsPrefixSuffix(output, leftIndex, rightIndex, fField, status); } -int32_t SimpleModifier::getPrefixLength(UErrorCode &status) const { - (void)status; +int32_t SimpleModifier::getPrefixLength() const { return fPrefixLength; } -int32_t SimpleModifier::getCodePointCount(UErrorCode &status) const { - (void)status; +int32_t SimpleModifier::getCodePointCount() const { int32_t count = 0; if (fPrefixLength > 0) { count += fCompiledPattern.countChar32(2, fPrefixLength); @@ -134,10 +179,35 @@ bool SimpleModifier::isStrong() const { return fStrong; } +bool SimpleModifier::containsField(UNumberFormatFields field) const { + (void)field; + // This method is not currently used. + U_ASSERT(false); + return false; +} + +void SimpleModifier::getParameters(Parameters& output) const { + output = fParameters; +} + +bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const { + auto* _other = dynamic_cast(&other); + if (_other == nullptr) { + return false; + } + if (fParameters.obj != nullptr) { + return fParameters.obj == _other->fParameters.obj; + } + return fCompiledPattern == _other->fCompiledPattern + && fField == _other->fField + && fStrong == _other->fStrong; +} + + int32_t SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex, Field field, UErrorCode &status) const { - if (fSuffixOffset == -1) { + if (fSuffixOffset == -1 && fPrefixLength + fSuffixLength > 0) { // There is no argument for the inner number; overwrite the entire segment with our string. return result.splice(startIndex, endIndex, fCompiledPattern, 2, 2 + fPrefixLength, field, status); } else { @@ -157,6 +227,65 @@ SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startI } } + +int32_t +SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result, + int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength, + Field field, UErrorCode& status) { + const UnicodeString& compiledPattern = compiled.compiledPattern; + int32_t argLimit = SimpleFormatter::getArgumentLimit( + compiledPattern.getBuffer(), compiledPattern.length()); + if (argLimit != 2) { + status = U_INTERNAL_PROGRAM_ERROR; + return 0; + } + int32_t offset = 1; // offset into compiledPattern + int32_t length = 0; // chars added to result + + int32_t prefixLength = compiledPattern.charAt(offset); + offset++; + if (prefixLength < ARG_NUM_LIMIT) { + // No prefix + prefixLength = 0; + } else { + prefixLength -= ARG_NUM_LIMIT; + result.insert(index + length, compiledPattern, offset, offset + prefixLength, field, status); + offset += prefixLength; + length += prefixLength; + offset++; + } + + int32_t infixLength = compiledPattern.charAt(offset); + offset++; + if (infixLength < ARG_NUM_LIMIT) { + // No infix + infixLength = 0; + } else { + infixLength -= ARG_NUM_LIMIT; + result.insert(index + length, compiledPattern, offset, offset + infixLength, field, status); + offset += infixLength; + length += infixLength; + offset++; + } + + int32_t suffixLength; + if (offset == compiledPattern.length()) { + // No suffix + suffixLength = 0; + } else { + suffixLength = compiledPattern.charAt(offset) - ARG_NUM_LIMIT; + offset++; + result.insert(index + length, compiledPattern, offset, offset + suffixLength, field, status); + length += suffixLength; + } + + *outPrefixLength = prefixLength; + *outSuffixLength = suffixLength; + + return length; +} + + int32_t ConstantMultiFieldModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const { int32_t length = output.insert(leftIndex, fPrefix, status); @@ -171,13 +300,11 @@ int32_t ConstantMultiFieldModifier::apply(NumberStringBuilder &output, int leftI return length; } -int32_t ConstantMultiFieldModifier::getPrefixLength(UErrorCode &status) const { - (void)status; +int32_t ConstantMultiFieldModifier::getPrefixLength() const { return fPrefix.length(); } -int32_t ConstantMultiFieldModifier::getCodePointCount(UErrorCode &status) const { - (void)status; +int32_t ConstantMultiFieldModifier::getCodePointCount() const { return fPrefix.codePointCount() + fSuffix.codePointCount(); } @@ -185,6 +312,29 @@ bool ConstantMultiFieldModifier::isStrong() const { return fStrong; } +bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const { + return fPrefix.containsField(field) || fSuffix.containsField(field); +} + +void ConstantMultiFieldModifier::getParameters(Parameters& output) const { + output = fParameters; +} + +bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) const { + auto* _other = dynamic_cast(&other); + if (_other == nullptr) { + return false; + } + if (fParameters.obj != nullptr) { + return fParameters.obj == _other->fParameters.obj; + } + return fPrefix.contentEquals(_other->fPrefix) + && fSuffix.contentEquals(_other->fSuffix) + && fOverwrite == _other->fOverwrite + && fStrong == _other->fStrong; +} + + CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const NumberStringBuilder &prefix, const NumberStringBuilder &suffix, bool overwrite, diff --git a/deps/icu-small/source/i18n/number_modifiers.h b/deps/icu-small/source/i18n/number_modifiers.h index a553100cd92a9b..65ada937d03345 100644 --- a/deps/icu-small/source/i18n/number_modifiers.h +++ b/deps/icu-small/source/i18n/number_modifiers.h @@ -31,12 +31,18 @@ class U_I18N_API ConstantAffixModifier : public Modifier, public UObject { int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const U_OVERRIDE; - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; + int32_t getPrefixLength() const U_OVERRIDE; - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; + int32_t getCodePointCount() const U_OVERRIDE; bool isStrong() const U_OVERRIDE; + bool containsField(UNumberFormatFields field) const U_OVERRIDE; + + void getParameters(Parameters& output) const U_OVERRIDE; + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; + private: UnicodeString fPrefix; UnicodeString fSuffix; @@ -52,21 +58,30 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory { public: SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong); + SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong, + const Modifier::Parameters parameters); + // Default constructor for LongNameHandler.h SimpleModifier(); int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const U_OVERRIDE; - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; + int32_t getPrefixLength() const U_OVERRIDE; - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; + int32_t getCodePointCount() const U_OVERRIDE; bool isStrong() const U_OVERRIDE; + bool containsField(UNumberFormatFields field) const U_OVERRIDE; + + void getParameters(Parameters& output) const U_OVERRIDE; + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; + /** * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because - * DoubleSidedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it. + * NumberStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it. * *

    * Formats a value that is already stored inside the StringBuilder result between the indices @@ -85,16 +100,33 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory { * @return The number of characters (UTF-16 code points) that were added to the StringBuilder. */ int32_t - formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex, Field field, - UErrorCode &status) const; + formatAsPrefixSuffix(NumberStringBuilder& result, int32_t startIndex, int32_t endIndex, Field field, + UErrorCode& status) const; + + /** + * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code. + * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other. + * + *

    + * Applies the compiled two-argument pattern to the NumberStringBuilder. + * + *

    + * This method is optimized for the case where the prefix and suffix are often empty, such as + * in the range pattern like "{0}-{1}". + */ + static int32_t + formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result, + int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength, + Field field, UErrorCode& status); private: UnicodeString fCompiledPattern; Field fField; - bool fStrong; - int32_t fPrefixLength; - int32_t fSuffixOffset; - int32_t fSuffixLength; + bool fStrong = false; + int32_t fPrefixLength = 0; + int32_t fSuffixOffset = -1; + int32_t fSuffixLength = 0; + Modifier::Parameters fParameters; }; /** @@ -103,6 +135,18 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory { */ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { public: + ConstantMultiFieldModifier( + const NumberStringBuilder &prefix, + const NumberStringBuilder &suffix, + bool overwrite, + bool strong, + const Modifier::Parameters parameters) + : fPrefix(prefix), + fSuffix(suffix), + fOverwrite(overwrite), + fStrong(strong), + fParameters(parameters) {} + ConstantMultiFieldModifier( const NumberStringBuilder &prefix, const NumberStringBuilder &suffix, @@ -116,12 +160,18 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const U_OVERRIDE; - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; + int32_t getPrefixLength() const U_OVERRIDE; - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; + int32_t getCodePointCount() const U_OVERRIDE; bool isStrong() const U_OVERRIDE; + bool containsField(UNumberFormatFields field) const U_OVERRIDE; + + void getParameters(Parameters& output) const U_OVERRIDE; + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; + protected: // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by // value and is treated internally as immutable. @@ -129,6 +179,7 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { NumberStringBuilder fSuffix; bool fOverwrite; bool fStrong; + Modifier::Parameters fParameters; }; /** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */ @@ -192,13 +243,11 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory { return 0; } - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE { - (void)status; + int32_t getPrefixLength() const U_OVERRIDE { return 0; } - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE { - (void)status; + int32_t getCodePointCount() const U_OVERRIDE { return 0; } @@ -206,55 +255,75 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory { return fStrong; } + bool containsField(UNumberFormatFields field) const U_OVERRIDE { + (void)field; + return false; + } + + void getParameters(Parameters& output) const U_OVERRIDE { + output.obj = nullptr; + } + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE { + return other.getCodePointCount() == 0; + } + private: bool fStrong; }; /** - * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more - * Modifiers and returns the modifier appropriate for the current situation. + * This implementation of ModifierStore adopts Modifer pointers. */ -class U_I18N_API ParameterizedModifier : public UMemory { +class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory { public: - // NOTE: mods is zero-initialized (to nullptr) - ParameterizedModifier() : mods() { - } + virtual ~AdoptingModifierStore(); - // No copying! - ParameterizedModifier(const ParameterizedModifier &other) = delete; + static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER; - ~ParameterizedModifier() { - for (const Modifier *mod : mods) { - delete mod; - } - } + AdoptingModifierStore() = default; - void adoptPositiveNegativeModifiers( - const Modifier *positive, const Modifier *zero, const Modifier *negative) { - mods[2] = positive; - mods[1] = zero; - mods[0] = negative; - } + // No copying! + AdoptingModifierStore(const AdoptingModifierStore &other) = delete; - /** The modifier is ADOPTED. */ - void adoptSignPluralModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) { + /** + * Sets the Modifier with the specified signum and plural form. + */ + void adoptModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) { + U_ASSERT(mods[getModIndex(signum, plural)] == nullptr); mods[getModIndex(signum, plural)] = mod; } + /** + * Sets the Modifier with the specified signum. + * The modifier will apply to all plural forms. + */ + void adoptModifierWithoutPlural(int8_t signum, const Modifier *mod) { + U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr); + mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod; + } + /** Returns a reference to the modifier; no ownership change. */ - const Modifier *getModifier(int8_t signum) const { - return mods[signum + 1]; + const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE { + const Modifier* modifier = mods[getModIndex(signum, plural)]; + if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) { + modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; + } + return modifier; } /** Returns a reference to the modifier; no ownership change. */ - const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const { - return mods[getModIndex(signum, plural)]; + const Modifier *getModifierWithoutPlural(int8_t signum) const { + return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; } private: - const Modifier *mods[3 * StandardPlural::COUNT]; + // NOTE: mods is zero-initialized (to nullptr) + const Modifier *mods[3 * StandardPlural::COUNT] = {}; inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) { + U_ASSERT(signum >= -1 && signum <= 1); + U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT); return static_cast(plural) * 3 + (signum + 1); } }; diff --git a/deps/icu-small/source/i18n/number_multiplier.cpp b/deps/icu-small/source/i18n/number_multiplier.cpp index a27142c9bd689b..ecb50dd9b82019 100644 --- a/deps/icu-small/source/i18n/number_multiplier.cpp +++ b/deps/icu-small/source/i18n/number_multiplier.cpp @@ -143,14 +143,14 @@ void Scale::applyReciprocalTo(impl::DecimalQuantity& quantity) const { void MultiplierFormatHandler::setAndChain(const Scale& multiplier, const MicroPropsGenerator* parent) { - this->multiplier = multiplier; - this->parent = parent; + fMultiplier = multiplier; + fParent = parent; } void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroProps& micros, UErrorCode& status) const { - parent->processQuantity(quantity, micros, status); - multiplier.applyTo(quantity); + fParent->processQuantity(quantity, micros, status); + fMultiplier.applyTo(quantity); } #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_multiplier.h b/deps/icu-small/source/i18n/number_multiplier.h index 82c30c78426cdb..d8235dc601b559 100644 --- a/deps/icu-small/source/i18n/number_multiplier.h +++ b/deps/icu-small/source/i18n/number_multiplier.h @@ -28,8 +28,8 @@ class U_I18N_API MultiplierFormatHandler : public MicroPropsGenerator, public UM UErrorCode& status) const U_OVERRIDE; private: - Scale multiplier; - const MicroPropsGenerator *parent; + Scale fMultiplier; + const MicroPropsGenerator *fParent; }; diff --git a/deps/icu-small/source/i18n/number_padding.cpp b/deps/icu-small/source/i18n/number_padding.cpp index 97e7b6014f9aac..31684d7208b606 100644 --- a/deps/icu-small/source/i18n/number_padding.cpp +++ b/deps/icu-small/source/i18n/number_padding.cpp @@ -62,7 +62,7 @@ Padder Padder::forProperties(const DecimalFormatProperties& properties) { int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2, NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const { - int32_t modLength = mod1.getCodePointCount(status) + mod2.getCodePointCount(status); + int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount(); int32_t requiredPadding = fWidth - modLength - string.codePointCount(); U_ASSERT(leftIndex == 0 && rightIndex == string.length()); // fix the previous line to remove this assertion diff --git a/deps/icu-small/source/i18n/number_patternmodifier.cpp b/deps/icu-small/source/i18n/number_patternmodifier.cpp index 6417e14378bea6..4c61a0d35bca82 100644 --- a/deps/icu-small/source/i18n/number_patternmodifier.cpp +++ b/deps/icu-small/source/i18n/number_patternmodifier.cpp @@ -24,11 +24,11 @@ MutablePatternModifier::MutablePatternModifier(bool isStrong) : fStrong(isStrong) {} void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo) { - this->patternInfo = patternInfo; + fPatternInfo = patternInfo; } void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) { - this->signDisplay = signDisplay; + fSignDisplay = signDisplay; this->perMilleReplacesPercent = perMille; } @@ -36,20 +36,20 @@ void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols, const CurrencySymbols* currencySymbols, const UNumberUnitWidth unitWidth, const PluralRules* rules) { U_ASSERT((rules != nullptr) == needsPlurals()); - this->symbols = symbols; - this->currencySymbols = currencySymbols; - this->unitWidth = unitWidth; - this->rules = rules; + fSymbols = symbols; + fCurrencySymbols = currencySymbols; + fUnitWidth = unitWidth; + fRules = rules; } void MutablePatternModifier::setNumberProperties(int8_t signum, StandardPlural::Form plural) { - this->signum = signum; - this->plural = plural; + fSignum = signum; + fPlural = plural; } bool MutablePatternModifier::needsPlurals() const { UErrorCode statusLocal = U_ZERO_ERROR; - return patternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal); + return fPatternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal); // Silently ignore any error codes. } @@ -69,7 +69,7 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren StandardPlural::Form::MANY, StandardPlural::Form::OTHER}; - auto pm = new ParameterizedModifier(); + auto pm = new AdoptingModifierStore(); if (pm == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return nullptr; @@ -79,26 +79,25 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren // Slower path when we require the plural keyword. for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) { setNumberProperties(1, plural); - pm->adoptSignPluralModifier(1, plural, createConstantModifier(status)); + pm->adoptModifier(1, plural, createConstantModifier(status)); setNumberProperties(0, plural); - pm->adoptSignPluralModifier(0, plural, createConstantModifier(status)); + pm->adoptModifier(0, plural, createConstantModifier(status)); setNumberProperties(-1, plural); - pm->adoptSignPluralModifier(-1, plural, createConstantModifier(status)); + pm->adoptModifier(-1, plural, createConstantModifier(status)); } if (U_FAILURE(status)) { delete pm; return nullptr; } - return new ImmutablePatternModifier(pm, rules, parent); // adopts pm + return new ImmutablePatternModifier(pm, fRules, parent); // adopts pm } else { // Faster path when plural keyword is not needed. setNumberProperties(1, StandardPlural::Form::COUNT); - Modifier* positive = createConstantModifier(status); + pm->adoptModifierWithoutPlural(1, createConstantModifier(status)); setNumberProperties(0, StandardPlural::Form::COUNT); - Modifier* zero = createConstantModifier(status); + pm->adoptModifierWithoutPlural(0, createConstantModifier(status)); setNumberProperties(-1, StandardPlural::Form::COUNT); - Modifier* negative = createConstantModifier(status); - pm->adoptPositiveNegativeModifiers(positive, zero, negative); + pm->adoptModifierWithoutPlural(-1, createConstantModifier(status)); if (U_FAILURE(status)) { delete pm; return nullptr; @@ -112,15 +111,15 @@ ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErro NumberStringBuilder b; insertPrefix(a, 0, status); insertSuffix(b, 0, status); - if (patternInfo->hasCurrencySign()) { + if (fPatternInfo->hasCurrencySign()) { return new CurrencySpacingEnabledModifier( - a, b, !patternInfo->hasBody(), fStrong, *symbols, status); + a, b, !fPatternInfo->hasBody(), fStrong, *fSymbols, status); } else { - return new ConstantMultiFieldModifier(a, b, !patternInfo->hasBody(), fStrong); + return new ConstantMultiFieldModifier(a, b, !fPatternInfo->hasBody(), fStrong); } } -ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules, +ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules, const MicroPropsGenerator* parent) : pm(pm), rules(rules), parent(parent) {} @@ -132,7 +131,7 @@ void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroP void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const { if (rules == nullptr) { - micros.modMiddle = pm->getModifier(quantity.signum()); + micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum()); } else { // TODO: Fix this. Avoid the copy. DecimalQuantity copy(quantity); @@ -144,7 +143,7 @@ void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const { if (rules == nullptr) { - return pm->getModifier(signum); + return pm->getModifierWithoutPlural(signum); } else { return pm->getModifier(signum, plural); } @@ -153,13 +152,13 @@ const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlu /** Used by the unsafe code path. */ MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) { - this->parent = parent; + fParent = parent; return *this; } void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros, UErrorCode& status) const { - parent->processQuantity(fq, micros, status); + fParent->processQuantity(fq, micros, status); // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. auto nonConstThis = const_cast(this); @@ -167,7 +166,7 @@ void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& mi // TODO: Fix this. Avoid the copy. DecimalQuantity copy(fq); micros.rounder.apply(copy, status); - nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy)); + nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(fRules, copy)); } else { nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT); } @@ -183,7 +182,7 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI int32_t suffixLen = nonConstThis->insertSuffix(output, rightIndex + prefixLen, status); // If the pattern had no decimal stem body (like #,##0.00), overwrite the value. int32_t overwriteLen = 0; - if (!patternInfo->hasBody()) { + if (!fPatternInfo->hasBody()) { overwriteLen = output.splice( leftIndex + prefixLen, rightIndex + prefixLen, @@ -199,28 +198,30 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI prefixLen, rightIndex + overwriteLen + prefixLen, suffixLen, - *symbols, + *fSymbols, status); return prefixLen + overwriteLen + suffixLen; } -int32_t MutablePatternModifier::getPrefixLength(UErrorCode& status) const { +int32_t MutablePatternModifier::getPrefixLength() const { // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. auto nonConstThis = const_cast(this); // Enter and exit CharSequence Mode to get the length. + UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception nonConstThis->prepareAffix(true); int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length return result; } -int32_t MutablePatternModifier::getCodePointCount(UErrorCode& status) const { +int32_t MutablePatternModifier::getCodePointCount() const { // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. auto nonConstThis = const_cast(this); // Render the affixes to get the length + UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception nonConstThis->prepareAffix(true); int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length nonConstThis->prepareAffix(false); @@ -232,6 +233,26 @@ bool MutablePatternModifier::isStrong() const { return fStrong; } +bool MutablePatternModifier::containsField(UNumberFormatFields field) const { + (void)field; + // This method is not currently used. + U_ASSERT(false); + return false; +} + +void MutablePatternModifier::getParameters(Parameters& output) const { + (void)output; + // This method is not currently used. + U_ASSERT(false); +} + +bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const { + (void)other; + // This method is not currently used. + U_ASSERT(false); + return false; +} + int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) { prepareAffix(true); int length = AffixUtils::unescape(currentAffix, sb, position, *this, status); @@ -247,40 +268,40 @@ int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int positi /** This method contains the heart of the logic for rendering LDML affix strings. */ void MutablePatternModifier::prepareAffix(bool isPrefix) { PatternStringUtils::patternInfoToStringBuilder( - *patternInfo, isPrefix, signum, signDisplay, plural, perMilleReplacesPercent, currentAffix); + *fPatternInfo, isPrefix, fSignum, fSignDisplay, fPlural, perMilleReplacesPercent, currentAffix); } UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const { UErrorCode localStatus = U_ZERO_ERROR; switch (type) { case AffixPatternType::TYPE_MINUS_SIGN: - return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol); + return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol); case AffixPatternType::TYPE_PLUS_SIGN: - return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol); + return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol); case AffixPatternType::TYPE_PERCENT: - return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol); + return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol); case AffixPatternType::TYPE_PERMILLE: - return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol); + return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol); case AffixPatternType::TYPE_CURRENCY_SINGLE: { // UnitWidth ISO and HIDDEN overrides the singular currency symbol. - if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) { - return currencySymbols->getIntlCurrencySymbol(localStatus); - } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) { + if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) { + return fCurrencySymbols->getIntlCurrencySymbol(localStatus); + } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) { return UnicodeString(); - } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) { - return currencySymbols->getNarrowCurrencySymbol(localStatus); + } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) { + return fCurrencySymbols->getNarrowCurrencySymbol(localStatus); } else { - return currencySymbols->getCurrencySymbol(localStatus); + return fCurrencySymbols->getCurrencySymbol(localStatus); } } case AffixPatternType::TYPE_CURRENCY_DOUBLE: - return currencySymbols->getIntlCurrencySymbol(localStatus); + return fCurrencySymbols->getIntlCurrencySymbol(localStatus); case AffixPatternType::TYPE_CURRENCY_TRIPLE: // NOTE: This is the code path only for patterns containing "¤¤¤". // Plural currencies set via the API are formatted in LongNameHandler. // This code path is used by DecimalFormat via CurrencyPluralInfo. - U_ASSERT(plural != StandardPlural::Form::COUNT); - return currencySymbols->getPluralName(plural, localStatus); + U_ASSERT(fPlural != StandardPlural::Form::COUNT); + return fCurrencySymbols->getPluralName(fPlural, localStatus); case AffixPatternType::TYPE_CURRENCY_QUAD: return UnicodeString(u"\uFFFD"); case AffixPatternType::TYPE_CURRENCY_QUINT: diff --git a/deps/icu-small/source/i18n/number_patternmodifier.h b/deps/icu-small/source/i18n/number_patternmodifier.h index f1359bd5747d89..ea80d6305e75b4 100644 --- a/deps/icu-small/source/i18n/number_patternmodifier.h +++ b/deps/icu-small/source/i18n/number_patternmodifier.h @@ -18,13 +18,13 @@ U_NAMESPACE_BEGIN // Export an explicit template instantiation of the LocalPointer that is used as a -// data member of ParameterizedModifier. +// data member of AdoptingModifierStore. // (When building DLLs for Windows this is required.) #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN // Ignore warning 4661 as LocalPointerBase does not use operator== or operator!= #pragma warning(suppress: 4661) -template class U_I18N_API LocalPointerBase; -template class U_I18N_API LocalPointer; +template class U_I18N_API LocalPointerBase; +template class U_I18N_API LocalPointer; #endif namespace number { @@ -45,10 +45,10 @@ class U_I18N_API ImmutablePatternModifier : public MicroPropsGenerator, public U const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const; private: - ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules, + ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules, const MicroPropsGenerator* parent); - const LocalPointer pm; + const LocalPointer pm; const PluralRules* rules; const MicroPropsGenerator* parent; @@ -178,12 +178,18 @@ class U_I18N_API MutablePatternModifier int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const U_OVERRIDE; - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; + int32_t getPrefixLength() const U_OVERRIDE; - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; + int32_t getCodePointCount() const U_OVERRIDE; bool isStrong() const U_OVERRIDE; + bool containsField(UNumberFormatFields field) const U_OVERRIDE; + + void getParameters(Parameters& output) const U_OVERRIDE; + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; + /** * Returns the string that substitutes a given symbol type in a pattern. */ @@ -196,22 +202,22 @@ class U_I18N_API MutablePatternModifier const bool fStrong; // Pattern details (initialized in setPatternInfo and setPatternAttributes) - const AffixPatternProvider *patternInfo; - UNumberSignDisplay signDisplay; + const AffixPatternProvider *fPatternInfo; + UNumberSignDisplay fSignDisplay; bool perMilleReplacesPercent; // Symbol details (initialized in setSymbols) - const DecimalFormatSymbols *symbols; - UNumberUnitWidth unitWidth; - const CurrencySymbols *currencySymbols; - const PluralRules *rules; + const DecimalFormatSymbols *fSymbols; + UNumberUnitWidth fUnitWidth; + const CurrencySymbols *fCurrencySymbols; + const PluralRules *fRules; // Number details (initialized in setNumberProperties) - int8_t signum; - StandardPlural::Form plural; + int8_t fSignum; + StandardPlural::Form fPlural; // QuantityChain details (initialized in addToChain) - const MicroPropsGenerator *parent; + const MicroPropsGenerator *fParent; // Transient fields for rendering UnicodeString currentAffix; diff --git a/deps/icu-small/source/i18n/number_scientific.cpp b/deps/icu-small/source/i18n/number_scientific.cpp index 40952024e995cc..07c1ce9dac2c89 100644 --- a/deps/icu-small/source/i18n/number_scientific.cpp +++ b/deps/icu-small/source/i18n/number_scientific.cpp @@ -76,17 +76,16 @@ int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftInd return i - rightIndex; } -int32_t ScientificModifier::getPrefixLength(UErrorCode &status) const { - (void)status; +int32_t ScientificModifier::getPrefixLength() const { // TODO: Localized exponent separator location. return 0; } -int32_t ScientificModifier::getCodePointCount(UErrorCode &status) const { - (void)status; - // This method is not used for strong modifiers. - U_ASSERT(false); - return 0; +int32_t ScientificModifier::getCodePointCount() const { + // NOTE: This method is only called one place, NumberRangeFormatterImpl. + // The call site only cares about != 0 and != 1. + // Return a very large value so that if this method is used elsewhere, we should notice. + return 999; } bool ScientificModifier::isStrong() const { @@ -94,6 +93,27 @@ bool ScientificModifier::isStrong() const { return true; } +bool ScientificModifier::containsField(UNumberFormatFields field) const { + (void)field; + // This method is not used for inner modifiers. + U_ASSERT(false); + return false; +} + +void ScientificModifier::getParameters(Parameters& output) const { + // Not part of any plural sets + output.obj = nullptr; +} + +bool ScientificModifier::semanticallyEquivalent(const Modifier& other) const { + auto* _other = dynamic_cast(&other); + if (_other == nullptr) { + return false; + } + // TODO: Check for locale symbols and settings as well? Could be less efficient. + return fExponent == _other->fExponent; +} + // Note: Visual Studio does not compile this function without full name space. Why? icu::number::impl::ScientificHandler::ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols, const MicroPropsGenerator *parent) : diff --git a/deps/icu-small/source/i18n/number_scientific.h b/deps/icu-small/source/i18n/number_scientific.h index 974ab3adb614ca..e377bd941efaeb 100644 --- a/deps/icu-small/source/i18n/number_scientific.h +++ b/deps/icu-small/source/i18n/number_scientific.h @@ -24,12 +24,18 @@ class U_I18N_API ScientificModifier : public UMemory, public Modifier { int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const U_OVERRIDE; - int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; + int32_t getPrefixLength() const U_OVERRIDE; - int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; + int32_t getCodePointCount() const U_OVERRIDE; bool isStrong() const U_OVERRIDE; + bool containsField(UNumberFormatFields field) const U_OVERRIDE; + + void getParameters(Parameters& output) const U_OVERRIDE; + + bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; + private: int32_t fExponent; const ScientificHandler *fHandler; diff --git a/deps/icu-small/source/i18n/number_stringbuilder.cpp b/deps/icu-small/source/i18n/number_stringbuilder.cpp index 37770d11d51dfb..74ba33fbbc159f 100644 --- a/deps/icu-small/source/i18n/number_stringbuilder.cpp +++ b/deps/icu-small/source/i18n/number_stringbuilder.cpp @@ -241,6 +241,9 @@ NumberStringBuilder::insert(int32_t index, const NumberStringBuilder &other, UEr } int32_t NumberStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) { + U_ASSERT(index >= 0); + U_ASSERT(index <= fLength); + U_ASSERT(count >= 0); if (index == 0 && fZero - count >= 0) { // Append to start fZero -= count; @@ -485,4 +488,13 @@ void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpi } } +bool NumberStringBuilder::containsField(Field field) const { + for (int32_t i = 0; i < fLength; i++) { + if (field == fieldAt(i)) { + return true; + } + } + return false; +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_stringbuilder.h b/deps/icu-small/source/i18n/number_stringbuilder.h index cd8ce2f805e994..b14ad9ede2f90f 100644 --- a/deps/icu-small/source/i18n/number_stringbuilder.h +++ b/deps/icu-small/source/i18n/number_stringbuilder.h @@ -106,6 +106,8 @@ class U_I18N_API NumberStringBuilder : public UMemory { void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; + bool containsField(Field field) const; + private: bool fUsingHeap = false; ValueOrHeapArray fChars; diff --git a/deps/icu-small/source/i18n/number_types.h b/deps/icu-small/source/i18n/number_types.h index 57da72f8aa0ac1..00a6818869fdc2 100644 --- a/deps/icu-small/source/i18n/number_types.h +++ b/deps/icu-small/source/i18n/number_types.h @@ -16,6 +16,7 @@ #include "uassert.h" #include "unicode/platform.h" #include "unicode/uniset.h" +#include "standardplural.h" U_NAMESPACE_BEGIN namespace number { namespace impl { @@ -45,6 +46,7 @@ class Modifier; class MutablePatternModifier; class DecimalQuantity; class NumberStringBuilder; +class ModifierStore; struct MicroProps; @@ -127,12 +129,13 @@ class U_I18N_API AffixPatternProvider { virtual bool hasBody() const = 0; }; + /** * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else, * like a {@link com.ibm.icu.text.SimpleFormatter} pattern. * - * A Modifier is usually immutable, except in cases such as {@link MurkyModifier}, which are mutable for performance + * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance * reasons. * * Exported as U_I18N_API because it is a base class for other exported types @@ -162,12 +165,12 @@ class U_I18N_API Modifier { * * @return The number of characters (UTF-16 code units) in the prefix. */ - virtual int32_t getPrefixLength(UErrorCode& status) const = 0; + virtual int32_t getPrefixLength() const = 0; /** * Returns the number of code points in the modifier, prefix plus suffix. */ - virtual int32_t getCodePointCount(UErrorCode& status) const = 0; + virtual int32_t getCodePointCount() const = 0; /** * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed @@ -177,8 +180,57 @@ class U_I18N_API Modifier { * @return Whether the modifier is strong. */ virtual bool isStrong() const = 0; + + /** + * Whether the modifier contains at least one occurrence of the given field. + */ + virtual bool containsField(UNumberFormatFields field) const = 0; + + /** + * A fill-in for getParameters(). obj will always be set; if non-null, the other + * two fields are also safe to read. + */ + struct U_I18N_API Parameters { + const ModifierStore* obj = nullptr; + int8_t signum; + StandardPlural::Form plural; + + Parameters(); + Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural); + }; + + /** + * Gets a set of "parameters" for this Modifier. + * + * TODO: Make this return a `const Parameters*` more like Java? + */ + virtual void getParameters(Parameters& output) const = 0; + + /** + * Returns whether this Modifier is *semantically equivalent* to the other Modifier; + * in many cases, this is the same as equal, but parameters should be ignored. + */ + virtual bool semanticallyEquivalent(const Modifier& other) const = 0; }; + +/** + * This is *not* a modifier; rather, it is an object that can return modifiers + * based on given parameters. + * + * Exported as U_I18N_API because it is a base class for other exported types. + */ +class U_I18N_API ModifierStore { + public: + virtual ~ModifierStore(); + + /** + * Returns a Modifier with the given parameters (best-effort). + */ + virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0; +}; + + /** * This interface is used when all number formatting settings, including the locale, are known, except for the quantity * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the diff --git a/deps/icu-small/source/i18n/numfmt.cpp b/deps/icu-small/source/i18n/numfmt.cpp index 13f23131b1851b..ef47e1e01b5ee6 100644 --- a/deps/icu-small/source/i18n/numfmt.cpp +++ b/deps/icu-small/source/i18n/numfmt.cpp @@ -1326,13 +1326,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale, // if the locale has "@compat=host", create a host-specific NumberFormat if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { - Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case UNUM_DECIMAL: curr = FALSE; // fall-through + U_FALLTHROUGH; case UNUM_CURRENCY: case UNUM_CURRENCY_ISO: // do not support plural formatting here @@ -1340,14 +1340,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale, case UNUM_CURRENCY_ACCOUNTING: case UNUM_CASH_CURRENCY: case UNUM_CURRENCY_STANDARD: - f = new Win32NumberFormat(desiredLocale, curr, status); - + { + LocalPointer f(new Win32NumberFormat(desiredLocale, curr, status), status); if (U_SUCCESS(status)) { - return f; + return f.orphan(); } - - delete f; - break; + } + break; default: break; } @@ -1417,8 +1416,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } } - - NumberFormat *f; + LocalPointer f; if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; @@ -1453,7 +1451,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale, return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); - f = r; + f.adoptInstead(r); } else { // replace single currency sign in the pattern with double currency sign // if the style is UNUM_CURRENCY_ISO @@ -1462,9 +1460,22 @@ NumberFormat::makeInstance(const Locale& desiredLocale, UnicodeString(TRUE, gDoubleCurrencySign, 2)); } - // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. - DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); - DecimalFormat* df = new DecimalFormat(pattern, syms, style, status); + // "new DecimalFormat()" does not adopt the symbols argument if its memory allocation fails. + // So we can't use adoptInsteadAndCheckErrorCode as we need to know if the 'new' failed. + DecimalFormatSymbols *syms = symbolsToAdopt.getAlias(); + LocalPointer df(new DecimalFormat(pattern, syms, style, status)); + + if (df.isValid()) { + // if the DecimalFormat object was successfully new'ed, then it will own symbolsToAdopt, even if the status is a failure. + symbolsToAdopt.orphan(); + } + else { + status = U_MEMORY_ALLOCATION_ERROR; + } + + if (U_FAILURE(status)) { + return nullptr; + } // if it is cash currency style, setCurrencyUsage with usage if (style == UNUM_CASH_CURRENCY){ @@ -1472,25 +1483,18 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } if (U_FAILURE(status)) { - delete df; - return NULL; + return nullptr; } - f = df; - if (f == NULL) { - delete syms; - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } + f.adoptInstead(df.orphan()); } f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { - delete f; return NULL; } - return f; + return f.orphan(); } /** diff --git a/deps/icu-small/source/i18n/numparse_currency.cpp b/deps/icu-small/source/i18n/numparse_currency.cpp index ae8196ec483799..598ace56533c36 100644 --- a/deps/icu-small/source/i18n/numparse_currency.cpp +++ b/deps/icu-small/source/i18n/numparse_currency.cpp @@ -111,7 +111,9 @@ bool CombinedCurrencyMatcher::matchCurrency(StringSegment& segment, ParsedNumber int32_t overlap2; if (!fCurrency2.isEmpty()) { - overlap2 = segment.getCaseSensitivePrefixLength(fCurrency2); + // ISO codes should be accepted case-insensitive. + // https://unicode-org.atlassian.net/browse/ICU-13696 + overlap2 = segment.getCommonPrefixLength(fCurrency2); } else { overlap2 = -1; } diff --git a/deps/icu-small/source/i18n/numparse_impl.cpp b/deps/icu-small/source/i18n/numparse_impl.cpp index 5fa52f63351c31..3192a3959389a7 100644 --- a/deps/icu-small/source/i18n/numparse_impl.cpp +++ b/deps/icu-small/source/i18n/numparse_impl.cpp @@ -159,10 +159,10 @@ NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatPr // ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern, // and to maintain regressive behavior, divide by 100 even if no percent sign is present. - if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) { + if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) { parser->addMatcher(parser->fLocalMatchers.percent = {symbols}); } - if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) { + if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) { parser->addMatcher(parser->fLocalMatchers.permille = {symbols}); } diff --git a/deps/icu-small/source/i18n/numparse_scientific.cpp b/deps/icu-small/source/i18n/numparse_scientific.cpp index 611695e57d4743..de38957440817c 100644 --- a/deps/icu-small/source/i18n/numparse_scientific.cpp +++ b/deps/icu-small/source/i18n/numparse_scientific.cpp @@ -56,6 +56,11 @@ bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErr return false; } + // Only accept one exponent per string. + if (0 != (result.flags & FLAG_HAS_EXPONENT)) { + return false; + } + // First match the scientific separator, and then match another number after it. // NOTE: This is guarded by the smoke test; no need to check fExponentSeparatorString length again. int overlap1 = segment.getCommonPrefixLength(fExponentSeparatorString); diff --git a/deps/icu-small/source/i18n/numrange_fluent.cpp b/deps/icu-small/source/i18n/numrange_fluent.cpp new file mode 100644 index 00000000000000..12b006c8ad5540 --- /dev/null +++ b/deps/icu-small/source/i18n/numrange_fluent.cpp @@ -0,0 +1,472 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numrange_impl.h" +#include "util.h" +#include "number_utypes.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +// This function needs to be declared in this namespace so it can be friended. +// NOTE: In Java, this logic is handled in the resolve() function. +void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) { + macros.formatter1.fMacros.locale = macros.locale; + macros.formatter2.fMacros.locale = macros.locale; +} + + +template +Derived NumberRangeFormatterSettings::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = formatter; + copy.fMacros.singleFormatter = true; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = formatter; + move.fMacros.singleFormatter = true; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = std::move(formatter); + copy.fMacros.singleFormatter = true; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = std::move(formatter); + move.fMacros.singleFormatter = true; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = formatter; + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = formatter; + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = std::move(formatter); + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = std::move(formatter); + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter2 = formatter; + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter2 = formatter; + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter2 = std::move(formatter); + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template +Derived NumberRangeFormatterSettings::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter2 = std::move(formatter); + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template +Derived NumberRangeFormatterSettings::collapse(UNumberRangeCollapse collapse) const& { + Derived copy(*this); + copy.fMacros.collapse = collapse; + return copy; +} + +template +Derived NumberRangeFormatterSettings::collapse(UNumberRangeCollapse collapse) && { + Derived move(std::move(*this)); + move.fMacros.collapse = collapse; + return move; +} + +template +Derived NumberRangeFormatterSettings::identityFallback(UNumberRangeIdentityFallback identityFallback) const& { + Derived copy(*this); + copy.fMacros.identityFallback = identityFallback; + return copy; +} + +template +Derived NumberRangeFormatterSettings::identityFallback(UNumberRangeIdentityFallback identityFallback) && { + Derived move(std::move(*this)); + move.fMacros.identityFallback = identityFallback; + return move; +} + +// Declare all classes that implement NumberRangeFormatterSettings +// See https://stackoverflow.com/a/495056/1407170 +template +class icu::number::NumberRangeFormatterSettings; +template +class icu::number::NumberRangeFormatterSettings; + + +UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() { + UnlocalizedNumberRangeFormatter result; + return result; +} + +LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) { + return with().locale(locale); +} + + +template using NFS = NumberRangeFormatterSettings; +using LNF = LocalizedNumberRangeFormatter; +using UNF = UnlocalizedNumberRangeFormatter; + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other) + : UNF(static_cast&>(other)) {} + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS& other) + : NFS(other) { + // No additional fields to assign +} + +// Make default copy constructor call the NumberRangeFormatterSettings copy constructor. +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT + : UNF(static_cast&&>(src)) {} + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS&& src) U_NOEXCEPT + : NFS(std::move(src)) { + // No additional fields to assign +} + +UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) { + NFS::operator=(static_cast&>(other)); + // No additional fields to assign + return *this; +} + +UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT { + NFS::operator=(static_cast&&>(src)); + // No additional fields to assign + return *this; +} + +// Make default copy constructor call the NumberRangeFormatterSettings copy constructor. +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other) + : LNF(static_cast&>(other)) {} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS& other) + : NFS(other) { + // No additional fields to assign +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT + : LNF(static_cast&&>(src)) {} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS&& src) U_NOEXCEPT + : NFS(std::move(src)) { + // Steal the compiled formatter + LNF&& _src = static_cast(src); + auto* stolen = _src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); +} + +LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) { + NFS::operator=(static_cast&>(other)); + // Do not steal; just clear + delete fAtomicFormatter.exchange(nullptr); + return *this; +} + +LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT { + NFS::operator=(static_cast&&>(src)); + // Steal the compiled formatter + auto* stolen = src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); + return *this; +} + + +LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() { + delete fAtomicFormatter.exchange(nullptr); +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) { + fMacros = macros; + fMacros.locale = locale; + touchRangeLocales(fMacros); +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) { + fMacros = std::move(macros); + fMacros.locale = locale; + touchRangeLocales(fMacros); +} + +LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& { + return LocalizedNumberRangeFormatter(fMacros, locale); +} + +LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& { + return LocalizedNumberRangeFormatter(std::move(fMacros), locale); +} + + +FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange( + const Formattable& first, const Formattable& second, UErrorCode& status) const { + if (U_FAILURE(status)) { + return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR); + } + + auto results = new UFormattedNumberRangeData(); + if (results == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return FormattedNumberRange(status); + } + + first.populateDecimalQuantity(results->quantity1, status); + if (U_FAILURE(status)) { + return FormattedNumberRange(status); + } + + second.populateDecimalQuantity(results->quantity2, status); + if (U_FAILURE(status)) { + return FormattedNumberRange(status); + } + + formatImpl(*results, first == second, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumberRange(results); + } else { + delete results; + return FormattedNumberRange(status); + } +} + +void LocalizedNumberRangeFormatter::formatImpl( + UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const { + auto* impl = getFormatter(status); + if (U_FAILURE(status)) { + return; + } + if (impl == nullptr) { + status = U_INTERNAL_PROGRAM_ERROR; + return; + } + impl->format(results, equalBeforeRounding, status); +} + +const impl::NumberRangeFormatterImpl* +LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const { + // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp) + // See ICU-20146 + + if (U_FAILURE(status)) { + return nullptr; + } + + // First try to get the pre-computed formatter + auto* ptr = fAtomicFormatter.load(); + if (ptr != nullptr) { + return ptr; + } + + // Try computing the formatter on our own + auto* temp = new NumberRangeFormatterImpl(fMacros, status); + if (U_FAILURE(status)) { + return nullptr; + } + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + + // Note: ptr starts as nullptr; during compare_exchange, + // it is set to what is actually stored in the atomic + // if another thread beat us to computing the formatter object. + auto* nonConstThis = const_cast(this); + if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the formatter + delete temp; + return ptr; + } else { + // Our copy of the formatter got stored in the atomic + return temp; + } + +} + + +FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT + : fResults(src.fResults), fErrorCode(src.fErrorCode) { + // Disown src.fResults to prevent double-deletion + src.fResults = nullptr; + src.fErrorCode = U_INVALID_STATE_ERROR; +} + +FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT { + delete fResults; + fResults = src.fResults; + fErrorCode = src.fErrorCode; + // Disown src.fResults to prevent double-deletion + src.fResults = nullptr; + src.fErrorCode = U_INVALID_STATE_ERROR; + return *this; +} + +UnicodeString FormattedNumberRange::toString(UErrorCode& status) const { + if (U_FAILURE(status)) { + return ICU_Utility::makeBogusString(); + } + if (fResults == nullptr) { + status = fErrorCode; + return ICU_Utility::makeBogusString(); + } + return fResults->string.toUnicodeString(); +} + +Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) const { + if (U_FAILURE(status)) { + return appendable; + } + if (fResults == nullptr) { + status = fErrorCode; + return appendable; + } + appendable.appendString(fResults->string.chars(), fResults->string.length()); + return appendable; +} + +UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const { + if (U_FAILURE(status)) { + return FALSE; + } + if (fResults == nullptr) { + status = fErrorCode; + return FALSE; + } + // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool + return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE; +} + +void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const { + FieldPositionIteratorHandler fpih(&iterator, status); + getAllFieldPositionsImpl(fpih, status); +} + +void FormattedNumberRange::getAllFieldPositionsImpl( + FieldPositionIteratorHandler& fpih, UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } + if (fResults == nullptr) { + status = fErrorCode; + return; + } + fResults->string.getAllFieldPositions(fpih, status); +} + +UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const { + if (U_FAILURE(status)) { + return ICU_Utility::makeBogusString(); + } + if (fResults == nullptr) { + status = fErrorCode; + return ICU_Utility::makeBogusString(); + } + return fResults->quantity1.toScientificString(); +} + +UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const { + if (U_FAILURE(status)) { + return ICU_Utility::makeBogusString(); + } + if (fResults == nullptr) { + status = fErrorCode; + return ICU_Utility::makeBogusString(); + } + return fResults->quantity2.toScientificString(); +} + +UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const { + if (U_FAILURE(status)) { + return UNUM_IDENTITY_RESULT_NOT_EQUAL; + } + if (fResults == nullptr) { + status = fErrorCode; + return UNUM_IDENTITY_RESULT_NOT_EQUAL; + } + return fResults->identityResult; +} + +FormattedNumberRange::~FormattedNumberRange() { + delete fResults; +} + + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numrange_impl.cpp b/deps/icu-small/source/i18n/numrange_impl.cpp new file mode 100644 index 00000000000000..21365bfc59bca3 --- /dev/null +++ b/deps/icu-small/source/i18n/numrange_impl.cpp @@ -0,0 +1,486 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "unicode/numberrangeformatter.h" +#include "numrange_impl.h" +#include "patternprops.h" +#include "uresimp.h" +#include "util.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + +namespace { + +// Helper function for 2-dimensional switch statement +constexpr int8_t identity2d(UNumberRangeIdentityFallback a, UNumberRangeIdentityResult b) { + return static_cast(a) | (static_cast(b) << 4); +} + + +struct NumberRangeData { + SimpleFormatter rangePattern; + SimpleFormatter approximatelyPattern; +}; + +class NumberRangeDataSink : public ResourceSink { + public: + NumberRangeDataSink(NumberRangeData& data) : fData(data) {} + + void put(const char* key, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE { + ResourceTable miscTable = value.getTable(status); + if (U_FAILURE(status)) { return; } + for (int i = 0; miscTable.getKeyAndValue(i, key, value); i++) { + if (uprv_strcmp(key, "range") == 0) { + if (fData.rangePattern.getArgumentLimit() != 0) { + continue; // have already seen this pattern + } + fData.rangePattern = {value.getUnicodeString(status), status}; + } else if (uprv_strcmp(key, "approximately") == 0) { + if (fData.approximatelyPattern.getArgumentLimit() != 0) { + continue; // have already seen this pattern + } + fData.approximatelyPattern = {value.getUnicodeString(status), status}; + } + } + } + + private: + NumberRangeData& fData; +}; + +void getNumberRangeData(const char* localeName, const char* nsName, NumberRangeData& data, UErrorCode& status) { + if (U_FAILURE(status)) { return; } + LocalUResourceBundlePointer rb(ures_open(NULL, localeName, &status)); + if (U_FAILURE(status)) { return; } + NumberRangeDataSink sink(data); + + CharString dataPath; + dataPath.append("NumberElements/", -1, status); + dataPath.append(nsName, -1, status); + dataPath.append("/miscPatterns", -1, status); + ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status); + if (U_FAILURE(status)) { return; } + + // TODO: Is it necessary to manually fall back to latn, or does the data sink take care of that? + + if (data.rangePattern.getArgumentLimit() == 0) { + // No data! + data.rangePattern = {u"{0}–{1}", status}; + } + if (data.approximatelyPattern.getArgumentLimit() == 0) { + // No data! + data.approximatelyPattern = {u"~{0}", status}; + } +} + +class PluralRangesDataSink : public ResourceSink { + public: + PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {} + + void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE { + ResourceArray entriesArray = value.getArray(status); + if (U_FAILURE(status)) { return; } + fOutput.setCapacity(entriesArray.getSize()); + for (int i = 0; entriesArray.getValue(i, value); i++) { + ResourceArray pluralFormsArray = value.getArray(status); + if (U_FAILURE(status)) { return; } + pluralFormsArray.getValue(0, value); + StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status); + if (U_FAILURE(status)) { return; } + pluralFormsArray.getValue(1, value); + StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status); + if (U_FAILURE(status)) { return; } + pluralFormsArray.getValue(2, value); + StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status); + if (U_FAILURE(status)) { return; } + fOutput.addPluralRange(first, second, result); + } + } + + private: + StandardPluralRanges& fOutput; +}; + +void getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) { + if (U_FAILURE(status)) { return; } + LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status)); + if (U_FAILURE(status)) { return; } + + CharString dataPath; + dataPath.append("locales/", -1, status); + dataPath.append(locale.getLanguage(), -1, status); + if (U_FAILURE(status)) { return; } + int32_t setLen; + // Not all languages are covered: fail gracefully + UErrorCode internalStatus = U_ZERO_ERROR; + const UChar* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus); + if (U_FAILURE(internalStatus)) { return; } + + dataPath.clear(); + dataPath.append("rules/", -1, status); + dataPath.appendInvariantChars(set, setLen, status); + if (U_FAILURE(status)) { return; } + PluralRangesDataSink sink(output); + ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status); + if (U_FAILURE(status)) { return; } +} + +} // namespace + + +void StandardPluralRanges::initialize(const Locale& locale, UErrorCode& status) { + getPluralRangesData(locale, *this, status); +} + +void StandardPluralRanges::addPluralRange( + StandardPlural::Form first, + StandardPlural::Form second, + StandardPlural::Form result) { + U_ASSERT(fTriplesLen < fTriples.getCapacity()); + fTriples[fTriplesLen] = {first, second, result}; + fTriplesLen++; +} + +void StandardPluralRanges::setCapacity(int32_t length) { + if (length > fTriples.getCapacity()) { + fTriples.resize(length, 0); + } +} + +StandardPlural::Form +StandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const { + for (int32_t i=0; isemanticallyEquivalent(*micros2.modInner) + || !micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle) + || !micros1.modOuter->semanticallyEquivalent(*micros2.modOuter)) { + formatRange(data, micros1, micros2, status); + data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL; + return; + } + + // Check for identity + if (equalBeforeRounding) { + data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING; + } else if (data.quantity1 == data.quantity2) { + data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING; + } else { + data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL; + } + + switch (identity2d(fIdentityFallback, data.identityResult)) { + case identity2d(UNUM_IDENTITY_FALLBACK_RANGE, + UNUM_IDENTITY_RESULT_NOT_EQUAL): + case identity2d(UNUM_IDENTITY_FALLBACK_RANGE, + UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_RANGE, + UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY, + UNUM_IDENTITY_RESULT_NOT_EQUAL): + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_NOT_EQUAL): + case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_NOT_EQUAL): + formatRange(data, micros1, micros2, status); + break; + + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY, + UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY, + UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING): + formatApproximately(data, micros1, micros2, status); + break; + + case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING): + case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE, + UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING): + formatSingleValue(data, micros1, micros2, status); + break; + + default: + U_ASSERT(false); + break; + } +} + + +void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const { + if (U_FAILURE(status)) { return; } + if (fSameFormatters) { + int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status); + NumberFormatterImpl::writeAffixes(micros1, data.string, 0, length, status); + } else { + formatRange(data, micros1, micros2, status); + } +} + + +void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const { + if (U_FAILURE(status)) { return; } + if (fSameFormatters) { + int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status); + // HEURISTIC: Desired modifier order: inner, middle, approximately, outer. + length += micros1.modInner->apply(data.string, 0, length, status); + length += micros1.modMiddle->apply(data.string, 0, length, status); + length += fApproximatelyModifier.apply(data.string, 0, length, status); + micros1.modOuter->apply(data.string, 0, length, status); + } else { + formatRange(data, micros1, micros2, status); + } +} + + +void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const { + if (U_FAILURE(status)) { return; } + + // modInner is always notation (scientific); collapsable in ALL. + // modOuter is always units; collapsable in ALL, AUTO, and UNIT. + // modMiddle could be either; collapsable in ALL and sometimes AUTO and UNIT. + // Never collapse an outer mod but not an inner mod. + bool collapseOuter, collapseMiddle, collapseInner; + switch (fCollapse) { + case UNUM_RANGE_COLLAPSE_ALL: + case UNUM_RANGE_COLLAPSE_AUTO: + case UNUM_RANGE_COLLAPSE_UNIT: + { + // OUTER MODIFIER + collapseOuter = micros1.modOuter->semanticallyEquivalent(*micros2.modOuter); + + if (!collapseOuter) { + // Never collapse inner mods if outer mods are not collapsable + collapseMiddle = false; + collapseInner = false; + break; + } + + // MIDDLE MODIFIER + collapseMiddle = micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle); + + if (!collapseMiddle) { + // Never collapse inner mods if outer mods are not collapsable + collapseInner = false; + break; + } + + // MIDDLE MODIFIER HEURISTICS + // (could disable collapsing of the middle modifier) + // The modifiers are equal by this point, so we can look at just one of them. + const Modifier* mm = micros1.modMiddle; + if (fCollapse == UNUM_RANGE_COLLAPSE_UNIT) { + // Only collapse if the modifier is a unit. + // TODO: Make a better way to check for a unit? + // TODO: Handle case where the modifier has both notation and unit (compact currency)? + if (!mm->containsField(UNUM_CURRENCY_FIELD) && !mm->containsField(UNUM_PERCENT_FIELD)) { + collapseMiddle = false; + } + } else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) { + // Heuristic as of ICU 63: collapse only if the modifier is more than one code point. + if (mm->getCodePointCount() <= 1) { + collapseMiddle = false; + } + } + + if (!collapseMiddle || fCollapse != UNUM_RANGE_COLLAPSE_ALL) { + collapseInner = false; + break; + } + + // INNER MODIFIER + collapseInner = micros1.modInner->semanticallyEquivalent(*micros2.modInner); + + // All done checking for collapsability. + break; + } + + default: + collapseOuter = false; + collapseMiddle = false; + collapseInner = false; + break; + } + + NumberStringBuilder& string = data.string; + int32_t lengthPrefix = 0; + int32_t length1 = 0; + int32_t lengthInfix = 0; + int32_t length2 = 0; + int32_t lengthSuffix = 0; + + // Use #define so that these are evaluated at the call site. + #define UPRV_INDEX_0 (lengthPrefix) + #define UPRV_INDEX_1 (lengthPrefix + length1) + #define UPRV_INDEX_2 (lengthPrefix + length1 + lengthInfix) + #define UPRV_INDEX_3 (lengthPrefix + length1 + lengthInfix + length2) + + int32_t lengthRange = SimpleModifier::formatTwoArgPattern( + fRangeFormatter, + string, + 0, + &lengthPrefix, + &lengthSuffix, + UNUM_FIELD_COUNT, + status); + if (U_FAILURE(status)) { return; } + lengthInfix = lengthRange - lengthPrefix - lengthSuffix; + U_ASSERT(lengthInfix > 0); + + // SPACING HEURISTIC + // Add spacing unless all modifiers are collapsed. + // TODO: add API to control this? + // TODO: Use a data-driven heuristic like currency spacing? + // TODO: Use Unicode [:whitespace:] instead of PatternProps whitespace? (consider speed implications) + { + bool repeatInner = !collapseInner && micros1.modInner->getCodePointCount() > 0; + bool repeatMiddle = !collapseMiddle && micros1.modMiddle->getCodePointCount() > 0; + bool repeatOuter = !collapseOuter && micros1.modOuter->getCodePointCount() > 0; + if (repeatInner || repeatMiddle || repeatOuter) { + // Add spacing if there is not already spacing + if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_1))) { + lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', UNUM_FIELD_COUNT, status); + } + if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) { + lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', UNUM_FIELD_COUNT, status); + } + } + } + + length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status); + length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_2, status); + + // TODO: Support padding? + + if (collapseInner) { + // Note: this is actually a mix of prefix and suffix, but adding to infix length works + const Modifier& mod = resolveModifierPlurals(*micros1.modInner, *micros2.modInner); + lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status); + } else { + length1 += micros1.modInner->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status); + length2 += micros2.modInner->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status); + } + + if (collapseMiddle) { + // Note: this is actually a mix of prefix and suffix, but adding to infix length works + const Modifier& mod = resolveModifierPlurals(*micros1.modMiddle, *micros2.modMiddle); + lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status); + } else { + length1 += micros1.modMiddle->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status); + length2 += micros2.modMiddle->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status); + } + + if (collapseOuter) { + // Note: this is actually a mix of prefix and suffix, but adding to infix length works + const Modifier& mod = resolveModifierPlurals(*micros1.modOuter, *micros2.modOuter); + lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status); + } else { + length1 += micros1.modOuter->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status); + length2 += micros2.modOuter->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status); + } +} + + +const Modifier& +NumberRangeFormatterImpl::resolveModifierPlurals(const Modifier& first, const Modifier& second) const { + Modifier::Parameters parameters; + first.getParameters(parameters); + if (parameters.obj == nullptr) { + // No plural form; return a fallback (e.g., the first) + return first; + } + StandardPlural::Form firstPlural = parameters.plural; + + second.getParameters(parameters); + if (parameters.obj == nullptr) { + // No plural form; return a fallback (e.g., the first) + return first; + } + StandardPlural::Form secondPlural = parameters.plural; + + // Get the required plural form from data + StandardPlural::Form resultPlural = fPluralRanges.resolve(firstPlural, secondPlural); + + // Get and return the new Modifier + const Modifier* mod = parameters.obj->getModifier(parameters.signum, resultPlural); + U_ASSERT(mod != nullptr); + return *mod; +} + + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numrange_impl.h b/deps/icu-small/source/i18n/numrange_impl.h new file mode 100644 index 00000000000000..787fc656860d53 --- /dev/null +++ b/deps/icu-small/source/i18n/numrange_impl.h @@ -0,0 +1,114 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMRANGE_TYPES_H__ +#define __SOURCE_NUMRANGE_TYPES_H__ + +#include "unicode/numberformatter.h" +#include "unicode/numberrangeformatter.h" +#include "unicode/simpleformatter.h" +#include "number_types.h" +#include "number_decimalquantity.h" +#include "number_formatimpl.h" +#include "number_stringbuilder.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + + +/** + * Class similar to UFormattedNumberData. + * + * Has incomplete magic number logic that will need to be finished + * if this is to be exposed as C API in the future. + */ +struct UFormattedNumberRangeData : public UMemory { + // The magic number to identify incoming objects. + // Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end) + static constexpr int32_t kMagic = 0x46445200; + + // Data members: + int32_t fMagic = kMagic; + DecimalQuantity quantity1; + DecimalQuantity quantity2; + NumberStringBuilder string; + UNumberRangeIdentityResult identityResult = UNUM_IDENTITY_RESULT_COUNT; + + // No C conversion methods (no C API yet) +}; + + +class StandardPluralRanges : public UMemory { + public: + void initialize(const Locale& locale, UErrorCode& status); + StandardPlural::Form resolve(StandardPlural::Form first, StandardPlural::Form second) const; + + /** Used for data loading. */ + void addPluralRange( + StandardPlural::Form first, + StandardPlural::Form second, + StandardPlural::Form result); + + /** Used for data loading. */ + void setCapacity(int32_t length); + + private: + struct StandardPluralRangeTriple { + StandardPlural::Form first; + StandardPlural::Form second; + StandardPlural::Form result; + }; + + // TODO: An array is simple here, but it results in linear lookup time. + // Certain locales have 20-30 entries in this list. + // Consider changing to a smarter data structure. + typedef MaybeStackArray PluralRangeTriples; + PluralRangeTriples fTriples; + int32_t fTriplesLen = 0; +}; + + +class NumberRangeFormatterImpl : public UMemory { + public: + NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status); + + void format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const; + + private: + NumberFormatterImpl formatterImpl1; + NumberFormatterImpl formatterImpl2; + bool fSameFormatters; + + UNumberRangeCollapse fCollapse; + UNumberRangeIdentityFallback fIdentityFallback; + + SimpleFormatter fRangeFormatter; + SimpleModifier fApproximatelyModifier; + + StandardPluralRanges fPluralRanges; + + void formatSingleValue(UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const; + + void formatApproximately(UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const; + + void formatRange(UFormattedNumberRangeData& data, + MicroProps& micros1, MicroProps& micros2, + UErrorCode& status) const; + + const Modifier& resolveModifierPlurals(const Modifier& first, const Modifier& second) const; +}; + + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif //__SOURCE_NUMRANGE_TYPES_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numsys.cpp b/deps/icu-small/source/i18n/numsys.cpp index 087dd277eb4dd8..514fe05e5ae6de 100644 --- a/deps/icu-small/source/i18n/numsys.cpp +++ b/deps/icu-small/source/i18n/numsys.cpp @@ -79,43 +79,45 @@ NumberingSystem* U_EXPORT2 NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } if ( radix_in < 2 ) { status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; + return nullptr; } if ( !isAlgorithmic_in ) { if ( desc_in.countChar32() != radix_in ) { status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; + return nullptr; } } - NumberingSystem *ns = new NumberingSystem(); + LocalPointer ns(new NumberingSystem(), status); + if (U_FAILURE(status)) { + return nullptr; + } ns->setRadix(radix_in); ns->setDesc(desc_in); ns->setAlgorithmic(isAlgorithmic_in); - ns->setName(NULL); - return ns; + ns->setName(nullptr); + return ns.orphan(); } - NumberingSystem* U_EXPORT2 NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } UBool nsResolved = TRUE; UBool usingFallback = FALSE; char buffer[ULOC_KEYWORDS_CAPACITY]; - int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status); + int32_t count = inLocale.getKeywordValue("numbers", buffer, sizeof(buffer), status); if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) { // the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default. count = 0; @@ -129,20 +131,30 @@ NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) { nsResolved = FALSE; } } else { - uprv_strcpy(buffer,gDefault); + uprv_strcpy(buffer, gDefault); nsResolved = FALSE; } if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system UErrorCode localStatus = U_ZERO_ERROR; - UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &localStatus); - UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&localStatus); + LocalUResourceBundlePointer resource(ures_open(nullptr, inLocale.getName(), &localStatus)); + LocalUResourceBundlePointer numberElementsRes(ures_getByKey(resource.getAlias(), gNumberElements, nullptr, &localStatus)); + // Don't stomp on the catastrophic failure of OOM. + if (localStatus == U_MEMORY_ALLOCATION_ERROR) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } while (!nsResolved) { localStatus = U_ZERO_ERROR; count = 0; - const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes, buffer, &count, &localStatus); + const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes.getAlias(), buffer, &count, &localStatus); + // Don't stomp on the catastrophic failure of OOM. + if (localStatus == U_MEMORY_ALLOCATION_ERROR) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found - u_UCharsToChars(nsName,buffer,count); + u_UCharsToChars(nsName, buffer, count); buffer[count] = '\0'; // Make sure it is null terminated. nsResolved = TRUE; } @@ -158,16 +170,17 @@ NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) { } } } - ures_close(numberElementsRes); - ures_close(resource); } if (usingFallback) { status = U_USING_FALLBACK_WARNING; NumberingSystem *ns = new NumberingSystem(); + if (ns == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } return ns; } else { - return NumberingSystem::createInstanceByName(buffer,status); + return NumberingSystem::createInstanceByName(buffer, status); } } @@ -178,36 +191,37 @@ NumberingSystem::createInstance(UErrorCode& status) { NumberingSystem* U_EXPORT2 NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) { - UResourceBundle *numberingSystemsInfo = NULL; - UResourceBundle *nsTop, *nsCurrent; int32_t radix = 10; int32_t algorithmic = 0; - numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status); - nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status); - nsTop = ures_getByKey(nsCurrent,name,NULL,&status); - UnicodeString nsd = ures_getUnicodeStringByKey(nsTop,gDesc,&status); + LocalUResourceBundlePointer numberingSystemsInfo(ures_openDirect(nullptr, gNumberingSystems, &status)); + LocalUResourceBundlePointer nsCurrent(ures_getByKey(numberingSystemsInfo.getAlias(), gNumberingSystems, nullptr, &status)); + LocalUResourceBundlePointer nsTop(ures_getByKey(nsCurrent.getAlias(), name, nullptr, &status)); - ures_getByKey(nsTop,gRadix,nsCurrent,&status); - radix = ures_getInt(nsCurrent,&status); + UnicodeString nsd = ures_getUnicodeStringByKey(nsTop.getAlias(), gDesc, &status); - ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status); - algorithmic = ures_getInt(nsCurrent,&status); + ures_getByKey(nsTop.getAlias(), gRadix, nsCurrent.getAlias(), &status); + radix = ures_getInt(nsCurrent.getAlias(), &status); - UBool isAlgorithmic = ( algorithmic == 1 ); + ures_getByKey(nsTop.getAlias(), gAlgorithmic, nsCurrent.getAlias(), &status); + algorithmic = ures_getInt(nsCurrent.getAlias(), &status); - ures_close(nsCurrent); - ures_close(nsTop); - ures_close(numberingSystemsInfo); + UBool isAlgorithmic = ( algorithmic == 1 ); if (U_FAILURE(status)) { - status = U_UNSUPPORTED_ERROR; - return NULL; + // Don't stomp on the catastrophic failure of OOM. + if (status != U_MEMORY_ALLOCATION_ERROR) { + status = U_UNSUPPORTED_ERROR; + } + return nullptr; } - NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status); + LocalPointer ns(NumberingSystem::createInstance(radix, isAlgorithmic, nsd, status), status); + if (U_FAILURE(status)) { + return nullptr; + } ns->setName(name); - return ns; + return ns.orphan(); } /** @@ -241,11 +255,11 @@ void NumberingSystem::setDesc(const UnicodeString &d) { desc.setTo(d); } void NumberingSystem::setName(const char *n) { - if ( n == NULL ) { + if ( n == nullptr ) { name[0] = (char) 0; } else { uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY); - name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated. + name[NUMSYS_NAME_CAPACITY] = '\0'; // Make sure it is null terminated. } } UBool NumberingSystem::isAlgorithmic() const { @@ -254,43 +268,57 @@ UBool NumberingSystem::isAlgorithmic() const { StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) { // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback. - static StringEnumeration* availableNames = NULL; + static StringEnumeration* availableNames = nullptr; if (U_FAILURE(status)) { - return NULL; + return nullptr; } - if ( availableNames == NULL ) { + if ( availableNames == nullptr ) { // TODO: Simple array of UnicodeString objects, based on length of table resource? - LocalPointer numsysNames(new UVector(uprv_deleteUObject, NULL, status), status); + LocalPointer numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status); if (U_FAILURE(status)) { - return NULL; + return nullptr; } UErrorCode rbstatus = U_ZERO_ERROR; - UResourceBundle *numberingSystemsInfo = ures_openDirect(NULL, "numberingSystems", &rbstatus); - numberingSystemsInfo = ures_getByKey(numberingSystemsInfo,"numberingSystems",numberingSystemsInfo,&rbstatus); - if(U_FAILURE(rbstatus)) { - status = U_MISSING_RESOURCE_ERROR; + UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus); + numberingSystemsInfo = ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus); + if (U_FAILURE(rbstatus)) { + // Don't stomp on the catastrophic failure of OOM. + if (rbstatus == U_MEMORY_ALLOCATION_ERROR) { + status = rbstatus; + } else { + status = U_MISSING_RESOURCE_ERROR; + } ures_close(numberingSystemsInfo); - return NULL; + return nullptr; } - while ( ures_hasNext(numberingSystemsInfo) ) { - UResourceBundle *nsCurrent = ures_getNextResource(numberingSystemsInfo,NULL,&rbstatus); - const char *nsName = ures_getKey(nsCurrent); - numsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status); - ures_close(nsCurrent); + while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) { + LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus)); + if (rbstatus == U_MEMORY_ALLOCATION_ERROR) { + status = rbstatus; // we want to report OOM failure back to the caller. + break; + } + const char *nsName = ures_getKey(nsCurrent.getAlias()); + LocalPointer newElem(new UnicodeString(nsName, -1, US_INV), status); + if (U_SUCCESS(status)) { + numsysNames->addElement(newElem.getAlias(), status); + if (U_SUCCESS(status)) { + newElem.orphan(); // on success, the numsysNames vector owns newElem. + } + } } ures_close(numberingSystemsInfo); if (U_FAILURE(status)) { - return NULL; + return nullptr; } availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status); - if (availableNames == NULL) { + if (availableNames == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; - return NULL; + return nullptr; } numsysNames.orphan(); // The names got adopted. } @@ -305,10 +333,10 @@ NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& / const UnicodeString* NumsysNameEnumeration::snext(UErrorCode& status) { - if (U_SUCCESS(status) && pos < fNumsysNames->size()) { + if (U_SUCCESS(status) && (fNumsysNames != nullptr) && (pos < fNumsysNames->size())) { return (const UnicodeString*)fNumsysNames->elementAt(pos++); } - return NULL; + return nullptr; } void @@ -318,7 +346,7 @@ NumsysNameEnumeration::reset(UErrorCode& /*status*/) { int32_t NumsysNameEnumeration::count(UErrorCode& /*status*/) const { - return (fNumsysNames==NULL) ? 0 : fNumsysNames->size(); + return (fNumsysNames==nullptr) ? 0 : fNumsysNames->size(); } NumsysNameEnumeration::~NumsysNameEnumeration() { diff --git a/deps/icu-small/source/i18n/numsys_impl.h b/deps/icu-small/source/i18n/numsys_impl.h index 6385fa5408a152..733e102365369d 100644 --- a/deps/icu-small/source/i18n/numsys_impl.h +++ b/deps/icu-small/source/i18n/numsys_impl.h @@ -37,7 +37,7 @@ class NumsysNameEnumeration : public StringEnumeration { virtual int32_t count(UErrorCode& status) const; private: int32_t pos; - UVector *fNumsysNames; + UVector *fNumsysNames = nullptr; }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/olsontz.cpp b/deps/icu-small/source/i18n/olsontz.cpp index df025c0808388e..c3500574662585 100644 --- a/deps/icu-small/source/i18n/olsontz.cpp +++ b/deps/icu-small/source/i18n/olsontz.cpp @@ -140,7 +140,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, // Pre-32bit second transitions ures_getByKey(res, kTRANSPRE32, &r, &ec); transitionTimesPre32 = ures_getIntVector(&r, &len, &ec); - transitionCountPre32 = len >> 1; + transitionCountPre32 = static_cast(len >> 1); if (ec == U_MISSING_RESOURCE_ERROR) { // No pre-32bit transitions transitionTimesPre32 = NULL; @@ -153,7 +153,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, // 32bit second transitions ures_getByKey(res, kTRANS, &r, &ec); transitionTimes32 = ures_getIntVector(&r, &len, &ec); - transitionCount32 = len; + transitionCount32 = static_cast(len); if (ec == U_MISSING_RESOURCE_ERROR) { // No 32bit transitions transitionTimes32 = NULL; @@ -166,7 +166,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, // Post-32bit second transitions ures_getByKey(res, kTRANSPOST32, &r, &ec); transitionTimesPost32 = ures_getIntVector(&r, &len, &ec); - transitionCountPost32 = len >> 1; + transitionCountPost32 = static_cast(len >> 1); if (ec == U_MISSING_RESOURCE_ERROR) { // No pre-32bit transitions transitionTimesPost32 = NULL; diff --git a/deps/icu-small/source/i18n/plurrule.cpp b/deps/icu-small/source/i18n/plurrule.cpp index 9597e8eb00d023..3caa48a57bb700 100644 --- a/deps/icu-small/source/i18n/plurrule.cpp +++ b/deps/icu-small/source/i18n/plurrule.cpp @@ -65,13 +65,15 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration) PluralRules::PluralRules(UErrorCode& /*status*/) : UObject(), - mRules(NULL) + mRules(nullptr), + mInternalStatus(U_ZERO_ERROR) { } PluralRules::PluralRules(const PluralRules& other) : UObject(other), - mRules(NULL) + mRules(nullptr), + mInternalStatus(U_ZERO_ERROR) { *this=other; } @@ -86,54 +88,67 @@ SharedPluralRules::~SharedPluralRules() { PluralRules* PluralRules::clone() const { - return new PluralRules(*this); + PluralRules* newObj = new PluralRules(*this); + // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr if + // the newly created object was not fully constructed properly (an error occurred). + if (newObj != nullptr && U_FAILURE(newObj->mInternalStatus)) { + delete newObj; + newObj = nullptr; + } + return newObj; } PluralRules& PluralRules::operator=(const PluralRules& other) { if (this != &other) { delete mRules; - if (other.mRules==NULL) { - mRules = NULL; + mRules = nullptr; + mInternalStatus = other.mInternalStatus; + if (U_FAILURE(mInternalStatus)) { + // bail out early if the object we were copying from was already 'invalid'. + return *this; } - else { + if (other.mRules != nullptr) { mRules = new RuleChain(*other.mRules); + if (mRules == nullptr) { + mInternalStatus = U_MEMORY_ALLOCATION_ERROR; + } + else if (U_FAILURE(mRules->fInternalStatus)) { + // If the RuleChain wasn't fully copied, then set our status to failure as well. + mInternalStatus = mRules->fInternalStatus; + } } } - return *this; } StringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) { - StringEnumeration *result = new PluralAvailableLocalesEnumeration(status); - if (result == NULL && U_SUCCESS(status)) { - status = U_MEMORY_ALLOCATION_ERROR; + if (U_FAILURE(status)) { + return nullptr; } + LocalPointer result(new PluralAvailableLocalesEnumeration(status), status); if (U_FAILURE(status)) { - delete result; - result = NULL; + return nullptr; } - return result; + return result.orphan(); } PluralRules* U_EXPORT2 PluralRules::createRules(const UnicodeString& description, UErrorCode& status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } - PluralRuleParser parser; - PluralRules *newRules = new PluralRules(status); - if (U_SUCCESS(status) && newRules == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; + LocalPointer newRules(new PluralRules(status), status); + if (U_FAILURE(status)) { + return nullptr; } - parser.parse(description, newRules, status); + parser.parse(description, newRules.getAlias(), status); if (U_FAILURE(status)) { - delete newRules; - newRules = NULL; + newRules.adoptInstead(nullptr); } - return newRules; + return newRules.orphan(); } @@ -149,19 +164,17 @@ template<> U_I18N_API const SharedPluralRules *LocaleCacheKey::createObject( const void * /*unused*/, UErrorCode &status) const { const char *localeId = fLoc.getName(); - PluralRules *pr = PluralRules::internalForLocale( - localeId, UPLURAL_TYPE_CARDINAL, status); + LocalPointer pr(PluralRules::internalForLocale(localeId, UPLURAL_TYPE_CARDINAL, status), status); if (U_FAILURE(status)) { - return NULL; + return nullptr; } - SharedPluralRules *result = new SharedPluralRules(pr); - if (result == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - delete pr; - return NULL; + LocalPointer result(new SharedPluralRules(pr.getAlias()), status); + if (U_FAILURE(status)) { + return nullptr; } + pr.orphan(); // result was successfully created so it nows pr. result->addRef(); - return result; + return result.orphan(); } /* end plural rules cache */ @@ -171,13 +184,13 @@ const SharedPluralRules* U_EXPORT2 PluralRules::createSharedInstance( const Locale& locale, UPluralType type, UErrorCode& status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } if (type != UPLURAL_TYPE_CARDINAL) { status = U_UNSUPPORTED_ERROR; - return NULL; + return nullptr; } - const SharedPluralRules *result = NULL; + const SharedPluralRules *result = nullptr; UnifiedCache::getByLocale(locale, result, status); return result; } @@ -195,11 +208,11 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu const SharedPluralRules *shared = createSharedInstance( locale, type, status); if (U_FAILURE(status)) { - return NULL; + return nullptr; } PluralRules *result = (*shared)->clone(); shared->removeRef(); - if (result == NULL) { + if (result == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; } return result; @@ -208,20 +221,23 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu PluralRules* U_EXPORT2 PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } if (type >= UPLURAL_TYPE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; + return nullptr; } - PluralRules *newObj = new PluralRules(status); - if (newObj==NULL || U_FAILURE(status)) { - delete newObj; - return NULL; + LocalPointer newObj(new PluralRules(status), status); + if (U_FAILURE(status)) { + return nullptr; } UnicodeString locRule = newObj->getRuleFromResource(locale, type, status); - // TODO: which errors, if any, should be returned? + // TODO: which other errors, if any, should be returned? if (locRule.length() == 0) { + // If an out-of-memory error occurred, then stop and report the failure. + if (status == U_MEMORY_ALLOCATION_ERROR) { + return nullptr; + } // Locales with no specific rules (all numbers have the "other" category // will return a U_MISSING_RESOURCE_ERROR at this point. This is not // an error. @@ -229,13 +245,13 @@ PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCod status = U_ZERO_ERROR; } PluralRuleParser parser; - parser.parse(locRule, newObj, status); + parser.parse(locRule, newObj.getAlias(), status); // TODO: should rule parse errors be returned, or // should we silently use default rules? // Original impl used default rules. // Ask the question to ICU Core. - return newObj; + return newObj.orphan(); } UnicodeString @@ -250,7 +266,7 @@ PluralRules::select(double number) const { UnicodeString PluralRules::select(const IFixedDecimal &number) const { - if (mRules == NULL) { + if (mRules == nullptr) { return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1); } else { @@ -262,14 +278,18 @@ PluralRules::select(const IFixedDecimal &number) const { StringEnumeration* PluralRules::getKeywords(UErrorCode& status) const { - if (U_FAILURE(status)) return NULL; - StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status); if (U_FAILURE(status)) { - delete nameEnumerator; - return NULL; + return nullptr; } - - return nameEnumerator; + if (U_FAILURE(mInternalStatus)) { + status = mInternalStatus; + return nullptr; + } + LocalPointer nameEnumerator(new PluralKeywordEnumeration(mRules, status), status); + if (U_FAILURE(status)) { + return nullptr; + } + return nameEnumerator.orphan(); } double @@ -367,8 +387,15 @@ getSamplesFromString(const UnicodeString &samples, double *dest, int32_t PluralRules::getSamples(const UnicodeString &keyword, double *dest, int32_t destCapacity, UErrorCode& status) { + if (destCapacity == 0 || U_FAILURE(status)) { + return 0; + } + if (U_FAILURE(mInternalStatus)) { + status = mInternalStatus; + return 0; + } RuleChain *rc = rulesForKeyword(keyword); - if (rc == NULL || destCapacity == 0 || U_FAILURE(status)) { + if (rc == nullptr) { return 0; } int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, destCapacity, status); @@ -381,7 +408,7 @@ PluralRules::getSamples(const UnicodeString &keyword, double *dest, RuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const { RuleChain *rc; - for (rc = mRules; rc != NULL; rc = rc->fNext) { + for (rc = mRules; rc != nullptr; rc = rc->fNext) { if (rc->fKeyword == keyword) { break; } @@ -395,7 +422,7 @@ PluralRules::isKeyword(const UnicodeString& keyword) const { if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) { return true; } - return rulesForKeyword(keyword) != NULL; + return rulesForKeyword(keyword) != nullptr; } UnicodeString @@ -421,13 +448,13 @@ PluralRules::operator==(const PluralRules& other) const { return FALSE; } myKeywordList->reset(status); - while ((ptrKeyword=myKeywordList->snext(status))!=NULL) { + while ((ptrKeyword=myKeywordList->snext(status))!=nullptr) { if (!other.isKeyword(*ptrKeyword)) { return FALSE; } } otherKeywordList->reset(status); - while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) { + while ((ptrKeyword=otherKeywordList->snext(status))!=nullptr) { if (!this->isKeyword(*ptrKeyword)) { return FALSE; } @@ -460,29 +487,33 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr } switch (type) { case tAnd: - U_ASSERT(curAndConstraint != NULL); - curAndConstraint = curAndConstraint->add(); + U_ASSERT(curAndConstraint != nullptr); + curAndConstraint = curAndConstraint->add(status); break; case tOr: { - U_ASSERT(currentChain != NULL); + U_ASSERT(currentChain != nullptr); OrConstraint *orNode=currentChain->ruleHeader; - while (orNode->next != NULL) { + while (orNode->next != nullptr) { orNode = orNode->next; } orNode->next= new OrConstraint(); + if (orNode->next == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } orNode=orNode->next; - orNode->next=NULL; - curAndConstraint = orNode->add(); + orNode->next=nullptr; + curAndConstraint = orNode->add(status); } break; case tIs: - U_ASSERT(curAndConstraint != NULL); + U_ASSERT(curAndConstraint != nullptr); U_ASSERT(curAndConstraint->value == -1); - U_ASSERT(curAndConstraint->rangeList == NULL); + U_ASSERT(curAndConstraint->rangeList == nullptr); break; case tNot: - U_ASSERT(curAndConstraint != NULL); + U_ASSERT(curAndConstraint != nullptr); curAndConstraint->negated=TRUE; break; @@ -492,23 +523,29 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr case tIn: case tWithin: case tEqual: - U_ASSERT(curAndConstraint != NULL); - curAndConstraint->rangeList = new UVector32(status); - curAndConstraint->rangeList->addElement(-1, status); // range Low - curAndConstraint->rangeList->addElement(-1, status); // range Hi - rangeLowIdx = 0; - rangeHiIdx = 1; - curAndConstraint->value=PLURAL_RANGE_HIGH; - curAndConstraint->integerOnly = (type != tWithin); + { + U_ASSERT(curAndConstraint != nullptr); + LocalPointer newRangeList(new UVector32(status), status); + if (U_FAILURE(status)) { + break; + } + curAndConstraint->rangeList = newRangeList.orphan(); + curAndConstraint->rangeList->addElement(-1, status); // range Low + curAndConstraint->rangeList->addElement(-1, status); // range Hi + rangeLowIdx = 0; + rangeHiIdx = 1; + curAndConstraint->value=PLURAL_RANGE_HIGH; + curAndConstraint->integerOnly = (type != tWithin); + } break; case tNumber: - U_ASSERT(curAndConstraint != NULL); + U_ASSERT(curAndConstraint != nullptr); if ( (curAndConstraint->op==AndConstraint::MOD)&& (curAndConstraint->opNum == -1 ) ) { curAndConstraint->opNum=getNumberValue(token); } else { - if (curAndConstraint->rangeList == NULL) { + if (curAndConstraint->rangeList == nullptr) { // this is for an 'is' rule curAndConstraint->value = getNumberValue(token); } else { @@ -534,7 +571,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr case tComma: // TODO: rule syntax checking is inadequate, can happen with badly formed rules. // Catch cases like "n mod 10, is 1" here instead. - if (curAndConstraint == NULL || curAndConstraint->rangeList == NULL) { + if (curAndConstraint == nullptr || curAndConstraint->rangeList == nullptr) { status = U_UNEXPECTED_TOKEN; break; } @@ -545,7 +582,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr curAndConstraint->rangeList->addElement(-1, status); // range Hi break; case tMod: - U_ASSERT(curAndConstraint != NULL); + U_ASSERT(curAndConstraint != nullptr); curAndConstraint->op=AndConstraint::MOD; break; case tVariableN: @@ -553,24 +590,24 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr case tVariableF: case tVariableT: case tVariableV: - U_ASSERT(curAndConstraint != NULL); + U_ASSERT(curAndConstraint != nullptr); curAndConstraint->digitsType = type; break; case tKeyword: { RuleChain *newChain = new RuleChain; - if (newChain == NULL) { + if (newChain == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; break; } newChain->fKeyword = token; - if (prules->mRules == NULL) { + if (prules->mRules == nullptr) { prules->mRules = newChain; } else { // The new rule chain goes at the end of the linked list of rule chains, // unless there is an "other" keyword & chain. "other" must remain last. RuleChain *insertAfter = prules->mRules; - while (insertAfter->fNext!=NULL && + while (insertAfter->fNext!=nullptr && insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){ insertAfter=insertAfter->fNext; } @@ -578,8 +615,12 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr insertAfter->fNext = newChain; } OrConstraint *orNode = new OrConstraint(); + if (orNode == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } newChain->ruleHeader = orNode; - curAndConstraint = orNode->add(); + curAndConstraint = orNode->add(status); currentChain = newChain; } break; @@ -629,7 +670,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC if (U_FAILURE(errCode)) { return emptyStr; } - LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &errCode)); + LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &errCode)); if(U_FAILURE(errCode)) { return emptyStr; } @@ -646,7 +687,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC errCode = U_ILLEGAL_ARGUMENT_ERROR; return emptyStr; } - LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, NULL, &errCode)); + LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, nullptr, &errCode)); if(U_FAILURE(errCode)) { return emptyStr; } @@ -654,25 +695,25 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC const char *curLocaleName=locale.getName(); const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode); - if (s == NULL) { + if (s == nullptr) { // Check parent locales. UErrorCode status = U_ZERO_ERROR; char parentLocaleName[ULOC_FULLNAME_CAPACITY]; - const char *curLocaleName=locale.getName(); - uprv_strcpy(parentLocaleName, curLocaleName); + const char *curLocaleName2=locale.getName(); + uprv_strcpy(parentLocaleName, curLocaleName2); while (uloc_getParent(parentLocaleName, parentLocaleName, ULOC_FULLNAME_CAPACITY, &status) > 0) { resLen=0; s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status); - if (s != NULL) { + if (s != nullptr) { errCode = U_ZERO_ERROR; break; } status = U_ZERO_ERROR; } } - if (s==NULL) { + if (s==nullptr) { return emptyStr; } @@ -680,18 +721,18 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC u_UCharsToChars(s, setKey, resLen + 1); // printf("\n PluralRule: %s\n", setKey); - LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", NULL, &errCode)); + LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", nullptr, &errCode)); if(U_FAILURE(errCode)) { return emptyStr; } - LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, NULL, &errCode)); + LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, nullptr, &errCode)); if (U_FAILURE(errCode)) { return emptyStr; } int32_t numberKeys = ures_getSize(setRes.getAlias()); UnicodeString result; - const char *key=NULL; + const char *key=nullptr; for(int32_t i=0; idumpRules(rules); } return rules; } - -AndConstraint::AndConstraint() { - op = AndConstraint::NONE; - opNum=-1; - value = -1; - rangeList = NULL; - negated = FALSE; - integerOnly = FALSE; - digitsType = none; - next=NULL; -} - - AndConstraint::AndConstraint(const AndConstraint& other) { + this->fInternalStatus = other.fInternalStatus; + if (U_FAILURE(fInternalStatus)) { + return; // stop early if the object we are copying from is invalid. + } this->op = other.op; this->opNum=other.opNum; this->value=other.value; - this->rangeList=NULL; - if (other.rangeList != NULL) { - UErrorCode status = U_ZERO_ERROR; - this->rangeList = new UVector32(status); - this->rangeList->assign(*other.rangeList, status); + if (other.rangeList != nullptr) { + LocalPointer newRangeList(new UVector32(fInternalStatus), fInternalStatus); + if (U_FAILURE(fInternalStatus)) { + return; + } + this->rangeList = newRangeList.orphan(); + this->rangeList->assign(*other.rangeList, fInternalStatus); } this->integerOnly=other.integerOnly; this->negated=other.negated; this->digitsType = other.digitsType; - if (other.next==NULL) { - this->next=NULL; - } - else { + if (other.next != nullptr) { this->next = new AndConstraint(*other.next); + if (this->next == nullptr) { + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + } } } AndConstraint::~AndConstraint() { delete rangeList; - if (next!=NULL) { - delete next; - } + rangeList = nullptr; + delete next; + next = nullptr; } - UBool AndConstraint::isFulfilled(const IFixedDecimal &number) { UBool result = TRUE; @@ -776,7 +809,7 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) { if (op == MOD) { n = fmod(n, opNum); } - if (rangeList == NULL) { + if (rangeList == nullptr) { result = value == -1 || // empty rule n == value; // 'is' rule break; @@ -796,53 +829,67 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) { return result; } - AndConstraint* -AndConstraint::add() -{ +AndConstraint::add(UErrorCode& status) { + if (U_FAILURE(fInternalStatus)) { + status = fInternalStatus; + return nullptr; + } this->next = new AndConstraint(); + if (this->next == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } return this->next; } -OrConstraint::OrConstraint() { - childNode=NULL; - next=NULL; -} OrConstraint::OrConstraint(const OrConstraint& other) { - if ( other.childNode == NULL ) { - this->childNode = NULL; + this->fInternalStatus = other.fInternalStatus; + if (U_FAILURE(fInternalStatus)) { + return; // stop early if the object we are copying from is invalid. } - else { + if ( other.childNode != nullptr ) { this->childNode = new AndConstraint(*(other.childNode)); + if (this->childNode == nullptr) { + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + return; + } } - if (other.next == NULL ) { - this->next = NULL; - } - else { + if (other.next != nullptr ) { this->next = new OrConstraint(*(other.next)); + if (this->next == nullptr) { + fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + return; + } + if (U_FAILURE(this->next->fInternalStatus)) { + this->fInternalStatus = this->next->fInternalStatus; + } } } OrConstraint::~OrConstraint() { - if (childNode!=NULL) { - delete childNode; - } - if (next!=NULL) { - delete next; - } + delete childNode; + childNode = nullptr; + delete next; + next = nullptr; } AndConstraint* -OrConstraint::add() -{ +OrConstraint::add(UErrorCode& status) { + if (U_FAILURE(fInternalStatus)) { + status = fInternalStatus; + return nullptr; + } OrConstraint *curOrConstraint=this; { - while (curOrConstraint->next!=NULL) { + while (curOrConstraint->next!=nullptr) { curOrConstraint = curOrConstraint->next; } - U_ASSERT(curOrConstraint->childNode == NULL); + U_ASSERT(curOrConstraint->childNode == nullptr); curOrConstraint->childNode = new AndConstraint(); + if (curOrConstraint->childNode == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } } return curOrConstraint->childNode; } @@ -852,10 +899,10 @@ OrConstraint::isFulfilled(const IFixedDecimal &number) { OrConstraint* orRule=this; UBool result=FALSE; - while (orRule!=NULL && !result) { + while (orRule!=nullptr && !result) { result=TRUE; AndConstraint* andRule = orRule->childNode; - while (andRule!=NULL && result) { + while (andRule!=nullptr && result) { result = andRule->isFulfilled(number); andRule=andRule->next; } @@ -866,19 +913,33 @@ OrConstraint::isFulfilled(const IFixedDecimal &number) { } -RuleChain::RuleChain(): fKeyword(), fNext(NULL), ruleHeader(NULL), fDecimalSamples(), fIntegerSamples(), - fDecimalSamplesUnbounded(FALSE), fIntegerSamplesUnbounded(FALSE) { -} - RuleChain::RuleChain(const RuleChain& other) : - fKeyword(other.fKeyword), fNext(NULL), ruleHeader(NULL), fDecimalSamples(other.fDecimalSamples), + fKeyword(other.fKeyword), fDecimalSamples(other.fDecimalSamples), fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded), - fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded) { - if (other.ruleHeader != NULL) { + fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded), fInternalStatus(other.fInternalStatus) { + if (U_FAILURE(this->fInternalStatus)) { + return; // stop early if the object we are copying from is invalid. + } + if (other.ruleHeader != nullptr) { this->ruleHeader = new OrConstraint(*(other.ruleHeader)); + if (this->ruleHeader == nullptr) { + this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + } + else if (U_FAILURE(this->ruleHeader->fInternalStatus)) { + // If the OrConstraint wasn't fully copied, then set our status to failure as well. + this->fInternalStatus = this->ruleHeader->fInternalStatus; + return; // exit early. + } } - if (other.fNext != NULL ) { + if (other.fNext != nullptr ) { this->fNext = new RuleChain(*other.fNext); + if (this->fNext == nullptr) { + this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR; + } + else if (U_FAILURE(this->fNext->fInternalStatus)) { + // If the RuleChain wasn't fully copied, then set our status to failure as well. + this->fInternalStatus = this->fNext->fInternalStatus; + } } } @@ -887,11 +948,10 @@ RuleChain::~RuleChain() { delete ruleHeader; } - UnicodeString RuleChain::select(const IFixedDecimal &number) const { if (!number.isNaN() && !number.isInfinite()) { - for (const RuleChain *rules = this; rules != NULL; rules = rules->fNext) { + for (const RuleChain *rules = this; rules != nullptr; rules = rules->fNext) { if (rules->ruleHeader->isFulfilled(number)) { return rules->fKeyword; } @@ -923,17 +983,17 @@ void RuleChain::dumpRules(UnicodeString& result) { UChar digitString[16]; - if ( ruleHeader != NULL ) { + if ( ruleHeader != nullptr ) { result += fKeyword; result += COLON; result += SPACE; OrConstraint* orRule=ruleHeader; - while ( orRule != NULL ) { + while ( orRule != nullptr ) { AndConstraint* andRule=orRule->childNode; - while ( andRule != NULL ) { - if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) && (andRule->value == -1)) { + while ( andRule != nullptr ) { + if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) && (andRule->value == -1)) { // Empty Rules. - } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) ) { + } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) ) { result += tokenString(andRule->digitsType); result += UNICODE_STRING_SIMPLE(" is "); if (andRule->negated) { @@ -950,7 +1010,7 @@ RuleChain::dumpRules(UnicodeString& result) { uprv_itou(digitString,16, andRule->opNum,10,0); result += UnicodeString(digitString); } - if (andRule->rangeList==NULL) { + if (andRule->rangeList==nullptr) { if (andRule->negated) { result += UNICODE_STRING_SIMPLE(" is not "); uprv_itou(digitString,16, andRule->value,10,0); @@ -993,16 +1053,16 @@ RuleChain::dumpRules(UnicodeString& result) { } } } - if ( (andRule=andRule->next) != NULL) { + if ( (andRule=andRule->next) != nullptr) { result += UNICODE_STRING_SIMPLE(" and "); } } - if ( (orRule = orRule->next) != NULL ) { + if ( (orRule = orRule->next) != nullptr ) { result += UNICODE_STRING_SIMPLE(" or "); } } } - if ( fNext != NULL ) { + if ( fNext != nullptr ) { result += UNICODE_STRING_SIMPLE("; "); fNext->dumpRules(result); } @@ -1011,6 +1071,9 @@ RuleChain::dumpRules(UnicodeString& result) { UErrorCode RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const { + if (U_FAILURE(fInternalStatus)) { + return fInternalStatus; + } if ( arraySize < capacityOfKeywords-1 ) { keywords[arraySize++]=fKeyword; } @@ -1018,7 +1081,7 @@ RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int3 return U_BUFFER_OVERFLOW_ERROR; } - if ( fNext != NULL ) { + if ( fNext != nullptr ) { return fNext->getKeywords(capacityOfKeywords, keywords, arraySize); } else { @@ -1032,7 +1095,7 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const { return TRUE; } - if ( fNext != NULL ) { + if ( fNext != nullptr ) { return fNext->isKeyword(keywordParam); } else { @@ -1043,7 +1106,7 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const { PluralRuleParser::PluralRuleParser() : ruleIndex(0), token(), type(none), prevType(none), - curAndConstraint(NULL), currentChain(NULL), rangeLowIdx(-1), rangeHiIdx(-1) + curAndConstraint(nullptr), currentChain(nullptr), rangeLowIdx(-1), rangeHiIdx(-1) { } @@ -1341,21 +1404,36 @@ PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode return; } fKeywordNames.setDeleter(uprv_deleteUObject); - UBool addKeywordOther=TRUE; - RuleChain *node=header; - while(node!=NULL) { - fKeywordNames.addElement(new UnicodeString(node->fKeyword), status); + UBool addKeywordOther = TRUE; + RuleChain *node = header; + while (node != nullptr) { + auto newElem = new UnicodeString(node->fKeyword); + if (newElem == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + fKeywordNames.addElement(newElem, status); if (U_FAILURE(status)) { + delete newElem; return; } if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) { - addKeywordOther= FALSE; + addKeywordOther = FALSE; } - node=node->fNext; + node = node->fNext; } if (addKeywordOther) { - fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status); + auto newElem = new UnicodeString(PLURAL_KEYWORD_OTHER); + if (newElem == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + fKeywordNames.addElement(newElem, status); + if (U_FAILURE(status)) { + delete newElem; + return; + } } } @@ -1364,7 +1442,7 @@ PluralKeywordEnumeration::snext(UErrorCode& status) { if (U_SUCCESS(status) && pos < fKeywordNames.size()) { return (const UnicodeString*)fKeywordNames.elementAt(pos++); } - return NULL; + return nullptr; } void @@ -1374,7 +1452,7 @@ PluralKeywordEnumeration::reset(UErrorCode& /*status*/) { int32_t PluralKeywordEnumeration::count(UErrorCode& /*status*/) const { - return fKeywordNames.size(); + return fKeywordNames.size(); } PluralKeywordEnumeration::~PluralKeywordEnumeration() { @@ -1634,41 +1712,39 @@ int32_t FixedDecimal::getVisibleFractionDigitCount() const { PluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode &status) { - fLocales = NULL; - fRes = NULL; fOpenStatus = status; if (U_FAILURE(status)) { return; } - fOpenStatus = U_ZERO_ERROR; - LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &fOpenStatus)); - fLocales = ures_getByKey(rb.getAlias(), "locales", NULL, &fOpenStatus); + fOpenStatus = U_ZERO_ERROR; // clear any warnings. + LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &fOpenStatus)); + fLocales = ures_getByKey(rb.getAlias(), "locales", nullptr, &fOpenStatus); } PluralAvailableLocalesEnumeration::~PluralAvailableLocalesEnumeration() { ures_close(fLocales); ures_close(fRes); - fLocales = NULL; - fRes = NULL; + fLocales = nullptr; + fRes = nullptr; } const char *PluralAvailableLocalesEnumeration::next(int32_t *resultLength, UErrorCode &status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } if (U_FAILURE(fOpenStatus)) { status = fOpenStatus; - return NULL; + return nullptr; } fRes = ures_getNextResource(fLocales, fRes, &status); - if (fRes == NULL || U_FAILURE(status)) { + if (fRes == nullptr || U_FAILURE(status)) { if (status == U_INDEX_OUTOFBOUNDS_ERROR) { status = U_ZERO_ERROR; } - return NULL; + return nullptr; } const char *result = ures_getKey(fRes); - if (resultLength != NULL) { + if (resultLength != nullptr) { *resultLength = static_cast(uprv_strlen(result)); } return result; diff --git a/deps/icu-small/source/i18n/plurrule_impl.h b/deps/icu-small/source/i18n/plurrule_impl.h index 3ab445d5843c8b..f23ae168569d66 100644 --- a/deps/icu-small/source/i18n/plurrule_impl.h +++ b/deps/icu-small/source/i18n/plurrule_impl.h @@ -181,7 +181,6 @@ class PluralRuleParser: public UMemory { kRangeList, kSamples }; - }; enum PluralOperand { @@ -311,32 +310,36 @@ class AndConstraint : public UMemory { NONE, MOD } RuleOp; - RuleOp op; - int32_t opNum; // for mod expressions, the right operand of the mod. - int32_t value; // valid for 'is' rules only. - UVector32 *rangeList; // for 'in', 'within' rules. Null otherwise. - UBool negated; // TRUE for negated rules. - UBool integerOnly; // TRUE for 'within' rules. - tokenType digitsType; // n | i | v | f constraint. - AndConstraint *next; - - AndConstraint(); + RuleOp op = AndConstraint::NONE; + int32_t opNum = -1; // for mod expressions, the right operand of the mod. + int32_t value = -1; // valid for 'is' rules only. + UVector32 *rangeList = nullptr; // for 'in', 'within' rules. Null otherwise. + UBool negated = FALSE; // TRUE for negated rules. + UBool integerOnly = FALSE; // TRUE for 'within' rules. + tokenType digitsType = none; // n | i | v | f constraint. + AndConstraint *next = nullptr; + // Internal error status, used for errors that occur during the copy constructor. + UErrorCode fInternalStatus = U_ZERO_ERROR; + + AndConstraint() = default; AndConstraint(const AndConstraint& other); virtual ~AndConstraint(); - AndConstraint* add(); + AndConstraint* add(UErrorCode& status); // UBool isFulfilled(double number); UBool isFulfilled(const IFixedDecimal &number); }; class OrConstraint : public UMemory { public: - AndConstraint *childNode; - OrConstraint *next; - OrConstraint(); + AndConstraint *childNode = nullptr; + OrConstraint *next = nullptr; + // Internal error status, used for errors that occur during the copy constructor. + UErrorCode fInternalStatus = U_ZERO_ERROR; + OrConstraint() = default; OrConstraint(const OrConstraint& other); virtual ~OrConstraint(); - AndConstraint* add(); + AndConstraint* add(UErrorCode& status); // UBool isFulfilled(double number); UBool isFulfilled(const IFixedDecimal &number); }; @@ -344,15 +347,16 @@ class OrConstraint : public UMemory { class RuleChain : public UMemory { public: UnicodeString fKeyword; - RuleChain *fNext; - OrConstraint *ruleHeader; + RuleChain *fNext = nullptr; + OrConstraint *ruleHeader = nullptr; UnicodeString fDecimalSamples; // Samples strings from rule source UnicodeString fIntegerSamples; // without @decimal or @integer, otherwise unprocessed. - UBool fDecimalSamplesUnbounded; - UBool fIntegerSamplesUnbounded; - + UBool fDecimalSamplesUnbounded = FALSE; + UBool fIntegerSamplesUnbounded = FALSE; + // Internal error status, used for errors that occur during the copy constructor. + UErrorCode fInternalStatus = U_ZERO_ERROR; - RuleChain(); + RuleChain() = default; RuleChain(const RuleChain& other); virtual ~RuleChain(); @@ -386,8 +390,8 @@ class U_I18N_API PluralAvailableLocalesEnumeration: public StringEnumeration { virtual int32_t count(UErrorCode& status) const; private: UErrorCode fOpenStatus; - UResourceBundle *fLocales; - UResourceBundle *fRes; + UResourceBundle *fLocales = nullptr; + UResourceBundle *fRes = nullptr; }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/rbnf.cpp b/deps/icu-small/source/i18n/rbnf.cpp index ab9ad15e8c720d..74707ccd22d2ac 100644 --- a/deps/icu-small/source/i18n/rbnf.cpp +++ b/deps/icu-small/source/i18n/rbnf.cpp @@ -680,7 +680,7 @@ StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) c RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, const UnicodeString& locs, const Locale& alocale, UParseError& perror, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -689,7 +689,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -705,7 +705,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, const UnicodeString& locs, UParseError& perror, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -714,7 +714,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -730,7 +730,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, LocalizationInfo* info, const Locale& alocale, UParseError& perror, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -739,7 +739,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -754,7 +754,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, UParseError& perror, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -763,7 +763,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -779,7 +779,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, const Locale& aLocale, UParseError& perror, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -788,7 +788,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -801,7 +801,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, } RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status) - : ruleSets(NULL) + : fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -810,7 +810,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -868,7 +868,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs) : NumberFormat(rhs) - , ruleSets(NULL) + , fRuleSets(NULL) , ruleSetDescriptions(NULL) , numRuleSets(0) , defaultRuleSet(NULL) @@ -877,7 +877,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs) , decimalFormatSymbols(NULL) , defaultInfinityRule(NULL) , defaultNaNRule(NULL) - , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) + , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary) , lenient(FALSE) , lenientParseRules(NULL) , localizations(NULL) @@ -950,8 +950,8 @@ RuleBasedNumberFormat::operator==(const Format& other) const ? FALSE : *localizations == rhs.localizations))) { - NFRuleSet** p = ruleSets; - NFRuleSet** q = rhs.ruleSets; + NFRuleSet** p = fRuleSets; + NFRuleSet** q = rhs.fRuleSets; if (p == NULL) { return q == NULL; } else if (q == NULL) { @@ -972,8 +972,8 @@ UnicodeString RuleBasedNumberFormat::getRules() const { UnicodeString result; - if (ruleSets != NULL) { - for (NFRuleSet** p = ruleSets; *p; ++p) { + if (fRuleSets != NULL) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { (*p)->appendRules(result); } } @@ -987,9 +987,9 @@ RuleBasedNumberFormat::getRuleSetName(int32_t index) const UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1); return string; } - else if (ruleSets) { + else if (fRuleSets) { UnicodeString result; - for (NFRuleSet** p = ruleSets; *p; ++p) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { NFRuleSet* rs = *p; if (rs->isPublic()) { if (--index == -1) { @@ -1010,8 +1010,8 @@ RuleBasedNumberFormat::getNumberOfRuleSetNames() const if (localizations) { result = localizations->getNumberOfRuleSets(); } - else if (ruleSets) { - for (NFRuleSet** p = ruleSets; *p; ++p) { + else if (fRuleSets) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { if ((**p).isPublic()) { ++result; } @@ -1098,8 +1098,8 @@ RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, c NFRuleSet* RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const { - if (U_SUCCESS(status) && ruleSets) { - for (NFRuleSet** p = ruleSets; *p; ++p) { + if (U_SUCCESS(status) && fRuleSets) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { NFRuleSet* rs = *p; if (rs->isNamed(name)) { return rs; @@ -1132,11 +1132,17 @@ RuleBasedNumberFormat::format(const DecimalQuantity &number, // The DecimalFormat will provide more accurate results. // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. - NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); + LocalPointer decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status); + if (decimalFormat.isNull()) { + return appendTo; + } Formattable f; - f.adoptDecimalQuantity(new DecimalQuantity(number)); + LocalPointer decimalQuantity(new DecimalQuantity(number), status); + if (decimalQuantity.isNull()) { + return appendTo; + } + f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity. decimalFormat->format(f, appendTo, posIter, status); - delete decimalFormat; } } return appendTo; @@ -1165,11 +1171,17 @@ RuleBasedNumberFormat::format(const DecimalQuantity &number, // The DecimalFormat will provide more accurate results. // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. - NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); + LocalPointer decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status); + if (decimalFormat.isNull()) { + return appendTo; + } Formattable f; - f.adoptDecimalQuantity(new DecimalQuantity(number)); + LocalPointer decimalQuantity(new DecimalQuantity(number), status); + if (decimalQuantity.isNull()) { + return appendTo; + } + f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity. decimalFormat->format(f, appendTo, pos, status); - delete decimalFormat; } } return appendTo; @@ -1312,11 +1324,19 @@ RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); + if (decimalFormat == nullptr) { + return toAppendTo; + } Formattable f; FieldPosition pos(FieldPosition::DONT_CARE); - DecimalQuantity *digitList = new DecimalQuantity(); - digitList->setToLong(number); - f.adoptDecimalQuantity(digitList); + DecimalQuantity *decimalQuantity = new DecimalQuantity(); + if (decimalQuantity == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + delete decimalFormat; + return toAppendTo; + } + decimalQuantity->setToLong(number); + f.adoptDecimalQuantity(decimalQuantity); // f now owns decimalQuantity. decimalFormat->format(f, toAppendTo, pos, status); delete decimalFormat; } @@ -1358,7 +1378,7 @@ RuleBasedNumberFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const { - if (!ruleSets) { + if (!fRuleSets) { parsePosition.setErrorIndex(0); return; } @@ -1369,7 +1389,7 @@ RuleBasedNumberFormat::parse(const UnicodeString& text, ParsePosition high_pp(0); Formattable high_result; - for (NFRuleSet** p = ruleSets; *p; ++p) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { NFRuleSet *rp = *p; if (rp->isPublic() && rp->isParseable()) { ParsePosition working_pp(0); @@ -1457,7 +1477,7 @@ void RuleBasedNumberFormat::initDefaultRuleSet() { defaultRuleSet = NULL; - if (!ruleSets) { + if (!fRuleSets) { return; } @@ -1465,7 +1485,7 @@ RuleBasedNumberFormat::initDefaultRuleSet() const UnicodeString ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal")); const UnicodeString duration(UNICODE_STRING_SIMPLE("%duration")); - NFRuleSet**p = &ruleSets[0]; + NFRuleSet**p = &fRuleSets[0]; while (*p) { if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) { defaultRuleSet = *p; @@ -1477,7 +1497,7 @@ RuleBasedNumberFormat::initDefaultRuleSet() defaultRuleSet = *--p; if (!defaultRuleSet->isPublic()) { - while (p != ruleSets) { + while (p != fRuleSets) { if ((*--p)->isPublic()) { defaultRuleSet = *p; break; @@ -1547,7 +1567,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali // from the description lenientParseRules = new UnicodeString(); /* test for NULL */ - if (lenientParseRules == 0) { + if (lenientParseRules == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1568,15 +1588,15 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali ++numRuleSets; // our rule list is an array of the appropriate size - ruleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *)); + fRuleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *)); /* test for NULL */ - if (ruleSets == 0) { + if (fRuleSets == 0) { status = U_MEMORY_ALLOCATION_ERROR; return; } for (int i = 0; i <= numRuleSets; ++i) { - ruleSets[i] = NULL; + fRuleSets[i] = NULL; } // divide up the descriptions into individual rule-set descriptions @@ -1592,7 +1612,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali } ruleSetDescriptions = new UnicodeString[numRuleSets]; - if (ruleSetDescriptions == 0) { + if (ruleSetDescriptions == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1602,8 +1622,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali int32_t start = 0; for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) { ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start); - ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status); - if (ruleSets[curRuleSet] == 0) { + fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status); + if (fRuleSets[curRuleSet] == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1611,8 +1631,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali start = p + 1; } ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start); - ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status); - if (ruleSets[curRuleSet] == 0) { + fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status); + if (fRuleSets[curRuleSet] == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1630,11 +1650,11 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali initDefaultRuleSet(); // finally, we can go back through the temporary descriptions - // list and finish seting up the substructure (and we throw + // list and finish setting up the substructure (and we throw // away the temporary descriptions as we go) { for (int i = 0; i < numRuleSets; i++) { - ruleSets[i]->parseRules(ruleSetDescriptions[i], status); + fRuleSets[i]->parseRules(ruleSetDescriptions[i], status); } } @@ -1680,7 +1700,7 @@ RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status) if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) || (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) { - UErrorCode status = U_ZERO_ERROR; + status = U_ZERO_ERROR; capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status); if (U_FAILURE(status)) { delete capitalizationBrkIter; @@ -1704,8 +1724,8 @@ RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale) int32_t len = 0; const int32_t * intVector = ures_getIntVector(rb, &len, &status); if (U_SUCCESS(status) && intVector != NULL && len >= 2) { - capitalizationForUIListMenu = intVector[0]; - capitalizationForStandAlone = intVector[1]; + capitalizationForUIListMenu = static_cast(intVector[0]); + capitalizationForStandAlone = static_cast(intVector[1]); } } ures_close(rb); @@ -1740,7 +1760,7 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description) start = p + 1; } - // when we get here, we've seeked off the end of the sring, and + // when we get here, we've seeked off the end of the string, and // we terminate the loop (we continue until *start* is -1 rather // than until *p* is -1, because otherwise we'd miss the last // rule in the description) @@ -1756,12 +1776,12 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description) void RuleBasedNumberFormat::dispose() { - if (ruleSets) { - for (NFRuleSet** p = ruleSets; *p; ++p) { + if (fRuleSets) { + for (NFRuleSet** p = fRuleSets; *p; ++p) { delete *p; } - uprv_free(ruleSets); - ruleSets = NULL; + uprv_free(fRuleSets); + fRuleSets = NULL; } if (ruleSetDescriptions) { @@ -1811,7 +1831,7 @@ const RuleBasedCollator* RuleBasedNumberFormat::getCollator() const { #if !UCONFIG_NO_COLLATION - if (!ruleSets) { + if (!fRuleSets) { return NULL; } @@ -1820,7 +1840,7 @@ RuleBasedNumberFormat::getCollator() const // create a default collator based on the formatter's locale, // then pull out that collator's rules, append any additional // rules specified in the description, and create a _new_ - // collator based on the combinaiton of those rules + // collator based on the combination of those rules UErrorCode status = U_ZERO_ERROR; @@ -1863,13 +1883,10 @@ RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode &status) // lazy-evaluate the DecimalFormatSymbols object. This object // is shared by all DecimalFormat instances belonging to this // formatter - if (decimalFormatSymbols == NULL) { - DecimalFormatSymbols* temp = new DecimalFormatSymbols(locale, status); + if (decimalFormatSymbols == nullptr) { + LocalPointer temp(new DecimalFormatSymbols(locale, status), status); if (U_SUCCESS(status)) { - decimalFormatSymbols = temp; - } - else { - delete temp; + decimalFormatSymbols = temp.orphan(); } } return decimalFormatSymbols; @@ -1889,17 +1906,14 @@ NFRule* RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode &status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } if (defaultInfinityRule == NULL) { UnicodeString rule(UNICODE_STRING_SIMPLE("Inf: ")); rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol)); - NFRule* temp = new NFRule(this, rule, status); + LocalPointer temp(new NFRule(this, rule, status), status); if (U_SUCCESS(status)) { - defaultInfinityRule = temp; - } - else { - delete temp; + defaultInfinityRule = temp.orphan(); } } return defaultInfinityRule; @@ -1915,17 +1929,14 @@ NFRule* RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode &status) { if (U_FAILURE(status)) { - return NULL; + return nullptr; } - if (defaultNaNRule == NULL) { + if (defaultNaNRule == nullptr) { UnicodeString rule(UNICODE_STRING_SIMPLE("NaN: ")); rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol)); - NFRule* temp = new NFRule(this, rule, status); + LocalPointer temp(new NFRule(this, rule, status), status); if (U_SUCCESS(status)) { - defaultNaNRule = temp; - } - else { - delete temp; + defaultNaNRule = temp.orphan(); } } return defaultNaNRule; @@ -1963,15 +1974,15 @@ RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsTo defaultNaNRule = NULL; initializeDefaultNaNRule(status); // Reset with the new DecimalFormatSymbols - if (ruleSets) { + if (fRuleSets) { for (int32_t i = 0; i < numRuleSets; i++) { - ruleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status); + fRuleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status); } } } } -// Setting the symbols is equlivalent to adopting a newly created localized symbols. +// Setting the symbols is equivalent to adopting a newly created localized symbols. void RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) { @@ -1983,7 +1994,11 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType, const UnicodeString &pattern, UErrorCode& status) const { - return new PluralFormat(locale, pluralType, pattern, status); + auto *pf = new PluralFormat(locale, pluralType, pattern, status); + if (pf == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } + return pf; } /** @@ -1991,7 +2006,7 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType, * @return A rounding mode */ DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const { - return roundingMode; + return fRoundingMode; } /** @@ -2000,7 +2015,7 @@ DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const { * @param roundingMode A rounding mode */ void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) { - this->roundingMode = roundingMode; + fRoundingMode = roundingMode; } U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/rbt.h b/deps/icu-small/source/i18n/rbt.h index 005fb853847b11..a18452ab2ecb49 100644 --- a/deps/icu-small/source/i18n/rbt.h +++ b/deps/icu-small/source/i18n/rbt.h @@ -29,261 +29,9 @@ class TransliterationRuleData; /** * RuleBasedTransliterator is a transliterator - * that reads a set of rules in order to determine how to perform - * translations. Rule sets are stored in resource bundles indexed by - * name. Rules within a rule set are separated by semicolons (';'). - * To include a literal semicolon, prefix it with a backslash ('\'). - * Whitespace, as defined by Character.isWhitespace(), - * is ignored. If the first non-blank character on a line is '#', - * the entire line is ignored as a comment.

    - * - *

    Each set of rules consists of two groups, one forward, and one - * reverse. This is a convention that is not enforced; rules for one - * direction may be omitted, with the result that translations in - * that direction will not modify the source text. In addition, - * bidirectional forward-reverse rules may be specified for - * symmetrical transformations.

    - * - *

    Rule syntax

    - * - *

    Rule statements take one of the following forms:

    - * - *
    - *
    $alefmadda=\u0622;
    - *
    Variable definition. The name on the - * left is assigned the text on the right. In this example, - * after this statement, instances of the left hand name, - * "$alefmadda", will be replaced by - * the Unicode character U+0622. Variable names must begin - * with a letter and consist only of letters, digits, and - * underscores. Case is significant. Duplicate names cause - * an exception to be thrown, that is, variables cannot be - * redefined. The right hand side may contain well-formed - * text of any length, including no text at all ("$empty=;"). - * The right hand side may contain embedded UnicodeSet - * patterns, for example, "$softvowel=[eiyEIY]".
    - *
     
    - *
    ai>$alefmadda;
    - *
    Forward translation rule. This rule - * states that the string on the left will be changed to the - * string on the right when performing forward - * transliteration.
    - *
     
    - *
    ai<$alefmadda;
    - *
    Reverse translation rule. This rule - * states that the string on the right will be changed to - * the string on the left when performing reverse - * transliteration.
    - *
    - * - *
    - *
    ai<>$alefmadda;
    - *
    Bidirectional translation rule. This - * rule states that the string on the right will be changed - * to the string on the left when performing forward - * transliteration, and vice versa when performing reverse - * transliteration.
    - *
    - * - *

    Translation rules consist of a match pattern and an output - * string. The match pattern consists of literal characters, - * optionally preceded by context, and optionally followed by - * context. Context characters, like literal pattern characters, - * must be matched in the text being transliterated. However, unlike - * literal pattern characters, they are not replaced by the output - * text. For example, the pattern "abc{def}" - * indicates the characters "def" must be - * preceded by "abc" for a successful match. - * If there is a successful match, "def" will - * be replaced, but not "abc". The final '}' - * is optional, so "abc{def" is equivalent to - * "abc{def}". Another example is "{123}456" - * (or "123}456") in which the literal - * pattern "123" must be followed by "456". - *

    - * - *

    The output string of a forward or reverse rule consists of - * characters to replace the literal pattern characters. If the - * output string contains the character '|', this is - * taken to indicate the location of the cursor after - * replacement. The cursor is the point in the text at which the - * next replacement, if any, will be applied. The cursor is usually - * placed within the replacement text; however, it can actually be - * placed into the precending or following context by using the - * special character '@'. Examples:

    - * - *
    - *

    a {foo} z > | @ bar; # foo -> bar, move cursor - * before a
    - * {foo} xyz > bar @@|; # foo -> bar, cursor between - * y and z

    - *
    - * - *

    UnicodeSet

    - * - *

    UnicodeSet patterns may appear anywhere that - * makes sense. They may appear in variable definitions. - * Contrariwise, UnicodeSet patterns may themselves - * contain variable references, such as "$a=[a-z];$not_a=[^$a]", - * or "$range=a-z;$ll=[$range]".

    - * - *

    UnicodeSet patterns may also be embedded directly - * into rule strings. Thus, the following two rules are equivalent:

    - * - *
    - *

    $vowel=[aeiou]; $vowel>'*'; # One way to do this
    - * [aeiou]>'*'; - *                # - * Another way

    - *
    - * - *

    See {@link UnicodeSet} for more documentation and examples.

    - * - *

    Segments

    - * - *

    Segments of the input string can be matched and copied to the - * output string. This makes certain sets of rules simpler and more - * general, and makes reordering possible. For example:

    - * - *
    - *

    ([a-z]) > $1 $1; - *           # - * double lowercase letters
    - * ([:Lu:]) ([:Ll:]) > $2 $1; # reverse order of Lu-Ll pairs

    - *
    - * - *

    The segment of the input string to be copied is delimited by - * "(" and ")". Up to - * nine segments may be defined. Segments may not overlap. In the - * output string, "$1" through "$9" - * represent the input string segments, in left-to-right order of - * definition.

    - * - *

    Anchors

    - * - *

    Patterns can be anchored to the beginning or the end of the text. This is done with the - * special characters '^' and '$'. For example:

    - * - *
    - *

    ^ a   > 'BEG_A';   # match 'a' at start of text
    - *   a   > 'A';       # match other instances - * of 'a'
    - *   z $ > 'END_Z';   # match 'z' at end of text
    - *   z   > 'Z';       # match other instances - * of 'z'

    - *
    - * - *

    It is also possible to match the beginning or the end of the text using a UnicodeSet. - * This is done by including a virtual anchor character '$' at the end of the - * set pattern. Although this is usually the match chafacter for the end anchor, the set will - * match either the beginning or the end of the text, depending on its placement. For - * example:

    - * - *
    - *

    $x = [a-z$];   # match 'a' through 'z' OR anchor
    - * $x 1    > 2;   # match '1' after a-z or at the start
    - *    3 $x > 4;   # match '3' before a-z or at the end

    - *
    - * - *

    Example

    - * - *

    The following example rules illustrate many of the features of - * the rule language.

    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    Rule 1.abc{def}>x|y
    Rule 2.xyz>r
    Rule 3.yz>q
    - * - *

    Applying these rules to the string "adefabcdefz" - * yields the following results:

    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    |adefabcdefzInitial state, no rules match. Advance - * cursor.
    a|defabcdefzStill no match. Rule 1 does not match - * because the preceding context is not present.
    ad|efabcdefzStill no match. Keep advancing until - * there is a match...
    ade|fabcdefz...
    adef|abcdefz...
    adefa|bcdefz...
    adefab|cdefz...
    adefabc|defzRule 1 matches; replace "def" - * with "xy" and back up the cursor - * to before the 'y'.
    adefabcx|yzAlthough "xyz" is - * present, rule 2 does not match because the cursor is - * before the 'y', not before the 'x'. - * Rule 3 does match. Replace "yz" - * with "q".
    adefabcxq|The cursor is at the end; - * transliteration is complete.
    - * - *

    The order of rules is significant. If multiple rules may match - * at some point, the first matching rule is applied.

    - * - *

    Forward and reverse rules may have an empty output string. - * Otherwise, an empty left or right hand side of any statement is a - * syntax error.

    - * - *

    Single quotes are used to quote any character other than a - * digit or letter. To specify a single quote itself, inside or - * outside of quotes, use two single quotes in a row. For example, - * the rule "'>'>o''clock" changes the - * string ">" to the string "o'clock". - *

    - * - *

    Notes

    - * - *

    While a RuleBasedTransliterator is being built, it checks that - * the rules are added in proper order. For example, if the rule - * "a>x" is followed by the rule "ab>y", - * then the second rule will throw an exception. The reason is that - * the second rule can never be triggered, since the first rule - * always matches anything it matches. In other words, the first - * rule masks the second rule.

    + * built from a set of rules as defined for + * Transliterator::createFromRules(). + * See the C++ class Transliterator documentation for the rule syntax. * * @author Alan Liu * @internal Use transliterator factory methods instead since this class will be removed in that release. diff --git a/deps/icu-small/source/i18n/rbt_pars.cpp b/deps/icu-small/source/i18n/rbt_pars.cpp index 8e49a8473a5ab0..e07cc8b63a408c 100644 --- a/deps/icu-small/source/i18n/rbt_pars.cpp +++ b/deps/icu-small/source/i18n/rbt_pars.cpp @@ -194,9 +194,9 @@ const UnicodeFunctor* ParseData::lookupMatcher(UChar32 ch) const { const UnicodeFunctor* set = NULL; int32_t i = ch - data->variablesBase; if (i >= 0 && i < variablesVector->size()) { - int32_t i = ch - data->variablesBase; - set = (i < variablesVector->size()) ? - (UnicodeFunctor*) variablesVector->elementAt(i) : 0; + int32_t j = ch - data->variablesBase; + set = (j < variablesVector->size()) ? + (UnicodeFunctor*) variablesVector->elementAt(j) : 0; } return set; } @@ -1108,8 +1108,8 @@ void TransliteratorParser::parseRules(const UnicodeString& rule, } data->variableNames.removeAll(); - int32_t pos = UHASH_FIRST; - const UHashElement* he = variableNames.nextElement(pos); + int32_t p = UHASH_FIRST; + const UHashElement* he = variableNames.nextElement(p); while (he != NULL) { UnicodeString* tempus = (UnicodeString*)(((UnicodeString*)(he->value.pointer))->clone()); if (tempus == NULL) { @@ -1118,7 +1118,7 @@ void TransliteratorParser::parseRules(const UnicodeString& rule, } data->variableNames.put(*((UnicodeString*)(he->key.pointer)), tempus, status); - he = variableNames.nextElement(pos); + he = variableNames.nextElement(p); } } variablesVector.removeAllElements(); // keeps them from getting deleted when we succeed diff --git a/deps/icu-small/source/i18n/regexcmp.cpp b/deps/icu-small/source/i18n/regexcmp.cpp index 410ff9513bb82a..0c5fca6f67b3f9 100644 --- a/deps/icu-small/source/i18n/regexcmp.cpp +++ b/deps/icu-small/source/i18n/regexcmp.cpp @@ -28,6 +28,7 @@ #include "patternprops.h" #include "putilimp.h" #include "cmemory.h" +#include "cstr.h" #include "cstring.h" #include "uvectr32.h" #include "uvectr64.h" @@ -3892,7 +3893,7 @@ void RegexCompile::stripNOPs() { // //------------------------------------------------------------------------------ void RegexCompile::error(UErrorCode e) { - if (U_SUCCESS(*fStatus)) { + if (U_SUCCESS(*fStatus) || e == U_MEMORY_ALLOCATION_ERROR) { *fStatus = e; // Hmm. fParseErr (UParseError) line & offset fields are int32_t in public // API (see common/unicode/parseerr.h), while fLineNum and fCharNum are @@ -4370,209 +4371,209 @@ static inline void addIdentifierIgnorable(UnicodeSet *set, UErrorCode& ec) { // Includes trying the Java "properties" that aren't supported as // normal ICU UnicodeSet properties // -static const UChar posSetPrefix[] = {0x5b, 0x5c, 0x70, 0x7b, 0}; // "[\p{" -static const UChar negSetPrefix[] = {0x5b, 0x5c, 0x50, 0x7b, 0}; // "[\P{" UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UBool negated) { - UnicodeString setExpr; - UnicodeSet *set; - uint32_t usetFlags = 0; if (U_FAILURE(*fStatus)) { - return NULL; + return nullptr; } + LocalPointer set; + UErrorCode status = U_ZERO_ERROR; - // - // First try the property as we received it - // - if (negated) { - setExpr.append(negSetPrefix, -1); - } else { - setExpr.append(posSetPrefix, -1); - } - setExpr.append(propName); - setExpr.append(chRBrace); - setExpr.append(chRBracket); - if (fModeFlags & UREGEX_CASE_INSENSITIVE) { - usetFlags |= USET_CASE_INSENSITIVE; - } - set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus); - if (U_SUCCESS(*fStatus)) { - return set; - } - delete set; - set = NULL; - - // - // The property as it was didn't work. - - // Do [:word:]. It is not recognized as a property by UnicodeSet. "word" not standard POSIX - // or standard Java, but many other regular expression packages do recognize it. - - if (propName.caseCompare(UNICODE_STRING_SIMPLE("word"), 0) == 0) { - *fStatus = U_ZERO_ERROR; - set = new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET])); - if (set == NULL) { - *fStatus = U_MEMORY_ALLOCATION_ERROR; - return set; + do { // non-loop, exists to allow breaks from the block. + // + // First try the property as we received it + // + UnicodeString setExpr; + uint32_t usetFlags = 0; + setExpr.append(u"[\\p{", -1); + setExpr.append(propName); + setExpr.append(u"}]", -1); + if (fModeFlags & UREGEX_CASE_INSENSITIVE) { + usetFlags |= USET_CASE_INSENSITIVE; } - if (negated) { - set->complement(); + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(setExpr, usetFlags, NULL, status), status); + if (U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) { + break; } - return set; - } + // + // The incoming property wasn't directly recognized by ICU. - // Do Java fixes - - // InGreek -> InGreek or Coptic, that being the official Unicode name for that block. - // InCombiningMarksforSymbols -> InCombiningDiacriticalMarksforSymbols. - // - // Note on Spaces: either "InCombiningMarksForSymbols" or "InCombining Marks for Symbols" - // is accepted by Java. The property part of the name is compared - // case-insenstively. The spaces must be exactly as shown, either - // all there, or all omitted, with exactly one at each position - // if they are present. From checking against JDK 1.6 - // - // This code should be removed when ICU properties support the Java compatibility names - // (ICU 4.0?) - // - UnicodeString mPropName = propName; - if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InGreek"), 0) == 0) { - mPropName = UNICODE_STRING_SIMPLE("InGreek and Coptic"); - } - if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombining Marks for Symbols"), 0) == 0 || - mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombiningMarksforSymbols"), 0) == 0) { - mPropName = UNICODE_STRING_SIMPLE("InCombining Diacritical Marks for Symbols"); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) { - mPropName = UNICODE_STRING_SIMPLE("javaValidCodePoint"); - } + // Check [:word:] and [:all:]. These are not recognized as a properties by ICU UnicodeSet. + // Java accepts 'word' with mixed case. + // Java accepts 'all' only in all lower case. - // See if the property looks like a Java "InBlockName", which - // we will recast as "Block=BlockName" - // - if (mPropName.startsWith(u"In", 2) && propName.length()>=3) { - setExpr.truncate(4); // Leaves "[\p{", or "[\P{" - setExpr.append(u"Block=", -1); - setExpr.append(UnicodeString(mPropName, 2)); // Property with the leading "In" removed. - setExpr.append(chRBrace); - setExpr.append(chRBracket); - *fStatus = U_ZERO_ERROR; - set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus); - if (U_SUCCESS(*fStatus)) { - return set; + status = U_ZERO_ERROR; + if (propName.caseCompare(u"word", -1, 0) == 0) { + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET])), status); + break; + } + if (propName.compare(u"all", -1) == 0) { + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(0, 0x10ffff), status); + break; } - delete set; - set = NULL; - } - if (propName.startsWith(UNICODE_STRING_SIMPLE("java")) || - propName.compare(UNICODE_STRING_SIMPLE("all")) == 0) - { - UErrorCode localStatus = U_ZERO_ERROR; - //setExpr.remove(); - set = new UnicodeSet(); - // - // Try the various Java specific properties. - // These all begin with "java" + + // Do Java InBlock expressions // - if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDefined")) == 0) { - addCategory(set, U_GC_CN_MASK, localStatus); - set->complement(); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDigit")) == 0) { - addCategory(set, U_GC_ND_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaIdentifierIgnorable")) == 0) { - addIdentifierIgnorable(set, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaISOControl")) == 0) { - set->add(0, 0x1F).add(0x7F, 0x9F); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierPart")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - addCategory(set, U_GC_SC_MASK, localStatus); - addCategory(set, U_GC_PC_MASK, localStatus); - addCategory(set, U_GC_ND_MASK, localStatus); - addCategory(set, U_GC_NL_MASK, localStatus); - addCategory(set, U_GC_MC_MASK, localStatus); - addCategory(set, U_GC_MN_MASK, localStatus); - addIdentifierIgnorable(set, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierStart")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - addCategory(set, U_GC_NL_MASK, localStatus); - addCategory(set, U_GC_SC_MASK, localStatus); - addCategory(set, U_GC_PC_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetter")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetterOrDigit")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - addCategory(set, U_GC_ND_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLowerCase")) == 0) { - addCategory(set, U_GC_LL_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaMirrored")) == 0) { - set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSpaceChar")) == 0) { - addCategory(set, U_GC_Z_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSupplementaryCodePoint")) == 0) { - set->add(0x10000, UnicodeSet::MAX_VALUE); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaTitleCase")) == 0) { - addCategory(set, U_GC_LT_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierStart")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - addCategory(set, U_GC_NL_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierPart")) == 0) { - addCategory(set, U_GC_L_MASK, localStatus); - addCategory(set, U_GC_PC_MASK, localStatus); - addCategory(set, U_GC_ND_MASK, localStatus); - addCategory(set, U_GC_NL_MASK, localStatus); - addCategory(set, U_GC_MC_MASK, localStatus); - addCategory(set, U_GC_MN_MASK, localStatus); - addIdentifierIgnorable(set, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUpperCase")) == 0) { - addCategory(set, U_GC_LU_MASK, localStatus); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaValidCodePoint")) == 0) { - set->add(0, UnicodeSet::MAX_VALUE); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaWhitespace")) == 0) { - addCategory(set, U_GC_Z_MASK, localStatus); - set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f)); - set->add(9, 0x0d).add(0x1c, 0x1f); - } - else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) { - set->add(0, UnicodeSet::MAX_VALUE); + UnicodeString mPropName = propName; + if (mPropName.startsWith(u"In", 2) && mPropName.length() >= 3) { + status = U_ZERO_ERROR; + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status); + if (U_FAILURE(status)) { + break; + } + UnicodeString blockName(mPropName, 2); // Property with the leading "In" removed. + set->applyPropertyAlias(UnicodeString(u"Block"), blockName, status); + break; } - if (U_SUCCESS(localStatus) && !set->isEmpty()) { - *fStatus = U_ZERO_ERROR; - if (usetFlags & USET_CASE_INSENSITIVE) { + // Check for the Java form "IsBooleanPropertyValue", which we will recast + // as "BooleanPropertyValue". The property value can be either a + // a General Category or a Script Name. + + if (propName.startsWith(u"Is", 2) && propName.length()>=3) { + mPropName.remove(0, 2); // Strip the "Is" + if (mPropName.indexOf(u'=') >= 0) { + // Reject any "Is..." property expression containing an '=', that is, + // any non-binary property expression. + status = U_REGEX_PROPERTY_SYNTAX; + break; + } + + if (mPropName.caseCompare(u"assigned", -1, 0) == 0) { + mPropName.setTo(u"unassigned", -1); + negated = !negated; + } else if (mPropName.caseCompare(u"TitleCase", -1, 0) == 0) { + mPropName.setTo(u"Titlecase_Letter", -1); + } + + mPropName.insert(0, u"[\\p{", -1); + mPropName.append(u"}]", -1); + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(mPropName, *fStatus), status); + + if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) { set->closeOver(USET_CASE_INSENSITIVE); } - if (negated) { + break; + + } + + if (propName.startsWith(u"java", -1)) { + status = U_ZERO_ERROR; + set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status); + if (U_FAILURE(status)) { + break; + } + // + // Try the various Java specific properties. + // These all begin with "java" + // + if (propName.compare(u"javaDefined", -1) == 0) { + addCategory(set.getAlias(), U_GC_CN_MASK, status); set->complement(); } - return set; + else if (propName.compare(u"javaDigit", -1) == 0) { + addCategory(set.getAlias(), U_GC_ND_MASK, status); + } + else if (propName.compare(u"javaIdentifierIgnorable", -1) == 0) { + addIdentifierIgnorable(set.getAlias(), status); + } + else if (propName.compare(u"javaISOControl", -1) == 0) { + set->add(0, 0x1F).add(0x7F, 0x9F); + } + else if (propName.compare(u"javaJavaIdentifierPart", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + addCategory(set.getAlias(), U_GC_SC_MASK, status); + addCategory(set.getAlias(), U_GC_PC_MASK, status); + addCategory(set.getAlias(), U_GC_ND_MASK, status); + addCategory(set.getAlias(), U_GC_NL_MASK, status); + addCategory(set.getAlias(), U_GC_MC_MASK, status); + addCategory(set.getAlias(), U_GC_MN_MASK, status); + addIdentifierIgnorable(set.getAlias(), status); + } + else if (propName.compare(u"javaJavaIdentifierStart", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + addCategory(set.getAlias(), U_GC_NL_MASK, status); + addCategory(set.getAlias(), U_GC_SC_MASK, status); + addCategory(set.getAlias(), U_GC_PC_MASK, status); + } + else if (propName.compare(u"javaLetter", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + } + else if (propName.compare(u"javaLetterOrDigit", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + addCategory(set.getAlias(), U_GC_ND_MASK, status); + } + else if (propName.compare(u"javaLowerCase", -1) == 0) { + addCategory(set.getAlias(), U_GC_LL_MASK, status); + } + else if (propName.compare(u"javaMirrored", -1) == 0) { + set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, status); + } + else if (propName.compare(u"javaSpaceChar", -1) == 0) { + addCategory(set.getAlias(), U_GC_Z_MASK, status); + } + else if (propName.compare(u"javaSupplementaryCodePoint", -1) == 0) { + set->add(0x10000, UnicodeSet::MAX_VALUE); + } + else if (propName.compare(u"javaTitleCase", -1) == 0) { + addCategory(set.getAlias(), U_GC_LT_MASK, status); + } + else if (propName.compare(u"javaUnicodeIdentifierStart", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + addCategory(set.getAlias(), U_GC_NL_MASK, status); + } + else if (propName.compare(u"javaUnicodeIdentifierPart", -1) == 0) { + addCategory(set.getAlias(), U_GC_L_MASK, status); + addCategory(set.getAlias(), U_GC_PC_MASK, status); + addCategory(set.getAlias(), U_GC_ND_MASK, status); + addCategory(set.getAlias(), U_GC_NL_MASK, status); + addCategory(set.getAlias(), U_GC_MC_MASK, status); + addCategory(set.getAlias(), U_GC_MN_MASK, status); + addIdentifierIgnorable(set.getAlias(), status); + } + else if (propName.compare(u"javaUpperCase", -1) == 0) { + addCategory(set.getAlias(), U_GC_LU_MASK, status); + } + else if (propName.compare(u"javaValidCodePoint", -1) == 0) { + set->add(0, UnicodeSet::MAX_VALUE); + } + else if (propName.compare(u"javaWhitespace", -1) == 0) { + addCategory(set.getAlias(), U_GC_Z_MASK, status); + set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f)); + set->add(9, 0x0d).add(0x1c, 0x1f); + } else { + status = U_REGEX_PROPERTY_SYNTAX; + } + + if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) { + set->closeOver(USET_CASE_INSENSITIVE); + } + break; + } + + // Unrecognized property. ICU didn't like it as it was, and none of the Java compatibility + // extensions matched it. + status = U_REGEX_PROPERTY_SYNTAX; + } while (false); // End of do loop block. Code above breaks out of the block on success or hard failure. + + if (U_SUCCESS(status)) { + U_ASSERT(set.isValid()); + if (negated) { + set->complement(); } - delete set; - set = NULL; + return set.orphan(); + } else { + if (status == U_ILLEGAL_ARGUMENT_ERROR) { + status = U_REGEX_PROPERTY_SYNTAX; + } + error(status); + return nullptr; } - error(*fStatus); - return NULL; } - // // SetEval Part of the evaluation of [set expressions]. // Perform any pending (stacked) operations with precedence diff --git a/deps/icu-small/source/i18n/region.cpp b/deps/icu-small/source/i18n/region.cpp index 66f9ef35ded9ee..f182f61486e6d3 100644 --- a/deps/icu-small/source/i18n/region.cpp +++ b/deps/icu-small/source/i18n/region.cpp @@ -168,10 +168,18 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { continents->addElement(continentName,status); } + UResourceBundle *groupingBundle = nullptr; while ( ures_hasNext(groupingContainment.getAlias()) ) { - UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment.getAlias(),NULL,&status)); - groupings->addElement(groupingName,status); + groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status); + if (U_FAILURE(status)) { + break; + } + UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV); + if (groupingName) { + groupings->addElement(groupingName,status); + } } + ures_close(groupingBundle); for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) { LocalPointer r(new Region(), status); @@ -182,7 +190,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { r->idStr = *regionName; r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV); - r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known. + r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known. Formattable result; UErrorCode ps = U_ZERO_ERROR; @@ -190,7 +198,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { if ( U_SUCCESS(ps) ) { r->code = result.getLong(); // Convert string to number uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status); - r->type = URGN_SUBCONTINENT; + r->fType = URGN_SUBCONTINENT; } else { r->code = -1; } @@ -231,9 +239,9 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { } else { aliasFromRegion->code = -1; } - aliasFromRegion->type = URGN_DEPRECATED; + aliasFromRegion->fType = URGN_DEPRECATED; } else { - aliasFromRegion->type = URGN_DEPRECATED; + aliasFromRegion->fType = URGN_DEPRECATED; } { @@ -290,26 +298,26 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { UnicodeString WORLD_ID_STRING(WORLD_ID); r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&WORLD_ID_STRING); if ( r ) { - r->type = URGN_WORLD; + r->fType = URGN_WORLD; } UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID); r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING); if ( r ) { - r->type = URGN_UNKNOWN; + r->fType = URGN_UNKNOWN; } for ( int32_t i = 0 ; i < continents->size() ; i++ ) { r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)continents->elementAt(i)); if ( r ) { - r->type = URGN_CONTINENT; + r->fType = URGN_CONTINENT; } } for ( int32_t i = 0 ; i < groupings->size() ; i++ ) { r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)groupings->elementAt(i)); if ( r ) { - r->type = URGN_GROUPING; + r->fType = URGN_GROUPING; } } @@ -319,7 +327,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID); r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING); if ( r ) { - r->type = URGN_SUBCONTINENT; + r->fType = URGN_SUBCONTINENT; } // Load territory containment info from the supplemental data. @@ -356,7 +364,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { // Set the parent region to be the containing region of the child. // Regions of type GROUPING can't be set as the parent, since another region // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent. - if ( parentRegion->type != URGN_GROUPING) { + if ( parentRegion->fType != URGN_GROUPING) { childRegion->containingRegion = parentRegion; } } @@ -367,15 +375,15 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) { int32_t pos = UHASH_FIRST; while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) { Region *ar = (Region *)element->value.pointer; - if ( availableRegions[ar->type] == NULL ) { + if ( availableRegions[ar->fType] == NULL ) { LocalPointer newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status); - availableRegions[ar->type] = newAr.orphan(); + availableRegions[ar->fType] = newAr.orphan(); } LocalPointer arString(new UnicodeString(ar->idStr), status); if( U_FAILURE(status) ) { return; // error out } - availableRegions[ar->type]->addElement((void *)arString.orphan(),status); + availableRegions[ar->fType]->addElement((void *)arString.orphan(),status); } ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup); @@ -416,7 +424,7 @@ void Region::cleanupRegionData() { Region::Region () : code(-1), - type(URGN_UNKNOWN), + fType(URGN_UNKNOWN), containingRegion(NULL), containedRegions(NULL), preferredValues(NULL) { @@ -481,7 +489,7 @@ Region::getInstance(const char *region_code, UErrorCode &status) { return NULL; } - if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { + if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) { StringEnumeration *pv = r->getPreferredValues(status); pv->reset(status); const UnicodeString *ustr = pv->snext(status); @@ -529,7 +537,7 @@ Region::getInstance (int32_t code, UErrorCode &status) { return NULL; } - if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) { + if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) { StringEnumeration *pv = r->getPreferredValues(status); pv->reset(status); const UnicodeString *ustr = pv->snext(status); @@ -580,7 +588,7 @@ Region::getContainingRegion(URegionType type) const { return NULL; } - return ( containingRegion->type == type )? containingRegion: containingRegion->getContainingRegion(type); + return ( containingRegion->fType == type)? containingRegion: containingRegion->getContainingRegion(type); } /** @@ -618,9 +626,9 @@ Region::getContainedRegions( URegionType type, UErrorCode &status ) const { StringEnumeration *cr = getContainedRegions(status); for ( int32_t i = 0 ; i < cr->count(status) ; i++ ) { - const char *id = cr->next(NULL,status); - const Region *r = Region::getInstance(id,status); - if ( r->getType() == type ) { + const char *regionId = cr->next(NULL,status); + const Region *r = Region::getInstance(regionId,status); + if ( r->getType() == type) { result->addElement((void *)&r->idStr,status); } else { StringEnumeration *children = r->getContainedRegions(type, status); @@ -672,7 +680,7 @@ Region::contains(const Region &other) const { StringEnumeration* Region::getPreferredValues(UErrorCode &status) const { umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status) - if (U_FAILURE(status) || type != URGN_DEPRECATED) { + if (U_FAILURE(status) || fType != URGN_DEPRECATED) { return NULL; } return new RegionNameEnumeration(preferredValues,status); @@ -697,7 +705,7 @@ Region::getNumericCode() const { */ URegionType Region::getType() const { - return type; + return fType; } RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) { diff --git a/deps/icu-small/source/i18n/reldatefmt.cpp b/deps/icu-small/source/i18n/reldatefmt.cpp index 42ede7ae4d9903..ae251ed20b46a3 100644 --- a/deps/icu-small/source/i18n/reldatefmt.cpp +++ b/deps/icu-small/source/i18n/reldatefmt.cpp @@ -51,13 +51,13 @@ U_NAMESPACE_BEGIN // RelativeDateTimeFormatter specific data for a single locale class RelativeDateTimeCacheData: public SharedObject { public: - RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { + RelativeDateTimeCacheData() : combinedDateAndTime(nullptr) { // Initialize the cache arrays for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { - for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) { + for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) { for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) { - relativeUnitsFormatters[style][relUnit][0][pl] = NULL; - relativeUnitsFormatters[style][relUnit][1][pl] = NULL; + relativeUnitsFormatters[style][relUnit][0][pl] = nullptr; + relativeUnitsFormatters[style][relUnit][1][pl] = nullptr; } } } @@ -74,7 +74,7 @@ class RelativeDateTimeCacheData: public SharedObject { // e.g., Next Tuesday; Yesterday; etc. For third index, 0 // means past, e.g., 5 days ago; 1 means future, e.g., in 5 days. SimpleFormatter *relativeUnitsFormatters[UDAT_STYLE_COUNT] - [UDAT_RELATIVE_UNIT_COUNT][2][StandardPlural::COUNT]; + [UDAT_REL_UNIT_COUNT][2][StandardPlural::COUNT]; const UnicodeString& getAbsoluteUnitString(int32_t fStyle, UDateAbsoluteUnit unit, @@ -83,6 +83,10 @@ class RelativeDateTimeCacheData: public SharedObject { UDateRelativeUnit unit, int32_t pastFutureIndex, int32_t pluralUnit) const; + const SimpleFormatter* getRelativeDateTimeUnitFormatter(int32_t fStyle, + URelativeDateTimeUnit unit, + int32_t pastFutureIndex, + int32_t pluralUnit) const; const UnicodeString emptyString; @@ -107,7 +111,7 @@ class RelativeDateTimeCacheData: public SharedObject { RelativeDateTimeCacheData::~RelativeDateTimeCacheData() { // clear out the cache arrays for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { - for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) { + for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) { for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) { delete relativeUnitsFormatters[style][relUnit][0][pl]; delete relativeUnitsFormatters[style][relUnit][1][pl]; @@ -131,20 +135,41 @@ const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString( return emptyString; } - // Use fallback cache for SimpleFormatter relativeUnits. const SimpleFormatter* RelativeDateTimeCacheData::getRelativeUnitFormatter( int32_t fStyle, UDateRelativeUnit unit, int32_t pastFutureIndex, int32_t pluralUnit) const { + URelativeDateTimeUnit rdtunit = UDAT_REL_UNIT_COUNT; + switch (unit) { + case UDAT_RELATIVE_YEARS: rdtunit = UDAT_REL_UNIT_YEAR; break; + case UDAT_RELATIVE_MONTHS: rdtunit = UDAT_REL_UNIT_MONTH; break; + case UDAT_RELATIVE_WEEKS: rdtunit = UDAT_REL_UNIT_WEEK; break; + case UDAT_RELATIVE_DAYS: rdtunit = UDAT_REL_UNIT_DAY; break; + case UDAT_RELATIVE_HOURS: rdtunit = UDAT_REL_UNIT_HOUR; break; + case UDAT_RELATIVE_MINUTES: rdtunit = UDAT_REL_UNIT_MINUTE; break; + case UDAT_RELATIVE_SECONDS: rdtunit = UDAT_REL_UNIT_SECOND; break; + default: // a unit that the above method does not handle + return nullptr; + } + + return getRelativeDateTimeUnitFormatter(fStyle, rdtunit, pastFutureIndex, pluralUnit); + } + + // Use fallback cache for SimpleFormatter relativeUnits. + const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter( + int32_t fStyle, + URelativeDateTimeUnit unit, + int32_t pastFutureIndex, + int32_t pluralUnit) const { int32_t style = fStyle; do { - if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != NULL) { + if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) { return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit]; } style = fallBackCache[style]; } while (style != -1); - return NULL; // No formatter found. + return nullptr; // No formatter found. } static UBool getStringWithFallback( @@ -217,23 +242,35 @@ struct RelDateTimeFmtDataSink : public ResourceSink { // Converts the generic units to UDAT_RELATIVE version. switch (genUnit) { case SECOND: - return UDAT_RELATIVE_SECONDS; + return UDAT_REL_UNIT_SECOND; case MINUTE: - return UDAT_RELATIVE_MINUTES; + return UDAT_REL_UNIT_MINUTE; case HOUR: - return UDAT_RELATIVE_HOURS; + return UDAT_REL_UNIT_HOUR; case DAY: - return UDAT_RELATIVE_DAYS; + return UDAT_REL_UNIT_DAY; case WEEK: - return UDAT_RELATIVE_WEEKS; + return UDAT_REL_UNIT_WEEK; case MONTH: - return UDAT_RELATIVE_MONTHS; - /* - * case QUARTER: - * return UDATE_RELATIVE_QUARTERS; - */ + return UDAT_REL_UNIT_MONTH; + case QUARTER: + return UDAT_REL_UNIT_QUARTER; case YEAR: - return UDAT_RELATIVE_YEARS; + return UDAT_REL_UNIT_YEAR; + case SUNDAY: + return UDAT_REL_UNIT_SUNDAY; + case MONDAY: + return UDAT_REL_UNIT_MONDAY; + case TUESDAY: + return UDAT_REL_UNIT_TUESDAY; + case WEDNESDAY: + return UDAT_REL_UNIT_WEDNESDAY; + case THURSDAY: + return UDAT_REL_UNIT_THURSDAY; + case FRIDAY: + return UDAT_REL_UNIT_FRIDAY; + case SATURDAY: + return UDAT_REL_UNIT_SATURDAY; default: return -1; } @@ -248,10 +285,8 @@ struct RelDateTimeFmtDataSink : public ResourceSink { return UDAT_ABSOLUTE_WEEK; case MONTH: return UDAT_ABSOLUTE_MONTH; - /* TODO: Add in QUARTER - * case QUARTER: - * return UDAT_ABSOLUTE_QUARTER; - */ + case QUARTER: + return UDAT_ABSOLUTE_QUARTER; case YEAR: return UDAT_ABSOLUTE_YEAR; case SUNDAY: @@ -312,7 +347,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink { // Utility functions static UDateRelativeDateTimeFormatterStyle styleFromString(const char *s) { - int32_t len = uprv_strlen(s); + int32_t len = static_cast(uprv_strlen(s)); if (len >= 7 && uprv_strcmp(s + len - 7, "-narrow") == 0) { return UDAT_STYLE_NARROW; } @@ -430,7 +465,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink { } int32_t relUnitIndex = relUnitFromGeneric(genericUnit); - if (relUnitIndex == UDAT_RELATIVE_SECONDS && uprv_strcmp(key, "0") == 0 && + if (relUnitIndex == UDAT_REL_UNIT_SECOND && uprv_strcmp(key, "0") == 0 && outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN].isEmpty()) { // Handle "NOW" outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW] @@ -463,10 +498,10 @@ struct RelDateTimeFmtDataSink : public ResourceSink { outputData.relativeUnitsFormatters[style][relUnitIndex] [pastFutureIndex]; // Only set if not already established. - if (patterns[pluralIndex] == NULL) { + if (patterns[pluralIndex] == nullptr) { patterns[pluralIndex] = new SimpleFormatter( value.getUnicodeString(errorCode), 0, 1, errorCode); - if (patterns[pluralIndex] == NULL) { + if (patterns[pluralIndex] == nullptr) { errorCode = U_MEMORY_ALLOCATION_ERROR; } } @@ -546,7 +581,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink { consumeAlias(key, value, errorCode); } else { style = styleFromString(key); - int32_t unitSize = uprv_strlen(key) - styleSuffixLength(style); + int32_t unitSize = static_cast(uprv_strlen(key)) - styleSuffixLength(style); genericUnit = unitOrNegativeFromString(key, unitSize); if (style >= 0 && genericUnit != INVALID_UNIT) { consumeTimeUnit(key, value, errorCode); @@ -570,8 +605,14 @@ static void loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT] [UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT], const char* localeId, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } Locale locale(localeId); DateFormatSymbols dfSym(locale, status); + if (U_FAILURE(status)) { + return; + } for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { DateFormatSymbols::DtWidthType dtfmtWidth = styleToDateFormatSymbolWidth[style]; int32_t count; @@ -595,6 +636,9 @@ static UBool loadUnitData( RelDateTimeFmtDataSink sink(cacheData); ures_getAllItemsWithFallback(resource, "fields", sink, status); + if (U_FAILURE(status)) { + return false; + } // Get the weekday names from DateFormatSymbols. loadWeekdayNames(cacheData.absoluteUnits, localeId, status); @@ -619,7 +663,7 @@ static UBool getDateTimePattern( .append("/DateTimePatterns", status); LocalUResourceBundlePointer topLevel( ures_getByKeyWithFallback( - resource, pathBuffer.data(), NULL, &status)); + resource, pathBuffer.data(), nullptr, &status)); if (U_FAILURE(status)) { return FALSE; } @@ -636,68 +680,68 @@ static UBool getDateTimePattern( template<> U_I18N_API const RelativeDateTimeCacheData *LocaleCacheKey::createObject(const void * /*unused*/, UErrorCode &status) const { const char *localeId = fLoc.getName(); - LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status)); + LocalUResourceBundlePointer topLevel(ures_open(nullptr, localeId, &status)); if (U_FAILURE(status)) { - return NULL; + return nullptr; } LocalPointer result( new RelativeDateTimeCacheData()); if (result.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; - return NULL; + return nullptr; } if (!loadUnitData( topLevel.getAlias(), *result, localeId, status)) { - return NULL; + return nullptr; } UnicodeString dateTimePattern; if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) { - return NULL; + return nullptr; } result->adoptCombinedDateAndTime( new SimpleFormatter(dateTimePattern, 2, 2, status)); if (U_FAILURE(status)) { - return NULL; + return nullptr; } result->addRef(); return result.orphan(); } RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) : - fCache(NULL), - fNumberFormat(NULL), - fPluralRules(NULL), + fCache(nullptr), + fNumberFormat(nullptr), + fPluralRules(nullptr), fStyle(UDAT_STYLE_LONG), fContext(UDISPCTX_CAPITALIZATION_NONE), - fOptBreakIterator(NULL) { - init(NULL, NULL, status); + fOptBreakIterator(nullptr) { + init(nullptr, nullptr, status); } RelativeDateTimeFormatter::RelativeDateTimeFormatter( const Locale& locale, UErrorCode& status) : - fCache(NULL), - fNumberFormat(NULL), - fPluralRules(NULL), + fCache(nullptr), + fNumberFormat(nullptr), + fPluralRules(nullptr), fStyle(UDAT_STYLE_LONG), fContext(UDISPCTX_CAPITALIZATION_NONE), - fOptBreakIterator(NULL), + fOptBreakIterator(nullptr), fLocale(locale) { - init(NULL, NULL, status); + init(nullptr, nullptr, status); } RelativeDateTimeFormatter::RelativeDateTimeFormatter( const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) : - fCache(NULL), - fNumberFormat(NULL), - fPluralRules(NULL), + fCache(nullptr), + fNumberFormat(nullptr), + fPluralRules(nullptr), fStyle(UDAT_STYLE_LONG), fContext(UDISPCTX_CAPITALIZATION_NONE), - fOptBreakIterator(NULL), + fOptBreakIterator(nullptr), fLocale(locale) { - init(nfToAdopt, NULL, status); + init(nfToAdopt, nullptr, status); } RelativeDateTimeFormatter::RelativeDateTimeFormatter( @@ -706,12 +750,12 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter( UDateRelativeDateTimeFormatterStyle styl, UDisplayContext capitalizationContext, UErrorCode& status) : - fCache(NULL), - fNumberFormat(NULL), - fPluralRules(NULL), + fCache(nullptr), + fNumberFormat(nullptr), + fPluralRules(nullptr), fStyle(styl), fContext(capitalizationContext), - fOptBreakIterator(NULL), + fOptBreakIterator(nullptr), fLocale(locale) { if (U_FAILURE(status)) { return; @@ -727,7 +771,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter( } init(nfToAdopt, bi, status); } else { - init(nfToAdopt, NULL, status); + init(nfToAdopt, nullptr, status); } } @@ -744,7 +788,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter( fCache->addRef(); fNumberFormat->addRef(); fPluralRules->addRef(); - if (fOptBreakIterator != NULL) { + if (fOptBreakIterator != nullptr) { fOptBreakIterator->addRef(); } } @@ -764,16 +808,16 @@ RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=( } RelativeDateTimeFormatter::~RelativeDateTimeFormatter() { - if (fCache != NULL) { + if (fCache != nullptr) { fCache->removeRef(); } - if (fNumberFormat != NULL) { + if (fNumberFormat != nullptr) { fNumberFormat->removeRef(); } - if (fPluralRules != NULL) { + if (fPluralRules != nullptr) { fPluralRules->removeRef(); } - if (fOptBreakIterator != NULL) { + if (fOptBreakIterator != nullptr) { fOptBreakIterator->removeRef(); } } @@ -812,7 +856,7 @@ UnicodeString& RelativeDateTimeFormatter::format( const SimpleFormatter* formatter = fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralIndex); - if (formatter == NULL) { + if (formatter == nullptr) { // TODO: WARN - look at quantity formatter's action with an error. status = U_INVALID_FORMAT_ERROR; return appendTo; @@ -828,33 +872,35 @@ UnicodeString& RelativeDateTimeFormatter::formatNumeric( if (U_FAILURE(status)) { return appendTo; } - // TODO: - // The full implementation of this depends on CLDR data that is not yet available, - // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data. - // In the meantime do a quick bring-up by calling the old format method; this - // leaves some holes (even for data that is currently available, such as quarter). - // When the new CLDR data is available, update the data storage accordingly, - // rewrite this to use it directly, and rewrite the old format method to call this - // new one; that is covered by http://bugs.icu-project.org/trac/ticket/12171. - UDateRelativeUnit relunit = UDAT_RELATIVE_UNIT_COUNT; - switch (unit) { - case UDAT_REL_UNIT_YEAR: relunit = UDAT_RELATIVE_YEARS; break; - case UDAT_REL_UNIT_MONTH: relunit = UDAT_RELATIVE_MONTHS; break; - case UDAT_REL_UNIT_WEEK: relunit = UDAT_RELATIVE_WEEKS; break; - case UDAT_REL_UNIT_DAY: relunit = UDAT_RELATIVE_DAYS; break; - case UDAT_REL_UNIT_HOUR: relunit = UDAT_RELATIVE_HOURS; break; - case UDAT_REL_UNIT_MINUTE: relunit = UDAT_RELATIVE_MINUTES; break; - case UDAT_REL_UNIT_SECOND: relunit = UDAT_RELATIVE_SECONDS; break; - default: // a unit that the above method does not handle - status = U_UNSUPPORTED_ERROR; - return appendTo; - } UDateDirection direction = UDAT_DIRECTION_NEXT; if (std::signbit(offset)) { // needed to handle -0.0 direction = UDAT_DIRECTION_LAST; offset = -offset; } - return format(offset, direction, relunit, appendTo, status); + if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return appendTo; + } + int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0; + FieldPosition pos(FieldPosition::DONT_CARE); + + UnicodeString result; + UnicodeString formattedNumber; + + StandardPlural::Form pluralIndex = QuantityFormatter::selectPlural( + offset, **fNumberFormat, **fPluralRules, formattedNumber, pos, + status); + + const SimpleFormatter* formatter = + fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralIndex); + if (formatter == nullptr) { + // TODO: WARN - look at quantity formatter's action with an error. + status = U_INVALID_FORMAT_ERROR; + return appendTo; + } + formatter->format(formattedNumber, result, status); + adjustForContext(result); + return appendTo.append(result); } UnicodeString& RelativeDateTimeFormatter::format( @@ -871,7 +917,7 @@ UnicodeString& RelativeDateTimeFormatter::format( // Get string using fallback. UnicodeString result; result.fastCopyFrom(fCache->getAbsoluteUnitString(fStyle, unit, direction)); - if (fOptBreakIterator != NULL) { + if (fOptBreakIterator != nullptr) { adjustForContext(result); } return appendTo.append(result); @@ -908,6 +954,7 @@ UnicodeString& RelativeDateTimeFormatter::format( UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT; switch (unit) { case UDAT_REL_UNIT_YEAR: absunit = UDAT_ABSOLUTE_YEAR; break; + case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break; case UDAT_REL_UNIT_MONTH: absunit = UDAT_ABSOLUTE_MONTH; break; case UDAT_REL_UNIT_WEEK: absunit = UDAT_ABSOLUTE_WEEK; break; case UDAT_REL_UNIT_DAY: absunit = UDAT_ABSOLUTE_DAY; break; @@ -930,7 +977,7 @@ UnicodeString& RelativeDateTimeFormatter::format( const UnicodeString &unitFormatString = fCache->getAbsoluteUnitString(fStyle, absunit, direction); if (!unitFormatString.isEmpty()) { - if (fOptBreakIterator != NULL) { + if (fOptBreakIterator != nullptr) { UnicodeString result(unitFormatString); adjustForContext(result); return appendTo.append(result); @@ -951,7 +998,7 @@ UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( } void RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const { - if (fOptBreakIterator == NULL + if (fOptBreakIterator == nullptr || str.length() == 0 || !u_islower(str.char32At(0))) { return; } @@ -992,7 +1039,7 @@ void RelativeDateTimeFormatter::init( shared->removeRef(); } else { SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); - if (shared == NULL) { + if (shared == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1003,7 +1050,7 @@ void RelativeDateTimeFormatter::init( SharedObject::clearPtr(fOptBreakIterator); } else { SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias()); - if (shared == NULL) { + if (shared == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -1026,13 +1073,13 @@ ureldatefmt_open( const char* locale, UErrorCode* status ) { if (U_FAILURE(*status)) { - return NULL; + return nullptr; } LocalPointer formatter(new RelativeDateTimeFormatter(Locale(locale), (NumberFormat*)nfToAdopt, width, capitalizationContext, *status), *status); if (U_FAILURE(*status)) { - return NULL; + return nullptr; } return (URelativeDateTimeFormatter*)formatter.orphan(); } @@ -1054,13 +1101,13 @@ ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt, if (U_FAILURE(*status)) { return 0; } - if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) { + if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) { *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } UnicodeString res; - if (result != NULL) { - // NULL destination for pure preflighting: empty dummy string + if (result != nullptr) { + // nullptr destination for pure preflighting: empty dummy string // otherwise, alias the destination buffer (copied from udat_format) res.setTo(result, 0, resultCapacity); } @@ -1082,13 +1129,13 @@ ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt, if (U_FAILURE(*status)) { return 0; } - if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) { + if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) { *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } UnicodeString res; - if (result != NULL) { - // NULL destination for pure preflighting: empty dummy string + if (result != nullptr) { + // nullptr destination for pure preflighting: empty dummy string // otherwise, alias the destination buffer (copied from udat_format) res.setTo(result, 0, resultCapacity); } @@ -1112,9 +1159,9 @@ ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt, if (U_FAILURE(*status)) { return 0; } - if (result == NULL ? resultCapacity != 0 : resultCapacity < 0 || - (relativeDateString == NULL ? relativeDateStringLen != 0 : relativeDateStringLen < -1) || - (timeString == NULL ? timeStringLen != 0 : timeStringLen < -1)) { + if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 || + (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) || + (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) { *status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } diff --git a/deps/icu-small/source/i18n/reldtfmt.cpp b/deps/icu-small/source/i18n/reldtfmt.cpp index d3ab45dc631ba0..753672d905f16b 100644 --- a/deps/icu-small/source/i18n/reldtfmt.cpp +++ b/deps/icu-small/source/i18n/reldtfmt.cpp @@ -430,7 +430,7 @@ RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status) if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) || (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) { - UErrorCode status = U_ZERO_ERROR; + status = U_ZERO_ERROR; fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status); if (U_FAILURE(status)) { delete fCapitalizationBrkIter; @@ -456,8 +456,8 @@ RelativeDateFormat::initCapitalizationContextInfo(const Locale& thelocale) const int32_t * intVector = ures_getIntVector(rb.getAlias(), &len, &status); if (U_SUCCESS(status) && intVector != NULL && len >= 2) { - fCapitalizationOfRelativeUnitsForUIListMenu = intVector[0]; - fCapitalizationOfRelativeUnitsForStandAlone = intVector[1]; + fCapitalizationOfRelativeUnitsForUIListMenu = static_cast(intVector[0]); + fCapitalizationOfRelativeUnitsForStandAlone = static_cast(intVector[1]); } } #endif diff --git a/deps/icu-small/source/i18n/reldtfmt.h b/deps/icu-small/source/i18n/reldtfmt.h index 5063a6388f63b0..0403da11efda76 100644 --- a/deps/icu-small/source/i18n/reldtfmt.h +++ b/deps/icu-small/source/i18n/reldtfmt.h @@ -235,7 +235,6 @@ class RelativeDateFormat : public DateFormat { */ virtual const DateFormatSymbols* getDateFormatSymbols(void) const; - /* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */ /** * Set a particular UDisplayContext value in the formatter, such as * UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see diff --git a/deps/icu-small/source/i18n/rematch.cpp b/deps/icu-small/source/i18n/rematch.cpp index f2521822078169..95fd0d2240af95 100644 --- a/deps/icu-small/source/i18n/rematch.cpp +++ b/deps/icu-small/source/i18n/rematch.cpp @@ -801,7 +801,7 @@ UBool RegexMatcher::find(UErrorCode &status) { case START_LINE: { - UChar32 c; + UChar32 ch; if (startPos == fAnchorStart) { MatchAt(startPos, FALSE, status); if (U_FAILURE(status)) { @@ -811,17 +811,17 @@ UBool RegexMatcher::find(UErrorCode &status) { return TRUE; } UTEXT_SETNATIVEINDEX(fInputText, startPos); - c = UTEXT_NEXT32(fInputText); + ch = UTEXT_NEXT32(fInputText); startPos = UTEXT_GETNATIVEINDEX(fInputText); } else { UTEXT_SETNATIVEINDEX(fInputText, startPos); - c = UTEXT_PREVIOUS32(fInputText); + ch = UTEXT_PREVIOUS32(fInputText); UTEXT_SETNATIVEINDEX(fInputText, startPos); } if (fPattern->fFlags & UREGEX_UNIX_LINES) { for (;;) { - if (c == 0x0a) { + if (ch == 0x0a) { MatchAt(startPos, FALSE, status); if (U_FAILURE(status)) { return FALSE; @@ -836,7 +836,7 @@ UBool RegexMatcher::find(UErrorCode &status) { fHitEnd = TRUE; return FALSE; } - c = UTEXT_NEXT32(fInputText); + ch = UTEXT_NEXT32(fInputText); startPos = UTEXT_GETNATIVEINDEX(fInputText); // Note that it's perfectly OK for a pattern to have a zero-length // match at the end of a string, so we must make sure that the loop @@ -846,8 +846,8 @@ UBool RegexMatcher::find(UErrorCode &status) { } } else { for (;;) { - if (isLineTerminator(c)) { - if (c == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) { + if (isLineTerminator(ch)) { + if (ch == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) { (void)UTEXT_NEXT32(fInputText); startPos = UTEXT_GETNATIVEINDEX(fInputText); } @@ -865,7 +865,7 @@ UBool RegexMatcher::find(UErrorCode &status) { fHitEnd = TRUE; return FALSE; } - c = UTEXT_NEXT32(fInputText); + ch = UTEXT_NEXT32(fInputText); startPos = UTEXT_GETNATIVEINDEX(fInputText); // Note that it's perfectly OK for a pattern to have a zero-length // match at the end of a string, so we must make sure that the loop @@ -1034,7 +1034,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) { return FALSE; } } - U_ASSERT(FALSE); + U_ASSERT(FALSE); case START_STRING: case START_CHAR: @@ -1067,7 +1067,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) { case START_LINE: { - UChar32 c; + UChar32 ch; if (startPos == fAnchorStart) { MatchChunkAt(startPos, FALSE, status); if (U_FAILURE(status)) { @@ -1081,8 +1081,8 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) { if (fPattern->fFlags & UREGEX_UNIX_LINES) { for (;;) { - c = inputBuf[startPos-1]; - if (c == 0x0a) { + ch = inputBuf[startPos-1]; + if (ch == 0x0a) { MatchChunkAt(startPos, FALSE, status); if (U_FAILURE(status)) { return FALSE; @@ -1105,9 +1105,9 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) { } } else { for (;;) { - c = inputBuf[startPos-1]; - if (isLineTerminator(c)) { - if (c == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) { + ch = inputBuf[startPos-1]; + if (isLineTerminator(ch)) { + if (ch == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) { startPos++; } MatchChunkAt(startPos, FALSE, status); @@ -2774,7 +2774,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { int64_t *pat = fPattern->fCompiledPat->getBuffer(); const UChar *litText = fPattern->fLiteralText.getBuffer(); - UVector *sets = fPattern->fSets; + UVector *fSets = fPattern->fSets; fFrameSize = fPattern->fFrameSize; REStackFrame *fp = resetStack(); @@ -3376,7 +3376,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { // There is input left. Pick up one char and test it for set membership. UChar32 c = UTEXT_NEXT32(fInputText); - U_ASSERT(opValue > 0 && opValue < sets->size()); + U_ASSERT(opValue > 0 && opValue < fSets->size()); if (c<256) { Regex8BitSet *s8 = &fPattern->fSets8[opValue]; if (s8->contains(c)) { @@ -3384,7 +3384,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { break; } } else { - UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue); + UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue); if (s->contains(c)) { // The character is in the set. A Match. fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText); @@ -3671,9 +3671,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { if (newFP == (int64_t *)fp) { break; } - int32_t i; - for (i=0; isetSize(newStackSize); @@ -3830,9 +3830,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { // This makes the capture groups from within the look-ahead // expression available. int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize; - int32_t i; - for (i=0; isetSize(newStackSize); @@ -4123,9 +4123,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) { // This op scans through all matching input. // The following LOOP_C op emulates stack unwinding if the following pattern fails. { - U_ASSERT(opValue > 0 && opValue < sets->size()); + U_ASSERT(opValue > 0 && opValue < fSets->size()); Regex8BitSet *s8 = &fPattern->fSets8[opValue]; - UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue); + UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue); // Loop through input, until either the input is exhausted or // we reach a character that is not a member of the set. @@ -4350,7 +4350,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu int64_t *pat = fPattern->fCompiledPat->getBuffer(); const UChar *litText = fPattern->fLiteralText.getBuffer(); - UVector *sets = fPattern->fSets; + UVector *fSets = fPattern->fSets; const UChar *inputBuf = fInputText->chunkContents; @@ -4928,7 +4928,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu break; } - U_ASSERT(opValue > 0 && opValue < sets->size()); + U_ASSERT(opValue > 0 && opValue < fSets->size()); // There is input left. Pick up one char and test it for set membership. UChar32 c; @@ -4940,7 +4940,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu break; } } else { - UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue); + UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue); if (s->contains(c)) { // The character is in the set. A Match. break; @@ -5214,9 +5214,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu if (newFP == (int64_t *)fp) { break; } - int32_t i; - for (i=0; isetSize(newStackSize); @@ -5361,9 +5361,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu // This makes the capture groups from within the look-ahead // expression available. int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize; - int32_t i; - for (i=0; isetSize(newStackSize); @@ -5623,9 +5623,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu // This op scans through all matching input. // The following LOOP_C op emulates stack unwinding if the following pattern fails. { - U_ASSERT(opValue > 0 && opValue < sets->size()); + U_ASSERT(opValue > 0 && opValue < fSets->size()); Regex8BitSet *s8 = &fPattern->fSets8[opValue]; - UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue); + UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue); // Loop through input, until either the input is exhausted or // we reach a character that is not a member of the set. diff --git a/deps/icu-small/source/i18n/rulebasedcollator.cpp b/deps/icu-small/source/i18n/rulebasedcollator.cpp index ab65f10a3bdfa8..b057b6bbd5a12f 100644 --- a/deps/icu-small/source/i18n/rulebasedcollator.cpp +++ b/deps/icu-small/source/i18n/rulebasedcollator.cpp @@ -764,9 +764,9 @@ RuleBasedCollator::internalCompareUTF8(const char *left, int32_t leftLength, // Make sure both or neither strings have a known length. // We do not optimize for mixed length/termination. if(leftLength >= 0) { - if(rightLength < 0) { rightLength = uprv_strlen(right); } + if(rightLength < 0) { rightLength = static_cast(uprv_strlen(right)); } } else { - if(rightLength >= 0) { leftLength = uprv_strlen(left); } + if(rightLength >= 0) { leftLength = static_cast(uprv_strlen(left)); } } return doCompare(reinterpret_cast(left), leftLength, reinterpret_cast(right), rightLength, errorCode); @@ -862,9 +862,9 @@ class FCDUTF16NFDIterator : public UTF16NFDIterator { } else { str.setTo(text, (int32_t)(spanLimit - text)); { - ReorderingBuffer buffer(nfcImpl, str); - if(buffer.init(str.length(), errorCode)) { - nfcImpl.makeFCD(spanLimit, textLimit, &buffer, errorCode); + ReorderingBuffer r_buffer(nfcImpl, str); + if(r_buffer.init(str.length(), errorCode)) { + nfcImpl.makeFCD(spanLimit, textLimit, &r_buffer, errorCode); } } if(U_SUCCESS(errorCode)) { diff --git a/deps/icu-small/source/i18n/scriptset.cpp b/deps/icu-small/source/i18n/scriptset.cpp index 9358e63b9ee403..558d178e2f97ca 100644 --- a/deps/icu-small/source/i18n/scriptset.cpp +++ b/deps/icu-small/source/i18n/scriptset.cpp @@ -298,7 +298,7 @@ uhash_compareScriptSet(UElement key0, UElement key1) { icu::ScriptSet *s0 = static_cast(key0.pointer); icu::ScriptSet *s1 = static_cast(key1.pointer); int32_t diff = s0->countMembers() - s1->countMembers(); - if (diff != 0) return diff; + if (diff != 0) return static_cast(diff); int32_t i0 = s0->nextSetBit(0); int32_t i1 = s1->nextSetBit(0); while ((diff = i0-i1) == 0 && i0 > 0) { diff --git a/deps/icu-small/source/i18n/shareddateformatsymbols.h b/deps/icu-small/source/i18n/shareddateformatsymbols.h index ca9a2108190c4d..66a06ecae5476a 100644 --- a/deps/icu-small/source/i18n/shareddateformatsymbols.h +++ b/deps/icu-small/source/i18n/shareddateformatsymbols.h @@ -12,6 +12,9 @@ #define __SHARED_DATEFORMATSYMBOLS_H__ #include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + #include "sharedobject.h" #include "unicode/dtfmtsym.h" @@ -33,4 +36,6 @@ class U_I18N_API SharedDateFormatSymbols : public SharedObject { U_NAMESPACE_END +#endif /* !UCONFIG_NO_FORMATTING */ + #endif diff --git a/deps/icu-small/source/i18n/smpdtfmt.cpp b/deps/icu-small/source/i18n/smpdtfmt.cpp index b1b90882fceead..2bc8e49625fe29 100644 --- a/deps/icu-small/source/i18n/smpdtfmt.cpp +++ b/deps/icu-small/source/i18n/smpdtfmt.cpp @@ -244,9 +244,9 @@ SimpleDateFormat::NSOverride::~NSOverride() { void SimpleDateFormat::NSOverride::free() { NSOverride *cur = this; while (cur) { - NSOverride *next = cur->next; + NSOverride *next_temp = cur->next; delete cur; - cur = next; + cur = next_temp; } } @@ -1304,15 +1304,15 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin int32_t nsNameHash = nsName.hashCode(); // See if the numbering system is in the override list, if not, then add it. - NSOverride *cur = overrideList; + NSOverride *curr = overrideList; const SharedNumberFormat *snf = NULL; UBool found = FALSE; - while ( cur && !found ) { - if ( cur->hash == nsNameHash ) { - snf = cur->snf; + while ( curr && !found ) { + if ( curr->hash == nsNameHash ) { + snf = curr->snf; found = TRUE; } - cur = cur->next; + curr = curr->next; } if (!found) { @@ -1824,14 +1824,14 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, // Stealing am/pm value to use as our array index. // It works out: am/midnight are both 0, pm/noon are both 1, // 12 am is 12 midnight, and 12 pm is 12 noon. - int32_t value = cal.get(UCAL_AM_PM, status); + int32_t val = cal.get(UCAL_AM_PM, status); if (count <= 3) { - toAppend = &fSymbols->fAbbreviatedDayPeriods[value]; + toAppend = &fSymbols->fAbbreviatedDayPeriods[val]; } else if (count == 4 || count > 5) { - toAppend = &fSymbols->fWideDayPeriods[value]; + toAppend = &fSymbols->fWideDayPeriods[val]; } else { // count == 5 - toAppend = &fSymbols->fNarrowDayPeriods[value]; + toAppend = &fSymbols->fNarrowDayPeriods[val]; } } @@ -2281,10 +2281,10 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& if (i+1 < fPattern.length()) { // move to next pattern character - UChar ch = fPattern.charAt(i+1); + UChar c = fPattern.charAt(i+1); // check for whitespace - if (PatternProps::isWhiteSpace(ch)) { + if (PatternProps::isWhiteSpace(c)) { i++; // Advance over run in pattern while ((i+1)isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { + UErrorCode monthStatus = U_ZERO_ERROR; + if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) { cal.set(UCAL_MONTH, value); } else { cal.set(UCAL_MONTH, value - 1); @@ -3571,21 +3571,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR; // Try matching a time separator. - int32_t count = 1; + int32_t count_sep = 1; UnicodeString data[3]; fSymbols->getTimeSeparatorString(data[0]); // Add the default, if different from the locale. if (data[0].compare(&def_sep, 1) != 0) { - data[count++].setTo(def_sep); + data[count_sep++].setTo(def_sep); } // If lenient, add also the alternate, if different from the locale. if (isLenient() && data[0].compare(&alt_sep, 1) != 0) { - data[count++].setTo(alt_sep); + data[count_sep++].setTo(alt_sep); } - return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal); + return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal); } case UDAT_AM_PM_MIDNIGHT_NOON_FIELD: @@ -3674,7 +3674,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC } parseInt(*src, number, pos, allowNegative,currentNumberFormat); if (pos.getIndex() != parseStart) { - int32_t value = number.getLong(); + int32_t val = number.getLong(); // Don't need suffix processing here (as in number processing at the beginning of the function); // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes. @@ -3682,7 +3682,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) { // Check the range of the value int32_t bias = gFieldRangeBias[patternCharIndex]; - if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { + if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) { return -start; } } @@ -3696,35 +3696,35 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC if (!strcmp(cal.getType(),"hebrew")) { HebrewCalendar *hc = (HebrewCalendar*)&cal; if (cal.isSet(UCAL_YEAR)) { - UErrorCode status = U_ZERO_ERROR; - if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { - cal.set(UCAL_MONTH, value); + UErrorCode monthStatus = U_ZERO_ERROR; + if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) { + cal.set(UCAL_MONTH, val); } else { - cal.set(UCAL_MONTH, value - 1); + cal.set(UCAL_MONTH, val - 1); } } else { - saveHebrewMonth = value; + saveHebrewMonth = val; } } else { - cal.set(UCAL_MONTH, value - 1); + cal.set(UCAL_MONTH, val - 1); } break; case UDAT_STANDALONE_MONTH_FIELD: - cal.set(UCAL_MONTH, value - 1); + cal.set(UCAL_MONTH, val - 1); break; case UDAT_DOW_LOCAL_FIELD: case UDAT_STANDALONE_DAY_FIELD: - cal.set(UCAL_DOW_LOCAL, value); + cal.set(UCAL_DOW_LOCAL, val); break; case UDAT_QUARTER_FIELD: case UDAT_STANDALONE_QUARTER_FIELD: - cal.set(UCAL_MONTH, (value - 1) * 3); + cal.set(UCAL_MONTH, (val - 1) * 3); break; case UDAT_RELATED_YEAR_FIELD: - cal.setRelatedYear(value); + cal.setRelatedYear(val); break; default: - cal.set(field, value); + cal.set(field, val); break; } return pos.getIndex(); @@ -3971,7 +3971,7 @@ SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status) if (U_SUCCESS(status)) { if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) { - UErrorCode status = U_ZERO_ERROR; + status = U_ZERO_ERROR; fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status); if (U_FAILURE(status)) { delete fCapitalizationBrkIter; diff --git a/deps/icu-small/source/i18n/timezone.cpp b/deps/icu-small/source/i18n/timezone.cpp index f7f45c7d3eeffd..dbf614469e8311 100644 --- a/deps/icu-small/source/i18n/timezone.cpp +++ b/deps/icu-small/source/i18n/timezone.cpp @@ -1031,8 +1031,8 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) { UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section if (U_SUCCESS(ec)) { int32_t idLen = 0; - const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec); - result.fastCopyFrom(UnicodeString(TRUE, id, idLen)); + const UChar* id2 = ures_getStringByIndex(ares, zone, &idLen, &ec); + result.fastCopyFrom(UnicodeString(TRUE, id2, idLen)); U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec))); } ures_close(ares); @@ -1199,7 +1199,7 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local { UErrorCode status = U_ZERO_ERROR; UDate date = Calendar::getNow(); - UTimeZoneFormatTimeType timeType; + UTimeZoneFormatTimeType timeType = UTZFMT_TIME_TYPE_UNKNOWN; int32_t offset; if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) { @@ -1612,7 +1612,7 @@ TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode end = tzids + len; hasNext = FALSE; } - if (canonicalID.compare(start, end - start) == 0) { + if (canonicalID.compare(start, static_cast(end - start)) == 0) { winid = UnicodeString(ures_getKey(winzone), -1 , US_INV); found = TRUE; break; @@ -1673,7 +1673,7 @@ TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, Unic if (end == NULL) { id.setTo(tzids, -1); } else { - id.setTo(tzids, end - tzids); + id.setTo(tzids, static_cast(end - tzids)); } gotID = TRUE; } diff --git a/deps/icu-small/source/i18n/transreg.cpp b/deps/icu-small/source/i18n/transreg.cpp index 331f4efdeb339a..4884773faf5ac3 100644 --- a/deps/icu-small/source/i18n/transreg.cpp +++ b/deps/icu-small/source/i18n/transreg.cpp @@ -1330,12 +1330,12 @@ Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID int32_t passNumber = 1; for (int32_t i = 0; U_SUCCESS(status) && i < entry->u.dataVector->size(); i++) { // TODO: Should passNumber be turned into a decimal-string representation (1 -> "1")? - Transliterator* t = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++), + Transliterator* tl = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++), (TransliterationRuleData*)(entry->u.dataVector->elementAt(i)), FALSE); - if (t == 0) + if (tl == 0) status = U_MEMORY_ALLOCATION_ERROR; else - rbts->addElement(t, status); + rbts->addElement(tl, status); } if (U_FAILURE(status)) { delete rbts; diff --git a/deps/icu-small/source/i18n/tzfmt.cpp b/deps/icu-small/source/i18n/tzfmt.cpp index 69da4667bc89ac..df4dec1febf60a 100644 --- a/deps/icu-small/source/i18n/tzfmt.cpp +++ b/deps/icu-small/source/i18n/tzfmt.cpp @@ -2648,12 +2648,12 @@ TimeZoneFormat::checkAbuttingHoursAndMinutes() { UVector *items = fGMTOffsetPatternItems[type]; for (int32_t i = 0; i < items->size(); i++) { const GMTOffsetField* item = (GMTOffsetField*)items->elementAt(i); - GMTOffsetField::FieldType type = item->getType(); - if (type != GMTOffsetField::TEXT) { + GMTOffsetField::FieldType fieldType = item->getType(); + if (fieldType != GMTOffsetField::TEXT) { if (afterH) { fAbuttingOffsetHoursAndMinutes = TRUE; break; - } else if (type == GMTOffsetField::HOUR) { + } else if (fieldType == GMTOffsetField::HOUR) { afterH = TRUE; } } else if (afterH) { diff --git a/deps/icu-small/source/i18n/tzgnames.cpp b/deps/icu-small/source/i18n/tzgnames.cpp index c2e685272e9b36..5f5b7db30227cc 100644 --- a/deps/icu-small/source/i18n/tzgnames.cpp +++ b/deps/icu-small/source/i18n/tzgnames.cpp @@ -407,7 +407,7 @@ TZGNCore::initialize(const Locale& locale, UErrorCode& status) { // target region const char* region = fLocale.getCountry(); - int32_t regionLen = uprv_strlen(region); + int32_t regionLen = static_cast(uprv_strlen(region)); if (regionLen == 0) { char loc[ULOC_FULLNAME_CAPACITY]; uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status); diff --git a/deps/icu-small/source/i18n/tznames.cpp b/deps/icu-small/source/i18n/tznames.cpp index 689fdeb0915300..5a79c22aacf8f9 100644 --- a/deps/icu-small/source/i18n/tznames.cpp +++ b/deps/icu-small/source/i18n/tznames.cpp @@ -87,7 +87,7 @@ static void sweepCache() { const UHashElement* elem; double now = (double)uprv_getUTCtime(); - while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) { + while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos)) != 0) { TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer; if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) { // delete this entry diff --git a/deps/icu-small/source/i18n/tznames_impl.cpp b/deps/icu-small/source/i18n/tznames_impl.cpp index ef04b31c1357f4..6a303ea4a0110f 100644 --- a/deps/icu-small/source/i18n/tznames_impl.cpp +++ b/deps/icu-small/source/i18n/tznames_impl.cpp @@ -1285,7 +1285,7 @@ static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) { char mzIdChar[ZID_KEY_MAX + 1]; int32_t keyLen; - int32_t prefixLen = uprv_strlen(gMZPrefix); + int32_t prefixLen = static_cast(uprv_strlen(gMZPrefix)); keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV); uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen); uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen); @@ -1453,7 +1453,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink { virtual ~ZoneStringsLoader(); void* createKey(const char* key, UErrorCode& status) { - int32_t len = sizeof(char) * (uprv_strlen(key) + 1); + int32_t len = sizeof(char) * (static_cast(uprv_strlen(key)) + 1); char* newKey = (char*) uprv_malloc(len); if (newKey == NULL) { status = U_MEMORY_ALLOCATION_ERROR; @@ -1469,7 +1469,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink { } UnicodeString mzIDFromKey(const char* key) { - return UnicodeString(key + MZ_PREFIX_LEN, uprv_strlen(key) - MZ_PREFIX_LEN, US_INV); + return UnicodeString(key + MZ_PREFIX_LEN, static_cast(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV); } UnicodeString tzIDFromKey(const char* key) { @@ -1944,8 +1944,8 @@ TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *nod // metazone mapping for "CST" is America_Central, // but if region is one of CN/MO/TW, "CST" is parsed // as metazone China (China Standard Time). - for (int32_t i = 0; i < ninfo->nRegions; i++) { - const char *region = ninfo->parseRegions[i]; + for (int32_t j = 0; j < ninfo->nRegions; j++) { + const char *region = ninfo->parseRegions[j]; if (uprv_strcmp(fRegion, region) == 0) { match = ninfo; matchRegion = TRUE; @@ -2059,7 +2059,7 @@ static void U_CALLCONV prepareFind(UErrorCode &status) { const UnicodeString *mzID; StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status); if (U_SUCCESS(status)) { - while ((mzID = mzIDs->snext(status)) && U_SUCCESS(status)) { + while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) { const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status); if (U_FAILURE(status)) { break; @@ -2128,7 +2128,7 @@ TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale) : fLocale(locale) { UBool useWorld = TRUE; const char* region = fLocale.getCountry(); - int32_t regionLen = uprv_strlen(region); + int32_t regionLen = static_cast(uprv_strlen(region)); if (regionLen == 0) { UErrorCode status = U_ZERO_ERROR; char loc[ULOC_FULLNAME_CAPACITY]; diff --git a/deps/icu-small/source/i18n/ucln_in.h b/deps/icu-small/source/i18n/ucln_in.h index 318eafc143c968..4c13b9ffcb539a 100644 --- a/deps/icu-small/source/i18n/ucln_in.h +++ b/deps/icu-small/source/i18n/ucln_in.h @@ -32,6 +32,7 @@ typedef enum ECleanupI18NType { UCLN_I18N_SPOOFDATA, UCLN_I18N_TRANSLITERATOR, UCLN_I18N_REGEX, + UCLN_I18N_JAPANESE_CALENDAR, UCLN_I18N_ISLAMIC_CALENDAR, UCLN_I18N_CHINESE_CALENDAR, UCLN_I18N_HEBREW_CALENDAR, @@ -58,6 +59,7 @@ typedef enum ECleanupI18NType { UCLN_I18N_GENDERINFO, UCLN_I18N_CDFINFO, UCLN_I18N_REGION, + UCLN_I18N_LIST_FORMATTER, UCLN_I18N_COUNT /* This must be last */ } ECleanupI18NType; diff --git a/deps/icu-small/source/i18n/ucol_res.cpp b/deps/icu-small/source/i18n/ucol_res.cpp index 76975ecc01de63..56ed5b3c19caca 100644 --- a/deps/icu-small/source/i18n/ucol_res.cpp +++ b/deps/icu-small/source/i18n/ucol_res.cpp @@ -400,11 +400,11 @@ CollationLoader::loadFromData(UErrorCode &errorCode) { // Try to fetch the optional rules string. { UErrorCode internalErrorCode = U_ZERO_ERROR; - int32_t length; - const UChar *s = ures_getStringByKey(data, "Sequence", &length, + int32_t len; + const UChar *s = ures_getStringByKey(data, "Sequence", &len, &internalErrorCode); if(U_SUCCESS(internalErrorCode)) { - t->rules.setTo(TRUE, s, length); + t->rules.setTo(TRUE, s, len); } } @@ -426,10 +426,10 @@ CollationLoader::loadFromData(UErrorCode &errorCode) { LocalUResourceBundlePointer def( ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL, &internalErrorCode)); - int32_t length; - const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode); - if(U_SUCCESS(internalErrorCode) && length < UPRV_LENGTHOF(defaultType)) { - u_UCharsToChars(s, defaultType, length + 1); + int32_t len; + const UChar *s = ures_getString(def.getAlias(), &len, &internalErrorCode); + if(U_SUCCESS(internalErrorCode) && len < UPRV_LENGTHOF(defaultType)) { + u_UCharsToChars(s, defaultType, len + 1); } else { uprv_strcpy(defaultType, "standard"); } diff --git a/deps/icu-small/source/i18n/udat.cpp b/deps/icu-small/source/i18n/udat.cpp index d086067c034da6..b7d85cc179ef9a 100644 --- a/deps/icu-small/source/i18n/udat.cpp +++ b/deps/icu-small/source/i18n/udat.cpp @@ -603,7 +603,7 @@ udat_getSymbols(const UDateFormat *fmt, } else { return -1; } - int32_t count; + int32_t count = 0; const UnicodeString *res = NULL; switch(type) { diff --git a/deps/icu-small/source/common/ulistformatter.cpp b/deps/icu-small/source/i18n/ulistformatter.cpp similarity index 100% rename from deps/icu-small/source/common/ulistformatter.cpp rename to deps/icu-small/source/i18n/ulistformatter.cpp diff --git a/deps/icu-small/source/i18n/ulocdata.cpp b/deps/icu-small/source/i18n/ulocdata.cpp index 551f6c64ed5668..f651fee6fc4efa 100644 --- a/deps/icu-small/source/i18n/ulocdata.cpp +++ b/deps/icu-small/source/i18n/ulocdata.cpp @@ -372,7 +372,7 @@ ulocdata_getLocaleSeparator(ULocaleData *uld, p1=u_strstr(separator, sub1); if (p0!=NULL && p1!=NULL && p0<=p1) { separator = (const UChar *)p0 + subLen; - len = p1 - separator; + len = static_cast(p1 - separator); /* Desired separator is no longer zero-terminated; handle that if necessary */ if (len < resultCapacity) { u_strncpy(result, separator, len); diff --git a/deps/icu-small/source/i18n/unicode/alphaindex.h b/deps/icu-small/source/i18n/unicode/alphaindex.h index 54bd29ff88668a..4ebdf1cc56a1a8 100644 --- a/deps/icu-small/source/i18n/unicode/alphaindex.h +++ b/deps/icu-small/source/i18n/unicode/alphaindex.h @@ -266,6 +266,8 @@ class U_I18N_API AlphabeticIndex: public UObject { * Use getBucket() to get the bucket's properties. * * @param name the string to be sorted into an index bucket + * @param errorCode Error code, will be set with the reason if the + * operation fails. * @return the bucket number for the name * @stable ICU 51 */ @@ -377,9 +379,10 @@ class U_I18N_API AlphabeticIndex: public UObject { /** - * Get the default label used for abbreviated buckets between other index characters. - * For example, consider the labels when Latin and Greek are used: - * X Y Z ... Α Β Γ. + * Get the default label used for abbreviated buckets *between* other index characters. + * For example, consider the labels when Latin (X Y Z) and Greek (Α Β Γ) are used: + * + * X Y Z ... Α Β Γ. * * @return inflow label * @stable ICU 4.8 @@ -700,6 +703,7 @@ class U_I18N_API AlphabeticIndex: public UObject { /** * A (name, data) pair, to be sorted by name into one of the index buckets. * The user data is not used by the index implementation. + * \cond * @internal */ struct Record: public UMemory { @@ -708,6 +712,7 @@ class U_I18N_API AlphabeticIndex: public UObject { Record(const UnicodeString &name, const void *data); ~Record(); }; + /** \endcond */ #endif /* U_HIDE_INTERNAL_API */ private: diff --git a/deps/icu-small/source/i18n/unicode/calendar.h b/deps/icu-small/source/i18n/unicode/calendar.h index 48021534b422f6..023cf053f254fb 100644 --- a/deps/icu-small/source/i18n/unicode/calendar.h +++ b/deps/icu-small/source/i18n/unicode/calendar.h @@ -52,83 +52,64 @@ typedef int32_t UFieldResolutionTable[12][8]; class BasicTimeZone; /** - * Calendar is an abstract base class for converting between - * a UDate object and a set of integer fields such as - * YEAR, MONTH, DAY, HOUR, - * and so on. (A UDate object represents a specific instant in + * `Calendar` is an abstract base class for converting between + * a `UDate` object and a set of integer fields such as + * `YEAR`, `MONTH`, `DAY`, `HOUR`, and so on. + * (A `UDate` object represents a specific instant in * time with millisecond precision. See UDate - * for information about the UDate class.) + * for information about the `UDate` class.) * - *

    - * Subclasses of Calendar interpret a UDate + * Subclasses of `Calendar` interpret a `UDate` * according to the rules of a specific calendar system. - * The most commonly used subclass of Calendar is - * GregorianCalendar. Other subclasses could represent + * The most commonly used subclass of `Calendar` is + * `GregorianCalendar`. Other subclasses could represent * the various types of lunar calendars in use in many parts of the world. * - *

    - * NOTE: (ICU 2.6) The subclass interface should be considered unstable - * - it WILL change. + * **NOTE**: (ICU 2.6) The subclass interface should be considered unstable - + * it WILL change. * - *

    - * Like other locale-sensitive classes, Calendar provides a - * static method, createInstance, for getting a generally useful - * object of this type. Calendar's createInstance method - * returns the appropriate Calendar subclass whose + * Like other locale-sensitive classes, `Calendar` provides a + * static method, `createInstance`, for getting a generally useful + * object of this type. `Calendar`'s `createInstance` method + * returns the appropriate `Calendar` subclass whose * time fields have been initialized with the current date and time: - * \htmlonly

    \endhtmlonly - *
    - * Calendar *rightNow = Calendar::createInstance(errCode);
    - * 
    - * \htmlonly
    \endhtmlonly * - *

    - * A Calendar object can produce all the time field values + * Calendar *rightNow = Calendar::createInstance(errCode); + * + * A `Calendar` object can produce all the time field values * needed to implement the date-time formatting for a particular language * and calendar style (for example, Japanese-Gregorian, Japanese-Traditional). * - *

    - * When computing a UDate from time fields, some special circumstances + * When computing a `UDate` from time fields, some special circumstances * may arise: there may be insufficient information to compute the - * UDate (such as only year and month but no day in the month), + * `UDate` (such as only year and month but no day in the month), * there may be inconsistent information (such as "Tuesday, July 15, 1996" * -- July 15, 1996 is actually a Monday), or the input time might be ambiguous * because of time zone transition. * - *

    - * Insufficient information. The calendar will use default + * **Insufficient information.** The calendar will use default * information to specify the missing fields. This may vary by calendar; for * the Gregorian calendar, the default for a field is the same as that of the * start of the epoch: i.e., YEAR = 1970, MONTH = JANUARY, DATE = 1, etc. * - *

    - * Inconsistent information. If fields conflict, the calendar + * **Inconsistent information.** If fields conflict, the calendar * will give preference to fields set more recently. For example, when * determining the day, the calendar will look for one of the following * combinations of fields. The most recent combination, as determined by the * most recently set single field, will be used. * - * \htmlonly

    \endhtmlonly - *
    - * MONTH + DAY_OF_MONTH
    - * MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
    - * MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
    - * DAY_OF_YEAR
    - * DAY_OF_WEEK + WEEK_OF_YEAR
    - * 
    - * \htmlonly
    \endhtmlonly + * MONTH + DAY_OF_MONTH + * MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + * MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + * DAY_OF_YEAR + * DAY_OF_WEEK + WEEK_OF_YEAR * * For the time of day: * - * \htmlonly
    \endhtmlonly - *
    - * HOUR_OF_DAY
    - * AM_PM + HOUR
    - * 
    - * \htmlonly
    \endhtmlonly + * HOUR_OF_DAY + * AM_PM + HOUR * - *

    - * Ambiguous Wall Clock Time. When time offset from UTC has + * **Ambiguous Wall Clock Time.** When time offset from UTC has * changed, it produces an ambiguous time slot around the transition. For example, * many US locations observe daylight saving time. On the date switching to daylight * saving time in US, wall clock time jumps from 12:59 AM (standard) to 2:00 AM @@ -138,64 +119,66 @@ class BasicTimeZone; * In this example, 1:30 AM is interpreted as 1:30 AM standard time (non-exist), * so the final result will be 2:30 AM daylight time. * - *

    On the date switching back to standard time, wall clock time is moved back one + * On the date switching back to standard time, wall clock time is moved back one * hour at 2:00 AM. So wall clock time from 1:00 AM to 1:59 AM occur twice. In this * case, the ICU Calendar resolves the time using the UTC offset after the transition * by default. For example, 1:30 AM on the date is resolved as 1:30 AM standard time. * - *

    Ambiguous wall clock time resolution behaviors can be customized by Calendar APIs + * Ambiguous wall clock time resolution behaviors can be customized by Calendar APIs * {@link #setRepeatedWallTimeOption} and {@link #setSkippedWallTimeOption}. * These methods are available in ICU 49 or later versions. * - *

    - * Note: for some non-Gregorian calendars, different + * **Note:** for some non-Gregorian calendars, different * fields may be necessary for complete disambiguation. For example, a full - * specification of the historial Arabic astronomical calendar requires year, - * month, day-of-month and day-of-week in some cases. + * specification of the historical Arabic astronomical calendar requires year, + * month, day-of-month *and* day-of-week in some cases. * - *

    - * Note: There are certain possible ambiguities in + * **Note:** There are certain possible ambiguities in * interpretation of certain singular times, which are resolved in the * following ways: - *

      - *
    1. 24:00:00 "belongs" to the following day. That is, - * 23:59 on Dec 31, 1969 < 24:00 on Jan 1, 1970 < 24:01:00 on Jan 1, 1970 * - *
    2. Although historically not precise, midnight also belongs to "am", - * and noon belongs to "pm", so on the same day, - * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm - *
    + * 1. 24:00:00 "belongs" to the following day. That is, + * 23:59 on Dec 31, 1969 < 24:00 on Jan 1, 1970 < 24:01:00 on Jan 1, 1970 + * 2. Although historically not precise, midnight also belongs to "am", + * and noon belongs to "pm", so on the same day, + * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm * - *

    * The date or time format strings are not part of the definition of a * calendar, as those must be modifiable or overridable by the user at - * runtime. Use {@link DateFormat} - * to format dates. + * runtime. Use `DateFormat` to format dates. * - *

    - * Calendar provides an API for field "rolling", where fields + * `Calendar` provides an API for field "rolling", where fields * can be incremented or decremented, but wrap around. For example, rolling the - * month up in the date December 12, 1996 results in - * January 12, 1996. + * month up in the date December 12, **1996** results in + * January 12, **1996**. * - *

    - * Calendar also provides a date arithmetic function for + * `Calendar` also provides a date arithmetic function for * adding the specified (signed) amount of time to a particular time field. - * For example, subtracting 5 days from the date September 12, 1996 - * results in September 7, 1996. + * For example, subtracting 5 days from the date `September 12, 1996` + * results in `September 7, 1996`. * - *

    Supported range + * ***Supported range*** * - *

    The allowable range of Calendar has been - * narrowed. GregorianCalendar used to attempt to support - * the range of dates with millisecond values from - * Long.MIN_VALUE to Long.MAX_VALUE. - * The new Calendar protocol specifies the + * The allowable range of `Calendar` has been narrowed. `GregorianCalendar` used + * to attempt to support the range of dates with millisecond values from + * `Long.MIN_VALUE` to `Long.MAX_VALUE`. The new `Calendar` protocol specifies the * maximum range of supportable dates as those having Julian day numbers - * of -0x7F000000 to +0x7F000000. This - * corresponds to years from ~5,800,000 BCE to ~5,800,000 CE. Programmers - * should use the protected constants in Calendar to - * specify an extremely early or extremely late date.

    + * of `-0x7F000000` to `+0x7F000000`. This corresponds to years from ~5,800,000 BCE + * to ~5,800,000 CE. Programmers should use the protected constants in `Calendar` to + * specify an extremely early or extremely late date. + * + *

    + * The Japanese calendar uses a combination of era name and year number. + * When an emperor of Japan abdicates and a new emperor ascends the throne, + * a new era is declared and year number is reset to 1. Even if the date of + * abdication is scheduled ahead of time, the new era name might not be + * announced until just before the date. In such case, ICU4C may include + * a start date of future era without actual era name, but not enabled + * by default. ICU4C users who want to test the behavior of the future era + * can enable the tentative era by: + *

      + *
    • Environment variable ICU_ENABLE_TENTATIVE_ERA=true.
    • + *
    * * @stable ICU 2.0 */ @@ -903,7 +886,7 @@ class U_I18N_API Calendar : public UObject { /** * Sets the behavior for handling wall time repeating multiple times * at negative time zone offset transitions. For example, 1:30 AM on - * November 6, 2011 in US Eastern time (Ameirca/New_York) occurs twice; + * November 6, 2011 in US Eastern time (America/New_York) occurs twice; * 1:30 AM EDT, then 1:30 AM EST one hour later. When UCAL_WALLTIME_FIRST * is used, the wall time 1:30AM in this example will be interpreted as 1:30 AM EDT * (first occurrence). When UCAL_WALLTIME_LAST is used, it will be @@ -1718,9 +1701,7 @@ class U_I18N_API Calendar : public UObject { /** * Validate a single field of this calendar. Subclasses should * override this method to validate any calendar-specific fields. - * Generic fields can be handled by - * Calendar::validateField(). - * @see #validateField(int, int, int, int&) + * Generic fields can be handled by `Calendar::validateField()`. * @internal */ virtual void validateField(UCalendarDateFields field, UErrorCode &status); @@ -2171,7 +2152,7 @@ class U_I18N_API Calendar : public UObject { TimeZone* fZone; /** - * Option for rpeated wall time + * Option for repeated wall time * @see #setRepeatedWallTimeOption */ UCalendarWallTimeOption fRepeatedWallTime; @@ -2456,7 +2437,7 @@ class U_I18N_API Calendar : public UObject { BasicTimeZone* getBasicTimeZone() const; /** - * Find the previous zone transtion near the given time. + * Find the previous zone transition near the given time. * @param base The base time, inclusive * @param transitionTime Receives the result time * @param status The error status diff --git a/deps/icu-small/source/i18n/unicode/coll.h b/deps/icu-small/source/i18n/unicode/coll.h index d03570509ecebb..653434f54ca664 100644 --- a/deps/icu-small/source/i18n/unicode/coll.h +++ b/deps/icu-small/source/i18n/unicode/coll.h @@ -235,16 +235,16 @@ class U_I18N_API Collator : public UObject { * Returns TRUE if "other" is the same as "this". * * The base class implementation returns TRUE if "other" has the same type/class as "this": - * typeid(*this) == typeid(other). + * `typeid(*this) == typeid(other)`. * * Subclass implementations should do something like the following: - *
    -     *   if (this == &other) { return TRUE; }
    -     *   if (!Collator::operator==(other)) { return FALSE; }  // not the same class
          *
    -     *   const MyCollator &o = (const MyCollator&)other;
    -     *   (compare this vs. o's subclass fields)
    -     * 
    + * if (this == &other) { return TRUE; } + * if (!Collator::operator==(other)) { return FALSE; } // not the same class + * + * const MyCollator &o = (const MyCollator&)other; + * (compare this vs. o's subclass fields) + * * @param other Collator object to be compared * @return TRUE if other is the same as this. * @stable ICU 2.0 diff --git a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h index 7dc92f610062f4..9c1e9183f4657b 100644 --- a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h +++ b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h @@ -30,30 +30,31 @@ U_NAMESPACE_BEGIN class PluralRules; /** - *

    IMPORTANT: New users are strongly encouraged to see if + * **IMPORTANT:** New users are strongly encouraged to see if * numberformatter.h fits their use case. Although not deprecated, this header * is provided for backwards compatibility only. - *


    + * + * ----------------------------------------------------------------------------- * * The CompactDecimalFormat produces abbreviated numbers, suitable for display in * environments will limited real estate. For example, 'Hits: 1.2B' instead of * 'Hits: 1,200,000,000'. The format will be appropriate for the given language, * such as "1,2 Mrd." for German. - *

    + * * For numbers under 1000 trillion (under 10^15, such as 123,456,789,012,345), * the result will be short for supported languages. However, the result may * sometimes exceed 7 characters, such as when there are combining marks or thin * characters. In such cases, the visual width in fonts should still be short. - *

    + * * By default, there are 3 significant digits. After creation, if more than * three significant digits are set (with setMaximumSignificantDigits), or if a * fixed number of digits are set (with setMaximumIntegerDigits or * setMaximumFractionDigits), then result may be wider. - *

    + * * At this time, parsing is not supported, and will produce a U_UNSUPPORTED_ERROR. * Resetting the pattern prefixes or suffixes is not supported; the method calls * are ignored. - *

    + * * @stable ICU 51 */ class U_I18N_API CompactDecimalFormat : public DecimalFormat { @@ -61,9 +62,9 @@ class U_I18N_API CompactDecimalFormat : public DecimalFormat { /** * Returns a compact decimal instance for specified locale. - *

    - * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * + * **NOTE:** New users are strongly encouraged to use + * `number::NumberFormatter` instead of NumberFormat. * @param inLocale the given locale. * @param style whether to use short or long style. * @param status error code returned here. diff --git a/deps/icu-small/source/i18n/unicode/currpinf.h b/deps/icu-small/source/i18n/unicode/currpinf.h index 1a327c5bae0033..80b046251323e9 100644 --- a/deps/icu-small/source/i18n/unicode/currpinf.h +++ b/deps/icu-small/source/i18n/unicode/currpinf.h @@ -2,7 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* - * Copyright (C) 2009-2015, International Business Machines Corporation and * + * Copyright (C) 2009-2015, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -240,18 +240,27 @@ class U_I18N_API CurrencyPluralInfo : public UObject { /* * The plural rule is used to format currency plural name, * for example: "3.00 US Dollars". - * If there are 3 currency signs in the currency patttern, + * If there are 3 currency signs in the currency pattern, * the 3 currency signs will be replaced by currency plural name. */ PluralRules* fPluralRules; // locale Locale* fLocale; + +private: + /** + * An internal status variable used to indicate that the object is in an 'invalid' state. + * Used by copy constructor, the assignment operator and the clone method. + */ + UErrorCode fInternalStatus; }; inline UBool -CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); } +CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { + return !operator==(info); +} U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/unicode/currunit.h b/deps/icu-small/source/i18n/unicode/currunit.h index d5bc4aa6d6d482..48cadc10b704af 100644 --- a/deps/icu-small/source/i18n/unicode/currunit.h +++ b/deps/icu-small/source/i18n/unicode/currunit.h @@ -38,7 +38,7 @@ class U_I18N_API CurrencyUnit: public MeasureUnit { public: /** * Default constructor. Initializes currency code to "XXX" (no currency). - * @draft ICU 60 + * @stable ICU 60 */ CurrencyUnit(); @@ -59,17 +59,15 @@ class U_I18N_API CurrencyUnit: public MeasureUnit { */ CurrencyUnit(const CurrencyUnit& other); -#ifndef U_HIDE_DRAFT_API /** * Copy constructor from MeasureUnit. This constructor allows you to * restore a CurrencyUnit that was sliced to MeasureUnit. * * @param measureUnit The MeasureUnit to copy from. * @param ec Set to a failing value if the MeasureUnit is not a currency. - * @draft ICU 60 + * @stable ICU 60 */ CurrencyUnit(const MeasureUnit& measureUnit, UErrorCode &ec); -#endif /* U_HIDE_DRAFT_API */ /** * Assignment operator diff --git a/deps/icu-small/source/i18n/unicode/datefmt.h b/deps/icu-small/source/i18n/unicode/datefmt.h index c895183931546e..13c63d937675ea 100644 --- a/deps/icu-small/source/i18n/unicode/datefmt.h +++ b/deps/icu-small/source/i18n/unicode/datefmt.h @@ -43,13 +43,17 @@ U_NAMESPACE_BEGIN class TimeZone; class DateTimePatternGenerator; -// explicit template instantiation. see digitlst.h -// (When building DLLs for Windows this is required.) -#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +/** + * \cond + * Export an explicit template instantiation. (See digitlst.h, datefmt.h, and others.) + * (When building DLLs for Windows this is required.) + */ +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN) template class U_I18N_API EnumSet; #endif +/** \endcond */ /** * DateFormat is an abstract class for a family of classes that convert dates and diff --git a/deps/icu-small/source/i18n/unicode/dcfmtsym.h b/deps/icu-small/source/i18n/unicode/dcfmtsym.h index 2f824cec3087f5..55e3d8a6b3b5ec 100644 --- a/deps/icu-small/source/i18n/unicode/dcfmtsym.h +++ b/deps/icu-small/source/i18n/unicode/dcfmtsym.h @@ -181,7 +181,6 @@ class U_I18N_API DecimalFormatSymbols : public UObject { */ DecimalFormatSymbols(const Locale& locale, UErrorCode& status); -#ifndef U_HIDE_DRAFT_API /** * Creates a DecimalFormatSymbols instance for the given locale with digits and symbols * corresponding to the given NumberingSystem. @@ -196,10 +195,9 @@ class U_I18N_API DecimalFormatSymbols : public UObject { * @param ns The numbering system. * @param status Input/output parameter, set to success or * failure code upon return. - * @draft ICU 60 + * @stable ICU 60 */ DecimalFormatSymbols(const Locale& locale, const NumberingSystem& ns, UErrorCode& status); -#endif /* U_HIDE_DRAFT_API */ /** * Create a DecimalFormatSymbols object for the default locale. @@ -406,7 +404,7 @@ class U_I18N_API DecimalFormatSymbols : public UObject { * returning a const reference to one of the symbol strings. * The returned reference becomes invalid when the symbol is changed * or when the DecimalFormatSymbols are destroyed. - * Note: moved #ifndef U_HIDE_INTERNAL_API after this, since this is needed for inline in DecimalFormat + * Note: moved \#ifndef U_HIDE_INTERNAL_API after this, since this is needed for inline in DecimalFormat * * This is not currently stable API, but if you think it should be stable, * post a comment on the following ticket and the ICU team will take a look: @@ -531,7 +529,7 @@ inline const UnicodeString& DecimalFormatSymbols::getConstDigitSymbol(int32_t di ENumberFormatSymbol key = static_cast(kOneDigitSymbol + digit - 1); return fSymbols[key]; } -#endif +#endif /* U_HIDE_INTERNAL_API */ // ------------------------------------- diff --git a/deps/icu-small/source/i18n/unicode/decimfmt.h b/deps/icu-small/source/i18n/unicode/decimfmt.h index 3747f510f79c79..b3a5cc0495f144 100644 --- a/deps/icu-small/source/i18n/unicode/decimfmt.h +++ b/deps/icu-small/source/i18n/unicode/decimfmt.h @@ -63,19 +63,22 @@ class NumberParserImpl; } } -// explicit template instantiation. see digitlst.h -// (When building DLLs for Windows this is required.) -#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +/** + * \cond + * explicit template instantiation. see digitlst.h + * (When building DLLs for Windows this is required.) + */ +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN) template class U_I18N_API EnumSet; #endif +/** \endcond */ /** - *

    IMPORTANT: New users are strongly encouraged to see if + * **IMPORTANT:** New users are strongly encouraged to see if * numberformatter.h fits their use case. Although not deprecated, this header * is provided for backwards compatibility only. - *


    * * DecimalFormat is a concrete subclass of NumberFormat that formats decimal * numbers. It has a variety of features designed to make it possible to parse @@ -85,13 +88,13 @@ template class U_I18N_API EnumSetTo obtain a NumberFormat for a specific locale (including the default + * To obtain a NumberFormat for a specific locale (including the default * locale) call one of NumberFormat's factory methods such as * createInstance(). Do not call the DecimalFormat constructors directly, unless * you know what you are doing, since the NumberFormat factory methods may * return subclasses other than DecimalFormat. * - *

    Example Usage + * **Example Usage** * * \code * // Normally we would have a GUI with a menu for this @@ -135,11 +138,11 @@ template class U_I18N_API EnumSet - * Another example use createInstance(style) - *

    - *

    - * // Print out a number using the localized number, currency,
    + *
    + * **Another example use createInstance(style)**
    + *
    + * \code
    + * // Print out a number using the localized number, currency,
      * // percent, scientific, integer, iso currency, and plural currency
      * // format for each locale
      * Locale* locale = new Locale("en", "US");
    @@ -150,11 +153,13 @@ template class U_I18N_API    EnumSetformat(myNumber, str) << endl;
      *     format->parse(form->format(myNumber, str), fmtable, success);
    - * }
    + * delete form; + * } + * \endcode * * *

    Patterns @@ -690,7 +695,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of DecimalFormat. + * #icu::number::NumberFormatter instead of DecimalFormat. * @param status Output param set to success/failure code. If the * pattern is invalid this will be set to a failure code. * @stable ICU 2.0 @@ -708,7 +713,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of DecimalFormat. + * #icu::number::NumberFormatter instead of DecimalFormat. * @param pattern A non-localized pattern string. * @param status Output param set to success/failure code. If the * pattern is invalid this will be set to a failure code. @@ -728,7 +733,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * a NumberFormat factory method. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of DecimalFormat. + * #icu::number::NumberFormatter instead of DecimalFormat. * * @param pattern a non-localized pattern string * @param symbolsToAdopt the set of symbols to be used. The caller should not @@ -782,7 +787,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * May return U_UNSUPPORTED_ERROR if this instance does not support * the specified attribute. * @param attr the attribute to set - * @param newvalue new value + * @param newValue new value * @param status the error type * @return *this - for chaining (example: format.setAttribute(...).setAttribute(...) ) * @stable ICU 51 @@ -839,7 +844,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * a NumberFormat factory method. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of DecimalFormat. + * #icu::number::NumberFormatter instead of DecimalFormat. * * @param pattern a non-localized pattern string * @param symbolsToAdopt the set of symbols to be used. The caller should not @@ -864,7 +869,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * a NumberFormat factory method. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of DecimalFormat. + * #icu::number::NumberFormatter instead of DecimalFormat. * * @param pattern a non-localized pattern string * @param symbols the set of symbols to be used @@ -986,6 +991,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. * On output: the offsets of the alignment field. + * @param status Output param filled with success/failure status. * @return Reference to 'appendTo' parameter. * @internal */ @@ -1031,6 +1037,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. * On output: the offsets of the alignment field. + * @param status Output param filled with success/failure status. * @return Reference to 'appendTo' parameter. * @internal */ @@ -1726,7 +1733,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual void setDecimalPatternMatchRequired(UBool newValue); /** - * {@icu} Returns whether to ignore exponents when parsing. + * Returns whether to ignore exponents when parsing. * * @see #setParseNoExponent * @internal This API is a technical preview. It may change in an upcoming release. @@ -1734,7 +1741,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual UBool isParseNoExponent() const; /** - * {@icu} Specifies whether to stop parsing when an exponent separator is encountered. For + * Specifies whether to stop parsing when an exponent separator is encountered. For * example, parses "123E4" to 123 (with parse position 3) instead of 1230000 (with parse position * 5). * @@ -1744,7 +1751,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual void setParseNoExponent(UBool value); /** - * {@icu} Returns whether parsing is sensitive to case (lowercase/uppercase). + * Returns whether parsing is sensitive to case (lowercase/uppercase). * * @see #setParseCaseSensitive * @internal This API is a technical preview. It may change in an upcoming release. @@ -1752,7 +1759,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual UBool isParseCaseSensitive() const; /** - * {@icu} Whether to pay attention to case when parsing; default is to ignore case (perform + * Whether to pay attention to case when parsing; default is to ignore case (perform * case-folding). For example, "A" == "a" in case-insensitive but not case-sensitive mode. * * Currency symbols are never case-folded. For example, "us$1.00" will not parse in case-insensitive @@ -1763,7 +1770,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual void setParseCaseSensitive(UBool value); /** - * {@icu} Returns whether truncation of high-order integer digits should result in an error. + * Returns whether truncation of high-order integer digits should result in an error. * By default, setMaximumIntegerDigits truncates high-order digits silently. * * @see setFormatFailIfMoreThanMaxDigits @@ -1772,7 +1779,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual UBool isFormatFailIfMoreThanMaxDigits() const; /** - * {@icu} Sets whether truncation of high-order integer digits should result in an error. + * Sets whether truncation of high-order integer digits should result in an error. * By default, setMaximumIntegerDigits truncates high-order digits silently. * * @internal This API is a technical preview. It may change in an upcoming release. @@ -2017,16 +2024,17 @@ class U_I18N_API DecimalFormat : public NumberFormat { virtual void setCurrency(const char16_t* theCurrency); /** - * Sets the Currency Context object used to display currency. + * Sets the `Currency Usage` object used to display currency. * This takes effect immediately, if this format is a * currency format. - * @param currencyContext new currency context object to use. + * @param newUsage new currency usage object to use. + * @param ec input-output error code * @stable ICU 54 */ void setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec); /** - * Returns the Currency Context object used to display currency + * Returns the `Currency Usage` object used to display currency * @stable ICU 54 */ UCurrencyUsage getCurrencyUsage() const; @@ -2050,7 +2058,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { void formatToDecimalQuantity(const Formattable& number, number::impl::DecimalQuantity& output, UErrorCode& status) const; -#endif +#endif /* U_HIDE_INTERNAL_API */ #ifndef U_HIDE_DRAFT_API /** @@ -2072,7 +2080,6 @@ class U_I18N_API DecimalFormat : public NumberFormat { * FormattedNumber result = df->toNumberFormatter().formatDouble(123, status); * * - * @param output The variable into which to store the LocalizedNumberFormatter. * @return The output variable, for chaining. * @draft ICU 62 */ diff --git a/deps/icu-small/source/i18n/unicode/dtptngen.h b/deps/icu-small/source/i18n/unicode/dtptngen.h index feb465e7997401..26ccc64060f15a 100644 --- a/deps/icu-small/source/i18n/unicode/dtptngen.h +++ b/deps/icu-small/source/i18n/unicode/dtptngen.h @@ -498,27 +498,23 @@ class U_I18N_API DateTimePatternGenerator : public UObject { private: /** * Constructor. - * @stable ICU 3.8 */ DateTimePatternGenerator(UErrorCode & status); /** * Constructor. - * @stable ICU 3.8 */ DateTimePatternGenerator(const Locale& locale, UErrorCode & status); /** * Copy constructor. * @param other DateTimePatternGenerator to copy - * @stable ICU 3.8 */ DateTimePatternGenerator(const DateTimePatternGenerator& other); /** * Default assignment operator. * @param other DateTimePatternGenerator to copy - * @stable ICU 3.8 */ DateTimePatternGenerator& operator=(const DateTimePatternGenerator& other); @@ -542,6 +538,11 @@ class U_I18N_API DateTimePatternGenerator : public UObject { int32_t fAllowedHourFormats[7]; // Actually an array of AllowedHourFormat enum type, ending with UNKNOWN. + // Internal error code used for recording/reporting errors that occur during methods that do not + // have a UErrorCode parameter. For example: the Copy Constructor, or the ::clone() method. + // When this is set to an error the object is in an invalid state. + UErrorCode internalErrorCode; + /* internal flags masks for adjustFieldTypes etc. */ enum { kDTPGNoFlags = 0, @@ -569,11 +570,10 @@ class U_I18N_API DateTimePatternGenerator : public UObject { #endif // U_HIDE_DRAFT_API void getAppendName(UDateTimePatternField field, UnicodeString& value); UnicodeString mapSkeletonMetacharacters(const UnicodeString& patternForm, int32_t* flags, UErrorCode& status); - int32_t getCanonicalIndex(const UnicodeString& field); - const UnicodeString* getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields, const PtnSkeleton** specifiedSkeletonPtr = 0); + const UnicodeString* getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields, UErrorCode& status, const PtnSkeleton** specifiedSkeletonPtr = 0); UnicodeString adjustFieldTypes(const UnicodeString& pattern, const PtnSkeleton* specifiedSkeleton, int32_t flags, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS); - UnicodeString getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS); - int32_t getTopBitNumber(int32_t foundMask); + UnicodeString getBestAppending(int32_t missingFields, int32_t flags, UErrorCode& status, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS); + int32_t getTopBitNumber(int32_t foundMask) const; void setAvailableFormat(const UnicodeString &key, UErrorCode& status); UBool isAvailableFormatSet(const UnicodeString &key) const; void copyHashtable(Hashtable *other, UErrorCode &status); diff --git a/deps/icu-small/source/i18n/unicode/fmtable.h b/deps/icu-small/source/i18n/unicode/fmtable.h index 2359b61d46186e..a06c23dc3bd532 100644 --- a/deps/icu-small/source/i18n/unicode/fmtable.h +++ b/deps/icu-small/source/i18n/unicode/fmtable.h @@ -658,7 +658,7 @@ class U_I18N_API Formattable : public UObject { /** * Adopt, and set value from, a DecimalQuantity * Internal Function, do not use. - * @param dl the DecimalQuantity to be adopted + * @param dq the DecimalQuantity to be adopted * @internal */ void adoptDecimalQuantity(number::impl::DecimalQuantity *dq); diff --git a/deps/icu-small/source/i18n/unicode/gender.h b/deps/icu-small/source/i18n/unicode/gender.h index 467b64ec5ebad0..b7c31cb554a696 100644 --- a/deps/icu-small/source/i18n/unicode/gender.h +++ b/deps/icu-small/source/i18n/unicode/gender.h @@ -18,6 +18,11 @@ #ifndef _GENDER #define _GENDER +/** + * \file + * \brief C++ API: GenderInfo computes the gender of a list. + */ + #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING @@ -30,7 +35,7 @@ class GenderInfoTest; U_NAMESPACE_BEGIN -// Forward Declaration +/** \internal Forward Declaration */ void U_CALLCONV GenderInfo_initCache(UErrorCode &status); /** diff --git a/deps/icu-small/source/common/unicode/listformatter.h b/deps/icu-small/source/i18n/unicode/listformatter.h similarity index 79% rename from deps/icu-small/source/common/unicode/listformatter.h rename to deps/icu-small/source/i18n/unicode/listformatter.h index 180fbcb5cde5b7..5e36cf71cc54b7 100644 --- a/deps/icu-small/source/common/unicode/listformatter.h +++ b/deps/icu-small/source/i18n/unicode/listformatter.h @@ -26,6 +26,9 @@ U_NAMESPACE_BEGIN +class FieldPositionIterator; +class FieldPositionHandler; + /** @internal */ class Hashtable; @@ -33,7 +36,10 @@ class Hashtable; struct ListFormatInternal; /* The following can't be #ifndef U_HIDE_INTERNAL_API, needed for other .h file declarations */ -/** @internal */ +/** + * @internal + * \cond + */ struct ListFormatData : public UMemory { UnicodeString twoPattern; UnicodeString startPattern; @@ -43,6 +49,7 @@ struct ListFormatData : public UMemory { ListFormatData(const UnicodeString& two, const UnicodeString& start, const UnicodeString& middle, const UnicodeString& end) : twoPattern(two), startPattern(start), middlePattern(middle), endPattern(end) {} }; +/** \endcond */ /** @@ -61,7 +68,7 @@ struct ListFormatData : public UMemory { * The ListFormatter class is not intended for public subclassing. * @stable ICU 50 */ -class U_COMMON_API ListFormatter : public UObject{ +class U_I18N_API ListFormatter : public UObject{ public: @@ -133,6 +140,27 @@ class U_COMMON_API ListFormatter : public UObject{ UnicodeString& format(const UnicodeString items[], int32_t n_items, UnicodeString& appendTo, UErrorCode& errorCode) const; +#ifndef U_HIDE_DRAFT_API + /** + * Format a list of strings. + * + * @param items An array of strings to be combined and formatted. + * @param n_items Length of the array items. + * @param appendTo The string to which the formatted result will be + * appended. + * @param posIter On return, can be used to iterate over positions of + * fields generated by this format call. Field values are + * defined in UListFormatterField. Can be NULL. + * @param errorCode ICU error code returned here. + * @return Formatted string combining the elements of items, + * appended to appendTo. + * @draft ICU 63 + */ + UnicodeString& format(const UnicodeString items[], int32_t n_items, + UnicodeString & appendTo, FieldPositionIterator* posIter, + UErrorCode& errorCode) const; +#endif /* U_HIDE_DRAFT_API */ + #ifndef U_HIDE_INTERNAL_API /** @internal for MeasureFormat @@ -160,6 +188,10 @@ class U_COMMON_API ListFormatter : public UObject{ struct ListPatternsSink; static ListFormatInternal* loadListFormatInternal(const Locale& locale, const char* style, UErrorCode& errorCode); + UnicodeString& format_( + const UnicodeString items[], int32_t n_items, UnicodeString& appendTo, + int32_t index, int32_t &offset, FieldPositionHandler* handler, UErrorCode& errorCode) const; + ListFormatter(); ListFormatInternal* owned; diff --git a/deps/icu-small/source/i18n/unicode/measfmt.h b/deps/icu-small/source/i18n/unicode/measfmt.h index 14399dd59a700a..bbdd2364bdd997 100644 --- a/deps/icu-small/source/i18n/unicode/measfmt.h +++ b/deps/icu-small/source/i18n/unicode/measfmt.h @@ -104,7 +104,7 @@ class U_I18N_API MeasureFormat : public Format { * Constructor. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 53 */ MeasureFormat( @@ -114,7 +114,7 @@ class U_I18N_API MeasureFormat : public Format { * Constructor. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 53 */ MeasureFormat( @@ -202,7 +202,7 @@ class U_I18N_API MeasureFormat : public Format { * formatted string is 3.5 meters per second. * @param measure The measure object. In above example, 3.5 meters. * @param perUnit The per unit. In above example, it is - * *MeasureUnit::createSecond(status). + * `*%MeasureUnit::createSecond(status)`. * @param appendTo formatted string appended here. * @param pos the field position. * @param status the error. @@ -223,7 +223,7 @@ class U_I18N_API MeasureFormat : public Format { * @param unit The unit for which to get a display name. * @param status the error. * @return The display name in the locale and width specified in - * {@link MeasureFormat#getInstance}, or null if there is no display name available + * the MeasureFormat constructor, or null if there is no display name available * for the specified unit. * * @stable ICU 58 @@ -236,7 +236,7 @@ class U_I18N_API MeasureFormat : public Format { * locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param locale desired locale * @param ec input-output error code * @return a formatter object, or NULL upon error @@ -250,7 +250,7 @@ class U_I18N_API MeasureFormat : public Format { * locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param ec input-output error code * @return a formatter object, or NULL upon error * @stable ICU 3.0 @@ -348,7 +348,7 @@ class U_I18N_API MeasureFormat : public Format { const MeasureFormatCacheData *cache; const SharedNumberFormat *numberFormat; const SharedPluralRules *pluralRules; - UMeasureFormatWidth width; + UMeasureFormatWidth fWidth; // Declared outside of MeasureFormatSharedData because ListFormatter // objects are relatively cheap to copy; therefore, they don't need to be diff --git a/deps/icu-small/source/i18n/unicode/measunit.h b/deps/icu-small/source/i18n/unicode/measunit.h index f552253544f890..676fdeb9c8cd8a 100644 --- a/deps/icu-small/source/i18n/unicode/measunit.h +++ b/deps/icu-small/source/i18n/unicode/measunit.h @@ -368,6 +368,26 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit *createPartPerMillion(UErrorCode &status); +#ifndef U_HIDE_DRAFT_API + /** + * Returns unit of concentr: percent. + * Caller owns returned value and must free it. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createPercent(UErrorCode &status); +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API + /** + * Returns unit of concentr: permille. + * Caller owns returned value and must free it. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createPermille(UErrorCode &status); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns unit of consumption: liter-per-100kilometers. * Caller owns returned value and must free it. @@ -464,6 +484,16 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit *createMegabyte(UErrorCode &status); +#ifndef U_HIDE_DRAFT_API + /** + * Returns unit of digital: petabyte. + * Caller owns returned value and must free it. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createPetabyte(UErrorCode &status); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns unit of digital: terabit. * Caller owns returned value and must free it. @@ -984,6 +1014,16 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit *createWatt(UErrorCode &status); +#ifndef U_HIDE_DRAFT_API + /** + * Returns unit of pressure: atmosphere. + * Caller owns returned value and must free it. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createAtmosphere(UErrorCode &status); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns unit of pressure: hectopascal. * Caller owns returned value and must free it. diff --git a/deps/icu-small/source/i18n/unicode/msgfmt.h b/deps/icu-small/source/i18n/unicode/msgfmt.h index fef80107747bf8..074d93354000ef 100644 --- a/deps/icu-small/source/i18n/unicode/msgfmt.h +++ b/deps/icu-small/source/i18n/unicode/msgfmt.h @@ -124,7 +124,7 @@ class NumberFormat; * argNumber = '0' | ('1'..'9' ('0'..'9')*) * * argType = "number" | "date" | "time" | "spellout" | "ordinal" | "duration" - * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText + * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText | "::" argSkeletonText * * *

      @@ -166,7 +166,7 @@ class NumberFormat; * (none) * null * - * number + * number * (none) * NumberFormat.createInstance(getLocale(), status) * @@ -182,6 +182,9 @@ class NumberFormat; * argStyleText * new DecimalFormat(argStyleText, new DecimalFormatSymbols(getLocale(), status), status) * + * argSkeletonText + * NumberFormatter::forSkeleton(argSkeletonText, status).locale(getLocale()).toFormat(status) + * * date * (none) * DateFormat.createDateInstance(kDefault, getLocale(), status) @@ -199,7 +202,7 @@ class NumberFormat; * DateFormat.createDateInstance(kFull, getLocale(), status) * * argStyleText - * new SimpleDateFormat(argStyleText, getLocale(), status) + * new SimpleDateFormat(argStyleText, getLocale(), status) * * time * (none) @@ -218,7 +221,7 @@ class NumberFormat; * DateFormat.createTimeInstance(kFull, getLocale(), status) * * argStyleText - * new SimpleDateFormat(argStyleText, getLocale(), status) + * new SimpleDateFormat(argStyleText, getLocale(), status) * * spellout * argStyleText (optional) diff --git a/deps/icu-small/source/i18n/unicode/numberformatter.h b/deps/icu-small/source/i18n/unicode/numberformatter.h index 3ab08319f73bc7..469949a2878eb4 100644 --- a/deps/icu-small/source/i18n/unicode/numberformatter.h +++ b/deps/icu-small/source/i18n/unicode/numberformatter.h @@ -144,11 +144,31 @@ class MultiplierFormatHandler; class CurrencySymbols; class GeneratorHelpers; class DecNum; +class NumberRangeFormatterImpl; +struct RangeMacroProps; + +/** + * Used for NumberRangeFormatter and implemented in numrange_fluent.cpp. + * Declared here so it can be friended. + * + * @internal + */ +void touchRangeLocales(impl::RangeMacroProps& macros); } // namespace impl -// Reserve extra names in case they are added as classes in the future: +/** + * Extra name reserved in case it is needed in the future. + * + * @draft ICU 63 + */ typedef Notation CompactNotation; + +/** + * Extra name reserved in case it is needed in the future. + * + * @draft ICU 63 + */ typedef Notation SimpleNotation; /** @@ -308,10 +328,15 @@ class U_I18N_API Notation : public UMemory { union NotationUnion { // For NTN_SCIENTIFIC + /** @internal */ struct ScientificSettings { + /** @internal */ int8_t fEngineeringInterval; + /** @internal */ bool fRequireMinInt; + /** @internal */ impl::digits_t fMinExponentDigits; + /** @internal */ UNumberSignDisplay fExponentSignDisplay; } scientific; @@ -407,15 +432,39 @@ class U_I18N_API ScientificNotation : public Notation { friend class impl::NumberPropertyMapper; }; -// Reserve extra names in case they are added as classes in the future: +/** + * Extra name reserved in case it is needed in the future. + * + * @draft ICU 63 + */ typedef Precision SignificantDigitsPrecision; // Typedefs for ICU 60/61 compatibility. // These will be removed in ICU 64. // See http://bugs.icu-project.org/trac/ticket/13746 + +/** + * This will be removed in ICU 64. See ICU-13746. + * @deprecated ICU 63 + */ typedef Precision Rounder; + +/** + * This will be removed in ICU 64. See ICU-13746. + * @deprecated ICU 63 + */ typedef FractionPrecision FractionRounder; + +/** + * This will be removed in ICU 64. See ICU-13746. + * @deprecated ICU 63 + */ typedef IncrementPrecision IncrementRounder; + +/** + * This will be removed in ICU 64. See ICU-13746. + * @deprecated ICU 63 + */ typedef CurrencyPrecision CurrencyRounder; /** @@ -672,16 +721,25 @@ class U_I18N_API Precision : public UMemory { } fType; union PrecisionUnion { + /** @internal */ struct FractionSignificantSettings { // For RND_FRACTION, RND_SIGNIFICANT, and RND_FRACTION_SIGNIFICANT + /** @internal */ impl::digits_t fMinFrac; + /** @internal */ impl::digits_t fMaxFrac; + /** @internal */ impl::digits_t fMinSig; + /** @internal */ impl::digits_t fMaxSig; } fracSig; + /** @internal */ struct IncrementSettings { + /** @internal */ double fIncrement; + /** @internal */ impl::digits_t fMinFrac; + /** @internal */ impl::digits_t fMaxFrac; } increment; // For RND_INCREMENT UCurrencyUsage currencyUsage; // For RND_CURRENCY @@ -1205,7 +1263,7 @@ class U_I18N_API Grouper : public UMemory { public: #ifndef U_HIDE_INTERNAL_API /** @internal */ - static Grouper forStrategy(UGroupingStrategy grouping); + static Grouper forStrategy(UNumberGroupingStrategy grouping); /** * Resolve the values in Properties to a Grouper object. @@ -1216,7 +1274,7 @@ class U_I18N_API Grouper : public UMemory { // Future: static Grouper forProperties(DecimalFormatProperties& properties); /** @internal */ - Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping, UGroupingStrategy strategy) + Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping, UNumberGroupingStrategy strategy) : fGrouping1(grouping1), fGrouping2(grouping2), fMinGrouping(minGrouping), @@ -1251,10 +1309,10 @@ class U_I18N_API Grouper : public UMemory { int16_t fMinGrouping; /** - * The UGroupingStrategy that was used to create this Grouper, or UNUM_GROUPING_COUNT if this - * was not created from a UGroupingStrategy. + * The UNumberGroupingStrategy that was used to create this Grouper, or UNUM_GROUPING_COUNT if this + * was not created from a UNumberGroupingStrategy. */ - UGroupingStrategy fStrategy; + UNumberGroupingStrategy fStrategy; Grouper() : fGrouping1(-3) {}; @@ -1423,7 +1481,8 @@ struct U_I18N_API MacroProps : public UMemory { /** * An abstract base class for specifying settings related to number formatting. This class is implemented by - * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}. + * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}. This class is not intended for + * public subclassing. */ template class U_I18N_API NumberFormatterSettings { @@ -1710,7 +1769,7 @@ class U_I18N_API NumberFormatterSettings { * The exact grouping widths will be chosen based on the locale. * *

      - * Pass this method an element from the {@link UGroupingStrategy} enum. For example: + * Pass this method an element from the {@link UNumberGroupingStrategy} enum. For example: * *

            * NumberFormatter::with().grouping(UNUM_GROUPING_MIN2)
      @@ -1724,7 +1783,7 @@ class U_I18N_API NumberFormatterSettings {
            * @return The fluent chain.
            * @draft ICU 61
            */
      -    Derived grouping(UGroupingStrategy strategy) const &;
      +    Derived grouping(UNumberGroupingStrategy strategy) const &;
       
           /**
            * Overload of grouping() for use on an rvalue reference.
      @@ -1733,10 +1792,9 @@ class U_I18N_API NumberFormatterSettings {
            *            The grouping strategy to use.
            * @return The fluent chain.
            * @see #grouping
      -     * @provisional This API might change or be removed in a future release.
            * @draft ICU 62
            */
      -    Derived grouping(UGroupingStrategy strategy) &&;
      +    Derived grouping(UNumberGroupingStrategy strategy) &&;
       
           /**
            * Specifies the minimum and maximum number of digits to render before the decimal mark.
      @@ -1748,7 +1806,7 @@ class U_I18N_API NumberFormatterSettings {
            * 
    * *

    - * Pass this method the return value of {@link IntegerWidth#zeroFillTo(int)}. For example: + * Pass this method the return value of {@link IntegerWidth#zeroFillTo}. For example: * *

          * NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2))
    @@ -2099,15 +2157,18 @@ class U_I18N_API NumberFormatterSettings {
     
         // NOTE: Uses default copy and move constructors.
     
    -  protected:
    +  private:
         impl::MacroProps fMacros;
     
    -  private:
         // Don't construct me directly!  Use (Un)LocalizedNumberFormatter.
         NumberFormatterSettings() = default;
     
         friend class LocalizedNumberFormatter;
         friend class UnlocalizedNumberFormatter;
    +
    +    // Give NumberRangeFormatter access to the MacroProps
    +    friend void impl::touchRangeLocales(impl::RangeMacroProps& macros);
    +    friend class impl::NumberRangeFormatterImpl;
     };
     
     /**
    @@ -2124,13 +2185,6 @@ class U_I18N_API UnlocalizedNumberFormatter
          * Associate the given locale with the number formatter. The locale is used for picking the appropriate symbols,
          * formats, and other data for number display.
          *
    -     * 

    - * To use the Java default locale, call Locale::getDefault(): - * - *

    -     * NumberFormatter::with(). ... .locale(Locale::getDefault())
    -     * 
    - * * @param locale * The locale to use when loading data for number formatting. * @return The fluent chain. @@ -2156,7 +2210,6 @@ class U_I18N_API UnlocalizedNumberFormatter */ UnlocalizedNumberFormatter() = default; - // Make default copy constructor call the NumberFormatterSettings copy constructor. /** * Returns a copy of this UnlocalizedNumberFormatter. * @draft ICU 60 @@ -2271,7 +2324,7 @@ class U_I18N_API LocalizedNumberFormatter */ int32_t getCallCount() const; -#endif +#endif /* U_HIDE_INTERNAL_API */ /** * Creates a representation of this LocalizedNumberFormat as an icu::Format, enabling the use @@ -2295,7 +2348,6 @@ class U_I18N_API LocalizedNumberFormatter */ LocalizedNumberFormatter() = default; - // Make default copy constructor call the NumberFormatterSettings copy constructor. /** * Returns a copy of this LocalizedNumberFormatter. * @draft ICU 60 @@ -2333,11 +2385,12 @@ class U_I18N_API LocalizedNumberFormatter * * @param results * The results object. This method will mutate it to save the results. + * @param status * @internal */ void formatImpl(impl::UFormattedNumberData *results, UErrorCode &status) const; -#endif +#endif /* U_HIDE_INTERNAL_API */ /** * Destruct this LocalizedNumberFormatter, cleaning up any memory it might own. @@ -2359,6 +2412,8 @@ class U_I18N_API LocalizedNumberFormatter LocalizedNumberFormatter(impl::MacroProps &¯os, const Locale &locale); + void clear(); + void lnfMoveHelper(LocalizedNumberFormatter&& src); /** @@ -2430,7 +2485,7 @@ class U_I18N_API FormattedNumber : public UMemory { * @draft ICU 62 * @see Appendable */ - Appendable &appendTo(Appendable &appendable, UErrorCode& status); + Appendable &appendTo(Appendable &appendable, UErrorCode& status) const; #ifndef U_HIDE_DEPRECATED_API /** @@ -2457,9 +2512,9 @@ class U_I18N_API FormattedNumber : public UMemory { #endif /* U_HIDE_DEPRECATED_API */ /** - * Determines the start and end indices of the next occurrence of the given field in the - * output string. This allows you to determine the locations of, for example, the integer part, - * fraction part, or symbols. + * Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given + * field in the output string. This allows you to determine the locations of, for example, + * the integer part, fraction part, or symbols. * * If a field occurs just once, calling this method will find that occurrence and return it. If a * field occurs multiple times, this method may be called repeatedly with the following pattern: @@ -2478,7 +2533,7 @@ class U_I18N_API FormattedNumber : public UMemory { * Input+output variable. On input, the "field" property determines which field to look * up, and the "beginIndex" and "endIndex" properties determine where to begin the search. * On output, the "beginIndex" is set to the beginning of the first occurrence of the - * field with either begin or end indices after the input indices, "endIndex" is set to + * field with either begin or end indices after the input indices; "endIndex" is set to * the end of that occurrence of the field (exclusive index). If a field position is not * found, the method returns FALSE and the FieldPosition may or may not be changed. * @param status @@ -2537,7 +2592,7 @@ class U_I18N_API FormattedNumber : public UMemory { */ void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; -#endif +#endif /* U_HIDE_INTERNAL_API */ /** * Copying not supported; use move constructor instead. diff --git a/deps/icu-small/source/i18n/unicode/numberrangeformatter.h b/deps/icu-small/source/i18n/unicode/numberrangeformatter.h new file mode 100644 index 00000000000000..3e6248d934de61 --- /dev/null +++ b/deps/icu-small/source/i18n/unicode/numberrangeformatter.h @@ -0,0 +1,866 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMBERRANGEFORMATTER_H__ +#define __NUMBERRANGEFORMATTER_H__ + +#include +#include "unicode/appendable.h" +#include "unicode/fieldpos.h" +#include "unicode/fpositer.h" +#include "unicode/numberformatter.h" + +#ifndef U_HIDE_DRAFT_API + +/** + * \file + * \brief C++ API: Library for localized formatting of number, currency, and unit ranges. + * + * The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement. + *

    + * Usage example: + *

    + *

    + * NumberRangeFormatter::with()
    + *     .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
    + *     .numberFormatterFirst(NumberFormatter::with().adoptUnit(MeasureUnit::createMeter()))
    + *     .numberFormatterSecond(NumberFormatter::with().adoptUnit(MeasureUnit::createKilometer()))
    + *     .locale("en-GB")
    + *     .formatRange(750, 1.2, status)
    + *     .toString(status);
    + * // => "750 m - 1.2 km"
    + * 
    + *

    + * Like NumberFormatter, NumberRangeFormatter instances are immutable and thread-safe. This API is based on the + * fluent design pattern popularized by libraries such as Google's Guava. + * + * @author Shane Carr + */ + + +/** + * Defines how to merge fields that are identical across the range sign. + * + * @draft ICU 63 + */ +typedef enum UNumberRangeCollapse { + /** + * Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none, + * some, or all repeated pieces in a locale-sensitive way. + * + * The heuristics used for this option are subject to change over time. + * + * @draft ICU 63 + */ + UNUM_RANGE_COLLAPSE_AUTO, + + /** + * Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms" + * + * @draft ICU 63 + */ + UNUM_RANGE_COLLAPSE_NONE, + + /** + * Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand + * kilograms" + * + * @draft ICU 63 + */ + UNUM_RANGE_COLLAPSE_UNIT, + + /** + * Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the + * number. Example: "3.2 – 5.3 thousand kilograms" + * + * @draft ICU 63 + */ + UNUM_RANGE_COLLAPSE_ALL +} UNumberRangeCollapse; + +/** + * Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect + * when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber. + * + * @draft ICU 63 + * @see NumberRangeFormatter + */ +typedef enum UNumberRangeIdentityFallback { + /** + * Show the number as a single value rather than a range. Example: "$5" + * + * @draft ICU 63 + */ + UNUM_IDENTITY_FALLBACK_SINGLE_VALUE, + + /** + * Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding, + * show the single value. Example: "~$5" or "$5" + * + * @draft ICU 63 + */ + UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, + + /** + * Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the + * inputs are the same. Example: "~$5" + * + * @draft ICU 63 + */ + UNUM_IDENTITY_FALLBACK_APPROXIMATELY, + + /** + * Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the + * same. Example (with RangeCollapse.NONE): "$5 – $5" + * + * @draft ICU 63 + */ + UNUM_IDENTITY_FALLBACK_RANGE +} UNumberRangeIdentityFallback; + +/** + * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range + * were equal or not, and whether or not the identity fallback was applied. + * + * @draft ICU 63 + * @see NumberRangeFormatter + */ +typedef enum UNumberRangeIdentityResult { + /** + * Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied. + * + * @draft ICU 63 + * @see NumberRangeFormatter + */ + UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING, + + /** + * Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied. + * + * @draft ICU 63 + * @see NumberRangeFormatter + */ + UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING, + + /** + * Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied. + * + * @draft ICU 63 + * @see NumberRangeFormatter + */ + UNUM_IDENTITY_RESULT_NOT_EQUAL, + +#ifndef U_HIDE_INTERNAL_API + /** + * The number of entries in this enum. + * @internal + */ + UNUM_IDENTITY_RESULT_COUNT +#endif + +} UNumberRangeIdentityResult; + +U_NAMESPACE_BEGIN + +namespace number { // icu::number + +// Forward declarations: +class UnlocalizedNumberRangeFormatter; +class LocalizedNumberRangeFormatter; +class FormattedNumberRange; + +namespace impl { + +// Forward declarations: +struct RangeMacroProps; +class DecimalQuantity; +struct UFormattedNumberRangeData; +class NumberRangeFormatterImpl; + +} // namespace impl + +/** + * \cond + * Export an explicit template instantiation. See datefmt.h + * (When building DLLs for Windows this is required.) + */ +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN) +template struct U_I18N_API std::atomic; +#endif +/** \endcond */ + +// Other helper classes would go here, but there are none. + +namespace impl { // icu::number::impl + +// Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field +/** @internal */ +struct U_I18N_API RangeMacroProps : public UMemory { + /** @internal */ + UnlocalizedNumberFormatter formatter1; // = NumberFormatter::with(); + + /** @internal */ + UnlocalizedNumberFormatter formatter2; // = NumberFormatter::with(); + + /** @internal */ + bool singleFormatter = true; + + /** @internal */ + UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO; + + /** @internal */ + UNumberRangeIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY; + + /** @internal */ + Locale locale; + + // NOTE: Uses default copy and move constructors. + + /** + * Check all members for errors. + * @internal + */ + bool copyErrorTo(UErrorCode &status) const { + return formatter1.copyErrorTo(status) || formatter2.copyErrorTo(status); + } +}; + +} // namespace impl + +/** + * An abstract base class for specifying settings related to number formatting. This class is implemented by + * {@link UnlocalizedNumberRangeFormatter} and {@link LocalizedNumberRangeFormatter}. This class is not intended for + * public subclassing. + */ +template +class U_I18N_API NumberRangeFormatterSettings { + public: + /** + * Sets the NumberFormatter instance to use for the numbers in the range. The same formatter is applied to both + * sides of the range. + *

    + * The NumberFormatter instances must not have a locale applied yet; the locale specified on the + * NumberRangeFormatter will be used. + * + * @param formatter + * The formatter to use for both numbers in the range. + * @return The fluent chain. + * @draft ICU 63 + */ + Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) const &; + + /** + * Overload of numberFormatterBoth() for use on an rvalue reference. + * + * @param formatter + * The formatter to use for both numbers in the range. + * @return The fluent chain. + * @see #numberFormatterBoth + * @draft ICU 63 + */ + Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) &&; + + /** + * Overload of numberFormatterBoth() for use on an rvalue reference. + * + * @param formatter + * The formatter to use for both numbers in the range. + * @return The fluent chain. + * @see #numberFormatterBoth + * @draft ICU 63 + */ + Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) const &; + + /** + * Overload of numberFormatterBoth() for use on an rvalue reference. + * + * @param formatter + * The formatter to use for both numbers in the range. + * @return The fluent chain. + * @see #numberFormatterBoth + * @draft ICU 63 + */ + Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) &&; + + /** + * Sets the NumberFormatter instance to use for the first number in the range. + *

    + * The NumberFormatter instances must not have a locale applied yet; the locale specified on the + * NumberRangeFormatter will be used. + * + * @param formatterFirst + * The formatter to use for the first number in the range. + * @return The fluent chain. + * @draft ICU 63 + */ + Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) const &; + + /** + * Overload of numberFormatterFirst() for use on an rvalue reference. + * + * @param formatterFirst + * The formatter to use for the first number in the range. + * @return The fluent chain. + * @see #numberFormatterFirst + * @draft ICU 63 + */ + Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) &&; + + /** + * Overload of numberFormatterFirst() for use on an rvalue reference. + * + * @param formatterFirst + * The formatter to use for the first number in the range. + * @return The fluent chain. + * @see #numberFormatterFirst + * @draft ICU 63 + */ + Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) const &; + + /** + * Overload of numberFormatterFirst() for use on an rvalue reference. + * + * @param formatterFirst + * The formatter to use for the first number in the range. + * @return The fluent chain. + * @see #numberFormatterFirst + * @draft ICU 63 + */ + Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) &&; + + /** + * Sets the NumberFormatter instance to use for the second number in the range. + *

    + * The NumberFormatter instances must not have a locale applied yet; the locale specified on the + * NumberRangeFormatter will be used. + * + * @param formatterSecond + * The formatter to use for the second number in the range. + * @return The fluent chain. + * @draft ICU 63 + */ + Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) const &; + + /** + * Overload of numberFormatterSecond() for use on an rvalue reference. + * + * @param formatterSecond + * The formatter to use for the second number in the range. + * @return The fluent chain. + * @see #numberFormatterSecond + * @draft ICU 63 + */ + Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) &&; + + /** + * Overload of numberFormatterSecond() for use on an rvalue reference. + * + * @param formatterSecond + * The formatter to use for the second number in the range. + * @return The fluent chain. + * @see #numberFormatterSecond + * @draft ICU 63 + */ + Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) const &; + + /** + * Overload of numberFormatterSecond() for use on an rvalue reference. + * + * @param formatterSecond + * The formatter to use for the second number in the range. + * @return The fluent chain. + * @see #numberFormatterSecond + * @draft ICU 63 + */ + Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) &&; + + /** + * Sets the aggressiveness of "collapsing" fields across the range separator. Possible values: + *

    + *

      + *
    • ALL: "3-5K miles"
    • + *
    • UNIT: "3K - 5K miles"
    • + *
    • NONE: "3K miles - 5K miles"
    • + *
    • AUTO: usually UNIT or NONE, depending on the locale and formatter settings
    • + *
    + *

    + * The default value is AUTO. + * + * @param collapse + * The collapsing strategy to use for this range. + * @return The fluent chain. + * @draft ICU 63 + */ + Derived collapse(UNumberRangeCollapse collapse) const &; + + /** + * Overload of collapse() for use on an rvalue reference. + * + * @param collapse + * The collapsing strategy to use for this range. + * @return The fluent chain. + * @see #collapse + * @draft ICU 63 + */ + Derived collapse(UNumberRangeCollapse collapse) &&; + + /** + * Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are + * passed to the formatRange function, or if different numbers are passed to the function but they become the same + * after rounding rules are applied. Possible values: + *

    + *

      + *
    • SINGLE_VALUE: "5 miles"
    • + *
    • APPROXIMATELY_OR_SINGLE_VALUE: "~5 miles" or "5 miles", depending on whether the number was the same before + * rounding was applied
    • + *
    • APPROXIMATELY: "~5 miles"
    • + *
    • RANGE: "5-5 miles" (with collapse=UNIT)
    • + *
    + *

    + * The default value is APPROXIMATELY. + * + * @param identityFallback + * The strategy to use when formatting two numbers that end up being the same. + * @return The fluent chain. + * @draft ICU 63 + */ + Derived identityFallback(UNumberRangeIdentityFallback identityFallback) const &; + + /** + * Overload of identityFallback() for use on an rvalue reference. + * + * @param identityFallback + * The strategy to use when formatting two numbers that end up being the same. + * @return The fluent chain. + * @see #identityFallback + * @draft ICU 63 + */ + Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&; + + /** + * Sets the UErrorCode if an error occurred in the fluent chain. + * Preserves older error codes in the outErrorCode. + * @return TRUE if U_FAILURE(outErrorCode) + * @draft ICU 63 + */ + UBool copyErrorTo(UErrorCode &outErrorCode) const { + if (U_FAILURE(outErrorCode)) { + // Do not overwrite the older error code + return TRUE; + } + fMacros.copyErrorTo(outErrorCode); + return U_FAILURE(outErrorCode); + }; + + // NOTE: Uses default copy and move constructors. + + private: + impl::RangeMacroProps fMacros; + + // Don't construct me directly! Use (Un)LocalizedNumberFormatter. + NumberRangeFormatterSettings() = default; + + friend class LocalizedNumberRangeFormatter; + friend class UnlocalizedNumberRangeFormatter; +}; + +/** + * A NumberRangeFormatter that does not yet have a locale. In order to format, a locale must be specified. + * + * @see NumberRangeFormatter + * @draft ICU 63 + */ +class U_I18N_API UnlocalizedNumberRangeFormatter + : public NumberRangeFormatterSettings, public UMemory { + + public: + /** + * Associate the given locale with the number range formatter. The locale is used for picking the + * appropriate symbols, formats, and other data for number display. + * + * @param locale + * The locale to use when loading data for number formatting. + * @return The fluent chain. + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter locale(const icu::Locale &locale) const &; + + /** + * Overload of locale() for use on an rvalue reference. + * + * @param locale + * The locale to use when loading data for number formatting. + * @return The fluent chain. + * @see #locale + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter locale(const icu::Locale &locale) &&; + + /** + * Default constructor: puts the formatter into a valid but undefined state. + * + * @draft ICU 63 + */ + UnlocalizedNumberRangeFormatter() = default; + + /** + * Returns a copy of this UnlocalizedNumberRangeFormatter. + * @draft ICU 63 + */ + UnlocalizedNumberRangeFormatter(const UnlocalizedNumberRangeFormatter &other); + + /** + * Move constructor: + * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state. + * @draft ICU 63 + */ + UnlocalizedNumberRangeFormatter(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT; + + /** + * Copy assignment operator. + * @draft ICU 63 + */ + UnlocalizedNumberRangeFormatter& operator=(const UnlocalizedNumberRangeFormatter& other); + + /** + * Move assignment operator: + * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state. + * @draft ICU 63 + */ + UnlocalizedNumberRangeFormatter& operator=(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT; + + private: + explicit UnlocalizedNumberRangeFormatter( + const NumberRangeFormatterSettings& other); + + explicit UnlocalizedNumberRangeFormatter( + NumberRangeFormatterSettings&& src) U_NOEXCEPT; + + // To give the fluent setters access to this class's constructor: + friend class NumberRangeFormatterSettings; + + // To give NumberRangeFormatter::with() access to this class's constructor: + friend class NumberRangeFormatter; +}; + +/** + * A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available. + * + * @see NumberFormatter + * @draft ICU 63 + */ +class U_I18N_API LocalizedNumberRangeFormatter + : public NumberRangeFormatterSettings, public UMemory { + public: + /** + * Format the given Formattables to a string using the settings specified in the NumberRangeFormatter fluent setting + * chain. + * + * @param first + * The first number in the range, usually to the left in LTR locales. + * @param second + * The second number in the range, usually to the right in LTR locales. + * @param status + * Set if an error occurs while formatting. + * @return A FormattedNumberRange object; call .toString() to get the string. + * @draft ICU 63 + */ + FormattedNumberRange formatFormattableRange( + const Formattable& first, const Formattable& second, UErrorCode& status) const; + + /** + * Default constructor: puts the formatter into a valid but undefined state. + * + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter() = default; + + /** + * Returns a copy of this LocalizedNumberRangeFormatter. + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter(const LocalizedNumberRangeFormatter &other); + + /** + * Move constructor: + * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state. + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT; + + /** + * Copy assignment operator. + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter& operator=(const LocalizedNumberRangeFormatter& other); + + /** + * Move assignment operator: + * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state. + * @draft ICU 63 + */ + LocalizedNumberRangeFormatter& operator=(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT; + +#ifndef U_HIDE_INTERNAL_API + + /** + * @param results + * The results object. This method will mutate it to save the results. + * @param equalBeforeRounding + * Whether the number was equal before copying it into a DecimalQuantity. + * Used for determining the identity fallback behavior. + * @param status + * Set if an error occurs while formatting. + * @internal + */ + void formatImpl(impl::UFormattedNumberRangeData& results, bool equalBeforeRounding, + UErrorCode& status) const; + +#endif + + /** + * Destruct this LocalizedNumberRangeFormatter, cleaning up any memory it might own. + * @draft ICU 63 + */ + ~LocalizedNumberRangeFormatter(); + + private: + std::atomic fAtomicFormatter = {}; + + const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const; + + explicit LocalizedNumberRangeFormatter( + const NumberRangeFormatterSettings& other); + + explicit LocalizedNumberRangeFormatter( + NumberRangeFormatterSettings&& src) U_NOEXCEPT; + + LocalizedNumberRangeFormatter(const impl::RangeMacroProps ¯os, const Locale &locale); + + LocalizedNumberRangeFormatter(impl::RangeMacroProps &¯os, const Locale &locale); + + void clear(); + + // To give the fluent setters access to this class's constructor: + friend class NumberRangeFormatterSettings; + friend class NumberRangeFormatterSettings; + + // To give UnlocalizedNumberRangeFormatter::locale() access to this class's constructor: + friend class UnlocalizedNumberRangeFormatter; +}; + +/** + * The result of a number range formatting operation. This class allows the result to be exported in several data types, + * including a UnicodeString and a FieldPositionIterator. + * + * @draft ICU 63 + */ +class U_I18N_API FormattedNumberRange : public UMemory { + public: + /** + * Returns a UnicodeString representation of the formatted number range. + * + * @param status + * Set if an error occurs while formatting the number to the UnicodeString. + * @return a UnicodeString containing the localized number range. + * @draft ICU 63 + */ + UnicodeString toString(UErrorCode& status) const; + + /** + * Appends the formatted number range to an Appendable. + * + * @param appendable + * The Appendable to which to append the formatted number range string. + * @param status + * Set if an error occurs while formatting the number range to the Appendable. + * @return The same Appendable, for chaining. + * @draft ICU 63 + * @see Appendable + */ + Appendable &appendTo(Appendable &appendable, UErrorCode& status) const; + + /** + * Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given + * field in the output string. This allows you to determine the locations of, for example, + * the integer part, fraction part, or symbols. + * + * If both sides of the range have the same field, the field will occur twice, once before the + * range separator and once after the range separator, if applicable. + * + * If a field occurs just once, calling this method will find that occurrence and return it. If a + * field occurs multiple times, this method may be called repeatedly with the following pattern: + * + *

    +     * FieldPosition fpos(UNUM_INTEGER_FIELD);
    +     * while (formattedNumberRange.nextFieldPosition(fpos, status)) {
    +     *   // do something with fpos.
    +     * }
    +     * 
    + * + * This method is useful if you know which field to query. If you want all available field position + * information, use #getAllFieldPositions(). + * + * @param fieldPosition + * Input+output variable. See {@link FormattedNumber#nextFieldPosition}. + * @param status + * Set if an error occurs while populating the FieldPosition. + * @return TRUE if a new occurrence of the field was found; FALSE otherwise. + * @draft ICU 63 + * @see UNumberFormatFields + */ + UBool nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const; + + /** + * Export the formatted number range to a FieldPositionIterator. This allows you to determine which characters in + * the output string correspond to which fields, such as the integer part, fraction part, and sign. + * + * If information on only one field is needed, use #nextFieldPosition() instead. + * + * @param iterator + * The FieldPositionIterator to populate with all of the fields present in the formatted number. + * @param status + * Set if an error occurs while populating the FieldPositionIterator. + * @draft ICU 63 + * @see UNumberFormatFields + */ + void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const; + + /** + * Export the first formatted number as a decimal number. This endpoint + * is useful for obtaining the exact number being printed after scaling + * and rounding have been applied by the number range formatting pipeline. + * + * The syntax of the unformatted number is a "numeric string" + * as defined in the Decimal Arithmetic Specification, available at + * http://speleotrove.com/decimal + * + * @return A decimal representation of the first formatted number. + * @draft ICU 63 + * @see NumberRangeFormatter + * @see #getSecondDecimal + */ + UnicodeString getFirstDecimal(UErrorCode& status) const; + + /** + * Export the second formatted number as a decimal number. This endpoint + * is useful for obtaining the exact number being printed after scaling + * and rounding have been applied by the number range formatting pipeline. + * + * The syntax of the unformatted number is a "numeric string" + * as defined in the Decimal Arithmetic Specification, available at + * http://speleotrove.com/decimal + * + * @return A decimal representation of the second formatted number. + * @draft ICU 63 + * @see NumberRangeFormatter + * @see #getFirstDecimal + */ + UnicodeString getSecondDecimal(UErrorCode& status) const; + + /** + * Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was + * used. For example, if the first and second number were the same either before or after rounding occurred, an + * identity fallback was used. + * + * @return An indication the resulting identity situation in the formatted number range. + * @draft ICU 63 + * @see UNumberRangeIdentityFallback + */ + UNumberRangeIdentityResult getIdentityResult(UErrorCode& status) const; + + /** + * Copying not supported; use move constructor instead. + */ + FormattedNumberRange(const FormattedNumberRange&) = delete; + + /** + * Copying not supported; use move assignment instead. + */ + FormattedNumberRange& operator=(const FormattedNumberRange&) = delete; + + /** + * Move constructor: + * Leaves the source FormattedNumberRange in an undefined state. + * @draft ICU 63 + */ + FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT; + + /** + * Move assignment: + * Leaves the source FormattedNumberRange in an undefined state. + * @draft ICU 63 + */ + FormattedNumberRange& operator=(FormattedNumberRange&& src) U_NOEXCEPT; + + /** + * Destruct an instance of FormattedNumberRange, cleaning up any memory it might own. + * @draft ICU 63 + */ + ~FormattedNumberRange(); + + private: + // Can't use LocalPointer because UFormattedNumberRangeData is forward-declared + const impl::UFormattedNumberRangeData *fResults; + + // Error code for the terminal methods + UErrorCode fErrorCode; + + /** + * Internal constructor from data type. Adopts the data pointer. + * @internal + */ + explicit FormattedNumberRange(impl::UFormattedNumberRangeData *results) + : fResults(results), fErrorCode(U_ZERO_ERROR) {}; + + explicit FormattedNumberRange(UErrorCode errorCode) + : fResults(nullptr), fErrorCode(errorCode) {}; + + void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; + + // To give LocalizedNumberRangeFormatter format methods access to this class's constructor: + friend class LocalizedNumberRangeFormatter; +}; + +/** + * See the main description in numberrangeformatter.h for documentation and examples. + * + * @draft ICU 63 + */ +class U_I18N_API NumberRangeFormatter final { + public: + /** + * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently + * known at the call site. + * + * @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining. + * @draft ICU 63 + */ + static UnlocalizedNumberRangeFormatter with(); + + /** + * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call + * site. + * + * @param locale + * The locale from which to load formats and symbols for number range formatting. + * @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining. + * @draft ICU 63 + */ + static LocalizedNumberRangeFormatter withLocale(const Locale &locale); + + /** + * Use factory methods instead of the constructor to create a NumberFormatter. + */ + NumberRangeFormatter() = delete; +}; + +} // namespace number +U_NAMESPACE_END + +#endif // U_HIDE_DRAFT_API + +#endif // __NUMBERRANGEFORMATTER_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/unicode/numfmt.h b/deps/icu-small/source/i18n/unicode/numfmt.h index 572e6afc71b807..871fbd93e15e2e 100644 --- a/deps/icu-small/source/i18n/unicode/numfmt.h +++ b/deps/icu-small/source/i18n/unicode/numfmt.h @@ -56,7 +56,6 @@ class StringEnumeration; *

    IMPORTANT: New users are strongly encouraged to see if * numberformatter.h fits their use case. Although not deprecated, this header * is provided for backwards compatibility only. - *


    * * Abstract base class for all number formats. Provides interface for * formatting and parsing a number. Also provides methods for @@ -710,7 +709,7 @@ class U_I18N_API NumberFormat : public Format { * The default formatting style is locale dependent. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 2.0 */ static NumberFormat* U_EXPORT2 createInstance(UErrorCode&); @@ -721,7 +720,7 @@ class U_I18N_API NumberFormat : public Format { * @param inLocale the given locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 2.0 */ static NumberFormat* U_EXPORT2 createInstance(const Locale& inLocale, @@ -731,7 +730,7 @@ class U_I18N_API NumberFormat : public Format { * Create a specific style NumberFormat for the specified locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param desiredLocale the given locale. * @param style the given style. * @param errorCode Output param filled with success/failure status. @@ -770,7 +769,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a currency format for the current default locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 2.0 */ static NumberFormat* U_EXPORT2 createCurrencyInstance(UErrorCode&); @@ -779,7 +778,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a currency format for the specified locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param inLocale the given locale. * @stable ICU 2.0 */ @@ -790,7 +789,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a percentage format for the current default locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 2.0 */ static NumberFormat* U_EXPORT2 createPercentInstance(UErrorCode&); @@ -799,7 +798,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a percentage format for the specified locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param inLocale the given locale. * @stable ICU 2.0 */ @@ -810,7 +809,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a scientific format for the current default locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @stable ICU 2.0 */ static NumberFormat* U_EXPORT2 createScientificInstance(UErrorCode&); @@ -819,7 +818,7 @@ class U_I18N_API NumberFormat : public Format { * Returns a scientific format for the specified locale. *

    * NOTE: New users are strongly encouraged to use - * {@link NumberFormatter} instead of NumberFormat. + * {@link icu::number::NumberFormatter} instead of NumberFormat. * @param inLocale the given locale. * @stable ICU 2.0 */ @@ -1028,14 +1027,14 @@ class U_I18N_API NumberFormat : public Format { * Get the rounding mode. This will always return NumberFormat::ERoundingMode::kRoundUnnecessary * if the subclass does not support rounding. * @return A rounding mode - * @draft ICU 60 + * @stable ICU 60 */ virtual ERoundingMode getRoundingMode(void) const; /** * Set the rounding mode. If a subclass does not support rounding, this will do nothing. * @param roundingMode A rounding mode - * @draft ICU 60 + * @stable ICU 60 */ virtual void setRoundingMode(ERoundingMode roundingMode); diff --git a/deps/icu-small/source/i18n/unicode/plurfmt.h b/deps/icu-small/source/i18n/unicode/plurfmt.h index 9a83e52550c540..6b757c88419316 100644 --- a/deps/icu-small/source/i18n/unicode/plurfmt.h +++ b/deps/icu-small/source/i18n/unicode/plurfmt.h @@ -520,15 +520,7 @@ class U_I18N_API PluralFormat : public Format { */ virtual UClassID getDynamicClassID() const; -#if (defined(__xlC__) && (__xlC__ < 0x0C00)) || (U_PLATFORM == U_PF_OS390) || (U_PLATFORM ==U_PF_OS400) -// Work around a compiler bug on xlC 11.1 on AIX 7.1 that would -// prevent PluralSelectorAdapter from implementing private PluralSelector. -// xlC error message: -// 1540-0300 (S) The "private" member "class icu_49::PluralFormat::PluralSelector" cannot be accessed. -public: -#else private: -#endif /** * @internal */ @@ -564,10 +556,6 @@ class U_I18N_API PluralFormat : public Format { PluralRules* pluralRules; }; -#if defined(__xlC__) -// End of xlC bug workaround, keep remaining definitions private. -private: -#endif Locale locale; MessagePattern msgPattern; NumberFormat* numberFormat; diff --git a/deps/icu-small/source/i18n/unicode/plurrule.h b/deps/icu-small/source/i18n/unicode/plurrule.h index 03dea3f1b92988..daeed52bee632e 100644 --- a/deps/icu-small/source/i18n/unicode/plurrule.h +++ b/deps/icu-small/source/i18n/unicode/plurrule.h @@ -118,7 +118,6 @@ class SharedPluralRules; * Examples are in the following table: *

    * - * * * * @@ -155,7 +154,6 @@ class SharedPluralRules; * * * - * *
    ni232
    *

    * The difference between 'in' and 'within' is that 'in' only includes integers in the specified range, while 'within' @@ -499,6 +497,12 @@ class U_I18N_API PluralRules : public UObject { UnicodeString getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& status); RuleChain *rulesForKeyword(const UnicodeString &keyword) const; + /** + * An internal status variable used to indicate that the object is in an 'invalid' state. + * Used by copy constructor, the assignment operator and the clone method. + */ + UErrorCode mInternalStatus; + friend class PluralRuleParser; }; diff --git a/deps/icu-small/source/i18n/unicode/rbnf.h b/deps/icu-small/source/i18n/unicode/rbnf.h index 2d284909f8a1d4..f7cd85a322d1f5 100644 --- a/deps/icu-small/source/i18n/unicode/rbnf.h +++ b/deps/icu-small/source/i18n/unicode/rbnf.h @@ -313,7 +313,6 @@ enum URBNFRuleSetTag { * The rule for an IEEE 754 NaN (not a number). * * - * * nothing * If the rule's rule descriptor is left out, the base value is one plus the * preceding rule's base value (or zero if this is the first rule in the list) in a normal @@ -1013,14 +1012,14 @@ class U_I18N_API RuleBasedNumberFormat : public NumberFormat { /** * Get the rounding mode. * @return A rounding mode - * @draft ICU 60 + * @stable ICU 60 */ virtual ERoundingMode getRoundingMode(void) const; /** * Set the rounding mode. * @param roundingMode A rounding mode - * @draft ICU 60 + * @stable ICU 60 */ virtual void setRoundingMode(ERoundingMode roundingMode); @@ -1095,7 +1094,7 @@ class U_I18N_API RuleBasedNumberFormat : public NumberFormat { void format(double number, NFRuleSet& rs, UnicodeString& toAppendTo, UErrorCode& status) const; private: - NFRuleSet **ruleSets; + NFRuleSet **fRuleSets; UnicodeString* ruleSetDescriptions; int32_t numRuleSets; NFRuleSet *defaultRuleSet; @@ -1104,7 +1103,7 @@ class U_I18N_API RuleBasedNumberFormat : public NumberFormat { DecimalFormatSymbols* decimalFormatSymbols; NFRule *defaultInfinityRule; NFRule *defaultNaNRule; - ERoundingMode roundingMode; + ERoundingMode fRoundingMode; UBool lenient; UnicodeString* lenientParseRules; LocalizationInfo* localizations; diff --git a/deps/icu-small/source/i18n/unicode/region.h b/deps/icu-small/source/i18n/unicode/region.h index 667c4051f0eb74..ccd63901a5d1b1 100644 --- a/deps/icu-small/source/i18n/unicode/region.h +++ b/deps/icu-small/source/i18n/unicode/region.h @@ -192,7 +192,7 @@ class U_I18N_API Region : public UObject { char id[4]; UnicodeString idStr; int32_t code; - URegionType type; + URegionType fType; Region *containingRegion; UVector *containedRegions; UVector *preferredValues; diff --git a/deps/icu-small/source/i18n/unicode/reldatefmt.h b/deps/icu-small/source/i18n/unicode/reldatefmt.h index abd43522c3a965..dd8bc53d55f500 100644 --- a/deps/icu-small/source/i18n/unicode/reldatefmt.h +++ b/deps/icu-small/source/i18n/unicode/reldatefmt.h @@ -165,12 +165,20 @@ typedef enum UDateAbsoluteUnit { */ UDAT_ABSOLUTE_NOW, +#ifndef U_HIDE_DRAFT_API + /** + * Quarter + * @draft ICU 63 + */ + UDAT_ABSOLUTE_QUARTER, +#endif // U_HIDE_DRAFT_API + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UDateAbsoluteUnit value. * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - UDAT_ABSOLUTE_UNIT_COUNT + UDAT_ABSOLUTE_UNIT_COUNT = UDAT_ABSOLUTE_NOW + 2 #endif // U_HIDE_DEPRECATED_API } UDateAbsoluteUnit; @@ -328,7 +336,7 @@ class U_I18N_API RelativeDateTimeFormatter : public UObject { * @param nfToAdopt Constructed object takes ownership of this pointer. * It is an error for caller to delete this pointer or change its * contents after calling this constructor. - * @status Any error is returned here. + * @param status Any error is returned here. * @stable ICU 53 */ RelativeDateTimeFormatter( @@ -346,7 +354,7 @@ class U_I18N_API RelativeDateTimeFormatter : public UObject { * @param style the format style. The UDAT_RELATIVE bit field has no effect. * @param capitalizationContext A value from UDisplayContext that pertains to * capitalization. - * @status Any error is returned here. + * @param status Any error is returned here. * @stable ICU 54 */ RelativeDateTimeFormatter( diff --git a/deps/icu-small/source/i18n/unicode/smpdtfmt.h b/deps/icu-small/source/i18n/unicode/smpdtfmt.h index 305412b8d1535f..929c1b4675b407 100644 --- a/deps/icu-small/source/i18n/unicode/smpdtfmt.h +++ b/deps/icu-small/source/i18n/unicode/smpdtfmt.h @@ -1147,7 +1147,7 @@ class U_I18N_API SimpleDateFormat: public DateFormat { * Overrides base class method and * This method clears per field NumberFormat instances * previously set by {@see adoptNumberFormat(const UnicodeString&, NumberFormat*, UErrorCode)} - * @param adoptNF the NumbeferFormat used + * @param formatToAdopt the NumbeferFormat used * @stable ICU 54 */ void adoptNumberFormat(NumberFormat *formatToAdopt); @@ -1162,7 +1162,7 @@ class U_I18N_API SimpleDateFormat: public DateFormat { * Per field NumberFormat can also be cleared in {@see DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)} * * @param fields the fields to override(like y) - * @param adoptNF the NumbeferFormat used + * @param formatToAdopt the NumbeferFormat used * @param status Receives a status code, which will be U_ZERO_ERROR * if the operation succeeds. * @stable ICU 54 diff --git a/deps/icu-small/source/i18n/unicode/translit.h b/deps/icu-small/source/i18n/unicode/translit.h index dc31d97bc63643..6b4888145f1be5 100644 --- a/deps/icu-small/source/i18n/unicode/translit.h +++ b/deps/icu-small/source/i18n/unicode/translit.h @@ -31,7 +31,6 @@ U_NAMESPACE_BEGIN class UnicodeFilter; class UnicodeSet; -class CompoundTransliterator; class TransliteratorParser; class NormalizationTransliterator; class TransliteratorIDParser; @@ -77,8 +76,7 @@ class TransliteratorIDParser; * transliteration. For example, given a string input * and a transliterator t, the call * - * \htmlonly

    \endhtmlonlyString result = t.transliterate(input); - * \htmlonly
    \endhtmlonly + * String result = t.transliterate(input); * * will transliterate it and return the result. Other methods allow * the client to specify a substring to be transliterated and to use @@ -98,22 +96,20 @@ class TransliteratorIDParser; * contents of the buffer may show text being modified as each new * character arrives. * - *

    Consider the simple RuleBasedTransliterator: - * - * \htmlonly

    \endhtmlonly - * th>{theta}
    - * t>{tau} - *
    \htmlonly
    \endhtmlonly + *

    Consider the simple rule-based Transliterator: + *

    + *     th>{theta}
    + *     t>{tau}
    + * 
    * * When the user types 't', nothing will happen, since the * transliterator is waiting to see if the next character is 'h'. To * remedy this, we introduce the notion of a cursor, marked by a '|' * in the output string: - * - * \htmlonly
    \endhtmlonly - * t>|{tau}
    - * {tau}h>{theta} - *
    \htmlonly
    \endhtmlonly + *
    + *     t>|{tau}
    + *     {tau}h>{theta}
    + * 
    * * Now when the user types 't', tau appears, and if the next character * is 'h', the tau changes to a theta. This is accomplished by @@ -135,7 +131,7 @@ class TransliteratorIDParser; * which the transliterator last stopped, either because it reached * the end, or because it required more characters to disambiguate * between possible inputs. The CURSOR can also be - * explicitly set by rules in a RuleBasedTransliterator. + * explicitly set by rules in a rule-based Transliterator. * Any characters before the CURSOR index are frozen; * future keyboard transliteration calls within this input sequence * will not change them. New text is inserted at the @@ -237,6 +233,255 @@ class TransliteratorIDParser; * if the performance of these methods can be improved over the * performance obtained by the default implementations in this class. * + *

    Rule syntax + * + *

    A set of rules determines how to perform translations. + * Rules within a rule set are separated by semicolons (';'). + * To include a literal semicolon, prefix it with a backslash ('\'). + * Unicode Pattern_White_Space is ignored. + * If the first non-blank character on a line is '#', + * the entire line is ignored as a comment. + * + *

    Each set of rules consists of two groups, one forward, and one + * reverse. This is a convention that is not enforced; rules for one + * direction may be omitted, with the result that translations in + * that direction will not modify the source text. In addition, + * bidirectional forward-reverse rules may be specified for + * symmetrical transformations. + * + *

    Note: Another description of the Transliterator rule syntax is available in + * section + * Transform Rules Syntax of UTS #35: Unicode LDML. + * The rules are shown there using arrow symbols ← and → and ↔. + * ICU supports both those and the equivalent ASCII symbols < and > and <>. + * + *

    Rule statements take one of the following forms: + * + *

    + *
    $alefmadda=\\u0622;
    + *
    Variable definition. The name on the + * left is assigned the text on the right. In this example, + * after this statement, instances of the left hand name, + * "$alefmadda", will be replaced by + * the Unicode character U+0622. Variable names must begin + * with a letter and consist only of letters, digits, and + * underscores. Case is significant. Duplicate names cause + * an exception to be thrown, that is, variables cannot be + * redefined. The right hand side may contain well-formed + * text of any length, including no text at all ("$empty=;"). + * The right hand side may contain embedded UnicodeSet + * patterns, for example, "$softvowel=[eiyEIY]".
    + *
    ai>$alefmadda;
    + *
    Forward translation rule. This rule + * states that the string on the left will be changed to the + * string on the right when performing forward + * transliteration.
    + *
    ai<$alefmadda;
    + *
    Reverse translation rule. This rule + * states that the string on the right will be changed to + * the string on the left when performing reverse + * transliteration.
    + *
    + * + *
    + *
    ai<>$alefmadda;
    + *
    Bidirectional translation rule. This + * rule states that the string on the right will be changed + * to the string on the left when performing forward + * transliteration, and vice versa when performing reverse + * transliteration.
    + *
    + * + *

    Translation rules consist of a match pattern and an output + * string. The match pattern consists of literal characters, + * optionally preceded by context, and optionally followed by + * context. Context characters, like literal pattern characters, + * must be matched in the text being transliterated. However, unlike + * literal pattern characters, they are not replaced by the output + * text. For example, the pattern "abc{def}" + * indicates the characters "def" must be + * preceded by "abc" for a successful match. + * If there is a successful match, "def" will + * be replaced, but not "abc". The final '}' + * is optional, so "abc{def" is equivalent to + * "abc{def}". Another example is "{123}456" + * (or "123}456") in which the literal + * pattern "123" must be followed by "456". + * + *

    The output string of a forward or reverse rule consists of + * characters to replace the literal pattern characters. If the + * output string contains the character '|', this is + * taken to indicate the location of the cursor after + * replacement. The cursor is the point in the text at which the + * next replacement, if any, will be applied. The cursor is usually + * placed within the replacement text; however, it can actually be + * placed into the precending or following context by using the + * special character '@'. Examples: + * + *

    + *     a {foo} z > | @ bar; # foo -> bar, move cursor before a
    + *     {foo} xyz > bar @@|; # foo -> bar, cursor between y and z
    + * 
    + * + *

    UnicodeSet + * + *

    UnicodeSet patterns may appear anywhere that + * makes sense. They may appear in variable definitions. + * Contrariwise, UnicodeSet patterns may themselves + * contain variable references, such as "$a=[a-z];$not_a=[^$a]", + * or "$range=a-z;$ll=[$range]". + * + *

    UnicodeSet patterns may also be embedded directly + * into rule strings. Thus, the following two rules are equivalent: + * + *

    + *     $vowel=[aeiou]; $vowel>'*'; # One way to do this
    + *     [aeiou]>'*'; # Another way
    + * 
    + * + *

    See {@link UnicodeSet} for more documentation and examples. + * + *

    Segments + * + *

    Segments of the input string can be matched and copied to the + * output string. This makes certain sets of rules simpler and more + * general, and makes reordering possible. For example: + * + *

    + *     ([a-z]) > $1 $1; # double lowercase letters
    + *     ([:Lu:]) ([:Ll:]) > $2 $1; # reverse order of Lu-Ll pairs
    + * 
    + * + *

    The segment of the input string to be copied is delimited by + * "(" and ")". Up to + * nine segments may be defined. Segments may not overlap. In the + * output string, "$1" through "$9" + * represent the input string segments, in left-to-right order of + * definition. + * + *

    Anchors + * + *

    Patterns can be anchored to the beginning or the end of the text. This is done with the + * special characters '^' and '$'. For example: + * + *

    + *   ^ a   > 'BEG_A';   # match 'a' at start of text
    + *     a   > 'A'; # match other instances of 'a'
    + *     z $ > 'END_Z';   # match 'z' at end of text
    + *     z   > 'Z';       # match other instances of 'z'
    + * 
    + * + *

    It is also possible to match the beginning or the end of the text using a UnicodeSet. + * This is done by including a virtual anchor character '$' at the end of the + * set pattern. Although this is usually the match chafacter for the end anchor, the set will + * match either the beginning or the end of the text, depending on its placement. For + * example: + * + *

    + *   $x = [a-z$];   # match 'a' through 'z' OR anchor
    + *   $x 1    > 2;   # match '1' after a-z or at the start
    + *      3 $x > 4;   # match '3' before a-z or at the end
    + * 
    + * + *

    Example + * + *

    The following example rules illustrate many of the features of + * the rule language. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Rule 1.abc{def}>x|y
    Rule 2.xyz>r
    Rule 3.yz>q
    + * + *

    Applying these rules to the string "adefabcdefz" + * yields the following results: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    |adefabcdefzInitial state, no rules match. Advance + * cursor.
    a|defabcdefzStill no match. Rule 1 does not match + * because the preceding context is not present.
    ad|efabcdefzStill no match. Keep advancing until + * there is a match...
    ade|fabcdefz...
    adef|abcdefz...
    adefa|bcdefz...
    adefab|cdefz...
    adefabc|defzRule 1 matches; replace "def" + * with "xy" and back up the cursor + * to before the 'y'.
    adefabcx|yzAlthough "xyz" is + * present, rule 2 does not match because the cursor is + * before the 'y', not before the 'x'. + * Rule 3 does match. Replace "yz" + * with "q".
    adefabcxq|The cursor is at the end; + * transliteration is complete.
    + * + *

    The order of rules is significant. If multiple rules may match + * at some point, the first matching rule is applied. + * + *

    Forward and reverse rules may have an empty output string. + * Otherwise, an empty left or right hand side of any statement is a + * syntax error. + * + *

    Single quotes are used to quote any character other than a + * digit or letter. To specify a single quote itself, inside or + * outside of quotes, use two single quotes in a row. For example, + * the rule "'>'>o''clock" changes the + * string ">" to the string "o'clock". + * + *

    Notes + * + *

    While a Transliterator is being built from rules, it checks that + * the rules are added in proper order. For example, if the rule + * "a>x" is followed by the rule "ab>y", + * then the second rule will throw an exception. The reason is that + * the second rule can never be triggered, since the first rule + * always matches anything it matches. In other words, the first + * rule masks the second rule. + * * @author Alan Liu * @stable ICU 2.0 */ @@ -499,9 +744,9 @@ class U_I18N_API Transliterator : public UObject { * for details. * @param text the buffer holding transliterated and * untransliterated text - * @param index an array of three integers. See {@link #transliterate(Replaceable&, UTransPosition&, const UnicodeString*, UErrorCode&) const }. + * @param index an array of three integers. * @param status Output param to filled in with a success or an error. - * @see #transliterate(Replaceable, int[], String) + * @see #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode &) const * @stable ICU 2.0 */ virtual void transliterate(Replaceable& text, UTransPosition& index, @@ -632,7 +877,7 @@ class U_I18N_API Transliterator : public UObject { /** * Transliterate a substring of text, as specified by index, taking filters * into account. This method is for subclasses that need to delegate to - * another transliterator, such as CompoundTransliterator. + * another transliterator. * @param text the text to be transliterated * @param index the position indices * @param incremental if TRUE, then assume more characters may be inserted @@ -846,17 +1091,19 @@ class U_I18N_API Transliterator : public UObject { /** * Returns a Transliterator object constructed from - * the given rule string. This will be a RuleBasedTransliterator, + * the given rule string. This will be a rule-based Transliterator, * if the rule string contains only rules, or a - * CompoundTransliterator, if it contains ID blocks, or a - * NullTransliterator, if it contains ID blocks which parse as + * compound Transliterator, if it contains ID blocks, or a + * null Transliterator, if it contains ID blocks which parse as * empty for the given direction. + * * @param ID the id for the transliterator. * @param rules rules, separated by ';' * @param dir either FORWARD or REVERSE. - * @param parseError Struct to recieve information on position + * @param parseError Struct to receive information on position * of error if an error is encountered * @param status Output param set to success/failure code. + * @return a newly created Transliterator * @stable ICU 2.0 */ static Transliterator* U_EXPORT2 createFromRules(const UnicodeString& ID, diff --git a/deps/icu-small/source/i18n/unicode/tzfmt.h b/deps/icu-small/source/i18n/unicode/tzfmt.h index 633cd8dc6987ce..d2aa768b8c8b34 100644 --- a/deps/icu-small/source/i18n/unicode/tzfmt.h +++ b/deps/icu-small/source/i18n/unicode/tzfmt.h @@ -237,10 +237,10 @@ typedef enum UTimeZoneFormatParseOption { */ UTZFMT_PARSE_OPTION_ALL_STYLES = 0x01, /** - * When parsing a time zone display name in UTZFMT_STYLE_SPECIFIC_SHORT, + * When parsing a time zone display name in \link UTZFMT_STYLE_SPECIFIC_SHORT \endlink, * look for the IANA tz database compatible zone abbreviations in addition - * to the localized names coming from the {@link TimeZoneNames} currently - * used by the {@link TimeZoneFormat}. + * to the localized names coming from the icu::TimeZoneNames currently + * used by the icu::TimeZoneFormat. * @stable ICU 54 */ UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS = 0x02 diff --git a/deps/icu-small/source/i18n/unicode/ucal.h b/deps/icu-small/source/i18n/unicode/ucal.h index 10d8bc52745d2b..889a1ec51db52c 100644 --- a/deps/icu-small/source/i18n/unicode/ucal.h +++ b/deps/icu-small/source/i18n/unicode/ucal.h @@ -139,6 +139,19 @@ * For example, subtracting 5 days from the date September 12, 1996 * results in September 7, 1996. * + *

    + * The Japanese calendar uses a combination of era name and year number. + * When an emperor of Japan abdicates and a new emperor ascends the throne, + * a new era is declared and year number is reset to 1. Even if the date of + * abdication is scheduled ahead of time, the new era name might not be + * announced until just before the date. In such case, ICU4C may include + * a start date of future era without actual era name, but not enabled + * by default. ICU4C users who want to test the behavior of the future era + * can enable the tentative era by: + *

      + *
    • Environment variable ICU_ENABLE_TENTATIVE_ERA=true.
    • + *
    + * * @stable ICU 2.0 */ diff --git a/deps/icu-small/source/i18n/unicode/ucol.h b/deps/icu-small/source/i18n/unicode/ucol.h index b5bacbfcb4734e..f084ac61e614f3 100644 --- a/deps/icu-small/source/i18n/unicode/ucol.h +++ b/deps/icu-small/source/i18n/unicode/ucol.h @@ -1149,7 +1149,7 @@ ucol_getUCAVersion(const UCollator* coll, UVersionInfo info); * The recommended way to achieve "merged" sorting is by * concatenating strings with U+FFFE between them. * The concatenation has the same sort order as the merged sort keys, - * but merge(getSortKey(str1), getSortKey(str2)) may differ from getSortKey(str1 + '\uFFFE' + str2). + * but merge(getSortKey(str1), getSortKey(str2)) may differ from getSortKey(str1 + '\\uFFFE' + str2). * Using strings with U+FFFE may yield shorter sort keys. * * For details about Sort Key Features see @@ -1294,6 +1294,7 @@ U_STABLE uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCod * the top of one of the supported reordering groups, * and it must not be beyond the last of those groups. * See ucol_setMaxVariable(). + * @param coll collator to be set * @param varTop primary weight, as returned by ucol_setVariableTop or ucol_getVariableTop * @param status error code * @see ucol_getVariableTop diff --git a/deps/icu-small/source/i18n/unicode/ugender.h b/deps/icu-small/source/i18n/unicode/ugender.h index d015a2300cf6d6..903f3dd5deebbe 100644 --- a/deps/icu-small/source/i18n/unicode/ugender.h +++ b/deps/icu-small/source/i18n/unicode/ugender.h @@ -49,11 +49,11 @@ enum UGender { */ typedef enum UGender UGender; +struct UGenderInfo; /** * Opaque UGenderInfo object for use in C programs. * @stable ICU 50 */ -struct UGenderInfo; typedef struct UGenderInfo UGenderInfo; /** @@ -77,7 +77,7 @@ ugender_getInstance(const char *locale, UErrorCode *status); * @stable ICU 50 */ U_STABLE UGender U_EXPORT2 -ugender_getListGender(const UGenderInfo* genderinfo, const UGender *genders, int32_t size, UErrorCode *status); +ugender_getListGender(const UGenderInfo* genderInfo, const UGender *genders, int32_t size, UErrorCode *status); #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/common/unicode/ulistformatter.h b/deps/icu-small/source/i18n/unicode/ulistformatter.h similarity index 90% rename from deps/icu-small/source/common/unicode/ulistformatter.h rename to deps/icu-small/source/i18n/unicode/ulistformatter.h index e98a9f045221d9..242d7d21644762 100644 --- a/deps/icu-small/source/common/unicode/ulistformatter.h +++ b/deps/icu-small/source/i18n/unicode/ulistformatter.h @@ -33,6 +33,26 @@ struct UListFormatter; typedef struct UListFormatter UListFormatter; /**< C typedef for struct UListFormatter. @stable ICU 55 */ +#ifndef U_HIDE_DRAFT_API +/** + * FieldPosition and UFieldPosition selectors for format fields + * defined by ListFormatter. + * @draft ICU 63 + */ +typedef enum UListFormatterField { + /** + * The literal text in the result which came from the resources. + * @draft ICU 63 + */ + ULISTFMT_LITERAL_FIELD, + /** + * The element text in the result which came from the input strings. + * @draft ICU 63 + */ + ULISTFMT_ELEMENT_FIELD +} UListFormatterField; +#endif // U_HIDE_DRAFT_API + /** * Open a new UListFormatter object using the rules for a given locale. * @param locale diff --git a/deps/icu-small/source/i18n/unicode/unumberformatter.h b/deps/icu-small/source/i18n/unicode/unumberformatter.h index b37f80c503a76d..d05b15cdeccafb 100644 --- a/deps/icu-small/source/i18n/unicode/unumberformatter.h +++ b/deps/icu-small/source/i18n/unicode/unumberformatter.h @@ -91,7 +91,7 @@ * * *

    - * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}. + * This enum is similar to {@link UMeasureFormatWidth}. * * @draft ICU 60 */ @@ -190,10 +190,9 @@ typedef enum UNumberUnitWidth { * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the * grouping separator, use the "symbols" setter. * - * @draft ICU 61 -- TODO: This should be renamed to UNumberGroupingStrategy before promoting to stable, - * for consistency with the other enums. + * @draft ICU 63 */ -typedef enum UGroupingStrategy { +typedef enum UNumberGroupingStrategy { /** * Do not display grouping separators in any locale. * @@ -254,16 +253,28 @@ typedef enum UGroupingStrategy { * * @draft ICU 61 */ - UNUM_GROUPING_THOUSANDS, + UNUM_GROUPING_THOUSANDS +#ifndef U_HIDE_INTERNAL_API + , /** - * One more than the highest UGroupingStrategy value. + * One more than the highest UNumberGroupingStrategy value. * * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420. */ UNUM_GROUPING_COUNT +#endif /* U_HIDE_INTERNAL_API */ + +} UNumberGroupingStrategy; + +#ifndef U_HIDE_DEPRECATED_API +/** + * Old name for compatibility: will be removed in ICU 64. + * @deprecated ICU 63 + */ +typedef UNumberGroupingStrategy UGroupingStrategy; +#endif /* U_HIDE_DEPRECATED_API */ -} UGroupingStrategy; #endif /* U_HIDE_DRAFT_API */ #ifndef U_HIDE_DRAFT_API @@ -398,6 +409,8 @@ typedef enum UNumberDecimalSeparatorDisplay { #endif /* U_HIDE_DRAFT_API */ #ifndef U_HIDE_DRAFT_API + +struct UNumberFormatter; /** * C-compatible version of icu::number::LocalizedNumberFormatter. * @@ -405,10 +418,9 @@ typedef enum UNumberDecimalSeparatorDisplay { * * @draft ICU 62 */ -struct UNumberFormatter; typedef struct UNumberFormatter UNumberFormatter; - +struct UFormattedNumber; /** * C-compatible version of icu::number::FormattedNumber. * @@ -416,7 +428,6 @@ typedef struct UNumberFormatter UNumberFormatter; * * @draft ICU 62 */ -struct UFormattedNumber; typedef struct UFormattedNumber UFormattedNumber; @@ -559,7 +570,8 @@ unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t buf * * NOTE: All fields of the UFieldPosition must be initialized before calling this method. * - * @param fieldPosition + * @param uresult The object containing the formatted number. + * @param ufpos * Input+output variable. On input, the "field" property determines which field to look up, * and the "endIndex" property determines where to begin the search. On output, the * "beginIndex" field is set to the beginning of the first occurrence of the field after the @@ -580,7 +592,7 @@ unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* u * If you need information on only one field, use unumf_resultNextFieldPosition(). * * @param uresult The object containing the formatted number. - * @param fpositer + * @param ufpositer * A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration * information already present in the UFieldPositionIterator is deleted, and the iterator is reset * to apply to the fields in the formatted string created by this function call. The field values diff --git a/deps/icu-small/source/i18n/unicode/usearch.h b/deps/icu-small/source/i18n/unicode/usearch.h index 600f9142b45021..6b495ef00140f1 100644 --- a/deps/icu-small/source/i18n/unicode/usearch.h +++ b/deps/icu-small/source/i18n/unicode/usearch.h @@ -257,10 +257,9 @@ typedef enum { * match an e with the same diacritic or a plain e in the searched text. * * This option is similar to "asymmetric search" as described in - * - * UTS #10 Unicode Collation Algorithm * UTS 39 defines two strings to be confusable if they map to the same skeleton string. A skeleton can * be thought of as a "hash code". {@link uspoof_getSkeleton} computes the skeleton for a particular string, so * the following snippet is equivalent to the example above: @@ -128,7 +127,6 @@ * free(skel2); * \endcode * - *

    * If you need to check if a string is confusable with any string in a dictionary of many strings, rather than calling * {@link uspoof_areConfusable} many times in a loop, {@link uspoof_getSkeleton} can be used instead, as shown below: * @@ -172,14 +170,12 @@ * uspoof_close(sc); * \endcode * - *

    * Note: Since the Unicode confusables mapping table is frequently updated, confusable skeletons are not * guaranteed to be the same between ICU releases. We therefore recommend that you always compute confusable skeletons * at runtime and do not rely on creating a permanent, or difficult to update, database of skeletons. * *

    Spoof Detection

    * - *

    * The following snippet shows a minimal example of using USpoofChecker to perform spoof detection on a * string: * @@ -204,16 +200,13 @@ * uset_close(allowed); * \endcode * - *

    * As in the case for confusability checking, it is good practice to create one USpoofChecker instance at * startup, and call the cheaper {@link uspoof_check} online. We specify the set of * allowed characters to be those with type RECOMMENDED or INCLUSION, according to the recommendation in UTS 39. * - *

    * In addition to {@link uspoof_check}, the function {@link uspoof_checkUTF8} is exposed for UTF8-encoded char* strings, * and {@link uspoof_checkUnicodeString} is exposed for C++ programmers. * - *

    * If the {@link USPOOF_AUX_INFO} check is enabled, a limited amount of information on why a string failed the checks * is available in the returned bitmask. For complete information, use the {@link uspoof_check2} class of functions * with a {@link USpoofCheckResult} parameter: @@ -274,7 +267,6 @@ * // Explicit cleanup not necessary. * \endcode * - *

    * The return value is a bitmask of the checks that failed. In this case, there was one check that failed: * {@link USPOOF_RESTRICTION_LEVEL}, corresponding to the fifth bit (16). The possible checks are: * @@ -307,7 +299,6 @@ * uspoof_close(sc); * \endcode * - *

    * Here is an example in C++ showing how to compute the restriction level of a string: * * \code{.cpp} @@ -334,11 +325,9 @@ * printf("Restriction level: %#010x (status: %s)\n", restrictionLevel, u_errorName(status)); * \endcode * - *

    * The code '0x50000000' corresponds to the restriction level USPOOF_MINIMALLY_RESTRICTIVE. Since * USPOOF_MINIMALLY_RESTRICTIVE is weaker than USPOOF_MODERATELY_RESTRICTIVE, the string fails the check. * - *

    * Note: The Restriction Level is the most powerful of the checks. The full logic is documented in * UTS 39, but the basic idea is that strings * are restricted to contain characters from only a single script, except that most scripts are allowed to have @@ -352,15 +341,12 @@ * *

    Additional Information

    * - *

    * A USpoofChecker instance may be used repeatedly to perform checks on any number of identifiers. * - *

    * Thread Safety: The test functions for checking a single identifier, or for testing whether * two identifiers are possible confusable, are thread safe. They may called concurrently, from multiple threads, * using the same USpoofChecker instance. * - *

    * More generally, the standard ICU thread safety rules apply: functions that take a const USpoofChecker parameter are * thread safe. Those that take a non-const USpoofChecker are not thread safe.. * @@ -1219,14 +1205,21 @@ U_NAMESPACE_BEGIN /** * \class LocalUSpoofCheckResultPointer - * "Smart pointer" class, closes a USpoofCheckResult via {@link uspoof_closeCheckResult}. + * "Smart pointer" class, closes a USpoofCheckResult via `uspoof_closeCheckResult()`. * For most methods see the LocalPointerBase base class. * * @see LocalPointerBase * @see LocalPointer * @stable ICU 58 */ + +/** + * \cond + * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER. + * For now, suppress with a Doxygen cond + */ U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckResultPointer, USpoofCheckResult, uspoof_closeCheckResult); +/** \endcond */ U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/uregex.cpp b/deps/icu-small/source/i18n/uregex.cpp index 370384363483e7..f504aec91bd7c3 100644 --- a/deps/icu-small/source/i18n/uregex.cpp +++ b/deps/icu-small/source/i18n/uregex.cpp @@ -1654,8 +1654,8 @@ int32_t RegexCImpl::appendTail(RegularExpression *regexp, } else if (UTEXT_USES_U16(m->fInputText)) { srcIdx = (int32_t)nativeIdx; } else { - UErrorCode status = U_ZERO_ERROR; - srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &status); + UErrorCode newStatus = U_ZERO_ERROR; + srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &newStatus); } for (;;) { diff --git a/deps/icu-small/source/i18n/usearch.cpp b/deps/icu-small/source/i18n/usearch.cpp index e1e6c28e2bc985..0e4cca77a13ae0 100644 --- a/deps/icu-small/source/i18n/usearch.cpp +++ b/deps/icu-small/source/i18n/usearch.cpp @@ -498,7 +498,7 @@ inline void setShiftTable(int16_t shift[], int16_t backshift[], for (count = 0; count < cesize; count ++) { // number of ces from right of array to the count int temp = defaultforward - count - 1; - shift[hashFromCE32(cetable[count])] = temp > 1 ? temp : 1; + shift[hashFromCE32(cetable[count])] = temp > 1 ? static_cast(temp) : 1; } shift[hashFromCE32(cetable[cesize])] = 1; // for ignorables we just shift by one. see test examples. diff --git a/deps/icu-small/source/i18n/uspoof_impl.h b/deps/icu-small/source/i18n/uspoof_impl.h index 470a31f2c979bc..7d6d0f76e34275 100644 --- a/deps/icu-small/source/i18n/uspoof_impl.h +++ b/deps/icu-small/source/i18n/uspoof_impl.h @@ -20,7 +20,7 @@ #include "unicode/uspoof.h" #include "unicode/uscript.h" #include "unicode/udata.h" - +#include "udataswp.h" #include "utrie2.h" #if !UCONFIG_NO_NORMALIZATION diff --git a/deps/icu-small/source/i18n/vtzone.cpp b/deps/icu-small/source/i18n/vtzone.cpp index 0c76c9b6c98bf2..e39eada51b7f61 100644 --- a/deps/icu-small/source/i18n/vtzone.cpp +++ b/deps/icu-small/source/i18n/vtzone.cpp @@ -135,7 +135,7 @@ static UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeS digits[i++] = number % 10; number /= 10; } while (number != 0); - length = i; + length = static_cast(i); } else { // fixed digits for (i = 0; i < length; i++) { diff --git a/deps/icu-small/source/i18n/zonemeta.cpp b/deps/icu-small/source/i18n/zonemeta.cpp index 02562048a525da..b7139a807b3fb7 100644 --- a/deps/icu-small/source/i18n/zonemeta.cpp +++ b/deps/icu-small/source/i18n/zonemeta.cpp @@ -319,10 +319,10 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { id[len] = (char) 0; // Make sure it is null terminated. // replace '/' with ':' - char *p = id; - while (*p++) { - if (*p == '/') { - *p = ':'; + char *q = id; + while (*q++) { + if (*q == '/') { + *q = ':'; } } @@ -850,13 +850,13 @@ ZoneMeta::createCustomTimeZone(int32_t offset) { negative = TRUE; tmp = -offset; } - int32_t hour, min, sec; + uint8_t hour, min, sec; tmp /= 1000; - sec = tmp % 60; + sec = static_cast(tmp % 60); tmp /= 60; - min = tmp % 60; - hour = tmp / 60; + min = static_cast(tmp % 60); + hour = static_cast(tmp / 60); UnicodeString zid; formatCustomID(hour, min, sec, negative, zid); diff --git a/deps/icu-small/source/tools/genrb/parse.cpp b/deps/icu-small/source/tools/genrb/parse.cpp index ddfb082afe63f4..1f6246d3cfbf46 100644 --- a/deps/icu-small/source/tools/genrb/parse.cpp +++ b/deps/icu-small/source/tools/genrb/parse.cpp @@ -1018,6 +1018,11 @@ addCollation(ParseState* state, TableResource *result, const char *collationTyp icu::CollationInfo::printReorderRanges( *t->data, t->settings->reorderCodes, t->settings->reorderCodesLength); } +#if 0 // debugging output + } else { + printf("%s~%s collation tailoring part sizes:\n", state->filename, collationType); + icu::CollationInfo::printSizes(totalSize, indexes); +#endif } struct SResource *collationBin = bin_open(state->bundle, "%%CollationBin", totalSize, dest, NULL, NULL, status); result->add(collationBin, line, *status); diff --git a/deps/icu-small/source/tools/genrb/reslist.cpp b/deps/icu-small/source/tools/genrb/reslist.cpp index 2e04bbce21ef74..0493347ebe5194 100644 --- a/deps/icu-small/source/tools/genrb/reslist.cpp +++ b/deps/icu-small/source/tools/genrb/reslist.cpp @@ -1395,7 +1395,7 @@ SRBRoot::compactKeys(UErrorCode &errorCode) { int32_t offset; suffix = keys + map[j].oldpos; for (suffixLimit = suffix; *suffixLimit != 0; ++suffixLimit) {} - offset = (int32_t)(keyLimit - key) - (suffixLimit - suffix); + offset = static_cast((keyLimit - key) - (suffixLimit - suffix)); if (offset < 0) { break; /* suffix cannot be longer than the original */ } diff --git a/deps/icu-small/source/tools/pkgdata/pkgdata.cpp b/deps/icu-small/source/tools/pkgdata/pkgdata.cpp index d4dc271732d80f..d7e5721c2d0fab 100644 --- a/deps/icu-small/source/tools/pkgdata/pkgdata.cpp +++ b/deps/icu-small/source/tools/pkgdata/pkgdata.cpp @@ -511,7 +511,7 @@ main(int argc, char* argv[]) { static int runCommand(const char* command, UBool specialHandling) { char *cmd = NULL; char cmdBuffer[SMALL_BUFFER_MAX_SIZE]; - int32_t len = strlen(command); + int32_t len = static_cast(strlen(command)); if (len == 0) { return 0; @@ -904,7 +904,8 @@ static void createFileNames(UPKGOptions *o, const char mode, const char *version if (IN_DLL_MODE(mode)) { sprintf(libFileNames[LIB_FILE], "%s", libName); } else { - sprintf(libFileNames[LIB_FILE], "%s%s", + sprintf(libFileNames[LIB_FILE], "%s%s%s", + (strstr(libName, "icudt") ? "lib" : ""), pkgDataFlags[LIBPREFIX], libName); } @@ -1020,7 +1021,7 @@ static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) char name2[SMALL_BUFFER_MAX_SIZE]; /* file name to symlink */ const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : "."; -#if !defined(USING_CYGWIN) && U_PLATFORM != U_PF_MINGW +#if U_PLATFORM != U_PF_CYGWIN /* No symbolic link to make. */ if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 || uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) { @@ -1225,7 +1226,7 @@ static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, c if (f != NULL) { for(;;) { if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) { - bufferLength = uprv_strlen(buffer); + bufferLength = static_cast(uprv_strlen(buffer)); /* Remove new line character. */ if (bufferLength > 0) { buffer[bufferLength-1] = 0; diff --git a/deps/icu-small/source/tools/toolutil/filestrm.cpp b/deps/icu-small/source/tools/toolutil/filestrm.cpp index cfffa1b75d7724..a170c7b0f29e2e 100644 --- a/deps/icu-small/source/tools/toolutil/filestrm.cpp +++ b/deps/icu-small/source/tools/toolutil/filestrm.cpp @@ -104,14 +104,14 @@ T_FileStream_tmpfile() U_CAPI int32_t U_EXPORT2 T_FileStream_read(FileStream* fileStream, void* addr, int32_t len) { - return fread(addr, 1, len, (FILE*)fileStream); + return static_cast(fread(addr, 1, len, (FILE*)fileStream)); } U_CAPI int32_t U_EXPORT2 T_FileStream_write(FileStream* fileStream, const void* addr, int32_t len) { - return fwrite(addr, 1, len, (FILE*)fileStream); + return static_cast(fwrite(addr, 1, len, (FILE*)fileStream)); } U_CAPI void U_EXPORT2 diff --git a/deps/icu-small/source/tools/toolutil/filetools.cpp b/deps/icu-small/source/tools/toolutil/filetools.cpp index 176a791b0df853..6e88c94b5200b5 100644 --- a/deps/icu-small/source/tools/toolutil/filetools.cpp +++ b/deps/icu-small/source/tools/toolutil/filetools.cpp @@ -134,7 +134,7 @@ static int32_t whichFileModTimeIsLater(const char *file1, const char *file2) { /* Swap the file separater character given with the new one in the file path. */ U_CAPI void U_EXPORT2 swapFileSepChar(char *filePath, const char oldFileSepChar, const char newFileSepChar) { - for (int32_t i = 0, length = uprv_strlen(filePath); i < length; i++) { + for (int32_t i = 0, length = static_cast(uprv_strlen(filePath)); i < length; i++) { filePath[i] = (filePath[i] == oldFileSepChar ) ? newFileSepChar : filePath[i]; } } diff --git a/deps/icu-small/source/tools/toolutil/package.cpp b/deps/icu-small/source/tools/toolutil/package.cpp index d96c6dd36ddb41..f4e428a37e7153 100644 --- a/deps/icu-small/source/tools/toolutil/package.cpp +++ b/deps/icu-small/source/tools/toolutil/package.cpp @@ -610,7 +610,7 @@ Package::readPackage(const char *filename) { memcpy(prefix, s, ++prefixLength); // include the / } else { // Use the package basename as prefix. - int32_t inPkgNameLength=strlen(inPkgName); + int32_t inPkgNameLength= static_cast(strlen(inPkgName)); memcpy(prefix, inPkgName, inPkgNameLength); prefixLength=inPkgNameLength; @@ -1043,7 +1043,7 @@ Package::addItem(const char *name, uint8_t *data, int32_t length, UBool isDataOw memset(items+idx, 0, sizeof(Item)); // copy the item's name - items[idx].name=allocString(TRUE, strlen(name)); + items[idx].name=allocString(TRUE, static_cast(strlen(name))); strcpy(items[idx].name, name); pathToTree(items[idx].name); } else { diff --git a/deps/icu-small/source/tools/toolutil/swapimpl.cpp b/deps/icu-small/source/tools/toolutil/swapimpl.cpp index f3f333a005eb43..e8850cb9864168 100644 --- a/deps/icu-small/source/tools/toolutil/swapimpl.cpp +++ b/deps/icu-small/source/tools/toolutil/swapimpl.cpp @@ -243,7 +243,7 @@ uprops_swap(const UDataSwapper *ds, * swap the main properties UTrie * PT serialized properties trie, see utrie.h (byte size: 4*(i0-16)) */ - utrie2_swapAnyVersion(ds, + utrie_swapAnyVersion(ds, inData32+UPROPS_INDEX_COUNT, 4*(dataIndexes[UPROPS_PROPS32_INDEX]-UPROPS_INDEX_COUNT), outData32+UPROPS_INDEX_COUNT, @@ -274,7 +274,7 @@ uprops_swap(const UDataSwapper *ds, * swap the additional UTrie * i3 additionalTrieIndex; -- 32-bit unit index to the additional trie for more properties */ - utrie2_swapAnyVersion(ds, + utrie_swapAnyVersion(ds, inData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX], 4*(dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX]-dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX]), outData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX], @@ -336,7 +336,7 @@ ucase_swap(const UDataSwapper *ds, ((pInfo->formatVersion[0]==1 && pInfo->formatVersion[2]==UTRIE_SHIFT && pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT) || - 2<=pInfo->formatVersion[0] || pInfo->formatVersion[0]<=4) + (2<=pInfo->formatVersion[0] && pInfo->formatVersion[0]<=4)) )) { udata_printError(ds, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n", pInfo->dataFormat[0], pInfo->dataFormat[1], @@ -391,7 +391,7 @@ ucase_swap(const UDataSwapper *ds, /* swap the UTrie */ count=indexes[UCASE_IX_TRIE_SIZE]; - utrie2_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode); + utrie_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode); offset+=count; /* swap the uint16_t exceptions[] and unfold[] */ @@ -493,7 +493,7 @@ ubidi_swap(const UDataSwapper *ds, /* swap the UTrie */ count=indexes[UBIDI_IX_TRIE_SIZE]; - utrie2_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode); + utrie_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode); offset+=count; /* swap the uint32_t mirrors[] */ diff --git a/deps/icu-small/source/tools/toolutil/udbgutil.cpp b/deps/icu-small/source/tools/toolutil/udbgutil.cpp index dcc80ebe069519..285f68a0ec66a1 100644 --- a/deps/icu-small/source/tools/toolutil/udbgutil.cpp +++ b/deps/icu-small/source/tools/toolutil/udbgutil.cpp @@ -400,7 +400,7 @@ U_CAPI int32_t paramStatic(const USystemParams *param, char *target, int32_t targetCapacity, UErrorCode *status) { if(param->paramStr==NULL) return paramEmpty(param,target,targetCapacity,status); if(U_FAILURE(*status))return 0; - int32_t len = uprv_strlen(param->paramStr); + int32_t len = static_cast(uprv_strlen(param->paramStr)); if(target!=NULL) { uprv_strncpy(target,param->paramStr,uprv_min(len,targetCapacity)); } @@ -412,14 +412,14 @@ static const char *nullString = "(null)"; static int32_t stringToStringBuffer(char *target, int32_t targetCapacity, const char *str, UErrorCode *status) { if(str==NULL) str=nullString; - int32_t len = uprv_strlen(str); + int32_t len = static_cast(uprv_strlen(str)); if (U_SUCCESS(*status)) { if(target!=NULL) { uprv_strncpy(target,str,uprv_min(len,targetCapacity)); } } else { const char *s = u_errorName(*status); - len = uprv_strlen(s); + len = static_cast(uprv_strlen(s)); if(target!=NULL) { uprv_strncpy(target,s,uprv_min(len,targetCapacity)); } diff --git a/deps/icu-small/source/tools/toolutil/unewdata.cpp b/deps/icu-small/source/tools/toolutil/unewdata.cpp index 5c28e992c9a98b..22d8540881f454 100644 --- a/deps/icu-small/source/tools/toolutil/unewdata.cpp +++ b/deps/icu-small/source/tools/toolutil/unewdata.cpp @@ -61,17 +61,17 @@ udata_create(const char *dir, const char *type, const char *name, length = 0; /* Start with nothing */ if(dir != NULL && *dir !=0) /* Add directory length if one was given */ { - length += strlen(dir); + length += static_cast(strlen(dir)); /* Add 1 if dir doesn't end with path sep */ if (dir[strlen(dir) - 1]!= U_FILE_SEP_CHAR) { length++; } } - length += strlen(name); /* Add the filename length */ + length += static_cast(strlen(name)); /* Add the filename length */ if(type != NULL && *type !=0) { /* Add directory length if given */ - length += strlen(type); + length += static_cast(strlen(type)); } diff --git a/deps/icu-small/source/tools/toolutil/writesrc.cpp b/deps/icu-small/source/tools/toolutil/writesrc.cpp index c05a07acd3aa34..1a1dd3964d34a2 100644 --- a/deps/icu-small/source/tools/toolutil/writesrc.cpp +++ b/deps/icu-small/source/tools/toolutil/writesrc.cpp @@ -22,13 +22,14 @@ #include #include "unicode/utypes.h" #include "unicode/putil.h" +#include "unicode/ucptrie.h" #include "utrie2.h" #include "cstring.h" #include "writesrc.h" static FILE * usrc_createWithHeader(const char *path, const char *filename, - const char *generator, const char *header) { + const char *header, const char *generator) { char buffer[1024]; const char *p; char *q; @@ -71,20 +72,34 @@ usrc_createWithHeader(const char *path, const char *filename, } U_CAPI FILE * U_EXPORT2 -usrc_create(const char *path, const char *filename, const char *generator) { - // TODO: Add parameter for the first year this file was generated, not before 2016. - static const char *header= - "// © 2016 and later: Unicode, Inc. and others.\n" - "// License & terms of use: http://www.unicode.org/copyright.html\n" - "//\n" - "// Copyright (C) 1999-2016, International Business Machines\n" - "// Corporation and others. All Rights Reserved.\n" - "//\n" - "// file name: %s\n" - "//\n" - "// machine-generated by: %s\n" - "\n\n"; - return usrc_createWithHeader(path, filename, generator, header); +usrc_create(const char *path, const char *filename, int32_t copyrightYear, const char *generator) { + const char *header; + char buffer[200]; + if(copyrightYear<=2016) { + header= + "// © 2016 and later: Unicode, Inc. and others.\n" + "// License & terms of use: http://www.unicode.org/copyright.html\n" + "//\n" + "// Copyright (C) 1999-2016, International Business Machines\n" + "// Corporation and others. All Rights Reserved.\n" + "//\n" + "// file name: %s\n" + "//\n" + "// machine-generated by: %s\n" + "\n\n"; + } else { + sprintf(buffer, + "// © %d and later: Unicode, Inc. and others.\n" + "// License & terms of use: http://www.unicode.org/copyright.html\n" + "//\n" + "// file name: %%s\n" + "//\n" + "// machine-generated by: %%s\n" + "\n\n", + (int)copyrightYear); + header=buffer; + } + return usrc_createWithHeader(path, filename, header, generator); } U_CAPI FILE * U_EXPORT2 @@ -100,7 +115,7 @@ usrc_createTextData(const char *path, const char *filename, const char *generato "#\n" "# machine-generated by: %s\n" "\n\n"; - return usrc_createWithHeader(path, filename, generator, header); + return usrc_createWithHeader(path, filename, header, generator); } U_CAPI void U_EXPORT2 @@ -228,6 +243,68 @@ usrc_writeUTrie2Struct(FILE *f, } } +U_CAPI void U_EXPORT2 +usrc_writeUCPTrieArrays(FILE *f, + const char *indexPrefix, const char *dataPrefix, + const UCPTrie *pTrie, + const char *postfix) { + usrc_writeArray(f, indexPrefix, pTrie->index, 16, pTrie->indexLength, postfix); + int32_t width= + pTrie->valueWidth==UCPTRIE_VALUE_BITS_16 ? 16 : + pTrie->valueWidth==UCPTRIE_VALUE_BITS_32 ? 32 : + pTrie->valueWidth==UCPTRIE_VALUE_BITS_8 ? 8 : 0; + usrc_writeArray(f, dataPrefix, pTrie->data.ptr0, width, pTrie->dataLength, postfix); +} + +U_CAPI void U_EXPORT2 +usrc_writeUCPTrieStruct(FILE *f, + const char *prefix, + const UCPTrie *pTrie, + const char *indexName, const char *dataName, + const char *postfix) { + if(prefix!=NULL) { + fputs(prefix, f); + } + fprintf( + f, + " %s,\n" // index + " { %s },\n", // data (union) + indexName, + dataName); + fprintf( + f, + " %ld, %ld,\n" // indexLength, dataLength + " 0x%lx, 0x%x,\n" // highStart, shifted12HighStart + " %d, %d,\n" // type, valueWidth + " 0, 0,\n" // reserved32, reserved16 + " 0x%x, 0x%lx,\n" // index3NullOffset, dataNullOffset + " 0x%lx,\n", // nullValue + (long)pTrie->indexLength, (long)pTrie->dataLength, + (long)pTrie->highStart, pTrie->shifted12HighStart, + pTrie->type, pTrie->valueWidth, + pTrie->index3NullOffset, (long)pTrie->dataNullOffset, + (long)pTrie->nullValue); + if(postfix!=NULL) { + fputs(postfix, f); + } +} + +U_CAPI void U_EXPORT2 +usrc_writeUCPTrie(FILE *f, const char *name, const UCPTrie *pTrie) { + int32_t width= + pTrie->valueWidth==UCPTRIE_VALUE_BITS_16 ? 16 : + pTrie->valueWidth==UCPTRIE_VALUE_BITS_32 ? 32 : + pTrie->valueWidth==UCPTRIE_VALUE_BITS_8 ? 8 : 0; + char line[100], line2[100], line3[100]; + sprintf(line, "static const uint16_t %s_trieIndex[%%ld]={\n", name); + sprintf(line2, "static const uint%d_t %s_trieData[%%ld]={\n", (int)width, name); + usrc_writeUCPTrieArrays(f, line, line2, pTrie, "\n};\n\n"); + sprintf(line, "static const UCPTrie %s_trie={\n", name); + sprintf(line2, "%s_trieIndex", name); + sprintf(line3, "%s_trieData", name); + usrc_writeUCPTrieStruct(f, line, pTrie, line2, line3, "};\n\n"); +} + U_CAPI void U_EXPORT2 usrc_writeArrayOfMostlyInvChars(FILE *f, const char *prefix, diff --git a/deps/icu-small/source/tools/toolutil/writesrc.h b/deps/icu-small/source/tools/toolutil/writesrc.h index fdcf1f9a6b40f3..35ba256793c03a 100644 --- a/deps/icu-small/source/tools/toolutil/writesrc.h +++ b/deps/icu-small/source/tools/toolutil/writesrc.h @@ -23,6 +23,7 @@ #include #include "unicode/utypes.h" +#include "unicode/ucptrie.h" #include "utrie2.h" /** @@ -30,7 +31,7 @@ * Writes a C/Java-style comment with the generator name. */ U_CAPI FILE * U_EXPORT2 -usrc_create(const char *path, const char *filename, const char *generator); +usrc_create(const char *path, const char *filename, int32_t copyrightYear, const char *generator); /** * Creates a source text file and writes a header comment with the ICU copyright. @@ -75,6 +76,33 @@ usrc_writeUTrie2Struct(FILE *f, const char *indexName, const char *dataName, const char *postfix); +/** + * Calls usrc_writeArray() for the index and data arrays of a UCPTrie. + */ +U_CAPI void U_EXPORT2 +usrc_writeUCPTrieArrays(FILE *f, + const char *indexPrefix, const char *dataPrefix, + const UCPTrie *pTrie, + const char *postfix); + +/** + * Writes the UCPTrie struct values. + * The {} and declaration etc. need to be included in prefix/postfix or + * printed before and after the array contents. + */ +U_CAPI void U_EXPORT2 +usrc_writeUCPTrieStruct(FILE *f, + const char *prefix, + const UCPTrie *pTrie, + const char *indexName, const char *dataName, + const char *postfix); + +/** + * Writes the UCPTrie arrays and struct values. + */ +U_CAPI void U_EXPORT2 +usrc_writeUCPTrie(FILE *f, const char *name, const UCPTrie *pTrie); + /** * Writes the contents of an array of mostly invariant characters. * Characters 0..0x1f are printed as numbers, diff --git a/tools/icu/current_ver.dep b/tools/icu/current_ver.dep index 5e439928ebb540..ce0d89485ab312 100644 --- a/tools/icu/current_ver.dep +++ b/tools/icu/current_ver.dep @@ -1,6 +1,14 @@ [ { - "url": "https://sourceforge.net/projects/icu/files/ICU4C/62.1/icu4c-62_1-src.zip", - "md5": "408854f7b9b58311b68fab4b4dfc80be" + "url": "https://github.com/unicode-org/icu/releases/download/release-63-1/icu4c-63_1-src.zip", + "md5": "d25bc38089db64668fd86f34b4aa9b93" + }, + { + "url": "https://sourceforge.net/projects/icu/files/ICU4C/63.1/icu4c-63_1-src.zip", + "md5": "d25bc38089db64668fd86f34b4aa9b93" + }, + { + "url": "https://download.icu-project.org/files/icu4c/63.1/icu4c-63_1-src.zip", + "md5": "d25bc38089db64668fd86f34b4aa9b93" } ] From 97496f0fd998a3b6aff7970691b7148cd465d437 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 16 Oct 2018 10:38:37 +0200 Subject: [PATCH 38/84] n-api: make per-`Context`-ness of `napi_env` explicit Because instances of `napi_env` are created on a per-global-object basis and because since most N-API functions refer to builtin JS objects, `napi_env` is essentially in 1:1 correspondence with `v8::Context`. This was not clear from the implementation by itself, but has emerged from conversations with the N-API team. This patch changes the `napi_env` implementation to: - Actually store the `v8::Context` it represents. - Provide more direct access to the `node::Environment` to which the `Context` belongs. - Do not store the `uv_loop_t*` explicitly, since it can be inferred from the `node::Environment` and we actually have an N-API method for that. - Replace calls to `isolate->GetCurrentContext()` with the more appropriate `napi_env` `Context`. - Implement a better (although not perfect) way of cleaning up `napi_env` instances. PR-URL: https://github.com/nodejs/node/pull/23689 Reviewed-By: James M Snell Reviewed-By: Gus Caplan Reviewed-By: Matheus Marchini Reviewed-By: Ben Noordhuis Reviewed-By: Michael Dawson --- src/node_api.cc | 184 ++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 98 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index 83eef0ff2eea47..c92175c75fea0a 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -18,16 +18,32 @@ static napi_status napi_clear_last_error(napi_env env); struct napi_env__ { - explicit napi_env__(v8::Isolate* _isolate, uv_loop_t* _loop) - : isolate(_isolate), - last_error(), - loop(_loop) {} - v8::Isolate* isolate; + explicit napi_env__(v8::Local context) + : isolate(context->GetIsolate()), + context_persistent(isolate, context) { + CHECK_EQ(isolate, context->GetIsolate()); + CHECK_NOT_NULL(node_env()); + } + + v8::Isolate* const isolate; // Shortcut for context()->GetIsolate() + node::Persistent context_persistent; + + inline v8::Local context() const { + return StrongPersistentToLocal(context_persistent); + } + + inline node::Environment* node_env() const { + return node::Environment::GetCurrent(context()); + } + + inline void Ref() { refs++; } + inline void Unref() { if (--refs == 0) delete this; } + node::Persistent last_exception; napi_extended_error_info last_error; int open_handle_scopes = 0; int open_callback_scopes = 0; - uv_loop_t* loop = nullptr; + int refs = 1; }; #define NAPI_PRIVATE_KEY(context, suffix) \ @@ -720,10 +736,6 @@ v8::Local CreateAccessorCallbackData(napi_env env, return cbdata; } -static void DeleteEnv(napi_env env, void* data, void* hint) { - delete env; -} - static napi_env GetEnv(v8::Local context) { napi_env result; @@ -742,7 +754,7 @@ napi_env GetEnv(v8::Local context) { if (value->IsExternal()) { result = static_cast(value.As()->Value()); } else { - result = new napi_env__(isolate, node::GetCurrentEventLoop(isolate)); + result = new napi_env__(context); auto external = v8::External::New(isolate, result); // We must also stop hard if the result of assigning the env to the global @@ -750,9 +762,18 @@ napi_env GetEnv(v8::Local context) { CHECK(global->SetPrivate(context, NAPI_PRIVATE_KEY(context, env), external) .FromJust()); - // Create a self-destructing reference to external that will get rid of the - // napi_env when external goes out of scope. - Reference::New(result, external, 0, true, DeleteEnv, nullptr, nullptr); + // TODO(addaleax): There was previously code that tried to delete the + // napi_env when its v8::Context was garbage collected; + // However, as long as N-API addons using this napi_env are in place, + // the Context needs to be accessible and alive. + // Ideally, we’d want an on-addon-unload hook that takes care of this + // once all N-API addons using this napi_env are unloaded. + // For now, a per-Environment cleanup hook is the best we can do. + result->node_env()->AddCleanupHook( + [](void* arg) { + static_cast(arg)->Unref(); + }, + static_cast(result)); } return result; @@ -774,8 +795,7 @@ napi_status Unwrap(napi_env env, CHECK_ARG(env, result); } - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local value = v8impl::V8LocalValueFromJsValue(js_object); RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); @@ -808,7 +828,7 @@ napi_status ConcludeDeferred(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Local context = env->isolate->GetCurrentContext(); + v8::Local context = env->context(); node::Persistent* deferred_ref = NodePersistentFromJsDeferred(deferred); v8::Local v8_deferred = @@ -853,10 +873,12 @@ class ThreadSafeFunction : public node::AsyncResource { handles_closing(false) { ref.Reset(env->isolate, func); node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this); + env->Ref(); } ~ThreadSafeFunction() { node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this); + env->Unref(); } // These methods can be called from any thread. @@ -935,18 +957,21 @@ class ThreadSafeFunction : public node::AsyncResource { // These methods must only be called from the loop thread. napi_status Init() { + uv_loop_t* loop = nullptr; + CHECK_EQ(napi_get_uv_event_loop(env, &loop), napi_ok); + ThreadSafeFunction* ts_fn = this; - if (uv_async_init(env->loop, &async, AsyncCb) == 0) { + if (uv_async_init(loop, &async, AsyncCb) == 0) { if (max_queue_size > 0) { cond.reset(new node::ConditionVariable); } if ((max_queue_size == 0 || cond.get() != nullptr) && - uv_idle_init(env->loop, &idle) == 0) { + uv_idle_init(loop, &idle) == 0) { return napi_ok; } - NodeEnv()->CloseHandle( + env->node_env()->CloseHandle( reinterpret_cast(&async), [](uv_handle_t* handle) -> void { ThreadSafeFunction* ts_fn = @@ -1035,15 +1060,6 @@ class ThreadSafeFunction : public node::AsyncResource { } } - node::Environment* NodeEnv() { - // Grabbing the Node.js environment requires a handle scope because it - // looks up fields on the current context. - v8::HandleScope scope(env->isolate); - node::Environment* node_env = node::Environment::GetCurrent(env->isolate); - CHECK_NOT_NULL(node_env); - return node_env; - } - void MaybeStartIdle() { if (uv_idle_start(&idle, IdleCb) != 0) { v8::HandleScope scope(env->isolate); @@ -1079,13 +1095,13 @@ class ThreadSafeFunction : public node::AsyncResource { return; } handles_closing = true; - NodeEnv()->CloseHandle( + env->node_env()->CloseHandle( reinterpret_cast(&async), [](uv_handle_t* handle) -> void { ThreadSafeFunction* ts_fn = node::ContainerOf(&ThreadSafeFunction::async, reinterpret_cast(handle)); - ts_fn->NodeEnv()->CloseHandle( + ts_fn->env->node_env()->CloseHandle( reinterpret_cast(&ts_fn->idle), [](uv_handle_t* handle) -> void { ThreadSafeFunction* ts_fn = @@ -1175,8 +1191,7 @@ napi_status Wrap(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, js_object); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local value = v8impl::V8LocalValueFromJsValue(js_object); RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); @@ -1211,7 +1226,7 @@ napi_status Wrap(napi_env env, if (wrap_type == retrievable) { CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper), - v8::External::New(isolate, reference)).FromJust()); + v8::External::New(env->isolate, reference)).FromJust()); } return GET_RETURN_STATUS(env); @@ -1418,7 +1433,7 @@ napi_status napi_create_function(napi_env env, RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::MaybeLocal maybe_function = v8::Function::New(context, v8impl::FunctionCallbackWrapper::Invoke, @@ -1518,7 +1533,7 @@ napi_status napi_define_class(napi_env env, } } - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); *result = v8impl::JsValueFromV8LocalValue( scope.Escape(tpl->GetFunction(context).ToLocalChecked())); @@ -1550,8 +1565,7 @@ napi_status napi_get_property_names(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1572,8 +1586,7 @@ napi_status napi_set_property(napi_env env, CHECK_ARG(env, key); CHECK_ARG(env, value); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1595,8 +1608,7 @@ napi_status napi_has_property(napi_env env, CHECK_ARG(env, result); CHECK_ARG(env, key); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1618,8 +1630,7 @@ napi_status napi_get_property(napi_env env, CHECK_ARG(env, key); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local k = v8impl::V8LocalValueFromJsValue(key); v8::Local obj; @@ -1641,8 +1652,7 @@ napi_status napi_delete_property(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, key); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local k = v8impl::V8LocalValueFromJsValue(key); v8::Local obj; @@ -1663,8 +1673,7 @@ napi_status napi_has_own_property(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, key); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1684,8 +1693,7 @@ napi_status napi_set_named_property(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, value); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1708,8 +1716,7 @@ napi_status napi_has_named_property(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1732,8 +1739,7 @@ napi_status napi_get_named_property(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local key; CHECK_NEW_FROM_UTF8(env, key, utf8name); @@ -1758,8 +1764,7 @@ napi_status napi_set_element(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, value); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1779,8 +1784,7 @@ napi_status napi_has_element(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1800,8 +1804,7 @@ napi_status napi_get_element(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1820,8 +1823,7 @@ napi_status napi_delete_element(napi_env env, bool* result) { NAPI_PREAMBLE(env); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1843,8 +1845,7 @@ napi_status napi_define_properties(napi_env env, CHECK_ARG(env, properties); } - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -1965,8 +1966,7 @@ napi_status napi_get_prototype(napi_env env, NAPI_PREAMBLE(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); @@ -2141,7 +2141,7 @@ napi_status napi_create_bigint_words(napi_env env, CHECK_ARG(env, words); CHECK_ARG(env, result); - v8::Local context = env->isolate->GetCurrentContext(); + v8::Local context = env->context(); if (word_count > INT_MAX) { napi_throw_range_error(env, nullptr, "Maximum BigInt size exceeded"); @@ -2202,7 +2202,7 @@ static napi_status set_error_code(napi_env env, const char* code_cstring) { if ((code != nullptr) || (code_cstring != nullptr)) { v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local err_object = error.As(); v8::Local code_value = v8impl::V8LocalValueFromJsValue(code); @@ -2435,8 +2435,7 @@ napi_status napi_call_function(napi_env env, CHECK_ARG(env, argv); } - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local v8recv = v8impl::V8LocalValueFromJsValue(recv); @@ -2461,11 +2460,7 @@ napi_status napi_get_global(napi_env env, napi_value* result) { CHECK_ENV(env); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - // TODO(ianhall): what if we need the global object from a different - // context in the same isolate? - // Should napi_env be the current context rather than the current isolate? - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); *result = v8impl::JsValueFromV8LocalValue(context->Global()); return napi_clear_last_error(env); @@ -2857,8 +2852,7 @@ napi_status napi_coerce_to_object(napi_env env, CHECK_ARG(env, value); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local obj; CHECK_TO_OBJECT(env, context, obj, value); @@ -2873,8 +2867,7 @@ napi_status napi_coerce_to_bool(napi_env env, CHECK_ARG(env, value); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local b; CHECK_TO_BOOL(env, context, b, value); @@ -2890,8 +2883,7 @@ napi_status napi_coerce_to_number(napi_env env, CHECK_ARG(env, value); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local num; CHECK_TO_NUMBER(env, context, num, value); @@ -2907,8 +2899,7 @@ napi_status napi_coerce_to_string(napi_env env, CHECK_ARG(env, value); CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local str; CHECK_TO_STRING(env, context, str, value); @@ -3169,7 +3160,7 @@ napi_status napi_open_callback_scope(napi_env env, CHECK_ENV(env); CHECK_ARG(env, result); - v8::Local context = env->isolate->GetCurrentContext(); + v8::Local context = env->context(); node::async_context* node_async_context = reinterpret_cast(async_context_handle); @@ -3212,8 +3203,7 @@ napi_status napi_new_instance(napi_env env, } CHECK_ARG(env, result); - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local ctor; CHECK_TO_FUNCTION(env, ctor, constructor); @@ -3238,8 +3228,7 @@ napi_status napi_instanceof(napi_env env, *result = false; v8::Local ctor; - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); CHECK_TO_OBJECT(env, context, ctor, constructor); @@ -3269,7 +3258,7 @@ napi_status napi_async_init(napi_env env, CHECK_ARG(env, result); v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local v8_resource; if (async_resource != nullptr) { @@ -3319,8 +3308,7 @@ napi_status napi_make_callback(napi_env env, CHECK_ARG(env, argv); } - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local v8recv; CHECK_TO_OBJECT(env, context, v8recv, recv); @@ -3336,7 +3324,7 @@ napi_status napi_make_callback(napi_env env, } v8::MaybeLocal callback_result = node::MakeCallback( - isolate, v8recv, v8func, argc, + env->isolate, v8recv, v8func, argc, reinterpret_cast*>(const_cast(argv)), *node_async_context); @@ -3848,7 +3836,7 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork { : AsyncResource(env->isolate, async_resource, *v8::String::Utf8Value(env->isolate, async_resource_name)), - ThreadPoolWork(node::Environment::GetCurrent(env->isolate)), + ThreadPoolWork(env->node_env()), _env(env), _data(data), _execute(execute), @@ -3935,7 +3923,7 @@ napi_status napi_create_async_work(napi_env env, CHECK_ARG(env, execute); CHECK_ARG(env, result); - v8::Local context = env->isolate->GetCurrentContext(); + v8::Local context = env->context(); v8::Local resource; if (async_resource != nullptr) { @@ -3968,7 +3956,7 @@ napi_status napi_delete_async_work(napi_env env, napi_async_work work) { napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) { CHECK_ENV(env); CHECK_ARG(env, loop); - *loop = env->loop; + *loop = env->node_env()->event_loop(); return napi_clear_last_error(env); } @@ -4007,7 +3995,7 @@ napi_status napi_create_promise(napi_env env, CHECK_ARG(env, deferred); CHECK_ARG(env, promise); - auto maybe = v8::Promise::Resolver::New(env->isolate->GetCurrentContext()); + auto maybe = v8::Promise::Resolver::New(env->context()); CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); auto v8_resolver = maybe.ToLocalChecked(); @@ -4056,7 +4044,7 @@ napi_status napi_run_script(napi_env env, return napi_set_last_error(env, napi_string_expected); } - v8::Local context = env->isolate->GetCurrentContext(); + v8::Local context = env->context(); auto maybe_script = v8::Script::Compile(context, v8::Local::Cast(v8_script)); @@ -4093,7 +4081,7 @@ napi_create_threadsafe_function(napi_env env, v8::Local v8_func; CHECK_TO_FUNCTION(env, v8_func, func); - v8::Local v8_context = env->isolate->GetCurrentContext(); + v8::Local v8_context = env->context(); v8::Local v8_resource; if (async_resource == nullptr) { From 1851cf4f834caf1e2e9ad27636451f5fb96e0788 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 18 Oct 2018 16:37:24 -0700 Subject: [PATCH 39/84] doc, test: document and test vm timeout escapes Using `process.nextTick()`, `Promise`, or `queueMicrotask()`, it is possible to escape the `timeout` set when running code with `vm.runInContext()`, `vm.runInThisContext()`, and `vm.runInNewContext()`. This documents the issue and adds three known_issues tests. Refs: https://github.com/nodejs/node/issues/3020 PR-URL: https://github.com/nodejs/node/pull/23743 Refs: https://github.com/nodejs/node/issues/3020 Reviewed-By: Luigi Pinca Reviewed-By: Tiancheng "Timothy" Gu --- doc/api/vm.md | 32 +++++++++++++++ .../test-vm-timeout-escape-nexttick.js | 41 +++++++++++++++++++ .../test-vm-timeout-escape-promise.js | 39 ++++++++++++++++++ .../test-vm-timeout-escape-queuemicrotask.js | 40 ++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 test/known_issues/test-vm-timeout-escape-nexttick.js create mode 100644 test/known_issues/test-vm-timeout-escape-promise.js create mode 100644 test/known_issues/test-vm-timeout-escape-queuemicrotask.js diff --git a/doc/api/vm.md b/doc/api/vm.md index 5bf09de37940fb..842ae3b81a01de 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -962,6 +962,38 @@ within which it can operate. The process of creating the V8 Context and associating it with the `sandbox` object is what this document refers to as "contextifying" the `sandbox`. +## Timeout limitations when using process.nextTick(), Promises, and queueMicrotask() + +Because of the internal mechanics of how the `process.nextTick()` queue and +the microtask queue that underlies Promises are implemented within V8 and +Node.js, it is possible for code running within a context to "escape" the +`timeout` set using `vm.runInContext()`, `vm.runInNewContext()`, and +`vm.runInThisContext()`. + +For example, the following code executed by `vm.runInNewContext()` with a +timeout of 5 milliseconds schedules an infinite loop to run after a promise +resolves. The scheduled loop is never interrupted by the timeout: + +```js +const vm = require('vm'); + +function loop() { + while (1) console.log(Date.now()); +} + +vm.runInNewContext( + 'Promise.resolve().then(loop);', + { loop, console }, + { timeout: 5 } +); +``` + +This issue also occurs when the `loop()` call is scheduled using +the `process.nextTick()` and `queueMicrotask()` functions. + +This issue occurs because all contexts share the same microtask and nextTick +queues. + [`Error`]: errors.html#errors_class_error [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`]: errors.html#ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING [`URL`]: url.html#url_class_url diff --git a/test/known_issues/test-vm-timeout-escape-nexttick.js b/test/known_issues/test-vm-timeout-escape-nexttick.js new file mode 100644 index 00000000000000..8afe2fb8cebb15 --- /dev/null +++ b/test/known_issues/test-vm-timeout-escape-nexttick.js @@ -0,0 +1,41 @@ +'use strict'; + +// https://github.com/nodejs/node/issues/3020 +// Promises, nextTick, and queueMicrotask allow code to escape the timeout +// set for runInContext, runInNewContext, and runInThisContext + +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const NS_PER_MS = 1000000n; + +const hrtime = process.hrtime.bigint; +const nextTick = process.nextTick; + +function loop() { + const start = hrtime(); + while (1) { + const current = hrtime(); + const span = (current - start) / NS_PER_MS; + if (span >= 100n) { + throw new Error( + `escaped timeout at ${span} milliseconds!`); + } + } +} + +assert.throws(() => { + vm.runInNewContext( + 'nextTick(loop); loop();', + { + hrtime, + nextTick, + loop + }, + { timeout: 5 } + ); +}, { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 5ms' +}); diff --git a/test/known_issues/test-vm-timeout-escape-promise.js b/test/known_issues/test-vm-timeout-escape-promise.js new file mode 100644 index 00000000000000..4452c83cd182e3 --- /dev/null +++ b/test/known_issues/test-vm-timeout-escape-promise.js @@ -0,0 +1,39 @@ +'use strict'; + +// https://github.com/nodejs/node/issues/3020 +// Promises, nextTick, and queueMicrotask allow code to escape the timeout +// set for runInContext, runInNewContext, and runInThisContext + +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const NS_PER_MS = 1000000n; + +const hrtime = process.hrtime.bigint; + +function loop() { + const start = hrtime(); + while (1) { + const current = hrtime(); + const span = (current - start) / NS_PER_MS; + if (span >= 100n) { + throw new Error( + `escaped timeout at ${span} milliseconds!`); + } + } +} + +assert.throws(() => { + vm.runInNewContext( + 'Promise.resolve().then(loop); loop();', + { + hrtime, + loop + }, + { timeout: 5 } + ); +}, { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 5ms' +}); diff --git a/test/known_issues/test-vm-timeout-escape-queuemicrotask.js b/test/known_issues/test-vm-timeout-escape-queuemicrotask.js new file mode 100644 index 00000000000000..8de33bc24ddcdc --- /dev/null +++ b/test/known_issues/test-vm-timeout-escape-queuemicrotask.js @@ -0,0 +1,40 @@ +'use strict'; + +// https://github.com/nodejs/node/issues/3020 +// Promises, nextTick, and queueMicrotask allow code to escape the timeout +// set for runInContext, runInNewContext, and runInThisContext + +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const NS_PER_MS = 1000000n; + +const hrtime = process.hrtime.bigint; + +function loop() { + const start = hrtime(); + while (1) { + const current = hrtime(); + const span = (current - start) / NS_PER_MS; + if (span >= 100n) { + throw new Error( + `escaped timeout at ${span} milliseconds!`); + } + } +} + +assert.throws(() => { + vm.runInNewContext( + 'queueMicrotask(loop); loop();', + { + hrtime, + queueMicrotask, + loop + }, + { timeout: 5 } + ); +}, { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 5ms' +}); From 0f00ac9c7a9c35e3f69da0e47e851856034c573a Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 24 Oct 2018 08:03:07 -0700 Subject: [PATCH 40/84] test: mark test-vm-timeout-* known issue tests flaky These are known issues that can be flaky on certain platforms because they rely entirely on timing differences. PR-URL: https://github.com/nodejs/node/pull/23743 Refs: https://github.com/nodejs/node/issues/3020 Reviewed-By: Luigi Pinca Reviewed-By: Tiancheng "Timothy" Gu --- test/known_issues/known_issues.status | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/known_issues/known_issues.status b/test/known_issues/known_issues.status index e21913e232c03f..5a1ab289280d23 100644 --- a/test/known_issues/known_issues.status +++ b/test/known_issues/known_issues.status @@ -9,6 +9,9 @@ prefix known_issues [$system==win32] [$system==linux] +test-vm-timeout-escape-nexttick: PASS,FLAKY +test-vm-timeout-escape-promise: PASS,FLAKY +test-vm-timeout-escape-queuemicrotask: PASS,FLAKY [$system==macos] From b8f3bb107e79c5816ce22930d67d03a9202f718c Mon Sep 17 00:00:00 2001 From: cclauss Date: Tue, 24 Jul 2018 02:00:13 -0400 Subject: [PATCH 41/84] build: add lint-py which uses flake8 PR-URL: https://github.com/nodejs/node/pull/21952 Reviewed-By: Refael Ackermann --- Makefile | 24 +++++++++++++++++++++++- tools/pip/.gitignore | 2 ++ tools/pip/sitecustomize.py | 3 +++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tools/pip/.gitignore create mode 100644 tools/pip/sitecustomize.py diff --git a/Makefile b/Makefile index dadc1e91ec5b72..88be22fcace3ec 100644 --- a/Makefile +++ b/Makefile @@ -1208,6 +1208,28 @@ lint-addon-docs: test/addons/.docbuildstamp cpplint: lint-cpp @echo "Please use lint-cpp instead of cpplint" +.PHONY: lint-py-build +# python -m pip install flake8 +# Try with '--system' is to overcome systems that blindly set '--user' +lint-py-build: + @echo "Pip installing flake8 linter on $(shell $(PYTHON) --version)..." + $(PYTHON) -m pip install --upgrade -t tools/pip/site-packages flake8 || \ + $(PYTHON) -m pip install --upgrade --system -t tools/pip/site-packages flake8 + +ifneq ("","$(wildcard tools/pip/site-packages)") +.PHONY: lint-py +# Lints the Python code with flake8. +# Flag the build if there are Python syntax errors or undefined names +lint-py: + PYTHONPATH=tools/pip $(PYTHON) -m flake8 . \ + --count --show-source --statistics --select=E901,E999,F821,F822,F823 \ + --exclude=deps,lib,src,tools/*_macros.py,tools/gyp,tools/jinja2,tools/pip +else +lint-py: + @echo "Python linting with flake8 is not avalible" + @echo "Run 'make lint-py-build'" +endif + .PHONY: lint .PHONY: lint-ci ifneq ("","$(wildcard tools/node_modules/eslint/)") @@ -1221,7 +1243,7 @@ lint: ## Run JS, C++, MD and doc linters. CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+ # Related CI job: node-test-linter -lint-ci: lint-js-ci lint-cpp lint-md lint-addon-docs +lint-ci: lint-js-ci lint-cpp lint-py lint-md lint-addon-docs @if ! ( grep -IEqrs "$(CONFLICT_RE)" benchmark deps doc lib src test tools ) \ && ! ( find . -maxdepth 1 -type f | xargs grep -IEqs "$(CONFLICT_RE)" ); then \ exit 0 ; \ diff --git a/tools/pip/.gitignore b/tools/pip/.gitignore new file mode 100644 index 00000000000000..03eb26e01302fd --- /dev/null +++ b/tools/pip/.gitignore @@ -0,0 +1,2 @@ +*.pyc +site-packages \ No newline at end of file diff --git a/tools/pip/sitecustomize.py b/tools/pip/sitecustomize.py new file mode 100644 index 00000000000000..aa8087c8989604 --- /dev/null +++ b/tools/pip/sitecustomize.py @@ -0,0 +1,3 @@ +import os +import site +site.addsitedir(os.path.dirname(os.path.realpath(__file__)) + '/site-packages') From 5c35d0db474dc7912e0237df2de4397cac27a1e1 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Fri, 19 Oct 2018 22:14:35 -0400 Subject: [PATCH 42/84] build,meta: switch to gcc-4.9 on travis The version of `clang` provided in the Travis linux image uses libstdc++4.8 whice is below our minimal supported version. Switching to `make test -j1` is to avoid races during the test cycle causes by the main target being "unstable", that is it always builds some files, and relinks the binary, which is used by the test procedure. PR-URL: https://github.com/nodejs/node/pull/23778 Reviewed-By: Luigi Pinca Reviewed-By: Richard Lau --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 004c6ab4cf7236..21ec6dab70f994 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ language: cpp -compiler: - - clang sudo: false cache: ccache os: linux @@ -15,12 +13,15 @@ matrix: # Lint the first commit in the PR. - \[ -z "$TRAVIS_COMMIT_RANGE" \] || (echo -e '\nLinting the commit message according to the guidelines at https://goo.gl/p2fr5Q\n' && git log $TRAVIS_COMMIT_RANGE --pretty=format:'%h' --no-merges | tail -1 | xargs npx -q core-validate-commit --no-validate-metadata) - name: "Test Suite" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 install: + - export CC='ccache gcc-4.9' CXX='ccache g++-4.9' JOBS=2 - ./configure - make -j2 V= script: - - make -j2 test - before_install: - - export CXX="ccache clang++ -Qunused-arguments" - - export CC="ccache clang -Qunused-arguments -Wno-unknown-warning-option" - - export JOBS=2 + - PARALLEL_ARGS='--flaky-tests=skip' make -j1 test From 49b32af5abfb421fac1bfea2ecad01bd35b427d3 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 21 Oct 2018 18:55:30 +0200 Subject: [PATCH 43/84] doc: document nullptr comparisons in style guide This documents existing practices. PR-URL: https://github.com/nodejs/node/pull/23805 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius --- CPP_STYLE_GUIDE.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CPP_STYLE_GUIDE.md b/CPP_STYLE_GUIDE.md index e14de6cc48b1e3..5099f34ea866c9 100644 --- a/CPP_STYLE_GUIDE.md +++ b/CPP_STYLE_GUIDE.md @@ -18,6 +18,7 @@ * [Memory Management](#memory-management) * [Memory allocation](#memory-allocation) * [Use `nullptr` instead of `NULL` or `0`](#use-nullptr-instead-of-null-or-0) + * [Use explicit pointer comparisons](#use-explicit-pointer-comparisons) * [Ownership and Smart Pointers](#ownership-and-smart-pointers) * [Avoid non-const references](#avoid-non-const-references) * [Others](#others) @@ -195,6 +196,12 @@ class FancyContainer { Further reading in the [C++ Core Guidelines][ES.47]. +### Use explicit pointer comparisons + +Use explicit comparisons to `nullptr` when testing pointers, i.e. +`if (foo == nullptr)` instead of `if (foo)` and +`foo != nullptr` instead of `!foo`. + ### Ownership and Smart Pointers * [R.20]: Use `std::unique_ptr` or `std::shared_ptr` to represent ownership From e241398ef6fa672d50eadd31ef1153dd70e3d247 Mon Sep 17 00:00:00 2001 From: ZYSzys <17367077526@163.com> Date: Thu, 25 Oct 2018 11:16:24 +0800 Subject: [PATCH 44/84] doc: simplify path.basename() on POSIX and Windows PR-URL: https://github.com/nodejs/node/pull/23864 Reviewed-By: Rich Trott Reviewed-By: Colin Ihrig Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell --- doc/api/path.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/api/path.md b/doc/api/path.md index 2a1f06028ee6f4..c04bff0c476f46 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -18,9 +18,7 @@ on which a Node.js application is running. Specifically, when running on a Windows operating system, the `path` module will assume that Windows-style paths are being used. -For example, using the `path.basename()` function with the Windows file path -`C:\temp\myfile.html`, will yield different results when running on POSIX than -when run on Windows: +So using `path.basename()` might yield different results on POSIX and Windows: On POSIX: From 167e99b9a16645e2cf2ad9b2495e47211064a551 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Thu, 25 Oct 2018 04:02:23 -0700 Subject: [PATCH 45/84] timers: fix priority queue removeAt fn PR-URL: https://github.com/nodejs/node/pull/23870 Fixes: https://github.com/nodejs/node/issues/23860 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Matteo Collina Reviewed-By: Gus Caplan Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: James M Snell --- lib/internal/priority_queue.js | 7 +++++- test/parallel/test-priority-queue.js | 36 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/internal/priority_queue.js b/lib/internal/priority_queue.js index cb046507a667d9..2f1db934b43cc8 100644 --- a/lib/internal/priority_queue.js +++ b/lib/internal/priority_queue.js @@ -83,8 +83,13 @@ module.exports = class PriorityQueue { heap[pos] = heap[size + 1]; heap[size + 1] = undefined; - if (size > 0) + if (size > 0) { + // If not removing the last item, update the shifted item's position. + if (pos <= size && this[kSetPosition] !== undefined) + this[kSetPosition](heap[pos], pos); + this.percolateDown(1); + } } remove(value) { diff --git a/test/parallel/test-priority-queue.js b/test/parallel/test-priority-queue.js index 5b8f53a1766bb5..702b5528ba9611 100644 --- a/test/parallel/test-priority-queue.js +++ b/test/parallel/test-priority-queue.js @@ -95,3 +95,39 @@ const PriorityQueue = require('internal/priority_queue'); assert.strictEqual(queue.peek(), undefined); } + +{ + const queue = new PriorityQueue((a, b) => { + return a.value - b.value; + }, (node, pos) => (node.position = pos)); + + queue.insert({ value: 1, position: null }); + queue.insert({ value: 2, position: null }); + queue.insert({ value: 3, position: null }); + queue.insert({ value: 4, position: null }); + queue.insert({ value: 5, position: null }); + + queue.insert({ value: 2, position: null }); + const secondLargest = { value: 10, position: null }; + queue.insert(secondLargest); + const largest = { value: 15, position: null }; + queue.insert(largest); + + queue.removeAt(5); + assert.strictEqual(largest.position, 5); + + // check that removing 2nd to last item works fine + queue.removeAt(6); + assert.strictEqual(secondLargest.position, 6); + + // check that removing the last item doesn't throw + queue.removeAt(6); + + assert.strictEqual(queue.shift().value, 1); + assert.strictEqual(queue.shift().value, 2); + assert.strictEqual(queue.shift().value, 2); + assert.strictEqual(queue.shift().value, 4); + assert.strictEqual(queue.shift().value, 15); + + assert.strictEqual(queue.shift(), undefined); +} From 572ea60378110b15b31600ec723599709c5e6a57 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 20 Oct 2018 13:50:10 +0200 Subject: [PATCH 46/84] test: verify `performance.timerify()` works w/ non-Node Contexts PR-URL: https://github.com/nodejs/node/pull/23784 Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/node_perf.cc | 2 +- test/addons/non-node-context/binding.cc | 55 +++++++++++++++++++ test/addons/non-node-context/binding.gyp | 8 +++ .../test-perf-hooks-timerify.js | 17 ++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 test/addons/non-node-context/binding.cc create mode 100644 test/addons/non-node-context/binding.gyp create mode 100644 test/addons/non-node-context/test-perf-hooks-timerify.js diff --git a/src/node_perf.cc b/src/node_perf.cc index 5f1b70a5c4db6c..d3ee881f59d257 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -310,7 +310,7 @@ void TimerFunctionCall(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Verify that this is correct. + CHECK_NOT_NULL(env); Local context = env->context(); Local fn = args.Data().As(); size_t count = args.Length(); diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc new file mode 100644 index 00000000000000..324f5c5a1ef16f --- /dev/null +++ b/test/addons/non-node-context/binding.cc @@ -0,0 +1,55 @@ +#include +#include + +namespace { + +using v8::Context; +using v8::Function; +using v8::FunctionTemplate; +using v8::Isolate; +using v8::Local; +using v8::MaybeLocal; +using v8::NewStringType; +using v8::Object; +using v8::Script; +using v8::String; +using v8::Value; + +inline void RunInNewContext( + const v8::FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Local context = Context::New(isolate); + Context::Scope context_scope(context); + + context->Global()->Set( + context, + String::NewFromUtf8(isolate, "data", NewStringType::kNormal) + .ToLocalChecked(), + args[1]).FromJust(); + + assert(args[0]->IsString()); // source code + Local