diff --git a/Changelog-NG.txt b/Changelog-NG.txt index 55cdc6e8ff9..3ef91cfb495 100644 --- a/Changelog-NG.txt +++ b/Changelog-NG.txt @@ -1,6 +1,18 @@ Asuswrt-Merlin 384/NG Changelog =============================== +384.17 (xx-xxx-xxxx) + - NEW: Add Chacha20-poly1305 support to dropbear (themiron) + - UPDATED: dnsmasq to 2.81-openssl (themiron) + - UPDATED: openvpn to 2.4.9. + - UPDATED: curl to 7.69.1. + - UPDATED: openssl-1.1 to 1.1.1g (themiron) + - UPDATED: nano to 4.9.2. + - FIXED: RT-AC88U/RT-AC3100/RT-AC5300 could fail to upgrade + from newer stock versions to Asuswrt-Merlin. + - FIXED: Various webui issues with sorting DHCP reservations. + + 384.16 (5-Apr-2020) - NEW: Added support for the RT-AX58U and RT-AX3000 (same firmware), based on GPL 384_8253 + binary blobs 384_8137. diff --git a/release/src-rt/target.mak b/release/src-rt/target.mak index 5ed0bbc121c..64035d8f333 100644 --- a/release/src-rt/target.mak +++ b/release/src-rt/target.mak @@ -30,7 +30,7 @@ export RT-AC68U_BASE := IPV6SUPP=y HTTPS=y ARM=y BCM57=y AUTODICT=y BBEXTRAS=y U TFAT=y HFS="tuxera" NTFS="tuxera" REPEATER=y DUALWAN=y DNSFILTER=y UPNPIGD2=n \ NANO=y OPENSSL11=y NTPD=y DNSPRIVACY=y NETOOL=y TRACEROUTE=n -export RT-AC68U := $(RT-AC68U_BASE) FAKEHDR=y FORCE_SN=384 FORCE_EN=20000 +export RT-AC68U := $(RT-AC68U_BASE) FAKEHDR=y FORCE_SN=385 FORCE_EN=20000 export RT-AC68U += BUILD_NAME="RT-AC68U" NEWSSID_REV2=y DBLOG=y ETHOBD=y DWB=y UUPLUGIN=y BTM_11V=y \ BCN_RPT=y INFO_EXAP=y RAST_NONMESH_KVONLY=y IPERF3=y AVBLCHAN=y FILEFLEX=y @@ -60,7 +60,7 @@ export RT-AC87U := IPV6SUPP=y HTTPS=y ARM=y BCM57=y AUTODICT=y BBEXTRAS=y USBEXT # Broadcom HND ARM platform # export HND-94908_BASE := HND_ROUTER=y PROFILE="94908HND" SW_HW_AUTH=y AMAS=y UTF8_SSID=y ETHOBD=y DWB=y SAMBA3="3.6.x" -export RT-AC86U := $(HND-94908_BASE) +export RT-AC86U := $(HND-94908_BASE) FAKEHDR=y FORCE_SN=385 FORCE_EN=20000 export RT-AC86U += BUILD_NAME="RT-AC86U" NVSIZE="128" DHDAP=y DPSTA=y LACP=n WTFAST=y REPEATER=y \ IPV6SUPP=y HTTPS=y ARM=y AUTODICT=y BBEXTRAS=y USBEXTRAS=y \ EBTABLES=y MEDIASRV=y MODEM=y PARENTAL2=y ACCEL_PPTPD=y PRINTER=y WEBDAV=y \ @@ -111,7 +111,7 @@ export RT-AC88U_BASE := IPV6SUPP=y HTTPS=y ARM=y BCM57=y AUTODICT=y BBEXTRAS=y U ASPMD=n BCMEVENTD=n WLCLMLOAD=n BCM_MUMIMO=y LAN50=y ATCOVER=y GETREALIP=y DWB=y \ NOTIFICATION_CENTER=y NATNL_AICLOUD=y SYSSTATE=y SMARTSYNCBASE=y NATNL_AIHOME=y \ NFS=y DNSFILTER=y SNMPD=y TOR=y UPNPIGD2=n NANO=y OPENSSL11=y NTPD=y DNSPRIVACY=y \ - TRACEROUTE=n + TRACEROUTE=n FAKEHDR=y FORCE_SN=385 FORCE_EN=20000 export RT-AC88U := $(RT-AC88U_BASE) export RT-AC88U += BUILD_NAME="RT-AC88U" RGMII_BRCM5301X=y SWITCH2="RTL8365MB" BCM_MMC=n BCM_7114=y \ diff --git a/release/src-rt/version.conf b/release/src-rt/version.conf index b91f39fa2ab..bd7155df628 100644 --- a/release/src-rt/version.conf +++ b/release/src-rt/version.conf @@ -1,5 +1,5 @@ KERNEL_VER=3.0 FS_VER=0.4 -SERIALNO=384.16 -EXTENDNO=0 +SERIALNO=384.17 +EXTENDNO=beta1 RCNO=0 diff --git a/release/src/router/curl/CHANGES b/release/src/router/curl/CHANGES index b1f1e20ee38..2862b0eeb97 100644 --- a/release/src/router/curl/CHANGES +++ b/release/src/router/curl/CHANGES @@ -6,7125 +6,7198 @@ Changelog -Version 7.68.0 (8 Jan 2020) +Version 7.69.1 (11 Mar 2020) -Daniel Stenberg (8 Jan 2020) -- RELEASE-NOTES: 7.68.0 +Daniel Stenberg (11 Mar 2020) +- RELEASE-NOTES: 7.69.1 -- THANKS: updated with names from the 7.68.0 release +- THANKS: from the 7.69.1 release -- RELEASE-PROCEDURE: add four future release dates +- [Marc Hoersken brought this change] + + test1129: fix invalid case of closing XML-tag and Content-Length - and remove four past release dates + Fixes #5070 + Closes #5072 + +Marc Hoersken (10 Mar 2020) +- tests/data: fix static ip instead of dynamic value being used - [skip ci] + Follow up to 94ced8e -Marcel Raad (6 Jan 2020) -- TrackMemory tests: always remove CR before LF +- tests/data: fix static ip:port instead of dynamic values being used - It was removed for output containing ' =' via `s/ =.*//`. With classic - MinGW, this made lines with `free()` end with CRLF, but lines with e.g. - `malloc()` end with only LF. The tests expect LF only. + Closes #5065 + +- tests/server: fix missing use of exe_ext helper function - Closes https://github.com/curl/curl/pull/4788 + Follow up to 9819984 and 3dce984 + Reviewed-By: Daniel Stenberg + Closes #5064 -Daniel Stenberg (6 Jan 2020) -- multi.h: move INITIAL_MAX_CONCURRENT_STREAMS from public header +- runtests: log minimal and maximal used port numbers + +Daniel Stenberg (9 Mar 2020) +- [Jim Fuller brought this change] + + sftp: fix segfault regression introduced by #4747 - ... to the private multihhandle.h. It is not for public use and it - wasn't prefixed correctly anyway! + This fix adds a defensive check for the case where the char *name in + struct libssh2_knownhost is NULL - Closes #4790 + Fixes #5041 + Closes #5062 -- file: fix copyright year range - - Follow-up to 1b71bc532bd +- RELEASE-NOTES: synced -- curl -w: handle a blank input file correctly +- socks4: fix host resolve regression - Previously it would end up with an uninitialized memory buffer that - would lead to a crash or junk getting output. + 1. The socks4 state machine was broken in the host resolving phase - Added test 1271 to verify. + 2. The code now insists on IPv4-only when using SOCKS4 as the protocol + only supports that. - Reported-by: Brian Carpenter - Closes #4786 + Regression from #4907 and 4a4b63d, shipped in 7.69.0 + + Reported-by: amishmm on github + Bug: https://github.com/curl/curl/issues/5053#issuecomment-596191594 + Closes #5061 -- file: on Windows, refuse paths that start with \\ +- [Patrick Monnerat brought this change] + + silly web server: silent a compilation warning - ... as that might cause an unexpected SMB connection to a given host - name. + Recent gcc warns when byte count of strncpy() equals the destination + buffer size. Since the destination buffer is previously cleared and + the source string is always shorter, reducing the byte count by one + silents the warning without affecting the result. - Reported-by: Fernando Muñoz - CVE-2019-15601 - Bug: https://curl.haxx.se/docs/CVE-2019-15601.html + Closes #5059 -Jay Satiro (6 Jan 2020) -- CURLOPT_READFUNCTION.3: fix fopen params in example +- [Patrick Monnerat brought this change] -- CURLOPT_READFUNCTION.3: fix variable name in example + cookie: get_top_domain() sets zero length for null domains - Reported-by: Paul Joyce + This silents a compilation warning with gcc -O3. + +- [Patrick Monnerat brought this change] + + test 1560: avoid valgrind false positives - Fixes https://github.com/curl/curl/issues/4787 + When using maximum code optimization level (-O3), valgrind wrongly + detects uses of uninitialized values in strcmp(). + + Preset buffers with all zeroes to avoid that. -Daniel Stenberg (5 Jan 2020) -- curl:getparameter return error for --http3 if libcurl doesn't support +Steve Holme (8 Mar 2020) +- sha256: Added WinCrypt implementation - Closes #4785 + Closed #5030 -- docs: mention CURL_MAX_INPUT_LENGTH restrictions +- sha256: Added SecureTransport implementation + +Daniel Stenberg (7 Mar 2020) +- lib1564: reduce number of mid-wait wakeup calls - ... for curl_easy_setopt() and curl_url_set(). + This test does A LOT of *wakeup() calls and then calls curl_multi_poll() + twice. The first *poll() is then expected to return early and the second + not - as the first is supposed to drain the socketpair pipe. - [skip ci] + It turns out however that when given "excessive" amounts of writes to + the pipe, some operating systems (the Solaris based are known) will + return EAGAIN before the pipe is drained, which in our test case causes + the second *poll() call to also abort early. - Closes #4783 + This change attempts to avoid the OS-specific behaviors in the test by + reducing the amount of wakeup calls from 1234567 to 10. + + Reported-by: Andy Fiddaman + Fixes #5037 + Closes #5058 -- curl: properly free mimepost data +- [Patrick Monnerat brought this change] + + mime: fix the binary encoder to handle large data properly - ... as it could otherwise leak memory when a transfer failed. + New test 666 checks this is effective. + As upload buffer size is significant in this kind of tests, shorten it + in similar test 652. - Added test 1293 to verify. + Fixes #4860 + Closes #4833 + Reported-by: RuurdBeerstra on github + +- [Patrick Monnerat brought this change] + + mime: do not perform more than one read in a row - Reported-by: Brian Carpenter - Fixes #4781 - Closes #4782 + Input buffer filling may delay the data sending if data reads are slow. + To overcome this problem, file and callback data reads do not accumulate + in buffer anymore. All other data (memory data and mime framing) are + considered as fast and still concatenated in buffer. + As this may highly impact performance in terms of data overhead, an early + end of part data check is added to spare a read call. + When encoding a part's data, an encoder may require more bytes than made + available by a single read. In this case, the above rule does not apply + and reads are performed until the encoder is able to deliver some data. + + Tests 643, 644, 645, 650 and 654 have been adapted to the output data + changes, with test data size reduced to avoid the boredom of long lists of + 1-byte chunks in verification data. + New test 667 checks mimepost using single-byte read callback with encoder. + New test 668 checks the end of part data early detection. + + Fixes #4826 + Reported-by: MrdUkk on github -- curl: cleanup multi handle on failure +- [Patrick Monnerat brought this change] + + mime: latch last read callback status. - ... to fix memory leak in error path. + In case a read callback returns a status (pause, abort, eof, + error) instead of a byte count, drain the bytes read so far but + remember this status for further processing. + Takes care of not losing data when pausing, and properly resume a + paused mime structure when requested. + New tests 670-673 check unpausing cases, with easy or multi + interface and mime or form api. - Fixes #4772 - Closes #4780 - Reported-by: Brian Carpenter + Fixes #4813 + Reported-by: MrdUkk on github -Marcel Raad (3 Jan 2020) -- lib: fix compiler warnings with `CURL_DISABLE_VERBOSE_STRINGS` +Marc Hoersken (7 Mar 2020) +- runtests: fix missing use of exe_ext helper function + +Daniel Stenberg (7 Mar 2020) +- [Ernst Sjöstrand brought this change] + + ares: store dns parameters for duphandle - Closes https://github.com/curl/curl/pull/4775 + With c-ares the dns parameters lives in ares_channel. Store them in the + curl handle and set them again in easy_duphandle. + + Regression introduced in #3228 (6765e6d), shipped in curl 7.63.0. + + Fixes #4893 + Closes #5020 + Signed-off-by: Ernst Sjöstrand -Daniel Stenberg (3 Jan 2020) -- COPYING: it's 2020! +- version: make curl_version* thread-safe without using global context - [skip ci] + Closes #5010 -Jay Satiro (3 Jan 2020) -- [Marc Aldorasi brought this change] +- RELEASE-NOTES: synced - tests: Fix bounce requests with truncated writes +Marc Hoersken (7 Mar 2020) +- tests: use native Sleep function as fallback on Windows - Prior to this change the swsbounce check in service_connection could - fail because prevtestno and prevpartno were not set, which would cause - the wrong response data to be sent to some tests and cause them to fail. + Reviewed-By: Daniel Stenberg + Closes #5054 + +- perl: align order and completeness of Windows OS checks + +Daniel Stenberg (7 Mar 2020) +- tool_cb_see: set correct copyright year range - Ref: https://github.com/curl/curl/pull/4717#issuecomment-570240785 + Follow-up to a39e5bfb9 -Marcel Raad (31 Dec 2019) -- tool: make a few char pointers point to const char instead +Marc Hoersken (7 Mar 2020) +- seek: fix fallback for missing ftruncate on Windows - These are read-only. + This fixes test 198 on versions of MinGW-w64 without ftruncate - Closes https://github.com/curl/curl/pull/4771 + Reviewed-By: Daniel Stenberg + Reviewed-By: Marcel Raad + Closes #5055 -Jay Satiro (31 Dec 2019) -- tests: Change NTLM tests to require SSL +- config-win32: Windows does not have ftruncate + +Daniel Stenberg (7 Mar 2020) +- pause: force a connection (re-)check after unpausing - Prior to this change tests that required NTLM feature did not require - SSL feature. + There might be data available that was already read off the socket, for + example in the TLS layer. - There are pending changes to cmake builds that will allow enabling NTLM - in non-SSL builds in Windows. In that case the NTLM auth strings created - are different from what is expected by the NTLM tests and they fail: + Reported-by: Anders Berg + Fixes #4966 + Closes #5049 + +- socks5: switch state properly when the resolve is done - "The issue with NTLM is that previous non-SSL builds would not enable - NTLM and so the NTLM tests would be skipped." + Regression from 4a4b63d (and #4907) + Reported-by: vitaha85 on github + Fixes #5053 + Closes #5056 + +Jay Satiro (7 Mar 2020) +- libssh: Fix matching user-specified MD5 hex key - Assisted-by: marc-groundctl@users.noreply.github.com + Prior to this change a match would never be successful because it + was mistakenly coded to compare binary data from libssh to a + user-specified hex string (ie CURLOPT_SSH_HOST_PUBLIC_KEY_MD5). - Ref: https://github.com/curl/curl/pull/4717#issuecomment-566218729 + Reported-by: fds242@users.noreply.github.com - Closes https://github.com/curl/curl/pull/4768 - -- [Michael Forney brought this change] + Fixes https://github.com/curl/curl/issues/4971 + Closes https://github.com/curl/curl/pull/4974 - bearssl: Improve I/O handling +Daniel Stenberg (6 Mar 2020) +- pause: bail out on bad input - Factor out common I/O loop as bearssl_run_until, which reads/writes TLS - records until the desired engine state is reached. This is now used for - the handshake, read, write, and close. + A NULL easy handle or an easy handle without an associated connection + cannot be paused or unpaused. - Match OpenSSL SSL_write behavior, and don't return the number of bytes - written until the corresponding records have been completely flushed - across the socket. This involves keeping track of the length of data - buffered into the TLS engine, and assumes that when CURLE_AGAIN is - returned, the write function will be called again with the same data - and length arguments. This is the same requirement of SSL_write. + Closes #5050 + +Steve Holme (6 Mar 2020) +- unit1612: fixed the inclusion and compilation of the HMAC unit test - Handle TLS close notify as EOF when reading by returning 0. + Follow up to 3f74e5e6 to fix: - Closes https://github.com/curl/curl/pull/4748 - -- travis: Fix error detection + - A typo in Makefile.inc where unit1611 was used instead + - Some compilation issues in unit1612.c - - Stop using inline shell scripts for before_script and script sections. + Closes #5024 + +Daniel Stenberg (6 Mar 2020) +- pause: return early for calls that don't change pause state - Prior to this change Travis could ignore errors from commands in inline - scripts. I don't understand how or why it happens. This is a workaround. + Reviewed-by: Patrick Monnerat + Ref: #4833 + Closes #5026 + +Jay Satiro (6 Mar 2020) +- curl_share_setopt.3: Note sharing cookies doesn't enable the engine - Assisted-by: Simon Warta + Follow-up to d0a7ee3 which fixed a bug in 7.66.0 that caused + CURL_LOCK_DATA_COOKIE to enable the easy handle's cookie engine. - Ref: https://github.com/travis-ci/travis-ci/issues/1066 + Bug: https://curl.haxx.se/mail/lib-2020-03/0019.html + Reported-by: Felipe Gasper - Fixes https://github.com/curl/curl/issues/3730 - Closes https://github.com/curl/curl/pull/3755 + Closes https://github.com/curl/curl/pull/5048 -- tool_operate: fix mem leak when failed config parse +- multi: skip EINTR check on wakeup socket if it was closed - Found by fuzzing the config file. + - Don't check errno on wakeup socket if sread returned 0 since sread + doesn't set errno in that case. - Reported-by: Geeknik Labs + This is a follow-up to cf7760a from several days ago which fixed + Curl_multi_wait to stop busy looping sread on the non-blocking wakeup + socket if it was closed (ie sread returns 0). Due to a logic error it + was still possible to busy loop in that case if errno == EINTR. - Fixes https://github.com/curl/curl/issues/4767 + Closes https://github.com/curl/curl/pull/5047 -- [Xiang Xiao brought this change] +Daniel Stenberg (6 Mar 2020) +- transfer: set correct copyright year range - lib: remove erroneous +x file permission on some c files +- urldata: remove the 'stream_was_rewound' connectdata struct member - Modified by commit eb9a604 accidentally. + ... as it is never set anywhere. - Closes https://github.com/curl/curl/pull/4756 - -- [Xiang Xiao brought this change] + Follow-up to 2f44e94ef + Closes #5046 - lib: fix warnings found when porting to NuttX +- Revert "pause: force-drain the transfer on unpause" - - Undefine DEBUGASSERT in curl_setup_once.h in case it was already - defined as a system macro. + This reverts commit fa0216b294af4c7113a9040ca65eefc7fc18ac1c (from #5000) - - Don't compile write32_le in curl_endian unless - CURL_SIZEOF_CURL_OFF_T > 4, since it's only used by Curl_write64_le. + Clearly that didn't solve the problem correctly. - - Include in socketpair.c. + Reported-by: Christopher Reid + Reopens #4966 + Fixes #5044 + +- RELEASE-NOTES: synced - Closes https://github.com/curl/curl/pull/4756 + and bumped curlver.h -- os400: Add missing CURLE error constants +- MANUAL: update a dict-using command line - Bug: https://github.com/curl/curl/pull/4754#issuecomment-569126922 - Reported-by: Emil Engler + The 'web1913' database is now invalid, use 'gcide' instead. -- CURLOPT_HEADERFUNCTION.3: Document that size is always 1 +- KNOWN_BUGS: configure --with-gssapi with Heimdal is ignored on macOS - For compatibility with `fwrite`, the `CURLOPT_HEADERFUNCTION` callback - is passed two `size_t` parameters which, when multiplied, designate the - number of bytes of data passed in. In practice, CURL always sets the - first parameter (`size`) to 1. + Closes #3841 + +- polarssl: remove more references and mentions - This practice is also enshrined in documentation and cannot be changed - in future. The documentation states that the default callback is - `fwrite`, which means `fwrite` must be a suitable function for this - purpose. However, the documentation also states that the callback must - return the number of *bytes* it successfully handled, whereas ISO C - `fwrite` returns the number of items (each of size `size`) which it - wrote. The only way these numbers can be equal is if `size` is 1. + Assisted-by: Jay Satiro + Follow-up to 6357a19ff29dac04 + Closes #5036 + +Marc Hoersken (4 Mar 2020) +- tests: wrap ignored test failures in braces + +- tests: align some Windows sleep defines with each other + +- tests: try to make sleeping portable by avoiding select - Since `size` is 1 and can never be changed in future anyway, document - that fact explicitly and let users rely on it. + select does not support just waiting on Windows: + https://perldoc.perl.org/perlport.html#select - Reported-by: Frank Gevaerts - Commit-message-by: Christopher Head + Reviewed-By: Daniel Stenberg + Closes #5035 + +Daniel Stenberg (4 Mar 2020) +- runtests.1: rephrase how to specify what tests to run - Ref: https://github.com/curl/curl/pull/2787 + Also mention the new tilde-prefixed way to ignore test results. - Fixes https://github.com/curl/curl/issues/4758 + Reviewed-By: Marc Hoersken + Closes #5033 -- examples/postinmemory.c: Call curl_global_cleanup always +- cirrus-ci: disable the FreeBSD 13 builds - Prior to this change curl_global_cleanup was not called if - curl_easy_init failed. + FreeBSD 13.0 is apparently close to a year away from a stable release + and has proven to cause intermittent builds failures recently. - Reported-by: kouzhudong@users.noreply.github.com + Assisted-by: Dan Fandrich + Assisted-by: Fedor Korotkov + Fixes #5028 + Closes #5029 + +Version 7.69.0 (4 Mar 2020) + +Daniel Stenberg (4 Mar 2020) +- RELEASE-NOTES: 7.69.0 + +- THANKS: from 7.69.0 - Fixes https://github.com/curl/curl/issues/4751 + Now sorted case insensitive -Daniel Stenberg (21 Dec 2019) -- url2file.c: fix copyright year +Marc Hoersken (3 Mar 2020) +- ci/tests: fix escaping of testnames and disable proxy for CI APIs - Follow-up to 525787269599b5 + Follow up to ada581f and c0d8b96 + Closes #5031 -- [Rickard Hallerbäck brought this change] +Jay Satiro (3 Mar 2020) +- cmake: Show HTTPS-proxy in the features output + + - Show HTTPS-proxy in the features output for those backends that + support it: OpenSSL, GnuTLS and NSS. + + Prior to this change HTTPS-proxy was missing from the cmake features + output even if curl was built with it. Only cmake output was affected. + Both the library and tool correctly reported the feature. + + Bug: https://curl.haxx.se/mail/lib-2020-03/0008.html + Reported-by: David Lopes + + Closes https://github.com/curl/curl/pull/5025 - examples/url2file.c: corrected a comment +Marc Hoersken (3 Mar 2020) +- ci/tests: Make it possible to still run but ignore failing tests - The comment was confusing and suggested that setting CURLOPT_NOPROGRESS - to 0L would both enable and disable debug output at the same time, like - a Schrödinger's cat of CURLOPTs. + This enables the development of a solution for the failing tests by + running them on CI while ignoring their result for the overall status. - Closes #4745 + Closes #4994 -- HISTORY: OSS-Fuzz started fuzzing libcurl in 2017 +- README.md: add Azure DevOps Pipelines build status badge -- RELEASE-NOTES: synced +- ci/tests: Move CI test result creation above environment setup + + This avoids using our test servers as proxy to the AppVeyor API. + + Closes #5022 -Jay Satiro (20 Dec 2019) -- ngtcp2: Support the latest update key callback type +- ci/tests: Send test results to AppVeyor for status overview - - Remove our cb_update_key in favor of ngtcp2's new - ngtcp2_crypto_update_key_cb which does the same thing. + Closes #5021 + +Daniel Stenberg (3 Mar 2020) +- Revert "sha256: Added SecureTransport implementation" - Several days ago the ngtcp2_update_key callback function prototype was - changed in ngtcp2/ngtcp2@42ce09c. Though it would be possible to - fix up our cb_update_key for that change they also added - ngtcp2_crypto_update_key_cb which does the same thing so we'll use that - instead. + This reverts commit 4feb38deed33fed14ff7c370a6a9153c661dbb9c (from #4956) - Ref: https://github.com/ngtcp2/ngtcp2/commit/42ce09c + That commit broke test 1610 on macos builds without TLS. - Closes https://github.com/curl/curl/pull/4735 + Closes #5027 -Daniel Stenberg (19 Dec 2019) -- sws: search for "Testno:" header uncondtionally if no testno +- dist: include tests/azure.pm in the tarball - Even if the initial request line wasn't found. With the fix to 1455, the - test number is now detected correctly. + Bug: https://github.com/curl/curl/commit/ada581f2cc32f48c1629b729707ac19208435b27#commitcomment-37601589 + Reported-by: Marcel Raad + +Steve Holme (3 Mar 2020) +- configure.ac: Disable metalink if mbedTLS is specified - (Problem found when running tests in random order.) + Follow up to cdcc9df1 and #5006. Even though I mentioned mbedTLS as + being one of the backends that metalink needs to be disabled for, I + seem to have included it in the list of allowed SSL/TLS backends in + comnfigure.ac :( - Closes #4744 + Closes #5013 -- tests: set LC_ALL in more tests +- sha256: Tidy up following recent changes - Follow-up to 23208e330ac0c21 + Reviewed-by: Daniel Stenberg + Closes #4956 + +- sha256: Added WinCrypt implementation + +- sha256: Added SecureTransport implementation + +- sha256: Added mbedtls implementation + +- sha256: Added GNU TLS gcrypt implementation + +- sha256: Added GNU TLS Nettle implementation + +Jay Satiro (2 Mar 2020) +- curl_escape.3: Add a link to curl_free - Closes #4743 + Ref: https://github.com/curl/curl/pull/5016#issuecomment-593628582 -- test165: set LC_ALL=en_US.UTF-8 too +- curl_getenv.3: Fix the memory handling description - On my current Debian Unstable with libidn2 2.2.0, I get an error if - LC_ALL is set to blank. Then curl errors out with: + - Tell the user to call curl_free() to free the pointer returned by + curl_getenv(). - curl: (3) Failed to convert www.åäö.se to ACE; could not convert string to UTF-8 + Prior to this change the user was directed to call free(), but that + would not work in cases where the library and application use separate C + runtimes and therefore have separate heap memory management. - Closes #4738 + Closes https://github.com/curl/curl/pull/5016 -- curl.h: add two defines for the "pre ISO C" case +Daniel Stenberg (2 Mar 2020) +- [Nick Zitzmann brought this change] + + md4: use init/update/final functions in Secure Transport - Without this fix, this caused a compilation failure on AIX with IBM xlc - 13.1.3 compiler. + We can use CC_MD4_Init/Update/Final without having to allocate memory + directly. - Reported-by: Ram Krushna Mishra - Fixes #4739 - Closes #4740 + Closes #4979 -- create_conn: prefer multiplexing to using new connections +Marc Hoersken (2 Mar 2020) +- ci/tests: some MacOS builds randomly take longer than 20min + +Daniel Stenberg (2 Mar 2020) +- multi_wait: stop loop when sread() returns zero - ... as it would previously prefer new connections rather than - multiplexing in most conditions! The (now removed) code was a leftover - from the Pipelining code that was translated wrongly into a - multiplex-only world. + It's unclear why it would ever return zero here, but this change fixes + Robert's problem and it shouldn't loop forever... - Reported-by: Kunal Ekawde - Bug: https://curl.haxx.se/mail/lib-2019-12/0060.html - Closes #4732 + Reported-by: Robert Dunaj + Bug: https://curl.haxx.se/mail/archive-2020-02/0011.html + Closes #5019 -- test1456: remove the use of a fixed local port +- http: mark POSTs with no body as "upload done" from the start - Fixup the test to instead not compare the port number. It sometimes - caused problems like this: - - "curl: (45) bind failed with errno 98: Address already in use" + As we have logic that checks if we get a >= 400 reponse code back before + the upload is done, which then got confused since it wasn't "done" but + yet there was no data to send! - Closes #4733 + Reported-by: IvanoG on github + Fixes #4996 + Closes #5002 -Jay Satiro (18 Dec 2019) -- CURLOPT_QUOTE.3: fix typos - - Prior to this change the EXAMPLE in the QUOTE/PREQUOTE/POSTQUOTE man - pages would not compile because a variable name was incorrect. +- tests: disable 962, 963 and 964 on Windows - Reported-by: Bylon2@users.noreply.github.com + These tests are also doing UTF-8 SMTP. - Fixes https://github.com/curl/curl/issues/4736 + Follow-up to df207d2dd93b9e73 -- [Gisle Vanem brought this change] +Marc Hoersken (2 Mar 2020) +- ci/tests: fine-tune Azure Pipeline timeouts with a small puffer - strerror: Fix compiler warning "empty expression" - - - Remove the final semi-colon in the SEC2TXT() macro definition. +Daniel Stenberg (2 Mar 2020) +- configure: bump the AC_COPYRIGHT year range + +- [Steve Holme brought this change] + + tests: disable SMTP UTF-8 tests on Windows - Before: #define SEC2TXT(sec) case sec: txt = #sec; break; + Fixes #4988 + Closes #4992 + +- formdata/mime: copyright year range update - After: #define SEC2TXT(sec) case sec: txt = #sec; break + Due to the merge/revert cycle + +- Revert "mime: latch last read callback status." - Prior to this change SEC2TXT(foo); would generate break;; which caused - the empty expression warning. + This reverts commit 87869e38d7afdec3ef1bb4965711458b088e254f. - Ref: https://github.com/curl/curl/commit/5b22e1a#r36458547 + Fixes #5014 + Closes #5015 + Reopens #4833 -Daniel Stenberg (18 Dec 2019) -- curl/parseconfig: use curl_free() to free memory allocated by libcurl +- Revert "mime: do not perform more than one read in a row" - Reported-by: bxac on github - Fixes #4730 - Closes #4731 + This reverts commit ed0f357f7d25566110d4302f33759f4ffb5a6f83. -- curl/parseconfig: fix mem-leak +- Revert "mime: fix the binary encoder to handle large data properly" - When looping, first trying '.curlrc' and then '_curlrc', the function - would not free the first string. - - Closes #4731 + This reverts commit b2caaa0681f329eed317ffb6ae6927f4a539f0c1. -- CURLOPT_URL.3: "curl supports SMB version 1 (only)" +- altsvc: both h3 backends now speak h3-27 - [skip ci] + ... also updated the HTTP3 build description for ngtcp2 accordingly. -- test1270: a basic -w redirect_url test +- [Patrick Monnerat brought this change] + + mime: fix the binary encoder to handle large data properly - Closes #4728 + New test 666 checks this is effective. + As upload buffer size is significant in this kind of tests, shorten it + in similar test 652. + + Fixes #4860 + Reported-by: RuurdBeerstra on github -- HISTORY: the SMB(S) support landed in 2014 +- [Patrick Monnerat brought this change] -- define: remove HAVE_ENGINE_LOAD_BUILTIN_ENGINES, not used anymore + mime: do not perform more than one read in a row - It is covered by USE_OPENSSL_ENGINE now. + Input buffer filling may delay the data sending if data reads are slow. + To overcome this problem, file and callback data reads do not accumulate + in buffer anymore. All other data (memory data and mime framing) are + considered as fast and still concatenated in buffer. + As this may highly impact performance in terms of data overhead, an early + end of part data check is added to spare a read call. + When encoding a part's data, an encoder may require more bytes than made + available by a single read. In this case, the above rule does not apply + and reads are performed until the encoder is able to deliver some data. - Reported-by: Gisle Vanem - Bug: https://github.com/curl/curl/commit/87b9337c8f76c21c57b204e88b68c6ecf3bd1ac0#commitcomment-36447951 + Tests 643, 644, 645, 650 and 654 have been adapted to the output data + changes, with test data size reduced to avoid the boredom of long lists of + 1-byte chunks in verification data. + New test 664 checks mimepost using single-byte read callback with encoder. + New test 665 checks the end of part data early detection. - Closes #4725 + Fixes #4826 + Reported-by: MrdUkk on github -- lib: remove ASSIGNWITHINCONDITION exceptions, use our code style +- [Patrick Monnerat brought this change] + + mime: latch last read callback status. - ... even for macros + In case a read callback returns a status (pause, abort, eof, + error) instead of a byte count, drain the bytes read so far but + remember this status for further processing. + Takes care of not losing data when pausing, and properly resume a + paused mime structure when requested. + New tests 670-673 check unpausing cases, with easy or multi + interface and mime or form api. - Reviewed-by: Daniel Gustafsson - Reviewed-by: Jay Satiro - Reported-by: Jay Satiro - Fixes #4683 - Closes #4722 - -- tests: make sure checksrc runs on header files too + Fixes #4813 + Reported-by: MrdUkk on github + Closes #4833 -- Revert "checksrc: fix regexp for ASSIGNWITHINCONDITION" +Steve Holme (1 Mar 2020) +- unit1651: Fixed conversion compilation warning - This reverts commit ba82673dac3e8d00a76aa5e3779a0cb80e7442af. + 371:17: warning: conversion to 'unsigned char' from 'int' may alter its + value [-Wconversion] - Bug: #4683 + Closes #5008 -- KNOWN_BUGS: TLS session cache doesn't work with TFO +- configure.ac: Disable metalink support if an incompatible SSL/TLS specified - [skip ci] - Closes #4301 - -- KNOWN_BUGS: Connection information when using TCP Fast Open + tool_metalink only supports cryptography from OpenSSL, GnuTLS, NSS, + The Win32 Crypto library and Apple's Common Crypto library. - Also point to #4296 for more details - Closes #4296 - -- KNOWN_BUGS: LDAP on Windows doesn't work + If an TLS backend such as mbedTLS or WolfSSL is specified then the + following error is given during compilation along, with a load of + unresolved extern errors: - Closes #4261 + Can't compile METALINK support without a crypto library. + + Reviewed-by: Daniel Stenberg + Closes #5006 -- docs: TLS SRP doesn't work with TLS 1.3 +Marc Hoersken (1 Mar 2020) +- ci/tests: Update Azure DevOps pipeline job display names - Reported-by: sayrer on github - Closes #4262 - [skip ci] + Make the configure step more descriptive and align others. -Dan Fandrich (16 Dec 2019) -- cirrus: Switch to the FreeBSD 12.1 point release & enable more tests. +- ci/tests: Fix typo in previous commit 597cf2 + +- ci/tests: Make sure that the AZURE_ACCESS_TOKEN is available - A few tests are now passing on FreeBSD, so no longer skip them. - [skip ci] + For security reasons the access token is not available to PR builds. + Therefore we should not try to use the DevOps API with an empty token. -Daniel Stenberg (16 Dec 2019) -- azure: the macos cmake doesn't need to install cmake +Daniel Stenberg (1 Mar 2020) +- build: remove all HAVE_OPENSSL_ENGINE_H defines - Error: cmake 3.15.5 is already installed - To upgrade to 3.16.1, run `brew upgrade cmake`. + ... as there's nothing in the code that actually uses the define! The + last reference was removed in 38203f158. - Closes #4723 + Closes #5007 -Jay Satiro (15 Dec 2019) -- winbuild: Document CURL_STATICLIB requirement for static libcurl +Jay Satiro (29 Feb 2020) +- [Rolf Eike Beer brought this change] + + CMake: clean up and improve build procedures - A static libcurl (ie winbuild mode=static) requires that the user define - CURL_STATICLIB when using it in their application. This is already - covered in the FAQ and INSTALL.md, but is a pretty important point so - now it's noted in the BUILD.WINDOWS.txt as well. + - remove check for unsupported old CMake versions - Assisted-by: Michael Vittiglio + - do not link to c-ares library twice - Closes https://github.com/curl/curl/pull/4721 - -Daniel Stenberg (15 Dec 2019) -- [Santino Keupp brought this change] - - libssh2: add support for ECDSA and ed25519 knownhost keys + - modernize custom Find modules - ... if a new enough libssh2 version is present. + - FindLibSSH2: + - pass version to FPHSA to show it in the output + - use LIBSSH2_VERSION define to extract the version number in + one shot. This variable exists in the header for 10 years. + - remove unneeded code - Source: https://curl.haxx.se/mail/archive-2019-12/0023.html - Co-Authored-by: Daniel Stenberg - Closes #4714 - -- lib1591: free memory properly on OOM, in the trailers callback + - FindNGHTTP2.cmake: + - drop needless FPHSA argument + - mark found variables as advanced - Detected by torture tests. + - FindNSS.cmake: + - show version number - Closes #4720 - -- runtests: --repeat=[num] to repeat tests + - FindCARES.cmake: + - drop default paths + - use FPHSA instead of checking things by hand - Closes #4715 - -- RELEASE-NOTES: synced - -- azure: add a torture test on mac + - remove needless explict variable dereference - Uses --shallow=25 to keep it small enough to get through in time. + - simplify count_true() - Closes #4712 - -- multi: free sockhash on OOM + - allow all policies up to version 3.16 to be set to NEW - This would otherwise leak memory in the error path. + - do not rerun check for -Wstrict-aliasing=3 every time - Detected by torture test 1540. + In contrast to every other compiler flag this has a = in it, which CMake + can't have in a variable name. - Closes #4713 - -Marcel Raad (13 Dec 2019) -- tests: use DoH feature for DoH tests + - only read the interesting strings from curlver.h - Previously, http/2 was used instead. + Reviewed-by: Peter Wu - Assisted-by: Jay Satiro - Closes https://github.com/curl/curl/pull/4692 + Closes https://github.com/curl/curl/pull/4975 -- hostip: suppress compiler warning +- runtests: fix output to command log - With `--disable-doh --disable-threaded-resolver`, the `dns` parameter - is not used. + - Record only the command of the most recently ran test in the command + log. - Closes https://github.com/curl/curl/pull/4692 - -- tests: fix build with `CURL_DISABLE_DOH` + This is a follow-up to 02988b7 from several weeks ago which fixed + writing to the command log, however it saved all commands for all tests + instead of just the most recently ran test as we would now expect. - Closes https://github.com/curl/curl/pull/4692 + Fixes https://github.com/curl/curl/commit/02988b7#commitcomment-37546876 + Closes https://github.com/curl/curl/pull/5001 -Daniel Stenberg (13 Dec 2019) -- azure: add a torture test +Steve Holme (1 Mar 2020) +- polarssl: Additional removal - Skipping all FTP tests for speed reasons. + Follow up to 6357a19f. - Closes #4697 + Reviewed-by: Daniel Stenberg + Closes #5004 -- azure: make the default build use --enable-debug --enable-werror +- [Jonathan Cardoso Machado brought this change] -- ntlm_wb: fix double-free in OOM + docs: fix typo on CURLINFO_RETRY_AFTER - alwaus -> always - Detected by torture testing test 1310 + Reviewed-by: Steve Holme + Closes #5005 + +- md5: Added implementation for mbedTLS - Closes #4710 + Reviewed-by: Jay Satiro + Closes #4980 -Dan Fandrich (13 Dec 2019) -- cirrus: Drop the FreeBSD 10.4 build +- md5: Use pointer notation for array parameters in GnuTLS implementation + +- md4: Use non-deprecated functions in mbedTLS >= 2.7.0 - Upstream support for 10.4 ended a year ago, and it looks like the image - is now gone, too. - [skip ci] + Closes #4983 -Daniel Stenberg (13 Dec 2019) -- unit1620: fix bad free in OOM +Marc Hoersken (29 Feb 2020) +- ci/tests: Send test results to Azure DevOps for reporting + +Daniel Stenberg (29 Feb 2020) +- pause: force-drain the transfer on unpause - Closes #4709 + ... since the socket might not actually be readable anymore when for + example the data is already buffered in the TLS layer. + + Fixes #4966 + Reported-by: Anders Berg + Closes #5000 -- unit1609: fix mem-leak in OOM +- TODO: curl --proxycommand - Closes #4709 + Suggested-by: Kristian Mide + Closes #4941 -- unit1607: fix mem-leak in OOM +- smtp: overwriting 'from' leaks memory - Closes #4709 + Detected by Coverity. CID 1418139. + + Also, make sure to return error if the new 'from' allocation fails. + + Closes #4997 -- lib1559: fix mem-leak in OOM +- CIfuzz: switch off 'dry_run' mode - Closes #4709 + Follow-up from #4960: now make it fail if it detects problems. + + Closes #4998 -- lib1557: fix mem-leak in OOM +Marc Hoersken (28 Feb 2020) +- ci/tests: Increase timeouts of Windows builds due to new tests - Closes #4709 + Recently added tests increased their runtime above the limit of 60min. -- altsvc: make the save function ignore NULL filenames +- ci/tests: align Azure Pipeline job names with each other + +- ci/tests: Add Windows builds via Azure Pipelines using Docker + +- tests: fix Python 3 compatibility of smbserver.py + +Daniel Stenberg (27 Feb 2020) +- runtests: restore the command log - It might happen in OOM situations. Detected bv torture tests. + The log file with all command lines for the invoked command lines is now + called logs/commands.log - Closes #4707 + Fixes #4911 + Closes #4989 -- curl: fix memory leak in OOM in etags logic +- smtp: fix memory leak on exit path - Detected by torture tests + Detected by Coverity. CID 1418139. "leaked_storage: Variable 'from' + going out of scope leaks the storage it points to" - Closes #4706 + Closes #4990 -- doh: make it behave when built without proxy support +Steve Holme (27 Feb 2020) +- gtls: Fixed compilation when using GnuTLS < 3.5.0 - Reported-by: Marcel Raad - Bug: https://github.com/curl/curl/pull/4692#issuecomment-564115734 + Reverts the functionality from 41fcb4f when compiling with GnuTLS older + than 3.5.0. - Closes #4704 + Reviewed-by: Daniel Stenberg + Closes #4984 -- curl: improved cleanup in upload error path +- RELEASE-NOTES: Corrected the link to issue #4892 + +Daniel Stenberg (27 Feb 2020) +- Curl_is_ASCII_name: handle a NULL argument - Memory leak found by torture test 58 + Make the function tolerate a NULL pointer input to avoid dereferencing + that pointer. - Closes #4705 + Follow-up to efce3ea5a85126d + Detected by OSS-Fuzz + Reviewed-By: Steve Holme + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20907 + Fixes #4985 + Closes #4986 -- mailmap: fix Andrew Ishchuk +- RELEASE-NOTES: synced -- travis: make torture use --shallow=40 +- http2: make pausing/unpausing set/clear local stream window - As a first step to enable it to run over a more diverse set of tests in - a reasonable time. + This reduces the HTTP/2 window size to 32 MB since libcurl might have to + buffer up to this amount of data in memory and yet we don't want it set + lower to potentially impact tranfer performance on high speed networks. + + Requires nghttp2 commit b3f85e2daa629 + (https://github.com/nghttp2/nghttp2/pull/1444) to work properly, to end + up in the next release after 1.40.0. + + Fixes #4939 + Closes #4940 -- runtests: introduce --shallow to reduce huge torture tests +- [Anderson Toshiyuki Sasaki brought this change] + + libssh: improve known hosts handling - When set, shallow mode limits runtests -t to make no more than NUM fails - per test case. If more are found, it will randomly discard entries until - the number is right. The random seed can also be set. + Previously, it was not possible to get a known hosts file entry due to + the lack of an API. ssh_session_get_known_hosts_entry(), introduced in + libssh-0.9.0, allows libcurl to obtain such information and behave the + same as when compiled with libssh2. - This is particularly useful when running MANY tests as then most torture - failures will already fail the same functions over and over and make the - total operation painfully tedious. + This also tries to avoid the usage of deprecated functions when the + replacements are available. The behaviour will not change if versions + older than libssh-0.8.0 are used. - Closes #4699 + Signed-off-by: Anderson Toshiyuki Sasaki + + Fixes #4953 + Closes #4962 -- conncache: CONNECT_ONLY connections assumed always in-use +Steve Holme (27 Feb 2020) +- tests: Automatically deduce the tool name from the test case for unit tests - This makes them never to be considered "the oldest" to be discarded when - reaching the connection cache limit. The reasoning here is that - CONNECT_ONLY is primarily used in combination with using the - connection's socket post connect and since that is used outside of - curl's knowledge we must assume that it is in use until explicitly - closed. + It is still possible to override the executable to run during the test, + using the tag, but this patch removes the requirement that the + tag must be present for unit tests. - Reported-by: Pavel Pavlov - Reported-by: Pavel Löbl - Fixes #4426 - Fixes #4369 - Closes #4696 + It also removes the possibility of human error when existing test cases + are used as the basis for new tests, as recently witnessed in 81c37124. + + Reviewed-by: Daniel Stenberg + Closes #4976 -- [Gisle Vanem brought this change] +- test1323: Added the missing 'unit test' feature requirement in the test case - vtls: make BearSSL possible to set with CURL_SSL_BACKEND +Daniel Stenberg (26 Feb 2020) +- cookie: remove unnecessary check for 'out != 0' - Ref: https://github.com/curl/curl/commit/9b879160df01e7ddbb4770904391d3b74114302b#commitcomment-36355622 + ... as it will always be non-NULL at this point. - Closes #4698 - -- RELEASE-NOTES: synced + Detected by Coverity: CID 1459009 -- travis: remove "coverage", make it "torture" +- http: added 417 response treatment - The coveralls service and test coverage numbers are just too unreliable. - Removed badge from README.md as well. + When doing a request with a body + Expect: 100-continue and the server + responds with a 417, the same request will be retried immediately + without the Expect: header. - Fixes #4694 - Closes #4695 - -- azure: add libssh2 and cmake macos builds + Added test 357 to verify. - Removed the macos libssh2 build from travis + Also added a control instruction to tell the sws test server to not read + the request body if Expect: is present, which the new test 357 uses. - Closes #4686 + Reported-by: bramus on github + Fixes #4949 + Closes #4964 -- curl: use errorf() better +Steve Holme (26 Feb 2020) +- smtp: Tidy up, following recent changes, to maintain the coding style - Change series of error outputs to use errorf(). + Closes #4892 + +- smtp: Support the SMTPUTF8 extension for the EXPN command - Only errors that are due to mistakes in command line option usage should - use helpf(), other types of errors in the tool should rather use - errorf(). - - Closes #4691 + Simply notify the server we support the SMTPUTF8 extension if it does. -Jay Satiro (9 Dec 2019) -- [Marc Hoersken brought this change] +- smtp: Support the SMTPUTF8 extension in the VRFY command - tests: make it possible to set executable extensions - - This enables the use of Windows Subsystem for Linux (WSL) to run the - testsuite against Windows binaries while using Linux servers. - - This commit introduces the following environment variables: - - CURL_TEST_EXE_EXT: set the executable extension for all components - - CURL_TEST_EXE_EXT_TOOL: set it for the curl tool only - - CURL_TEST_EXE_EXT_SSH: set it for the SSH tools only +- smtp: Support the SMTPUTF8 extension in the RCPT TO command - Later testcurl.pl could be adjusted to make use of those variables. - - CURL_TEST_EXE_EXT_SRV: set it for the test servers only + Note: The RCPT TO command isn't required to advertise to the server that + it contains UTF-8 characters, instead the server is told that a mail may + contain UTF-8 in any envelope command via the MAIL command. + +- smtp: Support the SMTPUTF8 extension in the MAIL command - (This is one of several commits to support use of WSL for the tests.) + Support the SMTPUTF8 extension when sending mailbox information in the + MAIL command (FROM and AUTH parameters). Non-ASCII domain names will + be ACE encoded, if IDN is supported, whilst non-ASCII characters in + the local address part are passed to the server. - Closes https://github.com/curl/curl/pull/3899 + Reported-by: ygthien on github + Fixes #4828 -- [Marc Hoersken brought this change] +- smtp: Detect server support for the UTF-8 extension as defined in RFC-6531 - tests: fix permissions of ssh keys in WSL - - Keys created on Windows Subsystem for Linux (WSL) require it for some - reason. - - (This is one of several commits to support use of WSL for the tests.) +- smtp: Support UTF-8 based host names in the VRFY command + +- smtp: Support UTF-8 based host names in the RCPT TO command + +- smtp: Support UTF-8 based host names in the MAIL command - Ref: https://github.com/curl/curl/pull/3899 + Non-ASCII host names will be ACE encoded if IDN is supported. -- [Marc Hoersken brought this change] +- url: Make the IDN conversion functions available to others - tests: use \r\n for log messages in WSL +- smtp: Added UTF-8 mailbox tests to verify existing behaviour + +- ftpserver: Updated VRFY_smtp() so the response isn't necessary in the test case + +- ftpserver: Corrected the e-mail address regex in MAIL_smtp() and RCTP_smtp() - Bash in Windows Subsystem for Linux (WSL) requires it for some reason. + The dot character between the host and the tld was not being escaped, + which meant it specified a match of 'any' character rather than an + explicit dot separator. - (This is one of several commits to support use of WSL for the tests.) + Additionally removed the dot character from the host name as it allowed + the following to be specified as a valid address in our test cases: - Ref: https://github.com/curl/curl/pull/3899 - -- [Andrew Ishchuk brought this change] - - winbuild: Define CARES_STATICLIB when WITH_CARES=static + - When libcurl is built with MODE=static, c-ares is forced into static - linkage too. That doesn't happen when MODE=dll so linker would break - over undefined symbols. + Both are typos from 98f7ca7 and 8880f84 :( - closes https://github.com/curl/curl/pull/4688 + I can't remember whether my intention was to allow sub-domains to be + specified in the host or not with these additional dots, but by placing + it outside of the host means it can only be specified once per domain + and by placing a + after the new grouping support for sub-domains is + kept. + + Closes #4912 -Daniel Stenberg (9 Dec 2019) -- conn: always set bits.close with connclose() +- hmac: Added a unit test for the HMAC hash generation - Closes #4690 + Closes #4973 -- cirrus: enable clang sanitizers on freebsd 13 +- ntlm: Moved the HMAC MD5 function into the HMAC module as a generic function -- conncache: fix multi-thread use of shared connection cache +- tests: Added a unit test for MD4 digest generation - It could accidentally let the connection get used by more than one - thread, leading to double-free and more. + Closes #4970 + +- md4: Use const for the length input parameter - Reported-by: Christopher Reid - Fixes #4544 - Closes #4557 + This keeps the interface the same as md5 and sha256. -- azure: add a vanilla macos build +- test1610: Fixed the link to the unit test - Closes #4685 + Typo from 81c37124. -- curl: make the etag load logic work without fseek +- ntlm: Removed the dependency on the TLS libaries when using MD5 - The fseek()s were unnecessary and caused Coverity warning CID 1456554 + As we have our own MD5 implementation use the MD5 wrapper to remove the + TLS dependency. - Closes #4681 + Closes #4967 -- mailmap: Mohammad Hasbini +- md5/sha256: Updated the functions to allow non-string data to be hashed -- [Mohammad Hasbini brought this change] +- digest: Corrected the name of the local HTTP digest function + + Follow up to 2b5b37cb. Local static functions do not require the Curl + prefix. - docs: fix some typos +- tests: Added a unit test for SHA256 digest generation - Closes #4680 + Follow up to 2b5b37c. + + Closes #4968 + +- md4: Fixed compilation issues when using GNU TLS gcrypt + + * Don't include 'struct' in the gcrypt MD4_CTX typedef + * The call to gcry_md_read() should use a dereferenced ctx + * The call to gcry_md_close() should use a dereferenced ctx + + Additional minor whitespace issue in the USE_WIN32_CRYPTO code. + + Closes #4959 +Daniel Stenberg (21 Feb 2020) - RELEASE-NOTES: synced -Jay Satiro (5 Dec 2019) -- lib: fix some loose ends for recently added CURLSSLOPT_NO_PARTIALCHAIN - - Add support for CURLSSLOPT_NO_PARTIALCHAIN in CURLOPT_PROXY_SSL_OPTIONS - and OS400 package spec. +- http2: now require nghttp2 >= 1.12.0 - Also I added the option to the NameValue list in the tool even though it - isn't exposed as a command-line option (...yet?). (NameValue stringizes - the option name for the curl cmd -> libcurl source generator) + To simplify our code and since earlier versions lack important function + calls libcurl needs to function correctly. - Follow-up to 564d88a which added CURLSSLOPT_NO_PARTIALCHAIN. + nghttp2 1.12.0 was relased on June 26, 2016. - Ref: https://github.com/curl/curl/pull/4655 + Closes #4961 -- setopt: Fix ALPN / NPN user option when built without HTTP2 +- gtls: fix the copyright year - - Stop treating lack of HTTP2 as an unknown option error result for - CURLOPT_SSL_ENABLE_ALPN and CURLOPT_SSL_ENABLE_NPN. - - Prior to this change it was impossible to disable ALPN / NPN if libcurl - was built without HTTP2. Setting either option would result in - CURLE_UNKNOWN_OPTION and the respective internal option would not be - set. That was incorrect since ALPN and NPN are used independent of - HTTP2. + Follow-up from 41fcb4f609 + +- [jethrogb brought this change] + + GnuTLS: Always send client cert - Reported-by: Shailesh Kapse + TLS servers may request a certificate from the client. This request + includes a list of 0 or more acceptable issuer DNs. The client may use + this list to determine which certificate to send. GnuTLS's default + behavior is to not send a client certificate if there is no + match. However, OpenSSL's default behavior is to send the configured + certificate. The `GNUTLS_FORCE_CLIENT_CERT` flag mimics OpenSSL + behavior. - Fixes https://github.com/curl/curl/issues/4668 - Closes https://github.com/curl/curl/pull/4672 + Authored-by: jethrogb on github + Fixes #1411 + Closes #4958 -Daniel Stenberg (5 Dec 2019) -- etag: allow both --etag-compare and --etag-save in same cmdline +- [Leo Neat brought this change] + + github action: add CIFuzz - Fixes #4669 - Closes #4678 + Closes #4960 -Marcel Raad (5 Dec 2019) -- curl_setup: fix `CURLRES_IPV6` condition +- cleanup: comment typos - Move the definition of `CURLRES_IPV6` to before undefining - `HAVE_GETADDRINFO`. Regression from commit 67a08dca27a which caused - some tests to fail and others to be skipped with c-ares. + Spotted by 'codespell' - Fixes https://github.com/curl/curl/issues/4673 - Closes https://github.com/curl/curl/pull/4677 - -Daniel Stenberg (5 Dec 2019) -- test342: make it return a 304 as the tag matches + Closes #4957 -Peter Wu (4 Dec 2019) -- CMake: add support for building with the NSS vtls backend +Steve Holme (20 Feb 2020) +- win32: USE_WIN32_CRYPTO to enable Win32 based MD4, MD5 and SHA256 functions - Options are cross-checked with configure.ac and acinclude.m4. - Tested on Arch Linux, untested on other platforms like Windows or macOS. + Whilst lib\md4.c used this pre-processor, lib\md5.c and + src\tool_metalink.c did not and simply relied on the WIN32 + pre-processor directive. - Closes #4663 - Reviewed-by: Kamil Dudka + Reviewed-by: Marcel Raad + Closes #4955 -Daniel Stenberg (4 Dec 2019) -- azure: add more builds +Daniel Stenberg (19 Feb 2020) +- connect: remove some spurious infof() calls - ... removed two from travis (that now runs on azure instead) + As they were added primarily for debugging, they provide little use for + users. - Closes #4671 + Closes #4951 -- CURLOPT_VERBOSE.3: see also ERRORBUFFER +- HTTP-COOKIES: mention that a trailing newline is required + + ... so that we know we got the whole and not a partial line. + + Also, changed the formatting of the fields away from a table again since + the table format requires a github-markdown tool version that we don't + run on the web server atm. + + Reported-by: Sunny Bean + Fixes #4946 + Closes #4947 -- hostip4.c: bump copyright year range +- nit: Copyright year out of date + + Follow-up to 1fc0617dcc -Marcel Raad (3 Dec 2019) -- configure: enable IPv6 support without `getaddrinfo` +Jay Satiro (18 Feb 2020) +- tool_util: Improve Windows version of tvnow() - This makes it possible to recognize and connect to literal IPv6 - addresses when `getaddrinfo` is not available, which is already the - case for the CMake build. This affects e.g. classic MinGW because it - still targets Windows 2000 by default, where `getaddrinfo` is not - available, but general IPv6 support is. + - Change tool_util.c tvnow() for Windows to match more closely to + timeval.c Curl_now(). - Instead of checking for `getaddrinfo`, check for `sockaddr_in6` as the - CMake build does. + - Create a win32 init function for the tool, since some initialization + is required for the tvnow() changes. - Closes https://github.com/curl/curl/pull/4662 - -- curl_setup: disable IPv6 resolver without `getaddrinfo` + Prior to this change the monotonic time function used by curl in Windows + was determined at build-time and not runtime. That was a problem because + when curl was built targeted for compatibility with old versions of + Windows (eg _WIN32_WINNT < 0x0600) it would use GetTickCount which wraps + every 49.7 days that Windows has been running. - Also, use `CURLRES_IPV6` only for actual DNS resolution, not for IPv6 - address support. This makes it possible to connect to IPv6 literals by - setting `ENABLE_IPV6` even without `getaddrinfo` support. It also fixes - the CMake build when using the synchronous resolver without - `getaddrinfo` support. + This change makes curl behave similar to libcurl's tvnow function, which + determines at runtime whether the OS is Vista+ and if so calls + QueryPerformanceCounter instead. (Note QueryPerformanceCounter is used + because it has higher resolution than the more obvious candidate + GetTickCount64). The changes to tvnow are basically a copy and paste but + the types in some cases are different. - Closes https://github.com/curl/curl/pull/4662 - -Daniel Stenberg (3 Dec 2019) -- github action/azure pipeline: run 'make test-nonflaky' for tests + Ref: https://github.com/curl/curl/issues/3309 - To match travis and give more info on failures. + Closes https://github.com/curl/curl/pull/4847 -- openssl: CURLSSLOPT_NO_PARTIALCHAIN can disable partial cert chains +Daniel Stenberg (18 Feb 2020) +- SOCKS: fix typo in printf formatting - Closes #4655 - -- openssl: set X509_V_FLAG_PARTIAL_CHAIN + Follow-up to 4a4b63daa - Have intermediate certificates in the trust store be treated as - trust-anchors, in the same way as self-signed root CA certificates - are. This allows users to verify servers using the intermediate cert - only, instead of needing the whole chain. + Reported-by: Peter Piekarski + Bug: https://github.com/curl/curl/commit/4a4b63daaa01ef59b131d91e8e6e6dfe275c0f08#r37351330 + +- CURLOPT_REDIR_PROTOCOLS.3: update the DEFAULT section - Other TLS backends already accept partial chains. + to be in sync with the description above - Reported-by: Jeffrey Walton - Bug: https://curl.haxx.se/mail/lib-2019-11/0094.html + Reported-by: Joonas Kuorilehto + Fixes #4943 + Closes #4945 -- curl: show better error message when no homedir is found - - Reported-by: Vlastimil Ovčáčík - Fixes #4644 - Closes #4665 +- docs/GOVERNANCE: refreshed + added "donations" and "commercial support" -- OPENSOCKETFUNCTION.3: correct the purpose description +- altsvc: make saving the cache an atomic operation - Reported-by: Jeff Mears - Bug: https://curl.haxx.se/mail/lib-2019-12/0007.html + ... by writing the file to temp name then rename to the final when done. - Closes #4667 + Assisted-by: Jay Satiro + Fixes #4936 + Closes #4942 -- [Peter Wu brought this change] +- rename: a new file for Curl_rename() + + And make the cookie save function use it. - travis: do not use OVERRIDE_CC or OVERRIDE_CXX if empty +- cookies: make saving atomic with a rename - Fixes the macOS builds where OVERRIDE_CC and OVERRIDE_CXX are not set. + Saves the file as "[filename].[8 random hex digits].tmp" and renames + away the extension when done. - Reported-by: Jay Satiro - Fixes #4659 - Closes #4661 - Closes #4664 + Co-authored-by: Jay Satiro + Reported-by: Mike Frysinger + Fixes #4914 + Closes #4926 -- azure-pipelines: fix the test script +- RELEASE-NOTES: synced -- Azure Pipelines: initial CI setup +- socks: make the connect phase non-blocking - [skip ci] + Removes two entries from KNOWN_BUGS. + + Closes #4907 -- docs: add "added: 7.68.0" to the --etag-* docs +- multi: if Curl_readwrite sets 'comeback' use expire, not loop + + Otherwise, a very fast single transfer ricks starving out other + concurrent transfers. + + Closes #4927 -- copyright: fix the year ranges for two files +- ftp: convert 'sock_accepted' to a plain boolean - Follow-up to 9c1806ae + This was an array indexed with sockindex but it was only ever used for + the secondary socket. + + Closes #4929 -Jay Satiro (1 Dec 2019) -- build: Disable Visual Studio warning "conditional expression is constant" +Jay Satiro (15 Feb 2020) +- CURLINFO_COOKIELIST.3: Fix example - - Disable warning C4127 "conditional expression is constant" globally - in curl_setup.h for when building with Microsoft's compiler. + Prior to this change the example would try to import cookies from stdin, + which wasn't what was intended. - This mainly affects building with the Visual Studio project files found - in the projects dir. + Reported-by: 3dyd@users.noreply.github.com - Prior to this change the cmake and winbuild build systems already - disabled 4127 globally for when building with Microsoft's compiler. - Also, 4127 was already disabled for all build systems in the limited - circumstance of the WHILE_FALSE macro which disabled the warning - specifically for while(0). This commit removes the WHILE_FALSE macro and - all other cruft in favor of disabling globally in curl_setup. + Fixes https://github.com/curl/curl/issues/4930 + +Daniel Stenberg (14 Feb 2020) +- TODO: Paged searches on LDAP server - Background: + Closes #4452 + +- TODO: CURLOPT_SSL_CTX_FUNCTION for LDAPS - We have various macros that cause 0 or 1 to be evaluated, which would - cause warning C4127 in Visual Studio. For example this causes it: + Closes #4108 + +- azure: disable brotli on the macos debug-builds - #define Curl_resolver_asynch() 1 + Because of: - Full behavior is not clearly defined and inconsistent across versions. - However it is documented that since VS 2015 Update 3 Microsoft has - addressed this somewhat but not entirely, not warning on while(true) for - example. + brotli/decode.h:204:33: error: variable length array used [-Werror,-Wvla] + const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)], - Prior to this change some C4127 warnings occurred when I built with - Visual Studio using the generated projects in the projects dir. + Closes #4925 + +Steve Holme (13 Feb 2020) +- tool_home: Fix the copyright year being out of date - Closes https://github.com/curl/curl/pull/4658 + Follow up to 9dc350b6. -- openssl: retrieve reported LibreSSL version at runtime +Jay Satiro (12 Feb 2020) +- tool_homedir: Change GetEnv() to use libcurl's curl_getenv() - - Retrieve LibreSSL runtime version when supported (>= 2.7.1). + - Deduplicate GetEnv() code. - For earlier versions we continue to use the compile-time version. + - On Windows change ultimate call to use Windows API + GetEnvironmentVariable() instead of C runtime getenv(). - Ref: https://man.openbsd.org/OPENSSL_VERSION_NUMBER.3 + Prior to this change both libcurl and the tool had their own GetEnv + which over time diverged. Now the tool's GetEnv is a wrapper around + curl_getenv (libcurl API function which is itself a wrapper around + libcurl's GetEnv). - Closes https://github.com/curl/curl/pull/2425 + Furthermore this change fixes a bug in that Windows API + GetEnvironmentVariable() is called instead of C runtime getenv() to get + the environment variable since some changes aren't always visible to the + latter. + + Reported-by: Christoph M. Becker + + Fixes https://github.com/curl/curl/issues/4774 + Closes https://github.com/curl/curl/pull/4863 -- strerror: Add Curl_winapi_strerror for Win API specific errors +Daniel Stenberg (12 Feb 2020) +- strerror.h: Copyright year out of date - - In all code call Curl_winapi_strerror instead of Curl_strerror when - the error code is known to be from Windows GetLastError. + Follow-up to 1c4fa67e8a8fcf6 + +Jay Satiro (12 Feb 2020) +- strerror: Increase STRERROR_LEN 128 -> 256 - Curl_strerror prefers CRT error codes (errno) over Windows API error - codes (GetLastError) when the two overlap. When we know the error code - is from GetLastError it is more accurate to prefer the Windows API error - messages. + STRERROR_LEN is the constant used throughout the library to set the size + of the buffer on the stack that the curl strerror functions write to. - Reported-by: Richard Alcock + Prior to this change some extended length Windows error messages could + be truncated. - Fixes https://github.com/curl/curl/issues/4550 - Closes https://github.com/curl/curl/pull/4581 + Closes https://github.com/curl/curl/pull/4920 -Daniel Stenberg (2 Dec 2019) -- global_init: undo the "intialized" bump in case of failure +- multi: fix outdated comment - ... so that failures in the global init function don't count as a - working init and it can then be called again. + - Do not say that conn->data is "cleared" by multi_done(). - Reported-by: Paul Groke - Fixes #4636 - Closes #4653 + If the connection is in use then multi_done assigns another easy handle + still using the connection to conn->data, therefore in that case it is + not cleared. + + Closes https://github.com/curl/curl/pull/4901 -- parsedate: offer a getdate_capped() alternative +- easy: remove dead code - ... and use internally. This function will return TIME_T_MAX instead of - failure if the parsed data is found to be larger than what can be - represented. TIME_T_MAX being the largest value curl can represent. + multi is already assigned to data->multi by curl_multi_add_handle. - Reviewed-by: Daniel Gustafsson - Reported-by: JanB on github - Fixes #4152 - Closes #4651 + Closes https://github.com/curl/curl/pull/4900 -- docs: add more references to curl_multi_poll +Daniel Stenberg (12 Feb 2020) +- create-dirs.d: mention the mode - Fixes #4643 - Closes #4652 - -- sha256: bump the copyright year range - - Follow-up from 66e21520f + Reported-by: Dan Jacobson + Fixes #4766 + Closes #4916 -Daniel Gustafsson (28 Nov 2019) -- curl_setup_once: consistently use WHILE_FALSE in macros +- CURLOPT_ALTSVC_CTRL.3: fix the DEFAULT wording - The WHILE_FALSE construction is used to avoid compiler warnings in - macro constructions. This fixes a few instances where it was not - used in order to keep the code consistent. - - Closes #4649 - Reviewed-by: Daniel Stenberg + Assisted-by: Jay Satiro + Reported-by: Craig Andrews + Fixes #4909 + Closes #4910 -Daniel Stenberg (28 Nov 2019) -- [Steve Holme brought this change] +- RELEASE-NOTES: synced - http_ntlm: Remove duplicate NSS initialisation +Steve Holme (9 Feb 2020) +- smtp: Simplify the MAIL command and avoid a duplication of send strings - Given that this is performed by the NTLM code there is no need to - perform the initialisation in the HTTP layer. This also keeps the - initialisation the same as the SASL based protocols and also fixes a - possible compilation issue if both NSS and SSPI were to be used as - multiple SSL backends. + This avoids the duplication of strings when the optional AUTH and SIZE + parameters are required. It also assists with the modifications that + are part of #4892. - Reviewed-by: Kamil Dudka - Closes #3935 + Closes #4903 -Daniel Gustafsson (28 Nov 2019) -- checksrc: fix regexp for ASSIGNWITHINCONDITION +Daniel Stenberg (9 Feb 2020) +- altsvc: keep a copy of the file name to survive handle reset - The regexp looking for assignments within conditions was too greedy - and matched a too long string in the case of multiple conditionals - on the same line. This is basically only a problem in single line - macros, and the code which exemplified this was essentially: + The alt-svc cache survives a call to curl_easy_reset fine, but the file + name to use for saving the cache was cleared. Now the alt-svc cache has + a copy of the file name to survive handle resets. - do { if((x) != NULL) { x = NULL; } } while(0) + Added test 1908 to verify. - ..where the final parenthesis of while(0) matched the regexp, and - the legal assignment in the block triggered the warning. Fix by - making the regexp less greedy by matching for the tell-tale signs - of the if statement ending. + Reported-by: Craig Andrews + Fixes #4898 + Closes #4902 + +Steve Holme (9 Feb 2020) +- url: Include the failure reason when curl_win32_idn_to_ascii() fails - Also remove the one occurrence where the warning was disabled due - to a construction like the above, where the warning didn't apply - when fixed. + Provide the failure reason in the failf() info just as we do for the + libidn2 version of code. - Closes #4647 - Reviewed-by: Daniel Stenberg + Closes #4899 -Daniel Stenberg (28 Nov 2019) -- RELEASE-NOTES: synced +Jay Satiro (9 Feb 2020) +- asyn-thread: remove dead code -- [Maros Priputen brought this change] +Daniel Stenberg (8 Feb 2020) +- [Emil Engler brought this change] - curl: two new command line options for etags + github: Instructions to post "uname -a" on Unix systems in issues - --etag-compare and --etag-save - - Suggested-by: Paul Hoffman - Fixes #4277 - Closes #4543 - -Daniel Gustafsson (28 Nov 2019) -- docs: fix typos + Closes #4896 -Daniel Stenberg (28 Nov 2019) -- mailmap: Niall O'Reilly's name - -- [Niall O'Reilly brought this change] +- [Cristian Greco brought this change] - doh: use dedicated probe slots + configure.ac: fix comments about --with-quiche - ... to easier allow additional DNS transactions. + A simple s/nghttp3/quiche in some comments of --with-quiche. + Looks like a copy-paste error from --with-nghttp3. - Closes #4629 + Closes #4897 -- travis: build ngtcp2 with --enable-lib-only +Steve Holme (7 Feb 2020) +- checksrc.bat: Fix not being able to run script from the main curl directory - ... makes it skip the examples and other stuff we don't neeed. + If the script was ran from the main curl directory rather then the + projects directory then the script would simply exit without error: - Closes #4646 - -- [David Benjamin brought this change] - - ngtcp2: fix thread-safety bug in error-handling + C:\url> projects\checksrc.bat - ERR_error_string(NULL) should never be called. It places the error in a - global buffer, which is not thread-safe. Use ERR_error_string_n with a - local buffer instead. + The user would either need to change to the projects directory, + explicitly specify the current working directory, or perform a + oneline hacky workaround: - Closes #4645 - -- travis: export the CC/CXX variables when set + C:\url> cd projects + C:\url\projects> checksrc.bat - Suggested-by: Peter Wu - Fixes #4637 - Closes #4640 - -Marcel Raad (26 Nov 2019) -- dist: add error-codes.pl + C:\url> checksrc.bat %cd% - Follow-up to commit 74f441c6d31. - This should fix test 1175 when run via the daily source tarballs. + C:\url> pushd projects & checksrc.bat & popd - Closes https://github.com/curl/curl/pull/4638 + Closes #4894 -Daniel Stenberg (26 Nov 2019) -- [John Schroeder brought this change] +Daniel Stenberg (7 Feb 2020) +- [Pierre-Yves Bigourdan brought this change] - curl: fix --upload-file . hangs if delay in STDIN + digest: Do not quote algorithm in HTTP authorisation - Attempt to unpause a busy read in the CURLOPT_XFERINFOFUNCTION. - - When uploading from stdin in non-blocking mode, a delay in reading - the stream (EAGAIN) causes curl to pause sending data - (CURL_READFUNC_PAUSE). Prior to this change, a busy read was - detected and unpaused only in the CURLOPT_WRITEFUNCTION handler. - This change performs the same busy read handling in a - CURLOPT_XFERINFOFUNCTION handler. + RFC 7616 section 3.4 (The Authorization Header Field) states that "For + historical reasons, a sender MUST NOT generate the quoted string syntax + for the following parameters: algorithm, qop, and nc". This removes the + quoting for the algorithm parameter. - Fixes #2051 - Closes #4599 - Reported-by: bdry on github + Reviewed-by: Steve Holme + Closes #4890 -- [John Schroeder brought this change] +- ftp: remove the duplicated user/password struct fields + + Closes #4887 - XFERINFOFUNCTION: support CURL_PROGRESSFUNC_CONTINUE +- ftp: remove superfluous checking for crlf in user or pwd - (also for PROGRESSFUNCTION) + ... as this is already done much earlier in the URL parser. - By returning this value from the callback, the internal progress - function call is still called afterward. + Also add test case 894 that verifies that pop3 with an encodedd CR in + the user name is rejected. - Closes #4599 - -- [Michael Forney brought this change] + Closes #4887 - TLS: add BearSSL vtls implementation +Steve Holme (6 Feb 2020) +- ntlm_wb: Use Curl_socketpair() for greater portability - Closes #4597 + Reported-by: Daniel Stenberg + Closes #4886 -- curl_multi_wakeup.3: add example and AVAILABILITY +Daniel Stenberg (5 Feb 2020) +- [Frank Gevaerts brought this change] + + contributors: Also include people who contributed to curl-www - Reviewed-by: Gergely Nagy - Closes #4635 + Closes #4884 -- [Gergely Nagy brought this change] +- [Frank Gevaerts brought this change] - multi: add curl_multi_wakeup() - - This commit adds curl_multi_wakeup() which was previously in the TODO - list under the curl_multi_unblock name. + contrithanks: Use the most recent tag by default - On some platforms and with some configurations this feature might not be - available or can fail, in these cases a new error code - (CURLM_WAKEUP_FAILURE) is returned from curl_multi_wakeup(). + (similar to 5296abe) - Fixes #4418 - Closes #4608 + Closes #4883 -Jay Satiro (24 Nov 2019) -- [Xiaoyin Liu brought this change] +- scripts: use last set tag if none given + + Makes 'delta' and 'contributors.sh' easier to use. + + Make the delta script invoke contrithanks to get current number of + contributors instead of counting THANKS, for accuracy. + + Closes #4881 - schannel: fix --tls-max for when min is --tlsv1 or default +- ftp: shrink temp buffers used for PORT - Prior to this change schannel ignored --tls-max (CURL_SSLVERSION_MAX_ - macros) when --tlsv1 (CURL_SSLVERSION_TLSv1) or default TLS - (CURL_SSLVERSION_DEFAULT), using a max of TLS 1.2 always. + These two stack based buffers only need to be 46 + 66 bytes instead of + 256 + 1024. - Closes https://github.com/curl/curl/pull/4633 + Closes #4880 -- checksrc.bat: Add a check for vquic and vssh directories +- curl: error on --alt-svc use w/o support - Ref: https://github.com/curl/curl/pull/4607 + Make the tool check for alt-svc support at run-time and return error + accordingly if not present when the option is used. + + Reported-by: Harry Sintonen + Closes #4878 -- projects: Fix Visual Studio projects SSH builds +- docs/HTTP3: add --enable-alt-svc to curl's configure + +- RELEASE-PROCEDURE: feature win is closed post-release a few days - - Generate VQUIC and VSSH filenames in Visual Studio project files. + We've tried to uphold this already but let's make it official by + publicly stating this is the way we do it. - Prior to this change generated Visual Studio project configurations that - enabled SSH did not build properly. Broken since SSH files were moved to - lib/vssh 3 months ago in 5b2d703. + Closes #4877 + +- altsvc: set h3 version at a common single spot - Fixes https://github.com/curl/curl/issues/4492 - Fixes https://github.com/curl/curl/issues/4630 - Closes https://github.com/curl/curl/pull/4607 + ... and move the #ifdefs out of the functions. Addresses the fact they + were different before this change. + + Reported-by: Harry Sintonen + Closes #4876 -Daniel Stenberg (23 Nov 2019) -- RELEASE-NOTES: synced +- [Harry Sintonen brought this change] -Jay Satiro (22 Nov 2019) -- openssl: Revert to less sensitivity for SYSCALL errors + altsvc: improved header parser - - Disable the extra sensitivity except in debug builds (--enable-debug). + - Fixed the flag parsing to apply to specific alternative entry only, as + per RFC. The earlier code would also get totally confused by + multiprotocol header, parsing flags from the wrong part of the header. - - Improve SYSCALL error message logic in ossl_send and ossl_recv so that - "No error" / "Success" socket error text isn't shown on SYSCALL error. + - Fixed the parser terminating on unknown protocols, instead of skipping + them. - Prior to this change 0ab38f5 (precedes 7.67.0) increased the sensitivity - of OpenSSL's SSL_ERROR_SYSCALL error so that abrupt server closures were - also considered errors. For example, a server that does not send a known - protocol termination point (eg HTTP content length or chunked encoding) - _and_ does not send a TLS termination point (close_notify alert) would - cause an error if it closed the connection. + - Fixed a busyloop when protocol-id was present without an equal sign. - To be clear that behavior made it into release build 7.67.0 - unintentionally. Several users have reported it as an issue. + Closes #4875 + +- [Harry Sintonen brought this change] + + ngtcp2: fixed to only use AF_INET6 when ENABLE_IPV6 + +- docs/HTTP3: update the OpenSSL branch to use for ngtcp2 - Ultimately the idea is a good one, since it can help prevent against a - truncation attack. Other SSL backends may already behave similarly (such - as Windows native OS SSL Schannel). However much more of our user base - is using OpenSSL and there is a mass of legacy users in that space, so I - think that behavior should be partially reverted and then rolled out - slowly. + Reported-by: James Fuller + +Steve Holme (4 Feb 2020) +- ntlm: Pass the Curl_easy structure to the private winbind functions - This commit changes the behavior so that the increased sensitivity is - disabled in all curl builds except curl debug builds (DEBUGBUILD). If - after a period of time there are no major issues then it can be enabled - in dev and release builds with the newest OpenSSL (1.1.1+), since users - using the newest OpenSSL are the least likely to have legacy problems. + ...rather than the full conndata structure. + +Daniel Stenberg (4 Feb 2020) +- RELEASE-NOTES: synced + +- tool_operhlp: Copyright year out of date, should be 2020 - Bug: https://github.com/curl/curl/issues/4409#issuecomment-555955794 - Reported-by: Bjoern Franke + Follow-up from 2bc373740a3 + +- [Orgad Shaneh brought this change] + + curl: avoid using strlen for testing if a string is empty - Fixes https://github.com/curl/curl/issues/4624 - Closes https://github.com/curl/curl/pull/4623 + Closes #4873 -- [Daniel Stenberg brought this change] +Steve Holme (3 Feb 2020) +- ntlm: Ensure the HTTP header data is not stored in the challenge/response - openssl: improve error message for SYSCALL during connect +Marcel Raad (3 Feb 2020) +- openssl: remove redundant assignment - Reported-by: Paulo Roberto Tomasi - Bug: https://curl.haxx.se/mail/archive-2019-11/0005.html + Fixes a scan-build failure on Bionic. - Closes https://github.com/curl/curl/pull/4593 + Closes https://github.com/curl/curl/pull/4872 -Daniel Stenberg (22 Nov 2019) -- test1175: verify symbols-in-versions and libcurl-errors.3 in sync +- travis: update non-OpenSSL Linux jobs to Bionic - Closes #4628 - -- include: make CURLE_HTTP3 use a new error code + For the OpenSSL builds, test 323 [TLS-SRP to non-TLS-SRP server] is + failing with "curl returned 52, when expecting 35". - To avoid potential issues with error code reuse. + Closes https://github.com/curl/curl/pull/4872 + +Dan Fandrich (3 Feb 2020) +- cirrus: Add some missing semicolons - Reported-by: Christoph M. Becker - Assisted-by: Dan Fandrich - Fixes #4601 - Closes #4627 + Newlines aren't preserved in this section so they're needed to separate + commands. The exports luckily worked anyway as a single long line, but + erroneously exported a variable called "export" + [skip ci] -- bump: next release will be 7.68.0 +Daniel Gustafsson (2 Feb 2020) +- [Pedro Monreal brought this change] -- curl: add --parallel-immediate + cleanup: fix typos and wording in docs and comments - Starting with this change when doing parallel transfers, without this - option set, curl will prefer to create new transfers multiplexed on an - existing connection rather than creating a brand new one. + Closes #4869 + Reviewed-by: Emil Engler and Daniel Gustafsson + +Steve Holme (2 Feb 2020) +- ntlm: Move the winbind data into the NTLM data structure - --parallel-immediate can be set to tell curl to prefer to use new - connections rather than to wait and try to multiplex. + To assist with adding winbind support to the SASL NTLM authentication, + move the winbind specific data out of conndata into ntlmdata. + +Daniel Stenberg (30 Jan 2020) +- quiche: Copyright year out of date - libcurl-wise, this means that curl will set CURLOPT_PIPEWAIT by default - on parallel transfers. + Follow-up to 7fc63d72333a + +- altsvc: use h3-25 - Suggested-by: Tom van der Woerdt - Closes #4500 + Closes #4868 -Daniel Gustafsson (20 Nov 2019) -- [Victor Magierski brought this change] +- [Alessandro Ghedini brought this change] - docs: fix typos + quiche: update to draft-25 - Change 'experiemental' to 'experimental'. + Closes #4867 + +- ngtcp2: update to git master and its draft-25 support - Closes #4618 - Reviewed-by: Daniel Gustafsson + Closes #4865 -Jay Satiro (18 Nov 2019) -- projects: Fix Visual Studio wolfSSL configurations +- cookie: check __Secure- and __Host- case sensitively - - s/USE_CYASSL/USE_WOLFSSL/ + While most keywords in cookies are case insensitive, these prefixes are + specified explicitly to get checked "with a case-sensitive match". - - Remove old compatibility macros. + (From the 6265bis document in progress) - Follow-up to 1c6c59a from several months ago when CyaSSL named symbols - were renamed to wolfSSL. The wolfSSL library was formerly named CyaSSL - and we kept using their old name for compatibility reasons, until - earlier this year. - -Daniel Stenberg (18 Nov 2019) -- RELEASE-NOTES: synced + Ref: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-04 + Closes #4864 -- [Javier Blazquez brought this change] +- KNOWN_BUGS: Multiple methods in a single WWW-Authenticate: header - ngtcp2: use overflow buffer for extra HTTP/3 data +- oauth2-bearer.d: works for HTTP too - Fixes #4525 - Closes #4603 + Reported-by: Mischa Salle + Bug: https://curl.haxx.se/mail/lib-2020-01/0070.html + Closes #4862 -- altsvc: bump to h3-24 +- multi_done: if multiplexed, make conn->data point to another transfer - ... as both ngtcp2 and quiche now support that in their master branches + ... since the current transfer is being killed. Setting to NULL is + wrong, leaving it pointing to 'data' is wrong since that handle might be + about to get freed. - Closes #4604 + Fixes #4845 + Closes #4858 + Reported-by: dmitrmax on github -- ngtcp2: free used resources on disconnect +- location.d: the method change is from POST to GET only - Fixes #4614 - Closes #4615 + Not from generic non-GET to GET. + + Reported-by: Andrius Merkys + Ref: #4859 + Closes #4861 -- ngtcp2: handle key updates as ngtcp2 master branch tells us +- urlapi: guess scheme correct even with credentials given - Reviewed-by: Tatsuhiro Tsujikawa + In the "scheme-less" parsing case, we need to strip off credentials + first before we guess scheme based on the host name! - Fixes #4612 - Closes #4613 + Assisted-by: Jay Satiro + Fixes #4856 + Closes #4857 -Jay Satiro (17 Nov 2019) -- [Gergely Nagy brought this change] +- global_init: move the IPv6 works status bool to multi handle + + Previously it was stored in a global state which contributed to + curl_global_init's thread unsafety. This boolean is now instead figured + out in curl_multi_init() and stored in the multi handle. Less effective, + but thread safe. + + Closes #4851 - multi: Fix curl_multi_poll wait when extra_fds && !extra_nfds +- [Jay Satiro brought this change] + + README: mention that the docs is in docs/ - Prior to this change: + Reported-by: Austin Green + Fixes #4830 + Closes #4853 + +- curl.h: define CURL_WIN32 on windows - The check if an extra wait is necessary was based not on the - number of extra fds but on the pointer. + ... so that the subsequent logic below can use a single known define to know + when built on Windows (as we don't define WIN32 anymore). - If a non-null pointer was given in extra_fds, but extra_nfds - was zero, then the wait was skipped even though poll was not - called. + Follow-up to 1adebe7886ddf20b - Closes https://github.com/curl/curl/pull/4610 + Reported-by: crazydef on github + Assisted-by: Marcel Raad + Fixes #4854 + Closes #4855 -- lib: Move lib/ssh.h -> lib/vssh/ssh.h +- RELEASE-NOTES: synced + +- [Jon Rumsey brought this change] + + urldata: do string enums without #ifdefs for build scripts - Follow-up to 5b2d703 which moved ssh source files to vssh. + ... and check for inconsistencies for OS400 at build time with the new + chkstrings tool. - Closes https://github.com/curl/curl/pull/4609 + Closes #4822 -Daniel Stenberg (16 Nov 2019) -- [Andreas Falkenhahn brought this change] +- curl: make the -# spaceship bar not wrap the line + + The fixed-point math made us lose precision and thus a too high index + value could be used for outputting the hashtags which could overwrite + the newline. + + The fix increases the precision in the sine table (*100) and the + associated position math. + + Reported-by: Andrew Potter + Fixes #4849 + Closes #4850 - INSTALL.md: provide Android build instructions +- global_init: assume the EINTR bit by default - Closes #4606 + - Removed from global_init since it isn't thread-safe. The symbol will + still remain to not break compiles, it just won't have any effect going + forward. + + - make the internals NOT loop on EINTR (the opposite from previously). + It only risks returning from the select/poll/wait functions early, and that + should be risk-free. + + Closes #4840 -- [Niall O'Reilly brought this change] +- [Peter Piekarski brought this change] - doh: improced both encoding and decoding + conn: do not reuse connection if SOCKS proxy credentials differ - Improved estimation of expected_len and updated related comments; - increased strictness of QNAME-encoding, adding error detection for empty - labels and names longer than the overall limit; avoided treating DNAME - as unexpected; + Closes #4835 + +- llist: removed unused Curl_llist_move() - updated unit test 1655 with more thorough set of proofs and tests + (and the corresponding unit test) - Closes #4598 + Closes #4842 -- ngtcp2: increase QUIC window size when data is consumed +- conncache: removed unused Curl_conncache_bundle_size() + +- strcase: turn Curl_raw_tolower into static - Assisted-by: Javier Blazquez - Ref #4525 (partial fix) - Closes #4600 + Only ever used from within this file. -- [Melissa Mears brought this change] +- singleuse.pl: support new API functions, fix curl_dbg_ handling - config-win32: cpu-machine-OS for Windows on ARM +- wolfssh: make it init properly via Curl_ssh_init() - Define the OS macro properly for Windows on ARM builds. Also, we might - as well add the GCC-style IA-64 macro. + Closes #4846 + +- [Aron Rotteveel brought this change] + + form.d: fix two minor typos - Closes #4590 + Closes #4843 -- examples: add multi-poll.c +- openssl: make CURLINFO_CERTINFO not truncate x509v3 fields - Show how curl_multi_poll() makes it even easier to use the multi - interface. + Avoid "reparsing" the content and instead deliver more exactly what is + provided in the certificate and avoid truncating the data after 512 + bytes as done previously. This no longer removes embedded newlines. - Closes #4596 + Fixes #4837 + Reported-by: bnfp on github + Closes #4841 -- multi_poll: avoid busy-loop when called without easy handles attached +Jay Satiro (23 Jan 2020) +- CURLOPT_PROXY_SSL_OPTIONS.3: Sync with CURLOPT_SSL_OPTIONS.3 - Fixes #4594 - Closes #4595 - Reported-by: 3dyd on github + - Copy CURLOPT_SSL_OPTIONS.3 description to CURLOPT_PROXY_SSL_OPTIONS.3. + + Prior to this change CURLSSLOPT_NO_PARTIALCHAIN was missing from the + CURLOPT_PROXY_SSL_OPTIONS description. -- curl: fix -T globbing +Daniel Stenberg (22 Jan 2020) +- mk-ca-bundle: add support for CKA_NSS_SERVER_DISTRUST_AFTER - Regression from e59371a4936f8 (7.67.0) + For now, no cert in the bundle actually sets a date there... - Added test 490, 491 and 492 to verify the functionality. + Co-Authored-by: Jay Satiro + Reported-by: Christian Heimes + Fixes #4834 + Closes #4836 + +- RELEASE-NOTES: synced + +- [Pavel Volgarev brought this change] + + smtp: Allow RCPT TO command to fail for some recipients - Reported-by: Kamil Dudka - Reported-by: Anderson Sasaki + Introduces CURLOPT_MAIL_RCPT_ALLLOWFAILS. - Fixes #4588 - Closes #4591 + Verified with the new tests 3002-3007 + + Closes #4816 -- HISTORY: added cmake, HTTP/3 and parallel downloads with curl +- copyright: fix year ranges + + follow-up from dea17b519d (one of these days I'll learn to check before + I push) -- quiche: reject headers in the wrong order +- [nao brought this change] + + http: move "oauth_bearer" from connectdata to Curl_easy - Pseudo header MUST come before regular headers or cause an error. + Fixes the bug where oauth_bearer gets deallocated when we re-use a + connection. - Reported-by: Cynthia Coan - Fixes #4571 - Closes #4584 + Closes #4824 -- openssl: prevent recursive function calls from ctx callbacks +- [Emil Engler brought this change] + + curl: Let -D merge headers in one file again - Follow the pattern of many other callbacks. + Closes #4762 + Fixes #4753 + +- data.d: remove "Multiple files can also be specified" - Ref: #4546 - Closes #4585 + It is superfluous and could even be misleading. + + Bug: https://curl.haxx.se/mail/archive-2020-01/0016.html + Reported-by: Mike Norton + Closes #4832 -- CURL-DISABLE: initial docs for the CURL_DISABLE_* defines +Marcel Raad (20 Jan 2020) +- CMake: support specifying the target Windows version - The disable-scan script used in test 1165 is extended to also verify - that the docs cover all used defines and all defines offered by - configure. + Previously, it was only possible to set it to Windows Vista or XP by + setting the option `ENABLE_INET_PTON` to `ON` resp. `OFF`. + Use a new cache variable `CURL_TARGET_WINDOWS_VERSION` to be able to + explicitly set the target Windows version. `ENABLE_INET_PTON` is + ignored in this case. - Reported-by: SLDiggie on github - Fixes #4545 - Closes #4587 + Ref: https://github.com/curl/curl/pull/1639#issuecomment-313039352 + Ref: https://github.com/curl/curl/pull/4607#issuecomment-557541456 + Closes https://github.com/curl/curl/pull/4815 -- remove_handle: clear expire timers after multi_done() +Daniel Stenberg (20 Jan 2020) +- http.h: Copyright year out of date, should be 2020 - Since 59041f0, a new timer might be set in multi_done() so the clearing - of the timers need to happen afterwards! + Follow-up to 7ff9222ced8c + +- [加藤郁之 brought this change] + + HTTP: increase EXPECT_100_THRESHOLD to 1Mb - Reported-by: Max Kellermann - Fixes #4575 - Closes #4583 + Mentioned: https://curl.haxx.se/mail/lib-2020-01/0050.html + + Closes #4814 -Marcel Raad (10 Nov 2019) -- test1558: use double slash after file: +- ROADMAP: thread-safe `curl_global_init()` - Classic MinGW / MSYS 1 doesn't support `MSYS2_ARG_CONV_EXCL`, so this - test unnecessarily failed when using `file:/` instead of `file:///`. + I'd like to see this happen. + +- RELEASE-NOTES: synced + +- wolfssl: use the wc-prefixed symbol alternatives - Closes https://github.com/curl/curl/pull/4554 + The symbols without wc_ prefix are not always provided. + + Ref: https://github.com/wolfSSL/wolfssl/issues/2744 + + Closes #4827 -Daniel Stenberg (10 Nov 2019) -- pause: avoid updating socket if done was already called +- polarssl: removed - ... avoids unnecesary recursive risk when the transfer is already done. + As detailed in DEPRECATE.md, the polarssl support is now removed after + having been disabled for 6 months and nobody has missed it. - Reported-by: Richard Bowker - Fixes #4563 - Closes #4574 + The threadlock files used by mbedtls are renamed to an 'mbedtls' prefix + instead of the former 'polarssl' and the common functions that + previously were shared between mbedtls and polarssl and contained the + name 'polarssl' have now all been renamed to instead say 'mbedtls'. + + Closes #4825 -Jay Satiro (9 Nov 2019) -- strerror: Fix an error looking up some Windows error strings +Marcel Raad (16 Jan 2020) +- libssh2: fix variable type - - Use FORMAT_MESSAGE_IGNORE_INSERTS to ignore format specifiers in - Windows error strings. + This led to a conversion warning on 64-bit MinGW, which has 32-bit + `long` but 64-bit `size_t`. - Since we are not in control of the error code we don't know what - information may be needed by the error string's format specifiers. + Closes https://github.com/curl/curl/pull/4823 + +Daniel Stenberg (16 Jan 2020) +- curl:progressbarinit: ignore column width from terminals < 20 - Prior to this change Windows API error strings which contain specifiers - (think specifiers like similar to printf specifiers) would not be shown. - The FormatMessage Windows API call which turns a Windows error code into - a string could fail and set error ERROR_INVALID_PARAMETER if that error - string contained a format specifier. FormatMessage expects a va_list for - the specifiers, unless inserts are ignored in which case no substitution - is attempted. + To avoid division by zero - or other issues. - Ref: https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353 + Reported-by: Daniel Marjamäki + Closes #4818 -- [r-a-sattarov brought this change] +- wolfssh: set the password correctly for PASSWORD auth - system.h: fix for MCST lcc compiler +- wolfssh: remove fprintf() calls (and uses of __func__) + +Marcel Raad (14 Jan 2020) +- CMake: use check_symbol_exists also for inet_pton - Fixed build by MCST lcc compiler on MCST Elbrus 2000 architecture and do - some code cleanup. + It doesn't make much sense to only check if the function can be linked + when it's not declared in any header and that is treated as an error. + With the correct target Windows version set, the function is declared + in ws2tcpip.h and the comment above the modified block is invalid. - e2k (Elbrus 2000) - this is VLIW/EPIC architecture, like Intel Itanium - architecture. + Also, move the definition of `_WIN32_WINNT` up to before all symbol + availability checks so that we don't have to care which ones must be + done after it. - Ref: https://en.wikipedia.org/wiki/Elbrus_2000 + Tested with Visual Studio 2019 and current MinGW-w64. - Closes https://github.com/curl/curl/pull/4576 + Closes https://github.com/curl/curl/pull/4808 -Daniel Stenberg (8 Nov 2019) -- TODO: curl_multi_unblock +Jay Satiro (13 Jan 2020) +- schannel_verify: Fix alt names manual verify for UNICODE builds - Closes #4418 - -- TODO: Run web-platform-tests url tests + Follow-up to 29e40a6 from two days ago, which added that feature for + Windows 7 and earlier. The bug only occurred in same. - Closes #4477 + Ref: https://github.com/curl/curl/pull/4761 -- TODO: 1.4 alt-svc sharing +Daniel Stenberg (13 Jan 2020) +- HTTP-COOKIES.md: describe the cookie file format - Closes #4476 + ... and refer to that file from from CURLOPT_COOKIEFILE.3 and + CURLOPT_COOKIELIST.3 + + Assisted-by: Jay Satiro + Reported-by: bsammon on github + Fixes #4805 + Closes #4806 -- test1560: require IPv6 for IPv6 aware URL parsing +- [Tobias Hieta brought this change] + + CMake: Add support for CMAKE_LTO option. - The URL parser function can't reject a bad IPv6 address properly when - curl was built without IPv6 support. + This enables Link Time Optimization. LTO is a proven technique for + optimizing across compilation units. - Reported-by: Marcel Raad - Fixes #4556 - Closes #4572 + Closes #4799 -- checksrc: repair the copyrightyear check +- RELEASE-NOTES: synced + +- ConnectionExists: respect the max_concurrent_streams limits - - Consider a modified file to be committed this year. + A regression made the code use 'multiplexed' as a boolean instead of the + counter it is intended to be. This made curl try to "over-populate" + connections with new streams. - - Make the travis CHECKSRC also do COPYRIGHTYEAR scan in examples and - includes + This regression came with 41fcdf71a1, shipped in curl 7.65.0. - - Ignore 0 parents when getting latest commit date of file. + Also, respect the CURLMOPT_MAX_CONCURRENT_STREAMS value in the same + check. - since in the CI we're dealing with a truncated repo of last 50 commits, - the file's most recent commit may not be available. when this happens - git log and rev-list show the initial commit (ie first commit not to be - truncated) but that's incorrect so ignore it. + Reported-by: Kunal Ekawde + Fixes #4779 + Closes #4784 + +- curl: make #0 not output the full URL - Ref: https://github.com/curl/curl/pull/4547 + It was not intended nor documented! - Closes https://github.com/curl/curl/pull/4549 + Added test 1176 to verify. - Co-authored-by: Jay Satiro - -- copyrights: fix copyright year range + Reported-by: vshmuk on hackerone - .. because checksrc's copyright year check stopped working. + Closes #4812 + +- wolfSSH: new SSH backend - Ref: https://github.com/curl/curl/pull/4547 + Adds support for SFTP (not SCP) using WolfSSH. - Closes https://github.com/curl/curl/pull/4549 - -- RELEASE-NOTES: synced - -- curlver: bump to 7.67.1 + Closes #4231 -- mailmap: fixup Massimiliano Fantuzzi +- curl: remove 'config' field from OutStruct + + As it was just unnecessary duplicated information already stored in the + 'per_transfer' struct and that's around mostly anyway. + + The duplicated pointer caused problems when the code flow was aborted + before the dupe was filled in and could cause a NULL pointer access. + + Reported-by: Brian Carpenter + Fixes #4807 + Closes #4810 -- scripts/contributors: make committers get included too +- misc: Copyright year out of date, should be 2020 - in addition to authors + Follow-up to recent commits + + [skip ci] -Jay Satiro (8 Nov 2019) -- [Massimiliano Fantuzzi brought this change] +Jay Satiro (11 Jan 2020) +- [Santino Keupp brought this change] - configure: fix typo in help text + libssh2: add support for forcing a hostkey type - Closes https://github.com/curl/curl/pull/4570 + - Allow forcing the host's key type found in the known_hosts file. + + Currently, curl (with libssh2) does not take keys from your known_hosts + file into account when talking to a server. With this patch the + known_hosts file will be searched for an entry matching the hostname + and, if found, libssh2 will be told to claim this key type from the + server. + + Closes https://github.com/curl/curl/pull/4747 -Daniel Stenberg (7 Nov 2019) -- [Christian Schmitz brought this change] +- [Nicolas Guillier brought this change] - ntlm: USE_WIN32_CRYPTO check removed to get USE_NTLM2SESSION set + cmake: Improve libssh2 check on Windows - Closes #3704 + - Add "libssh2" name to FindLibSSH2 library search. + + On Windows systems, libSSH2 CMake installation may name the library + "LibSSH2". + + Prior to this change cmake only checked for name "ssh2". On Linux that + works fine because it will prepend the "lib", but it doesn't do that on + Windows. + + Closes https://github.com/curl/curl/pull/4804 -Jay Satiro (6 Nov 2019) -- [Wyatt O'Day brought this change] +- [Faizur Rahman brought this change] - build: fix for CURL_DISABLE_DOH + schannel: Make CURLOPT_CAINFO work better on Windows 7 - Fixes https://github.com/curl/curl/issues/4565 - Closes https://github.com/curl/curl/pull/4566 + - Support hostname verification via alternative names (SAN) in the + peer certificate when CURLOPT_CAINFO is used in Windows 7 and earlier. + + CERT_NAME_SEARCH_ALL_NAMES_FLAG doesn't exist before Windows 8. As a + result CertGetNameString doesn't quite work on those versions of + Windows. This change provides an alternative solution for + CertGetNameString by iterating through CERT_ALT_NAME_INFO for earlier + versions of Windows. + + Prior to this change many certificates failed the hostname validation + when CURLOPT_CAINFO was used in Windows 7 and earlier. Most certificates + now represent multiple hostnames and rely on the alternative names field + exclusively to represent their hostnames. + + Reported-by: Jeroen Ooms + + Fixes https://github.com/curl/curl/issues/3711 + Closes https://github.com/curl/curl/pull/4761 -- [Leonardo Taccari brought this change] +- [Emil Engler brought this change] - configure: avoid unportable `==' test(1) operator + ngtcp2: Add an error code for QUIC connection errors - Closes https://github.com/curl/curl/pull/4567 - -Version 7.67.0 (5 Nov 2019) + - Add new error code CURLE_QUIC_CONNECT_ERROR for QUIC connection + errors. + + Prior to this change CURLE_FAILED_INIT was used, but that was not + correct. + + Closes https://github.com/curl/curl/pull/4754 -Daniel Stenberg (5 Nov 2019) -- RELEASE-NOTES: synced +- multi: Change curl_multi_wait/poll to error on negative timeout - The 7.67.0 release + - Add new error CURLM_BAD_FUNCTION_ARGUMENT and return that error when + curl_multi_wait/poll is passed timeout param < 0. + + Prior to this change passing a negative value to curl_multi_wait/poll + such as -1 could cause the function to wait forever. + + Reported-by: hamstergene@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/4763 + + Closes https://github.com/curl/curl/pull/4765 -- THANKS: add new names from 7.67.0 +- [Marc Aldorasi brought this change] -- configure: only say ipv6 enabled when the variable is set + cmake: Enable SMB for Windows builds - Previously it could say "IPv6: enabled" at the end of the configure run - but the define wasn't set because of a missing getaddrinfo(). + - Define USE_WIN32_CRYPTO by default. This enables SMB. - Reported-by: Marcel Raad - Fixes #4555 - Closes #4560 + - Show whether SMB is enabled in the "Enabled features" output. + + - Fix mingw compiler warning for call to CryptHashData by casting away + const param. mingw CryptHashData prototype is wrong. + + Closes https://github.com/curl/curl/pull/4717 -Marcel Raad (2 Nov 2019) -- certs/Server-localhost-lastSAN-sv: regenerate with sha256 +- vtls: Refactor Curl_multissl_version to make the code clearer - All other certificates were regenerated in commit ba782baac30, but - this one was missed. - Fixes test3001 on modern systems. + Reported-by: Johannes Schindelin - Closes https://github.com/curl/curl/pull/4551 + Ref: https://github.com/curl/curl/pull/3863#pullrequestreview-241395121 + + Closes https://github.com/curl/curl/pull/4803 -Daniel Stenberg (2 Nov 2019) -- [Vilhelm Prytz brought this change] - - copyrights: update all copyright notices to 2019 on files changed this year - - Closes #4547 - -- [Bastien Bouclet brought this change] - - mbedtls: add error message for cert validity starting in the future +Daniel Stenberg (10 Jan 2020) +- fix: Copyright year out of date, should be 2020 - Closes #4552 + Follow-up to 875314ed0bf3b -Jay Satiro (1 Nov 2019) -- schannel_verify: Fix concurrent openings of CA file - - - Open the CA file using FILE_SHARE_READ mode so that others can read - from it as well. +Marcel Raad (10 Jan 2020) +- hostip: move code to resolve IP address literals to `Curl_resolv` - Prior to this change our schannel code opened the CA file without - sharing which meant concurrent openings (eg an attempt from another - thread or process) would fail during the time it was open without - sharing, which in curl's case would cause error: - "schannel: failed to open CA file". + The code was duplicated in the various resolver backends. - Bug: https://curl.haxx.se/mail/lib-2019-10/0104.html - Reported-by: Richard Alcock - -Daniel Stenberg (31 Oct 2019) -- gtls: make gnutls_bye() not wait for response on shutdown + Also, it was called after the call to `Curl_ipvalid`, which matters in + case of `CURLRES_IPV4` when called from `connect.c:bindlocal`. This + caused test 1048 to fail on classic MinGW. - ... as it can make it wait there for a long time for no good purpose. + The code ignores `conn->ip_version` as done previously in the + individual resolver backends. - Patched-by: Jay Satiro - Reported-by: Bylon2 on github - Adviced-by: Nikos Mavrogiannopoulos + Move the call to the `resolver_start` callback up to appease test 655, + which wants it to be called also for literal addresses. - Fixes #4487 - Closes #4541 + Closes https://github.com/curl/curl/pull/4798 -- [Michał Janiszewski brought this change] - - appveyor: publish artifacts on appveyor - - This allows obtaining upstream builds of curl directly from appveyor for - all the available configurations - - Closes #4509 +Daniel Stenberg (9 Jan 2020) +- scripts/delta: adapt to new public header layout -- url: make Curl_close() NULLify the pointer too +- test1167: verify global symbols in public headers are curl prefixed - This is the common pattern used in the code and by a unified approach we - avoid mistakes. + ... using the new badsymbols.pl perl script - Closes #4534 + Fixes #4793 + Closes #4794 -- [Trivikram Kamat brought this change] +- libtest/mk-lib1521: adapt to new public header layout - INSTALL: add missing space for configure commands +- include: remove non-curl prefixed defines - Closes #4539 + ...requires some rearranging of the setup of CURLOPT_ and CURLMOPT_ + enums. -- url: Curl_free_request_state() should also free doh handles +- curl.h: remove WIN32 define - ... or risk DoH memory leaks. - - Reported-by: Paul Dreik - Fixes #4463 - Closes #4527 + It isn't our job to define this in a public header - and it defines a + name outside of our naming scope. -- examples: remove the "this exact code has not been verified" +- tool_dirhie.c: fix the copyright year range - ... as really confuses the reader to not know what to believe! + Follow-up to: 4027bd72d9 -- [Trivikram Kamat brought this change] +- bump: work towards 7.69.0 is started - HTTP3: fix typo somehere1 > somewhere1 +Jay Satiro (9 Jan 2020) +- tool_dirhie: Allow directory traversal during creation - Closes #4535 - -Jay Satiro (28 Oct 2019) -- [Javier Blazquez brought this change] - - HTTP3: fix invalid use of sendto for connected UDP socket + - When creating a directory hierarchy do not error when mkdir fails due + to error EACCESS (13) "access denied". - On macOS/BSD, trying to call sendto on a connected UDP socket fails - with a EISCONN error. Because the singleipconnect has already called - connect on the socket when we're trying to use it for QUIC transfers - we need to use plain send instead. + Some file systems allow for directory traversal; in this case that it + should be possible to create child directories when permission to the + parent directory is restricted. - Fixes #4529 - Closes https://github.com/curl/curl/pull/4533 - -Daniel Stenberg (28 Oct 2019) -- RELEASE-NOTES: synced - -- [Javier Blazquez brought this change] - - HTTP3: fix Windows build + This is a regression caused by me in f16bed0 (precedes curl-7_61_1). + Basically I had assumed that if a directory already existed it would + fail only with error EEXIST, and not error EACCES. The latter may + happen if the directory exists but has certain restricted permissions. - The ngtcp2 QUIC backend was using the MSG_DONTWAIT flag for send/recv - in order to perform nonblocking operations. On Windows this flag does - not exist. Instead, the socket must be set to nonblocking mode via - ioctlsocket. + Reported-by: mbeifuss@users.noreply.github.com - This change sets the nonblocking flag on UDP sockets used for QUIC on - all platforms so the use of MSG_DONTWAIT is not needed. + Fixes https://github.com/curl/curl/issues/4796 + Closes https://github.com/curl/curl/pull/4797 + +Daniel Stenberg (9 Jan 2020) +- KNOWN_BUGS: AUTH PLAIN for SMTP is not working on all servers - Fixes #4531 - Closes #4532 + Closes #4080 -Marcel Raad (27 Oct 2019) -- appveyor: add --disable-proxy autotools build +- docs/RELEASE-PROCEDURE.md: pushed some release dates - This would have caught issue #3926. + Ref: https://curl.haxx.se/mail/lib-2020-01/0031.html + +- runtests: make random seed fixed for a month - Also make formatting more consistent. + When using randomized features of runtests (-R and --shallow) it is + useful to have a fixed random seed to make sure for example extra + commits in a branch or a rebase won't change the seed that would make + repeated runs work differently. - Closes https://github.com/curl/curl/pull/4526 - -Daniel Stenberg (25 Oct 2019) -- appveyor: make winbuilds with DEBUG=no/yes and VS 2015/2017 + As it is also useful to change seed sometimes, the default seed is now + determined based on the current month (and first line curl -V + output). When the month changes, so will the random seed. - ... and invoke "curl -V" once done + The specific seed is also shown in the standard test suite top header + and it can be set explictly with the new --seed=[num] option so that the + exact order of a previous run can be achieved. - Co-Authored-By: Jay Satiro + Closes #4734 + +- RELEASE-PROCEDURE.md: fix next release date (Feb 26) - Closes #4523 + [skip ci] -- [Francois Rivard brought this change] +Version 7.68.0 (8 Jan 2020) - schannel: reverse the order of certinfo insertions +Daniel Stenberg (8 Jan 2020) +- RELEASE-NOTES: 7.68.0 + +- THANKS: updated with names from the 7.68.0 release + +- RELEASE-PROCEDURE: add four future release dates - Fixes #4518 - Closes #4519 + and remove four past release dates + + [skip ci] -Marcel Raad (24 Oct 2019) -- test1591: fix spelling of http feature +Marcel Raad (6 Jan 2020) +- TrackMemory tests: always remove CR before LF - The test never got run because the feature name is `http` in lowercase. + It was removed for output containing ' =' via `s/ =.*//`. With classic + MinGW, this made lines with `free()` end with CRLF, but lines with e.g. + `malloc()` end with only LF. The tests expect LF only. - Closes https://github.com/curl/curl/pull/4520 + Closes https://github.com/curl/curl/pull/4788 -Daniel Stenberg (23 Oct 2019) -- [Michał Janiszewski brought this change] +Daniel Stenberg (6 Jan 2020) +- multi.h: move INITIAL_MAX_CONCURRENT_STREAMS from public header + + ... to the private multihhandle.h. It is not for public use and it + wasn't prefixed correctly anyway! + + Closes #4790 - appveyor: Use two parallel compilation on appveyor with CMake +- file: fix copyright year range - Appveyor provides 2 CPUs for each builder[1], make sure to use parallel - compilation, when running with CMake. CMake learned this new option in - version 3.12[2] and the version provided by appveyor is fresh enough. + Follow-up to 1b71bc532bd + +- curl -w: handle a blank input file correctly - Curl doesn't really take that long to build and it is using the slowest - builder available, msbuild, so expect only a moderate improvement in - build times. + Previously it would end up with an uninitialized memory buffer that + would lead to a crash or junk getting output. - [1] https://www.appveyor.com/docs/build-environment/ - [2] https://cmake.org/cmake/help/v3.12/release/3.12.html + Added test 1271 to verify. - Closes #4508 + Reported-by: Brian Carpenter + Closes #4786 -- conn-reuse: requests wanting NTLM can reuse non-NTLM connections +- file: on Windows, refuse paths that start with \\ - Added test case 338 to verify. + ... as that might cause an unexpected SMB connection to a given host + name. - Reported-by: Daniel Silverstone - Fixes #4499 - Closes #4514 - -Marcel Raad (23 Oct 2019) -- tests: add missing proxy features + Reported-by: Fernando Muñoz + CVE-2019-15601 + Bug: https://curl.haxx.se/docs/CVE-2019-15601.html -Daniel Stenberg (22 Oct 2019) -- RELEASE-NOTES: synced +Jay Satiro (6 Jan 2020) +- CURLOPT_READFUNCTION.3: fix fopen params in example -Marcel Raad (21 Oct 2019) -- tests: use %FILE_PWD for file:// URLs +- CURLOPT_READFUNCTION.3: fix variable name in example - This way, we always have exactly one slash after the host name, making - the tests pass when curl is compiled with the MSYS GCC. + Reported-by: Paul Joyce - Closes https://github.com/curl/curl/pull/4512 + Fixes https://github.com/curl/curl/issues/4787 -- tests: add `connect to non-listen` keywords - - These tests try to connect to ports nothing is listening on. +Daniel Stenberg (5 Jan 2020) +- curl:getparameter return error for --http3 if libcurl doesn't support - Closes https://github.com/curl/curl/pull/4511 + Closes #4785 -- runtests: get textaware info from curl instead of perl +- docs: mention CURL_MAX_INPUT_LENGTH restrictions - The MSYS system on Windows can run the test suite for curl built with - any toolset. When built with the MSYS GCC, curl uses Unix line endings, - while it uses Windows line endings when built with the MinGW GCC, and - `^O` reports 'msys' in both cases. Use the curl executable itself to - determine the line endings instead, which reports 'x86_64-pc-msys' when - built with the MSYS GCC. + ... for curl_easy_setopt() and curl_url_set(). - Closes https://github.com/curl/curl/pull/4506 - -Daniel Stenberg (20 Oct 2019) -- [Michał Janiszewski brought this change] - - appveyor: Add MSVC ARM64 build + [skip ci] - Closes #4507 + Closes #4783 -- http2_recv: a closed stream trumps pause state +- curl: properly free mimepost data - ... and thus should return 0, not EAGAIN. + ... as it could otherwise leak memory when a transfer failed. - Reported-by: Tom van der Woerdt - Fixes #4496 - Closes #4505 + Added test 1293 to verify. + + Reported-by: Brian Carpenter + Fixes #4781 + Closes #4782 -- http2: expire a timeout at end of stream +- curl: cleanup multi handle on failure - To make sure that transfer is being dealt with. Streams without - Content-Length need a final read to notice the end-of-stream state. + ... to fix memory leak in error path. - Reported-by: Tom van der Woerdt - Fixes #4496 + Fixes #4772 + Closes #4780 + Reported-by: Brian Carpenter -Dan Fandrich (18 Oct 2019) -- travis: Add an ARM64 build +Marcel Raad (3 Jan 2020) +- lib: fix compiler warnings with `CURL_DISABLE_VERBOSE_STRINGS` - Test 323 is failing for some reason, so disable it there for now. + Closes https://github.com/curl/curl/pull/4775 -Marcel Raad (18 Oct 2019) -- examples/sslbackend: fix -Wchar-subscripts warning +Daniel Stenberg (3 Jan 2020) +- COPYING: it's 2020! - With the `isdigit` implementation that comes with MSYS2, the argument - is used as an array subscript, resulting in a -Wchar-subscripts - warning. `isdigit`'s behavior is undefined if the argument is negative - and not EOF [0]. As done in lib/curl_ctype.h, cast the `char` variable - to `unsigned char` to avoid that. + [skip ci] + +Jay Satiro (3 Jan 2020) +- [Marc Aldorasi brought this change] + + tests: Fix bounce requests with truncated writes - [0] https://en.cppreference.com/w/c/string/byte/isdigit + Prior to this change the swsbounce check in service_connection could + fail because prevtestno and prevpartno were not set, which would cause + the wrong response data to be sent to some tests and cause them to fail. - Closes https://github.com/curl/curl/pull/4503 + Ref: https://github.com/curl/curl/pull/4717#issuecomment-570240785 -Daniel Stenberg (18 Oct 2019) -- configure: remove all cyassl references +Marcel Raad (31 Dec 2019) +- tool: make a few char pointers point to const char instead - In particular, this removes the case where configure would find an old - cyall installation rather than a wolfssl one if present. The library is - named wolfssl in modern days so there's no real need to keep support for - the former. + These are read-only. - Reported-by: Jacob Barthelmeh - Closes #4502 + Closes https://github.com/curl/curl/pull/4771 -Marcel Raad (17 Oct 2019) -- test1162: disable MSYS2's POSIX path conversion +Jay Satiro (31 Dec 2019) +- tests: Change NTLM tests to require SSL - This avoids MSYS2 converting the backslasb in the URL to a slash, - causing the test to fail. - -Daniel Stenberg (17 Oct 2019) -- RELEASE-NOTES: synced - -Jay Satiro (16 Oct 2019) -- CURLOPT_TIMEOUT.3: Clarify transfer timeout time includes queue time + Prior to this change tests that required NTLM feature did not require + SSL feature. - Prior to this change some users did not understand that the "request" - starts when the handle is added to the multi handle, or probably they - did not understand that some of those transfers may be queued and that - time is included in timeout. + There are pending changes to cmake builds that will allow enabling NTLM + in non-SSL builds in Windows. In that case the NTLM auth strings created + are different from what is expected by the NTLM tests and they fail: - Reported-by: Jeroen Ooms + "The issue with NTLM is that previous non-SSL builds would not enable + NTLM and so the NTLM tests would be skipped." - Fixes https://github.com/curl/curl/issues/4486 - Closes https://github.com/curl/curl/pull/4489 + Assisted-by: marc-groundctl@users.noreply.github.com + + Ref: https://github.com/curl/curl/pull/4717#issuecomment-566218729 + + Closes https://github.com/curl/curl/pull/4768 -- [Stian Soiland-Reyes brought this change] +- [Michael Forney brought this change] - tool_operate: Fix retry sleep time shown to user when Retry-After + bearssl: Improve I/O handling - - If server header Retry-After is being used for retry sleep time then - show that value to the user instead of the normal retry sleep time. + Factor out common I/O loop as bearssl_run_until, which reads/writes TLS + records until the desired engine state is reached. This is now used for + the handshake, read, write, and close. - This is a follow-up to 640b973 (7.66.0) which changed curl tool so that - the value from Retry-After header overrides other retry timing options. + Match OpenSSL SSL_write behavior, and don't return the number of bytes + written until the corresponding records have been completely flushed + across the socket. This involves keeping track of the length of data + buffered into the TLS engine, and assumes that when CURLE_AGAIN is + returned, the write function will be called again with the same data + and length arguments. This is the same requirement of SSL_write. - Closes https://github.com/curl/curl/pull/4498 - -Daniel Stenberg (16 Oct 2019) -- url: normalize CURLINFO_EFFECTIVE_URL + Handle TLS close notify as EOF when reading by returning 0. - The URL extracted with CURLINFO_EFFECTIVE_URL was returned as given as - input in most cases, which made it not get a scheme prefixed like before - if the URL was given without one, and it didn't remove dotdot sequences - etc. + Closes https://github.com/curl/curl/pull/4748 + +- travis: Fix error detection - Added test case 1907 to verify that this now works as intended and as - before 7.62.0. + - Stop using inline shell scripts for before_script and script sections. - Regression introduced in 7.62.0 + Prior to this change Travis could ignore errors from commands in inline + scripts. I don't understand how or why it happens. This is a workaround. - Reported-by: Christophe Dervieux - Fixes #4491 - Closes #4493 - -Marcel Raad (16 Oct 2019) -- tests: line ending fixes for Windows + Assisted-by: Simon Warta - Mark some files as text. + Ref: https://github.com/travis-ci/travis-ci/issues/1066 - Closes https://github.com/curl/curl/pull/4490 + Fixes https://github.com/curl/curl/issues/3730 + Closes https://github.com/curl/curl/pull/3755 -- tests: use proxy feature +- tool_operate: fix mem leak when failed config parse - This makes the tests succeed when using --disable-proxy. + Found by fuzzing the config file. - Closes https://github.com/curl/curl/pull/4488 + Reported-by: Geeknik Labs + + Fixes https://github.com/curl/curl/issues/4767 -- smbserver: fix Python 3 compatibility +- [Xiang Xiao brought this change] + + lib: remove erroneous +x file permission on some c files - Python 2's `ConfigParser` module is spelled `configparser` in Python 3. + Modified by commit eb9a604 accidentally. - Closes https://github.com/curl/curl/pull/4484 + Closes https://github.com/curl/curl/pull/4756 -- security: silence conversion warning +- [Xiang Xiao brought this change] + + lib: fix warnings found when porting to NuttX - With MinGW-w64, `curl_socket_t` is is a 32 or 64 bit unsigned integer, - while `read` expects a 32 bit signed integer. - Use `sread` instead of `read` to use the correct parameter type. + - Undefine DEBUGASSERT in curl_setup_once.h in case it was already + defined as a system macro. - Closes https://github.com/curl/curl/pull/4483 - -- connect: silence sign-compare warning + - Don't compile write32_le in curl_endian unless + CURL_SIZEOF_CURL_OFF_T > 4, since it's only used by Curl_write64_le. - With MinGW-w64 using WinSock, `curl_socklen_t` is signed, while the - result of `sizeof` is unsigned. + - Include in socketpair.c. - Closes https://github.com/curl/curl/pull/4483 + Closes https://github.com/curl/curl/pull/4756 -Daniel Stenberg (13 Oct 2019) -- TODO: Handle growing SFTP files +- os400: Add missing CURLE error constants - Closes #4344 + Bug: https://github.com/curl/curl/pull/4754#issuecomment-569126922 + Reported-by: Emil Engler -- KNOWN_BUGS: remove "CURLFORM_CONTENTLEN in an array" +- CURLOPT_HEADERFUNCTION.3: Document that size is always 1 - The curl_formadd() function is deprecated and shouldn't be used so the - real fix for applications is to switch to the curl_mime_* API. - -- KNOWN_BUGS: "LDAP on Windows does authentication wrong" + For compatibility with `fwrite`, the `CURLOPT_HEADERFUNCTION` callback + is passed two `size_t` parameters which, when multiplied, designate the + number of bytes of data passed in. In practice, CURL always sets the + first parameter (`size`) to 1. - Closes #3116 - -- appveyor: add a winbuild that uses VS2017 + This practice is also enshrined in documentation and cannot be changed + in future. The documentation states that the default callback is + `fwrite`, which means `fwrite` must be a suitable function for this + purpose. However, the documentation also states that the callback must + return the number of *bytes* it successfully handled, whereas ISO C + `fwrite` returns the number of items (each of size `size`) which it + wrote. The only way these numbers can be equal is if `size` is 1. - Closes #4482 - -- [Harry Sintonen brought this change] - - socketpair: fix include and define for older TCP header systems + Since `size` is 1 and can never be changed in future anyway, document + that fact explicitly and let users rely on it. - fixed build for systems that need netinet/in.h for IPPROTO_TCP and are - missing INADDR_LOOPBACK + Reported-by: Frank Gevaerts + Commit-message-by: Christopher Head - Closes #4480 + Ref: https://github.com/curl/curl/pull/2787 + + Fixes https://github.com/curl/curl/issues/4758 -- socketpair: fix double-close in error case +- examples/postinmemory.c: Call curl_global_cleanup always - Follow-up to bc2dbef0afc08 + Prior to this change curl_global_cleanup was not called if + curl_easy_init failed. + + Reported-by: kouzhudong@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/4751 -- gskit: use the generic Curl_socketpair +Daniel Stenberg (21 Dec 2019) +- url2file.c: fix copyright year + + Follow-up to 525787269599b5 -- asyn-thread: make use of Curl_socketpair() where available +- [Rickard Hallerbäck brought this change] -- socketpair: an implemention for Windows and more + examples/url2file.c: corrected a comment - Curl_socketpair() is designed to be used and work everywhere if there's - no native version or the native version isn't good enough. + The comment was confusing and suggested that setting CURLOPT_NOPROGRESS + to 0L would both enable and disable debug output at the same time, like + a Schrödinger's cat of CURLOPTs. - Closes #4466 + Closes #4745 + +- HISTORY: OSS-Fuzz started fuzzing libcurl in 2017 - RELEASE-NOTES: synced -- connect: return CURLE_OPERATION_TIMEDOUT for errno == ETIMEDOUT +Jay Satiro (20 Dec 2019) +- ngtcp2: Support the latest update key callback type - Previosly all connect() failures would return CURLE_COULDNT_CONNECT, no - matter what errno said. + - Remove our cb_update_key in favor of ngtcp2's new + ngtcp2_crypto_update_key_cb which does the same thing. - This makes for example --retry work on these transfer failures. + Several days ago the ngtcp2_update_key callback function prototype was + changed in ngtcp2/ngtcp2@42ce09c. Though it would be possible to + fix up our cb_update_key for that change they also added + ngtcp2_crypto_update_key_cb which does the same thing so we'll use that + instead. - Reported-by: Nathaniel J. Smith - Fixes #4461 - Clsoes #4462 - -- cirrus: switch off blackhole status on the freebsd CI machines - -- tests: use port 2 instead of 60000 for a safer non-listening port + Ref: https://github.com/ngtcp2/ngtcp2/commit/42ce09c - ... when the tests want "connection refused". + Closes https://github.com/curl/curl/pull/4735 -- KNOWN_BUGS: IDN tests failing on Windows +Daniel Stenberg (19 Dec 2019) +- sws: search for "Testno:" header uncondtionally if no testno - Closes #3747 - -Dan Fandrich (9 Oct 2019) -- cirrus: Increase the git clone depth. + Even if the initial request line wasn't found. With the fix to 1455, the + test number is now detected correctly. - If more commits are submitted to master between the time of triggering - the first Cirrus build and the time the final build gets started, the - desired commit is no longer at HEAD and the build will error out. - [skip ci] - -Daniel Stenberg (9 Oct 2019) -- docs: make sure the --no-progress-meter docs file is in dist too + (Problem found when running tests in random order.) + + Closes #4744 -- docs: document it as --no-progress-meter instead of the reverse +- tests: set LC_ALL in more tests - Follow-up to 93373a960c3bb4 + Follow-up to 23208e330ac0c21 - Reported-by: infinnovation-dev on github - Fixes #4474 - Closes #4475 + Closes #4743 -Dan Fandrich (9 Oct 2019) -- cirrus: Switch the FreeBSD 11.x build to 11.3 and add a 13.0 build. +- test165: set LC_ALL=en_US.UTF-8 too - Also, select the images using image_family to get the latest snapshots - automatically. - [skip ci] - -Daniel Stenberg (8 Oct 2019) -- curl: --no-progress-meter + On my current Debian Unstable with libidn2 2.2.0, I get an error if + LC_ALL is set to blank. Then curl errors out with: - New option that allows a user to ONLY switch off curl's progress meter - and leave everything else in "talkative" mode. + curl: (3) Failed to convert www.åäö.se to ACE; could not convert string to UTF-8 - Reported-by: Piotr Komborski - Fixes #4422 - Closes #4470 + Closes #4738 -- TODO: Consult %APPDATA% also for .netrc +- curl.h: add two defines for the "pre ISO C" case - Closes #4016 + Without this fix, this caused a compilation failure on AIX with IBM xlc + 13.1.3 compiler. + + Reported-by: Ram Krushna Mishra + Fixes #4739 + Closes #4740 -- CURLOPT_TIMEOUT.3: remove the mention of "minutes" +- create_conn: prefer multiplexing to using new connections - ... just say that limiting operations risk aborting otherwise fine - working transfers. If that means seconds, minutes or hours, we leave to - the user. + ... as it would previously prefer new connections rather than + multiplexing in most conditions! The (now removed) code was a leftover + from the Pipelining code that was translated wrongly into a + multiplex-only world. - Reported-by: Martin Gartner - Closes #4469 + Reported-by: Kunal Ekawde + Bug: https://curl.haxx.se/mail/lib-2019-12/0060.html + Closes #4732 -- [Andrei Valeriu BICA brought this change] +- test1456: remove the use of a fixed local port + + Fixup the test to instead not compare the port number. It sometimes + caused problems like this: + + "curl: (45) bind failed with errno 98: Address already in use" + + Closes #4733 - docs: added multi-event.c example +Jay Satiro (18 Dec 2019) +- CURLOPT_QUOTE.3: fix typos - Similar to multi-uv.c but using libevent 2. This is a simpler libevent - integration example then hiperfifo.c. + Prior to this change the EXAMPLE in the QUOTE/PREQUOTE/POSTQUOTE man + pages would not compile because a variable name was incorrect. - Closes #4471 + Reported-by: Bylon2@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/4736 -Jay Satiro (5 Oct 2019) -- [Nicolas brought this change] +- [Gisle Vanem brought this change] - ldap: fix OOM error on missing query string - - - Allow missing queries, don't return NO_MEMORY error in such a case. + strerror: Fix compiler warning "empty expression" - It is acceptable for there to be no specified query string, for example: + - Remove the final semi-colon in the SEC2TXT() macro definition. - curl ldap://ldap.forumsys.com + Before: #define SEC2TXT(sec) case sec: txt = #sec; break; - A regression bug in 1b443a7 caused this issue. + After: #define SEC2TXT(sec) case sec: txt = #sec; break - This is a partial fix for #4261. + Prior to this change SEC2TXT(foo); would generate break;; which caused + the empty expression warning. - Bug: https://github.com/curl/curl/issues/4261#issuecomment-525543077 - Reported-by: Jojojov@users.noreply.github.com - Analyzed-by: Samuel Surtees + Ref: https://github.com/curl/curl/commit/5b22e1a#r36458547 + +Daniel Stenberg (18 Dec 2019) +- curl/parseconfig: use curl_free() to free memory allocated by libcurl - Closes https://github.com/curl/curl/pull/4467 + Reported-by: bxac on github + Fixes #4730 + Closes #4731 -- [Paul B. Omta brought this change] +- curl/parseconfig: fix mem-leak + + When looping, first trying '.curlrc' and then '_curlrc', the function + would not free the first string. + + Closes #4731 - build: Remove unused HAVE_LIBSSL and HAVE_LIBCRYPTO defines +- CURLOPT_URL.3: "curl supports SMB version 1 (only)" - Closes https://github.com/curl/curl/pull/4460 + [skip ci] -Daniel Stenberg (5 Oct 2019) -- RELEASE-NOTES: synced +- test1270: a basic -w redirect_url test + + Closes #4728 -- [Stian Soiland-Reyes brought this change] +- HISTORY: the SMB(S) support landed in 2014 - curl: ensure HTTP 429 triggers --retry +- define: remove HAVE_ENGINE_LOAD_BUILTIN_ENGINES, not used anymore - This completes #3794. + It is covered by USE_OPENSSL_ENGINE now. - Also make sure the new tests from #4195 are enabled + Reported-by: Gisle Vanem + Bug: https://github.com/curl/curl/commit/87b9337c8f76c21c57b204e88b68c6ecf3bd1ac0#commitcomment-36447951 - Closes #4465 - -Marcel Raad (4 Oct 2019) -- [apique brought this change] + Closes #4725 - winbuild: add ENABLE_UNICODE option +- lib: remove ASSIGNWITHINCONDITION exceptions, use our code style - Fixes https://github.com/curl/curl/issues/4308 - Closes https://github.com/curl/curl/pull/4309 - -Daniel Stenberg (4 Oct 2019) -- ngtcp2: adapt to API change + ... even for macros - Closes #4457 + Reviewed-by: Daniel Gustafsson + Reviewed-by: Jay Satiro + Reported-by: Jay Satiro + Fixes #4683 + Closes #4722 -- cookies: change argument type for Curl_flush_cookies - - The second argument is really a 'bool' so use that and pass in TRUE/FALSE - to make it clear. - - Closes #4455 +- tests: make sure checksrc runs on header files too -- http2: move state-init from creation to pre-transfer +- Revert "checksrc: fix regexp for ASSIGNWITHINCONDITION" - To make sure that the HTTP/2 state is initialized correctly for - duplicated handles. It would otherwise easily generate "spurious" - PRIORITY frames to get sent over HTTP/2 connections when duplicated easy - handles were used. + This reverts commit ba82673dac3e8d00a76aa5e3779a0cb80e7442af. - Reported-by: Daniel Silverstone - Fixes #4303 - Closes #4442 + Bug: #4683 -- urlapi: fix use-after-free bug +- KNOWN_BUGS: TLS session cache doesn't work with TFO - Follow-up from 2c20109a9b5d04 + [skip ci] + Closes #4301 + +- KNOWN_BUGS: Connection information when using TCP Fast Open - Added test 663 to verify. + Also point to #4296 for more details + Closes #4296 + +- KNOWN_BUGS: LDAP on Windows doesn't work - Reported by OSS-Fuzz - Bug: https://crbug.com/oss-fuzz/17954 + Closes #4261 + +- docs: TLS SRP doesn't work with TLS 1.3 - Closes #4453 + Reported-by: sayrer on github + Closes #4262 + [skip ci] -- [Paul Dreik brought this change] +Dan Fandrich (16 Dec 2019) +- cirrus: Switch to the FreeBSD 12.1 point release & enable more tests. + + A few tests are now passing on FreeBSD, so no longer skip them. + [skip ci] - cookie: avoid harmless use after free +Daniel Stenberg (16 Dec 2019) +- azure: the macos cmake doesn't need to install cmake - This fix removes a use after free which can be triggered by - the internal cookie fuzzer, but otherwise is probably - impossible to trigger from an ordinary application. + Error: cmake 3.15.5 is already installed + To upgrade to 3.16.1, run `brew upgrade cmake`. - The following program reproduces it: + Closes #4723 + +Jay Satiro (15 Dec 2019) +- winbuild: Document CURL_STATICLIB requirement for static libcurl - curl_global_init(CURL_GLOBAL_DEFAULT); - CURL* handle=curl_easy_init(); - CookieInfo* info=Curl_cookie_init(handle,NULL,NULL,false); - curl_easy_setopt(handle, CURLOPT_COOKIEJAR, "/dev/null"); - Curl_flush_cookies(handle, true); - Curl_cookie_cleanup(info); - curl_easy_cleanup(handle); - curl_global_cleanup(); + A static libcurl (ie winbuild mode=static) requires that the user define + CURL_STATICLIB when using it in their application. This is already + covered in the FAQ and INSTALL.md, but is a pretty important point so + now it's noted in the BUILD.WINDOWS.txt as well. - This was found through fuzzing. + Assisted-by: Michael Vittiglio - Closes #4454 + Closes https://github.com/curl/curl/pull/4721 -- [Denis Chaplygin brought this change] +Daniel Stenberg (15 Dec 2019) +- [Santino Keupp brought this change] - docs: add note on failed handles not being counted by curl_multi_perform + libssh2: add support for ECDSA and ed25519 knownhost keys - Closes #4446 - -- CURLMOPT_MAX_CONCURRENT_STREAMS.3: fix SEE ALSO typo + ... if a new enough libssh2 version is present. + + Source: https://curl.haxx.se/mail/archive-2019-12/0023.html + Co-Authored-by: Daniel Stenberg + Closes #4714 -- [Niall O'Reilly brought this change] +- lib1591: free memory properly on OOM, in the trailers callback + + Detected by torture tests. + + Closes #4720 - ESNI: initial build/setup +- runtests: --repeat=[num] to repeat tests - Closes #4011 + Closes #4715 - RELEASE-NOTES: synced -- redirect: when following redirects to an absolute URL, URL encode it +- azure: add a torture test on mac - ... to make it handle for example (RFC violating) embeded spaces. + Uses --shallow=25 to keep it small enough to get through in time. - Reported-by: momala454 on github - Fixes #4445 - Closes #4447 - -- urlapi: fix URL encoding when setting a full URL - -- tool_operate: rename functions to make more sense + Closes #4712 -- curl: create easy handles on-demand and not ahead of time +- multi: free sockhash on OOM - This should again enable crazy-large download ranges of the style - [1-10000000] that otherwise easily ran out of memory starting in 7.66.0 - when this new handle allocating scheme was introduced. + This would otherwise leak memory in the error path. - Reported-by: Peter Sumatra - Fixes #4393 - Closes #4438 - -- [Kunal Ekawde brought this change] - - CURLMOPT_MAX_CONCURRENT_STREAMS: new setopt + Detected by torture test 1540. - Closes #4410 + Closes #4713 -- chunked-encoding: stop hiding the CURLE_BAD_CONTENT_ENCODING error +Marcel Raad (13 Dec 2019) +- tests: use DoH feature for DoH tests - Unknown content-encoding would get returned as CURLE_WRITE_ERROR if the - response is chunked-encoded. + Previously, http/2 was used instead. - Reported-by: Ilya Kosarev - Fixes #4310 - Closes #4449 + Assisted-by: Jay Satiro + Closes https://github.com/curl/curl/pull/4692 -Marcel Raad (1 Oct 2019) -- checksrc: fix uninitialized variable warning +- hostip: suppress compiler warning - The loop doesn't need to be executed without a file argument. + With `--disable-doh --disable-threaded-resolver`, the `dns` parameter + is not used. - Closes https://github.com/curl/curl/pull/4444 - -- urlapi: fix unused variable warning - - `dest` is only used with `ENABLE_IPV6`. - - Closes https://github.com/curl/curl/pull/4444 + Closes https://github.com/curl/curl/pull/4692 -- lib: silence conversion warnings +- tests: fix build with `CURL_DISABLE_DOH` - Closes https://github.com/curl/curl/pull/4444 + Closes https://github.com/curl/curl/pull/4692 -- AppVeyor: add 32-bit MinGW-w64 build - - With WinSSL and testing enabled so that it would have detected most of - the warnings fixed in [0] and [1]. +Daniel Stenberg (13 Dec 2019) +- azure: add a torture test - [0] https://github.com/curl/curl/pull/4398 - [1] https://github.com/curl/curl/pull/4415 + Skipping all FTP tests for speed reasons. - Closes https://github.com/curl/curl/pull/4433 + Closes #4697 -- AppVeyor: remove MSYS2_ARG_CONV_EXCL for winbuild +- azure: make the default build use --enable-debug --enable-werror + +- ntlm_wb: fix double-free in OOM - It's only used for MSYS2 with MinGW. + Detected by torture testing test 1310 - Closes - -Daniel Stenberg (30 Sep 2019) -- [Emil Engler brought this change] + Closes #4710 - git: add tests/server/disabled to .gitignore +Dan Fandrich (13 Dec 2019) +- cirrus: Drop the FreeBSD 10.4 build - Closes #4441 + Upstream support for 10.4 ended a year ago, and it looks like the image + is now gone, too. + [skip ci] -- altsvc: accept quoted ma and persist values - - As mandated by the spec. Test 1654 is extended to verify. +Daniel Stenberg (13 Dec 2019) +- unit1620: fix bad free in OOM - Closes #4443 - -- mailmap: a Lucas fix - -Alessandro Ghedini (29 Sep 2019) -- [Lucas Pardue brought this change] - - quiche: update HTTP/3 config creation to new API - -Daniel Stenberg (29 Sep 2019) -- BINDINGS: PureBasic, Net::Curl for perl and Nim - -- BINDINGS: Kapito is an Erlang library, basically a binding + Closes #4709 -- BINDINGS: added clj-curl +- unit1609: fix mem-leak in OOM - Reported-by: Lucas Severo + Closes #4709 -- [Jay Satiro brought this change] +- unit1607: fix mem-leak in OOM + + Closes #4709 - docs: disambiguate CURLUPART_HOST is for host name (ie no port) +- lib1559: fix mem-leak in OOM - Closes #4424 + Closes #4709 -- cookies: using a share with cookies shouldn't enable the cookie engine +- lib1557: fix mem-leak in OOM - The 'share object' only sets the storage area for cookies. The "cookie - engine" still needs to be enabled or activated using the normal cookie - options. + Closes #4709 + +- altsvc: make the save function ignore NULL filenames - This caused the curl command line tool to accidentally use cookies - without having been told to, since curl switched to using shared cookies - in 7.66.0. + It might happen in OOM situations. Detected bv torture tests. - Test 1166 verifies + Closes #4707 + +- curl: fix memory leak in OOM in etags logic - Updated test 506 + Detected by torture tests - Fixes #4429 - Closes #4434 - -- setopt: handle ALTSVC set to NULL - -- RELEASE-NOTES: synced - -- [grdowns brought this change] + Closes #4706 - INSTALL: add vcpkg installation instructions +- doh: make it behave when built without proxy support - Closes #4435 - -- [Zenju brought this change] + Reported-by: Marcel Raad + Bug: https://github.com/curl/curl/pull/4692#issuecomment-564115734 + + Closes #4704 - FTP: add test for FTPFILE_NOCWD: Avoid redundant CWDs +- curl: improved cleanup in upload error path - Add libtest 661 + Memory leak found by torture test 58 - Closes #4417 + Closes #4705 -- [Zenju brought this change] +- mailmap: fix Andrew Ishchuk - FTP: url-decode path before evaluation +- travis: make torture use --shallow=40 - Closes #4428 + As a first step to enable it to run over a more diverse set of tests in + a reasonable time. -Marcel Raad (27 Sep 2019) -- tests: fix narrowing conversion warnings +- runtests: introduce --shallow to reduce huge torture tests - `timediff_t` is 64 bits wide also on 32-bit systems since - commit b1616dad8f0. + When set, shallow mode limits runtests -t to make no more than NUM fails + per test case. If more are found, it will randomly discard entries until + the number is right. The random seed can also be set. - Closes https://github.com/curl/curl/pull/4415 - -Jay Satiro (27 Sep 2019) -- [julian brought this change] - - vtls: Fix comment typo about macosx-version-min compiler flag + This is particularly useful when running MANY tests as then most torture + failures will already fail the same functions over and over and make the + total operation painfully tedious. - Closes https://github.com/curl/curl/pull/4425 - -Daniel Stenberg (26 Sep 2019) -- [Yechiel Kalmenson brought this change] + Closes #4699 - README: minor grammar fix +- conncache: CONNECT_ONLY connections assumed always in-use - Closes #4431 - -- [Spezifant brought this change] - - HTTP3: fix prefix parameter for ngtcp2 build + This makes them never to be considered "the oldest" to be discarded when + reaching the connection cache limit. The reasoning here is that + CONNECT_ONLY is primarily used in combination with using the + connection's socket post connect and since that is used outside of + curl's knowledge we must assume that it is in use until explicitly + closed. - Closes #4430 - -- quiche: don't close connection at end of stream! + Reported-by: Pavel Pavlov + Reported-by: Pavel Löbl + Fixes #4426 + Fixes #4369 + Closes #4696 -- quiche: set 'drain' when returning without having drained the queues +- [Gisle Vanem brought this change] -- Revert "FTP: url-decode path before evaluation" + vtls: make BearSSL possible to set with CURL_SSL_BACKEND - This reverts commit 2f036a72d543e96128bd75cb0fedd88815fd42e2. - -- HTTP3: merged and simplified the two 'running' sections - -- HTTP3: show an --alt-svc using example too + Ref: https://github.com/curl/curl/commit/9b879160df01e7ddbb4770904391d3b74114302b#commitcomment-36355622 + + Closes #4698 -- [Zenju brought this change] +- RELEASE-NOTES: synced - FTP: url-decode path before evaluation +- travis: remove "coverage", make it "torture" - Closes #4423 + The coveralls service and test coverage numbers are just too unreliable. + Removed badge from README.md as well. + + Fixes #4694 + Closes #4695 -- openssl: use strerror on SSL_ERROR_SYSCALL +- azure: add libssh2 and cmake macos builds - Instead of showing the somewhat nonsensical errno number, use strerror() - to provide a more relatable error message. + Removed the macos libssh2 build from travis - Closes #4411 + Closes #4686 -- HTTP3: update quic.aiortc.org + add link to server list +- curl: use errorf() better - Reported-by: Jeremy Lainé + Change series of error outputs to use errorf(). + + Only errors that are due to mistakes in command line option usage should + use helpf(), other types of errors in the tool should rather use + errorf(). + + Closes #4691 -Jay Satiro (26 Sep 2019) -- url: don't set appconnect time for non-ssl/non-ssh connections +Jay Satiro (9 Dec 2019) +- [Marc Hoersken brought this change] + + tests: make it possible to set executable extensions - Prior to this change non-ssl/non-ssh connections that were reused set - TIMER_APPCONNECT [1]. Arguably that was incorrect since no SSL/SSH - handshake took place. + This enables the use of Windows Subsystem for Linux (WSL) to run the + testsuite against Windows binaries while using Linux servers. - [1]: TIMER_APPCONNECT is publicly known as CURLINFO_APPCONNECT_TIME in - libcurl and %{time_appconnect} in the curl tool. It is documented as - "the time until the SSL/SSH handshake is completed". + This commit introduces the following environment variables: + - CURL_TEST_EXE_EXT: set the executable extension for all components + - CURL_TEST_EXE_EXT_TOOL: set it for the curl tool only + - CURL_TEST_EXE_EXT_SSH: set it for the SSH tools only - Reported-by: Marcel Hernandez + Later testcurl.pl could be adjusted to make use of those variables. + - CURL_TEST_EXE_EXT_SRV: set it for the test servers only - Ref: https://github.com/curl/curl/issues/3760 + (This is one of several commits to support use of WSL for the tests.) - Closes https://github.com/curl/curl/pull/3773 + Closes https://github.com/curl/curl/pull/3899 -Daniel Stenberg (25 Sep 2019) -- ngtcp2: remove fprintf() calls +- [Marc Hoersken brought this change] + + tests: fix permissions of ssh keys in WSL - - convert some of them to H3BUF() calls to infof() - - remove some of them completely - - made DEBUG_HTTP3 defined only if CURLDEBUG is set for now + Keys created on Windows Subsystem for Linux (WSL) require it for some + reason. - Closes #4421 + (This is one of several commits to support use of WSL for the tests.) + + Ref: https://github.com/curl/curl/pull/3899 -- [Jay Satiro brought this change] +- [Marc Hoersken brought this change] - url: fix the NULL hostname compiler warning case + tests: use \r\n for log messages in WSL - Closes #4403 + Bash in Windows Subsystem for Linux (WSL) requires it for some reason. + + (This is one of several commits to support use of WSL for the tests.) + + Ref: https://github.com/curl/curl/pull/3899 -- [Jay Satiro brought this change] +- [Andrew Ishchuk brought this change] - travis: move the go install to linux-only + winbuild: Define CARES_STATICLIB when WITH_CARES=static - ... to repair the build again - Closes #4403 + When libcurl is built with MODE=static, c-ares is forced into static + linkage too. That doesn't happen when MODE=dll so linker would break + over undefined symbols. + + closes https://github.com/curl/curl/pull/4688 -- altsvc: correct the #ifdef for the ngtcp2 backend +Daniel Stenberg (9 Dec 2019) +- conn: always set bits.close with connclose() + + Closes #4690 -- altsvc: save h3 as h3-23 +- cirrus: enable clang sanitizers on freebsd 13 + +- conncache: fix multi-thread use of shared connection cache - Follow-up to d176a2c7e5 + It could accidentally let the connection get used by more than one + thread, leading to double-free and more. + + Reported-by: Christopher Reid + Fixes #4544 + Closes #4557 -- urlapi: question mark within fragment is still fragment +- azure: add a vanilla macos build - The parser would check for a query part before fragment, which caused it - to do wrong when the fragment contains a question mark. + Closes #4685 + +- curl: make the etag load logic work without fseek - Extended test 1560 to verify. + The fseek()s were unnecessary and caused Coverity warning CID 1456554 - Reported-by: Alex Konev - Fixes #4412 - Closes #4413 + Closes #4681 -- [Alex Samorukov brought this change] +- mailmap: Mohammad Hasbini - HTTP3.md: move -p for mkdir, remove -j for make +- [Mohammad Hasbini brought this change] + + docs: fix some typos - - mkdir on OSX/Darwin requires `-p` argument before dir + Closes #4680 + +- RELEASE-NOTES: synced + +Jay Satiro (5 Dec 2019) +- lib: fix some loose ends for recently added CURLSSLOPT_NO_PARTIALCHAIN - - portabbly figuring out number of cores is an exercise for somewhere - else + Add support for CURLSSLOPT_NO_PARTIALCHAIN in CURLOPT_PROXY_SSL_OPTIONS + and OS400 package spec. - Closes #4407 - -Patrick Monnerat (24 Sep 2019) -- os400: getpeername() and getsockname() return ebcdic AF_UNIX sockaddr, + Also I added the option to the NameValue list in the tool even though it + isn't exposed as a command-line option (...yet?). (NameValue stringizes + the option name for the curl cmd -> libcurl source generator) - As libcurl now uses these 2 system functions, wrappers are needed on os400 - to convert returned AF_UNIX sockaddrs to ascii. + Follow-up to 564d88a which added CURLSSLOPT_NO_PARTIALCHAIN. - This is a follow-up to commit 7fb54ef. - See also #4037. - Closes #4214 - -Jay Satiro (24 Sep 2019) -- [Lucas Pardue brought this change] + Ref: https://github.com/curl/curl/pull/4655 - strcase: fix raw lowercasing the letter X +- setopt: Fix ALPN / NPN user option when built without HTTP2 - Casing mistake in Curl_raw_tolower 'X' wasn't lowercased as 'x' prior to - this change. + - Stop treating lack of HTTP2 as an unknown option error result for + CURLOPT_SSL_ENABLE_ALPN and CURLOPT_SSL_ENABLE_NPN. - Follow-up to 0023fce which added the function several days ago. + Prior to this change it was impossible to disable ALPN / NPN if libcurl + was built without HTTP2. Setting either option would result in + CURLE_UNKNOWN_OPTION and the respective internal option would not be + set. That was incorrect since ALPN and NPN are used independent of + HTTP2. - Ref: https://github.com/curl/curl/pull/4401#discussion_r327396546 + Reported-by: Shailesh Kapse - Closes https://github.com/curl/curl/pull/4408 + Fixes https://github.com/curl/curl/issues/4668 + Closes https://github.com/curl/curl/pull/4672 -Daniel Stenberg (23 Sep 2019) -- http2: Expression 'stream->stream_id != - 1' is always true +Daniel Stenberg (5 Dec 2019) +- etag: allow both --etag-compare and --etag-save in same cmdline - PVS-Studio warning - Fixes #4402 + Fixes #4669 + Closes #4678 -- http2: A value is being subtracted from the unsigned variable +Marcel Raad (5 Dec 2019) +- curl_setup: fix `CURLRES_IPV6` condition - PVS-Studio warning - Fixes #4402 - -- libssh: part of conditional expression is always true: !result + Move the definition of `CURLRES_IPV6` to before undefining + `HAVE_GETADDRINFO`. Regression from commit 67a08dca27a which caused + some tests to fail and others to be skipped with c-ares. - PVS-Studio warning - Fixed #4402 + Fixes https://github.com/curl/curl/issues/4673 + Closes https://github.com/curl/curl/pull/4677 -- libssh: part of conditional expression is always true - - PVS-Studio warning - Fixes #4402 +Daniel Stenberg (5 Dec 2019) +- test342: make it return a 304 as the tag matches -- libssh: The expression is excessive or contains a misprint +Peter Wu (4 Dec 2019) +- CMake: add support for building with the NSS vtls backend - PVS-Studio warning - Fixes #4402 - -- quiche: The expression must be surrounded by parentheses + Options are cross-checked with configure.ac and acinclude.m4. + Tested on Arch Linux, untested on other platforms like Windows or macOS. - PVS-Studio warning - Fixes #4402 + Closes #4663 + Reviewed-by: Kamil Dudka -- vauth: The parameter 'status' must be surrounded by parentheses +Daniel Stenberg (4 Dec 2019) +- azure: add more builds - PVS-Studio warning - Fixes #4402 + ... removed two from travis (that now runs on azure instead) + + Closes #4671 -- [Paul Dreik brought this change] +- CURLOPT_VERBOSE.3: see also ERRORBUFFER - doh: allow only http and https in debug mode +- hostip4.c: bump copyright year range + +Marcel Raad (3 Dec 2019) +- configure: enable IPv6 support without `getaddrinfo` - Otherwise curl may be told to use for instance pop3 to - communicate with the doh server, which most likely - is not what you want. + This makes it possible to recognize and connect to literal IPv6 + addresses when `getaddrinfo` is not available, which is already the + case for the CMake build. This affects e.g. classic MinGW because it + still targets Windows 2000 by default, where `getaddrinfo` is not + available, but general IPv6 support is. - Found through fuzzing. + Instead of checking for `getaddrinfo`, check for `sockaddr_in6` as the + CMake build does. - Closes #4406 - -- [Paul Dreik brought this change] + Closes https://github.com/curl/curl/pull/4662 - doh: return early if there is no time left +- curl_setup: disable IPv6 resolver without `getaddrinfo` - Closes #4406 + Also, use `CURLRES_IPV6` only for actual DNS resolution, not for IPv6 + address support. This makes it possible to connect to IPv6 literals by + setting `ENABLE_IPV6` even without `getaddrinfo` support. It also fixes + the CMake build when using the synchronous resolver without + `getaddrinfo` support. + + Closes https://github.com/curl/curl/pull/4662 -- [Barry Pollard brought this change] +Daniel Stenberg (3 Dec 2019) +- github action/azure pipeline: run 'make test-nonflaky' for tests + + To match travis and give more info on failures. - http: lowercase headernames for HTTP/2 and HTTP/3 +- openssl: CURLSSLOPT_NO_PARTIALCHAIN can disable partial cert chains - Closes #4401 - Fixes #4400 + Closes #4655 -Marcel Raad (23 Sep 2019) -- vtls: fix narrowing conversion warnings +- openssl: set X509_V_FLAG_PARTIAL_CHAIN - Curl_timeleft returns `timediff_t`, which is 64 bits wide also on - 32-bit systems since commit b1616dad8f0. + Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. - Closes https://github.com/curl/curl/pull/4398 + Other TLS backends already accept partial chains. + + Reported-by: Jeffrey Walton + Bug: https://curl.haxx.se/mail/lib-2019-11/0094.html -Daniel Stenberg (23 Sep 2019) -- [Joel Depooter brought this change] +- curl: show better error message when no homedir is found + + Reported-by: Vlastimil Ovčáčík + Fixes #4644 + Closes #4665 - winbuild: Add manifest to curl.exe for proper OS version detection +- OPENSOCKETFUNCTION.3: correct the purpose description - This is a small fix to commit ebd213270a017a6830928ee2e1f4a9cabc799898 - in pull request #1221. That commit added the CURL_EMBED_MANIFEST flag to - CURL_RC_FLAGS. However, later in the file CURL_RC_FLAGS is - overwritten. The fix is to append values to CURL_RC_FLAGS instead of - overwriting + Reported-by: Jeff Mears + Bug: https://curl.haxx.se/mail/lib-2019-12/0007.html - Closes #4399 + Closes #4667 -- RELEASE-NOTES: synced +- [Peter Wu brought this change] -Marcel Raad (22 Sep 2019) -- openssl: fix compiler warning with LibreSSL - - It was already fixed for BoringSSL in commit a0f8fccb1e0. - LibreSSL has had the second argument to SSL_CTX_set_min_proto_version - as uint16_t ever since the function was added in [0]. + travis: do not use OVERRIDE_CC or OVERRIDE_CXX if empty - [0] https://github.com/libressl-portable/openbsd/commit/56f107201baefb5533486d665a58d8f57fd3aeda + Fixes the macOS builds where OVERRIDE_CC and OVERRIDE_CXX are not set. - Closes https://github.com/curl/curl/pull/4397 + Reported-by: Jay Satiro + Fixes #4659 + Closes #4661 + Closes #4664 -Daniel Stenberg (22 Sep 2019) -- curl: exit the create_transfers loop on errors +- azure-pipelines: fix the test script + +- Azure Pipelines: initial CI setup - When looping around the ranges and given URLs to create transfers, all - errors should exit the loop and return. Previously it would keep - looping. + [skip ci] + +- docs: add "added: 7.68.0" to the --etag-* docs + +- copyright: fix the year ranges for two files - Reported-by: SumatraPeter on github - Bug: #4393 - Closes #4396 + Follow-up to 9c1806ae -Jay Satiro (21 Sep 2019) -- socks: Fix destination host shown on SOCKS5 error +Jay Satiro (1 Dec 2019) +- build: Disable Visual Studio warning "conditional expression is constant" - Prior to this change when a server returned a socks5 connect error then - curl would parse the destination address:port from that data and show it - to the user as the destination: + - Disable warning C4127 "conditional expression is constant" globally + in curl_setup.h for when building with Microsoft's compiler. - curld -v --socks5 10.0.3.1:1080 http://google.com:99 - * SOCKS5 communication to google.com:99 - * SOCKS5 connect to IPv4 172.217.12.206 (locally resolved) - * Can't complete SOCKS5 connection to 253.127.0.0:26673. (1) - curl: (7) Can't complete SOCKS5 connection to 253.127.0.0:26673. (1) + This mainly affects building with the Visual Studio project files found + in the projects dir. - That's incorrect because the address:port included in the connect error - is actually a bind address:port (typically unused) and not the - destination address:port. This fix changes curl to show the destination - information that curl sent to the server instead: + Prior to this change the cmake and winbuild build systems already + disabled 4127 globally for when building with Microsoft's compiler. + Also, 4127 was already disabled for all build systems in the limited + circumstance of the WHILE_FALSE macro which disabled the warning + specifically for while(0). This commit removes the WHILE_FALSE macro and + all other cruft in favor of disabling globally in curl_setup. - curld -v --socks5 10.0.3.1:1080 http://google.com:99 - * SOCKS5 communication to google.com:99 - * SOCKS5 connect to IPv4 172.217.7.14:99 (locally resolved) - * Can't complete SOCKS5 connection to 172.217.7.14:99. (1) - curl: (7) Can't complete SOCKS5 connection to 172.217.7.14:99. (1) + Background: - curld -v --socks5-hostname 10.0.3.1:1080 http://google.com:99 - * SOCKS5 communication to google.com:99 - * SOCKS5 connect to google.com:99 (remotely resolved) - * Can't complete SOCKS5 connection to google.com:99. (1) - curl: (7) Can't complete SOCKS5 connection to google.com:99. (1) + We have various macros that cause 0 or 1 to be evaluated, which would + cause warning C4127 in Visual Studio. For example this causes it: - Ref: https://tools.ietf.org/html/rfc1928#section-6 + #define Curl_resolver_asynch() 1 - Closes https://github.com/curl/curl/pull/4394 - -Daniel Stenberg (21 Sep 2019) -- travis: enable ngtcp2 h3-23 builds + Full behavior is not clearly defined and inconsistent across versions. + However it is documented that since VS 2015 Update 3 Microsoft has + addressed this somewhat but not entirely, not warning on while(true) for + example. + + Prior to this change some C4127 warnings occurred when I built with + Visual Studio using the generated projects in the projects dir. + + Closes https://github.com/curl/curl/pull/4658 -- altsvc: both backends run h3-23 now +- openssl: retrieve reported LibreSSL version at runtime - Closes #4395 + - Retrieve LibreSSL runtime version when supported (>= 2.7.1). + + For earlier versions we continue to use the compile-time version. + + Ref: https://man.openbsd.org/OPENSSL_VERSION_NUMBER.3 + + Closes https://github.com/curl/curl/pull/2425 -- http: fix warning on conversion from int to bit +- strerror: Add Curl_winapi_strerror for Win API specific errors - Follow-up from 03ebe66d70 + - In all code call Curl_winapi_strerror instead of Curl_strerror when + the error code is known to be from Windows GetLastError. + + Curl_strerror prefers CRT error codes (errno) over Windows API error + codes (GetLastError) when the two overlap. When we know the error code + is from GetLastError it is more accurate to prefer the Windows API error + messages. + + Reported-by: Richard Alcock + + Fixes https://github.com/curl/curl/issues/4550 + Closes https://github.com/curl/curl/pull/4581 -- urldata: use 'bool' for the bit type on MSVC compilers +Daniel Stenberg (2 Dec 2019) +- global_init: undo the "intialized" bump in case of failure - Closes #4387 - Fixes #4379 + ... so that failures in the global init function don't count as a + working init and it can then be called again. + + Reported-by: Paul Groke + Fixes #4636 + Closes #4653 -- appveyor: upgrade VS2017 to VS2019 +- parsedate: offer a getdate_capped() alternative - Closes #4383 + ... and use internally. This function will return TIME_T_MAX instead of + failure if the parsed data is found to be larger than what can be + represented. TIME_T_MAX being the largest value curl can represent. + + Reviewed-by: Daniel Gustafsson + Reported-by: JanB on github + Fixes #4152 + Closes #4651 -- [Zenju brought this change] +- docs: add more references to curl_multi_poll + + Fixes #4643 + Closes #4652 - FTP: FTPFILE_NOCWD: avoid redundant CWDs +- sha256: bump the copyright year range - Closes #4382 + Follow-up from 66e21520f -- cookie: pass in the correct cookie amount to qsort() +Daniel Gustafsson (28 Nov 2019) +- curl_setup_once: consistently use WHILE_FALSE in macros - As the loop discards cookies without domain set. This bug would lead to - qsort() trying to sort uninitialized pointers. We have however not found - it a security problem. + The WHILE_FALSE construction is used to avoid compiler warnings in + macro constructions. This fixes a few instances where it was not + used in order to keep the code consistent. - Reported-by: Paul Dreik - Closes #4386 + Closes #4649 + Reviewed-by: Daniel Stenberg -- [Paul Dreik brought this change] +Daniel Stenberg (28 Nov 2019) +- [Steve Holme brought this change] - urlapi: avoid index underflow for short ipv6 hostnames + http_ntlm: Remove duplicate NSS initialisation - If the input hostname is "[", hlen will underflow to max of size_t when - it is subtracted with 2. + Given that this is performed by the NTLM code there is no need to + perform the initialisation in the HTTP layer. This also keeps the + initialisation the same as the SASL based protocols and also fixes a + possible compilation issue if both NSS and SSPI were to be used as + multiple SSL backends. - hostname[hlen] will then cause a warning by ubsanitizer: + Reviewed-by: Kamil Dudka + Closes #3935 + +Daniel Gustafsson (28 Nov 2019) +- checksrc: fix regexp for ASSIGNWITHINCONDITION - runtime error: addition of unsigned offset to 0x overflowed to - 0x + The regexp looking for assignments within conditions was too greedy + and matched a too long string in the case of multiple conditionals + on the same line. This is basically only a problem in single line + macros, and the code which exemplified this was essentially: - I think that in practice, the generated code will work, and the output - of hostname[hlen] will be the first character "[". + do { if((x) != NULL) { x = NULL; } } while(0) - This can be demonstrated by the following program (tested in both clang - and gcc, with -O3) + ..where the final parenthesis of while(0) matched the regexp, and + the legal assignment in the block triggered the warning. Fix by + making the regexp less greedy by matching for the tell-tale signs + of the if statement ending. - int main() { - char* hostname=strdup("["); - size_t hlen = strlen(hostname); + Also remove the one occurrence where the warning was disabled due + to a construction like the above, where the warning didn't apply + when fixed. - hlen-=2; - hostname++; - printf("character is %d\n",+hostname[hlen]); - free(hostname-1); - } + Closes #4647 + Reviewed-by: Daniel Stenberg + +Daniel Stenberg (28 Nov 2019) +- RELEASE-NOTES: synced + +- [Maros Priputen brought this change] + + curl: two new command line options for etags - I found this through fuzzing, and even if it seems harmless, the proper - thing is to return early with an error. + --etag-compare and --etag-save - Closes #4389 + Suggested-by: Paul Hoffman + Fixes #4277 + Closes #4543 -- [Tatsuhiro Tsujikawa brought this change] +Daniel Gustafsson (28 Nov 2019) +- docs: fix typos - ngtcp2: compile with latest ngtcp2 + nghttp3 draft-23 - - Closes #4392 +Daniel Stenberg (28 Nov 2019) +- mailmap: Niall O'Reilly's name -- THANKS-filter: deal with my typos 'Jat' => 'Jay' +- [Niall O'Reilly brought this change] -- travis: use go master + doh: use dedicated probe slots - ... as the boringssl builds needs a very recent version + ... to easier allow additional DNS transactions. - Co-authored-by: Jat Satiro - Closes #4361 + Closes #4629 -- tool_operate: removed unused variable 'done' +- travis: build ngtcp2 with --enable-lib-only - Fixes warning detected by PVS-Studio - Fixes #4374 - -- tool_operate: Expression 'config->resume_from' is always true + ... makes it skip the examples and other stuff we don't neeed. - Fixes warning detected by PVS-Studio - Fixes #4374 + Closes #4646 -- tool_getparam: remove duplicate switch case - - Fixes warning detected by PVS-Studio - Fixes #4374 +- [David Benjamin brought this change] -- libssh2: part of conditional expression is always true: !result + ngtcp2: fix thread-safety bug in error-handling - Fixes warning detected by PVS-Studio - Fixes #4374 - -- urlapi: Expression 'storep' is always true + ERR_error_string(NULL) should never be called. It places the error in a + global buffer, which is not thread-safe. Use ERR_error_string_n with a + local buffer instead. - Fixes warning detected by PVS-Studio - Fixes #4374 + Closes #4645 -- urlapi: 'scheme' is always true +- travis: export the CC/CXX variables when set - Fixes warning detected by PVS-Studio - Fixes #4374 + Suggested-by: Peter Wu + Fixes #4637 + Closes #4640 -- urlapi: part of conditional expression is always true: (relurl[0] == '/') +Marcel Raad (26 Nov 2019) +- dist: add error-codes.pl - Fixes warning detected by PVS-Studio - Fixes #4374 - -- setopt: store CURLOPT_RTSP_SERVER_CSEQ correctly + Follow-up to commit 74f441c6d31. + This should fix test 1175 when run via the daily source tarballs. - Fixes bug detected by PVS-Studio - Fixes #4374 + Closes https://github.com/curl/curl/pull/4638 -- mime: make Curl_mime_duppart() assert if called without valid dst - - Fixes warning detected by PVS-Studio - Fixes #4374 +Daniel Stenberg (26 Nov 2019) +- [John Schroeder brought this change] -- http_proxy: part of conditional expression is always true: !error + curl: fix --upload-file . hangs if delay in STDIN - Fixes warning detected by PVS-Studio - Fixes #4374 - -- imap: merged two case-branches performing the same action + Attempt to unpause a busy read in the CURLOPT_XFERINFOFUNCTION. - Fixes warning detected by PVS-Studio - Fixes #4374 + When uploading from stdin in non-blocking mode, a delay in reading + the stream (EAGAIN) causes curl to pause sending data + (CURL_READFUNC_PAUSE). Prior to this change, a busy read was + detected and unpaused only in the CURLOPT_WRITEFUNCTION handler. + This change performs the same busy read handling in a + CURLOPT_XFERINFOFUNCTION handler. + + Fixes #2051 + Closes #4599 + Reported-by: bdry on github -- multi: value '2L' is assigned to a boolean +- [John Schroeder brought this change] + + XFERINFOFUNCTION: support CURL_PROGRESSFUNC_CONTINUE - Fixes warning detected by PVS-Studio - Fixes #4374 + (also for PROGRESSFUNCTION) + + By returning this value from the callback, the internal progress + function call is still called afterward. + + Closes #4599 -- easy: part of conditional expression is always true: !result +- [Michael Forney brought this change] + + TLS: add BearSSL vtls implementation - Fixes warning detected by PVS-Studio - Fixes #4374 + Closes #4597 -- netrc: part of conditional expression is always true: !done +- curl_multi_wakeup.3: add example and AVAILABILITY - Fixes warning detected by PVS-Studio - Fixes #4374 + Reviewed-by: Gergely Nagy + Closes #4635 -- version: Expression 'left > 1' is always true +- [Gergely Nagy brought this change] + + multi: add curl_multi_wakeup() - Fixes warning detected by PVS-Studio - Fixes #4374 + This commit adds curl_multi_wakeup() which was previously in the TODO + list under the curl_multi_unblock name. + + On some platforms and with some configurations this feature might not be + available or can fail, in these cases a new error code + (CURLM_WAKEUP_FAILURE) is returned from curl_multi_wakeup(). + + Fixes #4418 + Closes #4608 -- url: remove dead code +Jay Satiro (24 Nov 2019) +- [Xiaoyin Liu brought this change] + + schannel: fix --tls-max for when min is --tlsv1 or default - Fixes warning detected by PVS-Studio - Fixes #4374 + Prior to this change schannel ignored --tls-max (CURL_SSLVERSION_MAX_ + macros) when --tlsv1 (CURL_SSLVERSION_TLSv1) or default TLS + (CURL_SSLVERSION_DEFAULT), using a max of TLS 1.2 always. + + Closes https://github.com/curl/curl/pull/4633 -- url: part of expression is always true: (bundle->multiuse == 0) +- checksrc.bat: Add a check for vquic and vssh directories - Fixes warning detected by PVS-Studio - Fixes #4374 + Ref: https://github.com/curl/curl/pull/4607 -- ftp: the conditional expression is always true +- projects: Fix Visual Studio projects SSH builds - ... both !result and (ftp->transfer != FTPTRANSFER_BODY)! + - Generate VQUIC and VSSH filenames in Visual Studio project files. - Fixes warning detected by PVS-Studio - Fixes #4374 + Prior to this change generated Visual Studio project configurations that + enabled SSH did not build properly. Broken since SSH files were moved to + lib/vssh 3 months ago in 5b2d703. + + Fixes https://github.com/curl/curl/issues/4492 + Fixes https://github.com/curl/curl/issues/4630 + Closes https://github.com/curl/curl/pull/4607 -- ftp: Expression 'ftpc->wait_data_conn' is always false +Daniel Stenberg (23 Nov 2019) +- RELEASE-NOTES: synced + +Jay Satiro (22 Nov 2019) +- openssl: Revert to less sensitivity for SYSCALL errors - Fixes warning detected by PVS-Studio - Fixes #4374 + - Disable the extra sensitivity except in debug builds (--enable-debug). + + - Improve SYSCALL error message logic in ossl_send and ossl_recv so that + "No error" / "Success" socket error text isn't shown on SYSCALL error. + + Prior to this change 0ab38f5 (precedes 7.67.0) increased the sensitivity + of OpenSSL's SSL_ERROR_SYSCALL error so that abrupt server closures were + also considered errors. For example, a server that does not send a known + protocol termination point (eg HTTP content length or chunked encoding) + _and_ does not send a TLS termination point (close_notify alert) would + cause an error if it closed the connection. + + To be clear that behavior made it into release build 7.67.0 + unintentionally. Several users have reported it as an issue. + + Ultimately the idea is a good one, since it can help prevent against a + truncation attack. Other SSL backends may already behave similarly (such + as Windows native OS SSL Schannel). However much more of our user base + is using OpenSSL and there is a mass of legacy users in that space, so I + think that behavior should be partially reverted and then rolled out + slowly. + + This commit changes the behavior so that the increased sensitivity is + disabled in all curl builds except curl debug builds (DEBUGBUILD). If + after a period of time there are no major issues then it can be enabled + in dev and release builds with the newest OpenSSL (1.1.1+), since users + using the newest OpenSSL are the least likely to have legacy problems. + + Bug: https://github.com/curl/curl/issues/4409#issuecomment-555955794 + Reported-by: Bjoern Franke + + Fixes https://github.com/curl/curl/issues/4624 + Closes https://github.com/curl/curl/pull/4623 -- ftp: Expression 'ftpc->wait_data_conn' is always true +- [Daniel Stenberg brought this change] + + openssl: improve error message for SYSCALL during connect - Fixes warning detected by PVS-Studio - Fixes #4374 + Reported-by: Paulo Roberto Tomasi + Bug: https://curl.haxx.se/mail/archive-2019-11/0005.html + + Closes https://github.com/curl/curl/pull/4593 -- ftp: part of conditional expression is always true: !result +Daniel Stenberg (22 Nov 2019) +- test1175: verify symbols-in-versions and libcurl-errors.3 in sync - Fixes warning detected by PVS-Studio - Fixes #4374 + Closes #4628 -- http: fix Expression 'http->postdata' is always false +- include: make CURLE_HTTP3 use a new error code - Fixes warning detected by PVS-Studio - Fixes #4374 - Reported-by: Valerii Zapodovnikov + To avoid potential issues with error code reuse. + + Reported-by: Christoph M. Becker + Assisted-by: Dan Fandrich + Fixes #4601 + Closes #4627 -- [Niall O'Reilly brought this change] +- bump: next release will be 7.68.0 - doh: avoid truncating DNS QTYPE to lower octet +- curl: add --parallel-immediate - Closes #4381 + Starting with this change when doing parallel transfers, without this + option set, curl will prefer to create new transfers multiplexed on an + existing connection rather than creating a brand new one. + + --parallel-immediate can be set to tell curl to prefer to use new + connections rather than to wait and try to multiplex. + + libcurl-wise, this means that curl will set CURLOPT_PIPEWAIT by default + on parallel transfers. + + Suggested-by: Tom van der Woerdt + Closes #4500 -- [Jens Finkhaeuser brought this change] +Daniel Gustafsson (20 Nov 2019) +- [Victor Magierski brought this change] - urlapi: CURLU_NO_AUTHORITY allows empty authority/host part + docs: fix typos - CURLU_NO_AUTHORITY is intended for use with unknown schemes (i.e. not - "file:///") to override cURL's default demand that an authority exists. + Change 'experiemental' to 'experimental'. - Closes #4349 + Closes #4618 + Reviewed-by: Daniel Gustafsson -- version: next release will be 7.67.0 +Jay Satiro (18 Nov 2019) +- projects: Fix Visual Studio wolfSSL configurations + + - s/USE_CYASSL/USE_WOLFSSL/ + + - Remove old compatibility macros. + + Follow-up to 1c6c59a from several months ago when CyaSSL named symbols + were renamed to wolfSSL. The wolfSSL library was formerly named CyaSSL + and we kept using their old name for compatibility reasons, until + earlier this year. +Daniel Stenberg (18 Nov 2019) - RELEASE-NOTES: synced -- url: only reuse TLS connections with matching pinning - - If the requests have different CURLOPT_PINNEDPUBLICKEY strings set, the - connection should not be reused. +- [Javier Blazquez brought this change] + + ngtcp2: use overflow buffer for extra HTTP/3 data + + Fixes #4525 + Closes #4603 + +- altsvc: bump to h3-24 - Bug: https://curl.haxx.se/mail/lib-2019-09/0061.html - Reported-by: Sebastian Haglund + ... as both ngtcp2 and quiche now support that in their master branches - Closes #4347 + Closes #4604 -- README: add OSS-Fuzz badge [skip ci] +- ngtcp2: free used resources on disconnect - Closes #4380 + Fixes #4614 + Closes #4615 -Michael Kaufmann (18 Sep 2019) -- http: merge two "case" statements +- ngtcp2: handle key updates as ngtcp2 master branch tells us + + Reviewed-by: Tatsuhiro Tsujikawa + + Fixes #4612 + Closes #4613 -Daniel Stenberg (18 Sep 2019) -- [Zenju brought this change] +Jay Satiro (17 Nov 2019) +- [Gergely Nagy brought this change] - FTP: remove trailing slash from path for LIST/MLSD + multi: Fix curl_multi_poll wait when extra_fds && !extra_nfds - Closes #4348 - -- mime: when disabled, avoid C99 macro + Prior to this change: - Closes #4368 + The check if an extra wait is necessary was based not on the + number of extra fds but on the pointer. + + If a non-null pointer was given in extra_fds, but extra_nfds + was zero, then the wait was skipped even though poll was not + called. + + Closes https://github.com/curl/curl/pull/4610 -- url: cleanup dangling DOH request headers too +- lib: Move lib/ssh.h -> lib/vssh/ssh.h - Follow-up to 9bc44ff64d9081 + Follow-up to 5b2d703 which moved ssh source files to vssh. - Credit to OSS-Fuzz - Bug: https://crbug.com/oss-fuzz/17269 + Closes https://github.com/curl/curl/pull/4609 + +Daniel Stenberg (16 Nov 2019) +- [Andreas Falkenhahn brought this change] + + INSTALL.md: provide Android build instructions - Closes #4372 + Closes #4606 -- [Christoph M. Becker brought this change] +- [Niall O'Reilly brought this change] - http2: relax verification of :authority in push promise requests + doh: improced both encoding and decoding - If the :authority pseudo header field doesn't contain an explicit port, - we assume it is valid for the default port, instead of rejecting the - request for all ports. + Improved estimation of expected_len and updated related comments; + increased strictness of QNAME-encoding, adding error detection for empty + labels and names longer than the overall limit; avoided treating DNAME + as unexpected; - Ref: https://curl.haxx.se/mail/lib-2019-09/0041.html + updated unit test 1655 with more thorough set of proofs and tests - Closes #4365 + Closes #4598 -- doh: clean up dangling DOH handles and memory on easy close - - If you set the same URL for target as for DoH (and it isn't a DoH - server), like "https://example.com" in both, the easy handles used for - the DoH requests could be left "dangling" and end up not getting freed. +- ngtcp2: increase QUIC window size when data is consumed - Reported-by: Paul Dreik - Closes #4366 + Assisted-by: Javier Blazquez + Ref #4525 (partial fix) + Closes #4600 -- unit1655: make it C90 compliant - - Unclear why this was not detected in the CI. - - Follow-up to b7666027296a +- [Melissa Mears brought this change] -- smb: check for full size message before reading message details + config-win32: cpu-machine-OS for Windows on ARM - To avoid reading of uninitialized data. + Define the OS macro properly for Windows on ARM builds. Also, we might + as well add the GCC-style IA-64 macro. - Assisted-by: Max Dymond - Bug: https://crbug.com/oss-fuzz/16907 - Closes #4363 + Closes #4590 -- quiche: persist connection details +- examples: add multi-poll.c - ... like we do for other protocols at connect time. This makes "curl -I" - and other things work. + Show how curl_multi_poll() makes it even easier to use the multi + interface. - Reported-by: George Liu - Fixes #4358 - Closes #4360 + Closes #4596 -- openssl: fix warning with boringssl and SSL_CTX_set_min_proto_version +- multi_poll: avoid busy-loop when called without easy handles attached - Follow-up to ffe34b7b59 - Closes #4359 - -- [Paul Dreik brought this change] + Fixes #4594 + Closes #4595 + Reported-by: 3dyd on github - doh: fix undefined behaviour and open up for gcc and clang optimization +- curl: fix -T globbing - The undefined behaviour is annoying when running fuzzing with - sanitizers. The codegen is the same, but the meaning is now not up for - dispute. See https://cppinsights.io/s/516a2ff4 + Regression from e59371a4936f8 (7.67.0) - By incrementing the pointer first, both gcc and clang recognize this as - a bswap and optimizes it to a single instruction. See - https://godbolt.org/z/994Zpx + Added test 490, 491 and 492 to verify the functionality. - Closes #4350 + Reported-by: Kamil Dudka + Reported-by: Anderson Sasaki + + Fixes #4588 + Closes #4591 -- [Paul Dreik brought this change] +- HISTORY: added cmake, HTTP/3 and parallel downloads with curl - doh: fix (harmless) buffer overrun +- quiche: reject headers in the wrong order - Added unit test case 1655 to verify. - Close #4352 + Pseudo header MUST come before regular headers or cause an error. - the code correctly finds the flaws in the old code, - if one temporarily restores doh.c to the old version. - -Alessandro Ghedini (15 Sep 2019) -- docs: remove trailing ':' from section names in CURLOPT_TRAILER* man - -- docs: fix typo in CURLOPT_HTTP_VERSION man - -GitHub (14 Sep 2019) -- [Daniel Stenberg brought this change] + Reported-by: Cynthia Coan + Fixes #4571 + Closes #4584 - CI: inintial github action job +- openssl: prevent recursive function calls from ctx callbacks - First shot at a CI build on github actions + Follow the pattern of many other callbacks. + + Ref: #4546 + Closes #4585 -Daniel Stenberg (13 Sep 2019) -- appveyor: add a winbuild +- CURL-DISABLE: initial docs for the CURL_DISABLE_* defines - Assisted-by: Marcel Raad - Assisted-by: Jay Satiro + The disable-scan script used in test 1165 is extended to also verify + that the docs cover all used defines and all defines offered by + configure. - Closes #4324 + Reported-by: SLDiggie on github + Fixes #4545 + Closes #4587 -- FTP: allow "rubbish" prepended to the SIZE response - - This is a protocol violation but apparently there are legacy proprietary - servers doing this. +- remove_handle: clear expire timers after multi_done() - Added test 336 and 337 to verify. + Since 59041f0, a new timer might be set in multi_done() so the clearing + of the timers need to happen afterwards! - Reported-by: Philippe Marguinaud - Closes #4339 - -- [Zenju brought this change] + Reported-by: Max Kellermann + Fixes #4575 + Closes #4583 - FTP: skip CWD to entry dir when target is absolute +Marcel Raad (10 Nov 2019) +- test1558: use double slash after file: - Closes #4332 + Classic MinGW / MSYS 1 doesn't support `MSYS2_ARG_CONV_EXCL`, so this + test unnecessarily failed when using `file:/` instead of `file:///`. + + Closes https://github.com/curl/curl/pull/4554 -Kamil Dudka (13 Sep 2019) -- curl: fix memory leaked by parse_metalink() +Daniel Stenberg (10 Nov 2019) +- pause: avoid updating socket if done was already called - This commit fixes a regression introduced by curl-7_65_3-5-gb88940850. - Detected by tests 2005, 2008, 2009, 2010, 2011, and 2012 with valgrind - and libmetalink enabled. + ... avoids unnecesary recursive risk when the transfer is already done. - Closes #4326 + Reported-by: Richard Bowker + Fixes #4563 + Closes #4574 -Daniel Stenberg (13 Sep 2019) -- parsedate: still provide the name arrays when disabled +Jay Satiro (9 Nov 2019) +- strerror: Fix an error looking up some Windows error strings - If FILE or FTP are enabled, since they also use them! + - Use FORMAT_MESSAGE_IGNORE_INSERTS to ignore format specifiers in + Windows error strings. - Reported-by: Roland Hieber - Fixes #4325 - Closes #4343 - -- [Gilles Vollant brought this change] - - curl:file2string: load large files much faster + Since we are not in control of the error code we don't know what + information may be needed by the error string's format specifiers. - ... by using a more efficient realloc scheme. + Prior to this change Windows API error strings which contain specifiers + (think specifiers like similar to printf specifiers) would not be shown. + The FormatMessage Windows API call which turns a Windows error code into + a string could fail and set error ERROR_INVALID_PARAMETER if that error + string contained a format specifier. FormatMessage expects a va_list for + the specifiers, unless inserts are ignored in which case no substitution + is attempted. - Bug: https://curl.haxx.se/mail/lib-2019-09/0045.html - Closes #4336 + Ref: https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353 -- openssl: close_notify on the FTP data connection doesn't mean closure +- [r-a-sattarov brought this change] + + system.h: fix for MCST lcc compiler - For FTPS transfers, curl gets close_notify on the data connection - without that being a signal to close the control connection! + Fixed build by MCST lcc compiler on MCST Elbrus 2000 architecture and do + some code cleanup. - Regression since 3f5da4e59a556fc (7.65.0) + e2k (Elbrus 2000) - this is VLIW/EPIC architecture, like Intel Itanium + architecture. - Reported-by: Zenju on github - Reviewed-by: Jay Satiro - Fixes #4329 - Closes #4340 - -- [Jimmy Gaussen brought this change] + Ref: https://en.wikipedia.org/wiki/Elbrus_2000 + + Closes https://github.com/curl/curl/pull/4576 - docs/HTTP3: fix `--with-ssl` ngtcp2 configure flag +Daniel Stenberg (8 Nov 2019) +- TODO: curl_multi_unblock - Closes #4338 - -- RELEASE-NOTES: synced + Closes #4418 -- curlver: bump to 7.66.1 +- TODO: Run web-platform-tests url tests + + Closes #4477 -- [Zenju brought this change] +- TODO: 1.4 alt-svc sharing + + Closes #4476 - setopt: make it easier to add new enum values +- test1560: require IPv6 for IPv6 aware URL parsing - ... by using the *_LAST define names better. + The URL parser function can't reject a bad IPv6 address properly when + curl was built without IPv6 support. - Closes #4321 + Reported-by: Marcel Raad + Fixes #4556 + Closes #4572 -- asyn-thread: s/AF_LOCAL/AF_UNIX for Solaris +- checksrc: repair the copyrightyear check - Reported-by: Dagobert Michelsen - Fixes #4328 - Closes #4333 - -- [Bernhard Walle brought this change] - - winbuild/MakefileBuild.vc: Add vssh + - Consider a modified file to be committed this year. - Without that modification, the Windows build using the makefiles doesn't - work. + - Make the travis CHECKSRC also do COPYRIGHTYEAR scan in examples and + includes - Signed-off-by: Bernhard Walle + - Ignore 0 parents when getting latest commit date of file. - Fixes #4322 - Closes #4323 - -Bernhard Walle (11 Sep 2019) -- winbuild/MakefileBuild.vc: Fix line endings + since in the CI we're dealing with a truncated repo of last 50 commits, + the file's most recent commit may not be available. when this happens + git log and rev-list show the initial commit (ie first commit not to be + truncated) but that's incorrect so ignore it. - The file had mixed line endings. + Ref: https://github.com/curl/curl/pull/4547 - Signed-off-by: Bernhard Walle - -Jay Satiro (11 Sep 2019) -- ldap: Stop using wide char version of ldapp_err2string + Closes https://github.com/curl/curl/pull/4549 - Despite ldapp_err2string being documented by MS as returning a - PCHAR (char *), when UNICODE it is mapped to ldap_err2stringW and - returns PWCHAR (wchar_t *). + Co-authored-by: Jay Satiro + +- copyrights: fix copyright year range - We have lots of code that expects ldap_err2string to return char *, - most of it failf used like this: + .. because checksrc's copyright year check stopped working. - failf(data, "LDAP local: Some error: %s", ldap_err2string(rc)); + Ref: https://github.com/curl/curl/pull/4547 - Closes https://github.com/curl/curl/pull/4272 + Closes https://github.com/curl/curl/pull/4549 -Version 7.66.0 (10 Sep 2019) +- RELEASE-NOTES: synced -Daniel Stenberg (10 Sep 2019) -- RELEASE-NOTES: curl 7.66.0 +- curlver: bump to 7.67.1 -- THANKS: from the 7.66.0 release +- mailmap: fixup Massimiliano Fantuzzi -- curl: make sure the parallel transfers do them all - - The logic could erroneously break the loop too early before all - transfers had been transferred. +- scripts/contributors: make committers get included too - Reported-by: Tom van der Woerdt - Fixes #4316 - Closes #4317 + in addition to authors -- urlapi: one colon is enough for the strspn() input (typo) +Jay Satiro (8 Nov 2019) +- [Massimiliano Fantuzzi brought this change] -- urlapi: verify the IPv6 numerical address - - It needs to parse correctly. Otherwise it could be tricked into letting - through a-f using host names that libcurl would then resolve. Like - '[ab.be]'. + configure: fix typo in help text - Reported-by: Thomas Vegas - Closes #4315 + Closes https://github.com/curl/curl/pull/4570 -- [Clément Notin brought this change] +Daniel Stenberg (7 Nov 2019) +- [Christian Schmitz brought this change] - openssl: use SSL_CTX_set__proto_version() when available - - OpenSSL 1.1.0 adds SSL_CTX_set__proto_version() that we now use - when available. Existing code is preserved for older versions of - OpenSSL. + ntlm: USE_WIN32_CRYPTO check removed to get USE_NTLM2SESSION set - Closes #4304 + Closes #3704 -- [Clément Notin brought this change] +Jay Satiro (6 Nov 2019) +- [Wyatt O'Day brought this change] - openssl: indent, re-organize and add comments + build: fix for CURL_DISABLE_DOH + + Fixes https://github.com/curl/curl/issues/4565 + Closes https://github.com/curl/curl/pull/4566 -- [migueljcrum brought this change] +- [Leonardo Taccari brought this change] - sspi: fix memory leaks + configure: avoid unportable `==' test(1) operator - Closes #4299 + Closes https://github.com/curl/curl/pull/4567 -- travis: disable ngtcp2 builds (again) +Version 7.67.0 (5 Nov 2019) -- Curl_fillreadbuffer: avoid double-free trailer buf on error - - Reviewed-by: Jay Satiro - Reported-by: Thomas Vegas +Daniel Stenberg (5 Nov 2019) +- RELEASE-NOTES: synced - Closes #4307 + The 7.67.0 release -- tool_setopt: handle a libcurl build without netrc support - - Reported-by: codesniffer13 on github - Fixes #4302 - Closes #4305 +- THANKS: add new names from 7.67.0 -- security:read_data fix bad realloc() +- configure: only say ipv6 enabled when the variable is set - ... that could end up a double-free + Previously it could say "IPv6: enabled" at the end of the configure run + but the define wasn't set because of a missing getaddrinfo(). - CVE-2019-5481 - Bug: https://curl.haxx.se/docs/CVE-2019-5481.html - -- [Thomas Vegas brought this change] + Reported-by: Marcel Raad + Fixes #4555 + Closes #4560 - tftp: Alloc maximum blksize, and use default unless OACK is received +Marcel Raad (2 Nov 2019) +- certs/Server-localhost-lastSAN-sv: regenerate with sha256 - Fixes potential buffer overflow from 'recvfrom()', should the server - return an OACK without blksize. + All other certificates were regenerated in commit ba782baac30, but + this one was missed. + Fixes test3001 on modern systems. - Bug: https://curl.haxx.se/docs/CVE-2019-5482.html - CVE-2019-5482 - -- [Thomas Vegas brought this change] + Closes https://github.com/curl/curl/pull/4551 - tftp: return error when packet is too small for options +Daniel Stenberg (2 Nov 2019) +- [Vilhelm Prytz brought this change] -- KNOWN_BUGS/TODO: cleanup and remove outdated issues + copyrights: update all copyright notices to 2019 on files changed this year + + Closes #4547 -- RELEASE-NOTES: synced +- [Bastien Bouclet brought this change] -- netrc: free 'home' on error - - Follow-up to f9c7ba9096ec2 - - Coverity CID 1453474 + mbedtls: add error message for cert validity starting in the future - Closes #4291 + Closes #4552 -- urldata: avoid 'generic', use dedicated pointers +Jay Satiro (1 Nov 2019) +- schannel_verify: Fix concurrent openings of CA file - For the 'proto' union within the connectdata struct. + - Open the CA file using FILE_SHARE_READ mode so that others can read + from it as well. - Closes #4290 - -- cleanup: move functions out of url.c and make them static + Prior to this change our schannel code opened the CA file without + sharing which meant concurrent openings (eg an attempt from another + thread or process) would fail during the time it was open without + sharing, which in curl's case would cause error: + "schannel: failed to open CA file". - Closes #4289 + Bug: https://curl.haxx.se/mail/lib-2019-10/0104.html + Reported-by: Richard Alcock -- smtp: check for and bail out on too short EHLO response - - Otherwise, a three byte response would make the smtp_state_ehlo_resp() - function misbehave. +Daniel Stenberg (31 Oct 2019) +- gtls: make gnutls_bye() not wait for response on shutdown - Credit to OSS-Fuzz - Bug: https://crbug.com/oss-fuzz/16918 + ... as it can make it wait there for a long time for no good purpose. - Assisted-by: Max Dymond + Patched-by: Jay Satiro + Reported-by: Bylon2 on github + Adviced-by: Nikos Mavrogiannopoulos - Closes #4287 + Fixes #4487 + Closes #4541 -- smb: init *msg to NULL in smb_send_and_recv() - - ... it might otherwise return OK from this function leaving that pointer - uninitialized. +- [Michał Janiszewski brought this change] + + appveyor: publish artifacts on appveyor - Bug: https://crbug.com/oss-fuzz/16907 + This allows obtaining upstream builds of curl directly from appveyor for + all the available configurations - Closes #4286 + Closes #4509 -- ROADMAP: updated after recent user poll +- url: make Curl_close() NULLify the pointer too - In rough prio order + This is the common pattern used in the code and by a unified approach we + avoid mistakes. + + Closes #4534 -- THANKS: remove duplicate +- [Trivikram Kamat brought this change] -- Curl_addr2string: take an addrlen argument too + INSTALL: add missing space for configure commands - This allows the function to figure out if a unix domain socket has a - file name or not associated with it! When a socket is created with - socketpair(), as done in the fuzzer testing, the path struct member is - uninitialized and must not be accessed. + Closes #4539 + +- url: Curl_free_request_state() should also free doh handles - Bug: https://crbug.com/oss-fuzz/16699 + ... or risk DoH memory leaks. - Closes #4283 - -- [Rolf Eike Beer brought this change] - - CMake: remove needless newlines at end of gss variables - -- [Rolf Eike Beer brought this change] - - CI: remove duplicate configure flag for LGTM.com - -- [Rolf Eike Beer brought this change] + Reported-by: Paul Dreik + Fixes #4463 + Closes #4527 - CMake: use platform dependent name for dlopen() library +- examples: remove the "this exact code has not been verified" - Closes #4279 + ... as really confuses the reader to not know what to believe! -- quiche: expire when poll returned data - - ... to make sure we continue draining the queue until empty +- [Trivikram Kamat brought this change] + + HTTP3: fix typo somehere1 > somewhere1 - Closes #4281 + Closes #4535 -- quiche: decrease available buffer size, don't assign it! +Jay Satiro (28 Oct 2019) +- [Javier Blazquez brought this change] + + HTTP3: fix invalid use of sendto for connected UDP socket - Found-by: Jeremy Lainé + On macOS/BSD, trying to call sendto on a connected UDP socket fails + with a EISCONN error. Because the singleipconnect has already called + connect on the socket when we're trying to use it for QUIC transfers + we need to use plain send instead. + + Fixes #4529 + Closes https://github.com/curl/curl/pull/4533 +Daniel Stenberg (28 Oct 2019) - RELEASE-NOTES: synced -- [Kyohei Kadota brought this change] - - curl: fix include conditions +- [Javier Blazquez brought this change] -- [Kyohei Kadota brought this change] + HTTP3: fix Windows build + + The ngtcp2 QUIC backend was using the MSG_DONTWAIT flag for send/recv + in order to perform nonblocking operations. On Windows this flag does + not exist. Instead, the socket must be set to nonblocking mode via + ioctlsocket. + + This change sets the nonblocking flag on UDP sockets used for QUIC on + all platforms so the use of MSG_DONTWAIT is not needed. + + Fixes #4531 + Closes #4532 - plan9: fix installation instructions +Marcel Raad (27 Oct 2019) +- appveyor: add --disable-proxy autotools build - Closes #4276 + This would have caught issue #3926. + + Also make formatting more consistent. + + Closes https://github.com/curl/curl/pull/4526 -- ngtcp2: on h3 stream close, call expire +Daniel Stenberg (25 Oct 2019) +- appveyor: make winbuilds with DEBUG=no/yes and VS 2015/2017 - ... to trigger a new read to detect the stream close! + ... and invoke "curl -V" once done - Closes #4275 + Co-Authored-By: Jay Satiro + + Closes #4523 -- [Tatsuhiro Tsujikawa brought this change] +- [Francois Rivard brought this change] - ngtcp2: build latest ngtcp2 and ngtcp2_crypto_openssl + schannel: reverse the order of certinfo insertions - Closes #4278 + Fixes #4518 + Closes #4519 -- ngtcp2: set flow control window to stream buffer size +Marcel Raad (24 Oct 2019) +- test1591: fix spelling of http feature - Closes #4274 + The test never got run because the feature name is `http` in lowercase. + + Closes https://github.com/curl/curl/pull/4520 -- [Christopher Head brought this change] +Daniel Stenberg (23 Oct 2019) +- [Michał Janiszewski brought this change] - CURLOPT_HEADERFUNCTION.3: clarify + appveyor: Use two parallel compilation on appveyor with CMake - Closes #4273 - -- CURLINFO docs: mention that in redirects times are added + Appveyor provides 2 CPUs for each builder[1], make sure to use parallel + compilation, when running with CMake. CMake learned this new option in + version 3.12[2] and the version provided by appveyor is fresh enough. - Suggested-by: Brandon Dong - Fixes #4250 - Closes #4269 + Curl doesn't really take that long to build and it is using the slowest + builder available, msbuild, so expect only a moderate improvement in + build times. + + [1] https://www.appveyor.com/docs/build-environment/ + [2] https://cmake.org/cmake/help/v3.12/release/3.12.html + + Closes #4508 -- travis: enable ngtcp2 builds again +- conn-reuse: requests wanting NTLM can reuse non-NTLM connections - Switched to the openssl-quic-draft-22 openssl branch. + Added test case 338 to verify. - Closes #4271 + Reported-by: Daniel Silverstone + Fixes #4499 + Closes #4514 -- HTTP3: switched openssl branch to use +Marcel Raad (23 Oct 2019) +- tests: add missing proxy features -- [Tatsuhiro Tsujikawa brought this change] +Daniel Stenberg (22 Oct 2019) +- RELEASE-NOTES: synced - ngtcp2: Build with latest ngtcp2 and ngtcp2_crypto_openssl +Marcel Raad (21 Oct 2019) +- tests: use %FILE_PWD for file:// URLs - Closes #4270 + This way, we always have exactly one slash after the host name, making + the tests pass when curl is compiled with the MSYS GCC. + + Closes https://github.com/curl/curl/pull/4512 -- http2: when marked for closure and wanted to close == OK +- tests: add `connect to non-listen` keywords - It could otherwise return an error even when closed correctly if GOAWAY - had been received previously. + These tests try to connect to ports nothing is listening on. - Reported-by: Tom van der Woerdt - Fixes #4267 - Closes #4268 + Closes https://github.com/curl/curl/pull/4511 -- RELEASE-NOTES: synced +- runtests: get textaware info from curl instead of perl + + The MSYS system on Windows can run the test suite for curl built with + any toolset. When built with the MSYS GCC, curl uses Unix line endings, + while it uses Windows line endings when built with the MinGW GCC, and + `^O` reports 'msys' in both cases. Use the curl executable itself to + determine the line endings instead, which reports 'x86_64-pc-msys' when + built with the MSYS GCC. + + Closes https://github.com/curl/curl/pull/4506 -- build-openssl: fix build with Visual Studio 2019 +Daniel Stenberg (20 Oct 2019) +- [Michał Janiszewski brought this change] + + appveyor: Add MSVC ARM64 build - Reviewed-by: Marcel Raad - Contributed-by: osabc on github - Fixes #4188 - Closes #4266 + Closes #4507 -Kamil Dudka (26 Aug 2019) -- vauth: return CURLE_AUTH_ERROR on gss_init_sec_context() failure +- http2_recv: a closed stream trumps pause state - This is a follow-up to https://github.com/curl/curl/pull/3864 . + ... and thus should return 0, not EAGAIN. - Closes #4224 + Reported-by: Tom van der Woerdt + Fixes #4496 + Closes #4505 -Daniel Stenberg (26 Aug 2019) -- KNOWN_BUGS: USE_UNIX_SOCKETS on Windows +- http2: expire a timeout at end of stream - Closes #4040 + To make sure that transfer is being dealt with. Streams without + Content-Length need a final read to notice the end-of-stream state. + + Reported-by: Tom van der Woerdt + Fixes #4496 -- quiche: send the HTTP body correctly on callback uploads +Dan Fandrich (18 Oct 2019) +- travis: Add an ARM64 build - Closes #4265 + Test 323 is failing for some reason, so disable it there for now. -- travis: disable ngtcp2 builds (temporarily) +Marcel Raad (18 Oct 2019) +- examples/sslbackend: fix -Wchar-subscripts warning - Just too many API changes right now + With the `isdigit` implementation that comes with MSYS2, the argument + is used as an array subscript, resulting in a -Wchar-subscripts + warning. `isdigit`'s behavior is undefined if the argument is negative + and not EOF [0]. As done in lib/curl_ctype.h, cast the `char` variable + to `unsigned char` to avoid that. - Closes #4264 - -- ngtcp2: add support for SSLKEYLOGFILE + [0] https://en.cppreference.com/w/c/string/byte/isdigit - Closes #4260 + Closes https://github.com/curl/curl/pull/4503 -- ngtcp2: improve h3 response receiving +Daniel Stenberg (18 Oct 2019) +- configure: remove all cyassl references - Closes #4259 - -- ngtcp2: use nghttp3_version() - -- ngtcp2: sync with upstream API changes + In particular, this removes the case where configure would find an old + cyall installation rather than a wolfssl one if present. The library is + named wolfssl in modern days so there's no real need to keep support for + the former. - Assisted-by: Tatsuhiro Tsujikawa - -- [Kyle Abramowitz brought this change] + Reported-by: Jacob Barthelmeh + Closes #4502 - scp: fix directory name length used in memcpy - - Fix read off end of array due to bad pointer math in getworkingpath for - SCP home directory case. +Marcel Raad (17 Oct 2019) +- test1162: disable MSYS2's POSIX path conversion - Closes #4258 + This avoids MSYS2 converting the backslasb in the URL to a slash, + causing the test to fail. -- http: the 'closed' struct field is used by both ngh2 and ngh3 +Daniel Stenberg (17 Oct 2019) +- RELEASE-NOTES: synced + +Jay Satiro (16 Oct 2019) +- CURLOPT_TIMEOUT.3: Clarify transfer timeout time includes queue time - and remove 'header_recvbuf', not used for anything + Prior to this change some users did not understand that the "request" + starts when the handle is added to the multi handle, or probably they + did not understand that some of those transfers may be queued and that + time is included in timeout. - Reported-by: Jeremy Lainé + Reported-by: Jeroen Ooms - Closes #4257 + Fixes https://github.com/curl/curl/issues/4486 + Closes https://github.com/curl/curl/pull/4489 -- ngtcp2: accept upload via callback - - Closes #4256 +- [Stian Soiland-Reyes brought this change] -- defines: avoid underscore-prefixed defines - - Double-underscored or underscore plus uppercase letter at least. + tool_operate: Fix retry sleep time shown to user when Retry-After - ... as they're claimed to be reserved. + - If server header Retry-After is being used for retry sleep time then + show that value to the user instead of the normal retry sleep time. - Reported-by: patnyb on github + This is a follow-up to 640b973 (7.66.0) which changed curl tool so that + the value from Retry-After header overrides other retry timing options. - Fixes #4254 - Closes #4255 + Closes https://github.com/curl/curl/pull/4498 -- travis: add a build using ngtcp2 + nghttp3 (and a patched OpenSSL) +Daniel Stenberg (16 Oct 2019) +- url: normalize CURLINFO_EFFECTIVE_URL + + The URL extracted with CURLINFO_EFFECTIVE_URL was returned as given as + input in most cases, which made it not get a scheme prefixed like before + if the URL was given without one, and it didn't remove dotdot sequences + etc. + + Added test case 1907 to verify that this now works as intended and as + before 7.62.0. - Runs no tests + Regression introduced in 7.62.0 - Closes #4253 + Reported-by: Christophe Dervieux + Fixes #4491 + Closes #4493 -- travis: bump to using nghttp2 version 1.39.2 +Marcel Raad (16 Oct 2019) +- tests: line ending fixes for Windows - Closes #4252 - -- [Gisle Vanem brought this change] + Mark some files as text. + + Closes https://github.com/curl/curl/pull/4490 - docs/examples/curlx: fix errors +- tests: use proxy feature - Initialise 'mimetype' and require the -p12 arg. + This makes the tests succeed when using --disable-proxy. - Closes #4248 + Closes https://github.com/curl/curl/pull/4488 -- cleanup: remove DOT_CHAR completely +- smbserver: fix Python 3 compatibility - Follow-up to f9c7ba9096ec + Python 2's `ConfigParser` module is spelled `configparser` in Python 3. - The use of DOT_CHAR for ".ssh" was probably a mistake and is removed - now. + Closes https://github.com/curl/curl/pull/4484 + +- security: silence conversion warning - Pointed-out-by: Gisle Vanem - Bug: https://github.com/curl/curl/pull/4230#issuecomment-522960638 + With MinGW-w64, `curl_socket_t` is is a 32 or 64 bit unsigned integer, + while `read` expects a 32 bit signed integer. + Use `sread` instead of `read` to use the correct parameter type. - Closes #4247 + Closes https://github.com/curl/curl/pull/4483 -- spnego_sspi: add typecast to fix build warning +- connect: silence sign-compare warning - Reported in build "Win32 target on Debian Stretch (64-bit) - - i686-w64-mingw32 - gcc-20170516" + With MinGW-w64 using WinSock, `curl_socklen_t` is signed, while the + result of `sizeof` is unsigned. - Closes #4245 + Closes https://github.com/curl/curl/pull/4483 -- openssl: build warning free with boringssl +Daniel Stenberg (13 Oct 2019) +- TODO: Handle growing SFTP files - Closes #4244 + Closes #4344 -- curl: make --libcurl use CURL_HTTP_VERSION_3 +- KNOWN_BUGS: remove "CURLFORM_CONTENTLEN in an array" - Closes #4243 + The curl_formadd() function is deprecated and shouldn't be used so the + real fix for applications is to switch to the curl_mime_* API. -- ngtcp2: make postfields-set posts work +- KNOWN_BUGS: "LDAP on Windows does authentication wrong" - Closes #4242 + Closes #3116 -- http: remove chunked-encoding and expect header use for HTTP/3 +- appveyor: add a winbuild that uses VS2017 + + Closes #4482 -- [Alessandro Ghedini brought this change] +- [Harry Sintonen brought this change] - configure: use pkg-config to detect quiche + socketpair: fix include and define for older TCP header systems - This removes the need to hard-code the quiche target path in - configure.ac. + fixed build for systems that need netinet/in.h for IPPROTO_TCP and are + missing INADDR_LOOPBACK - This depends on https://github.com/cloudflare/quiche/pull/128 + Closes #4480 + +- socketpair: fix double-close in error case - Closes #4237 + Follow-up to bc2dbef0afc08 -- CURLOPT_SSL_VERIFYHOST: treat the value 1 as 2 +- gskit: use the generic Curl_socketpair + +- asyn-thread: make use of Curl_socketpair() where available + +- socketpair: an implemention for Windows and more - For a long time (since 7.28.1) we've returned error when setting the - value to 1 to make applications notice that we stopped supported the old - behavior for 1. Starting now, we treat 1 and 2 exactly the same. + Curl_socketpair() is designed to be used and work everywhere if there's + no native version or the native version isn't good enough. - Closes #4241 + Closes #4466 -- curl: use .curlrc (with a dot) on Windows as well +- RELEASE-NOTES: synced + +- connect: return CURLE_OPERATION_TIMEDOUT for errno == ETIMEDOUT - Fall-back to _curlrc if the dot-version is missing. + Previosly all connect() failures would return CURLE_COULDNT_CONNECT, no + matter what errno said. - Co-Authored-By: Steve Holme + This makes for example --retry work on these transfer failures. - Closes #4230 + Reported-by: Nathaniel J. Smith + Fixes #4461 + Clsoes #4462 -- netrc: make the code try ".netrc" on Windows as well - - ... but fall back and try "_netrc" too if the dot version didn't work. - - Co-Authored-By: Steve Holme +- cirrus: switch off blackhole status on the freebsd CI machines -- ngtcp2: use ngtcp2_version() to get the run-time version - - ... which of course doesn't have to be the same used at build-time. +- tests: use port 2 instead of 60000 for a safer non-listening port - Function just recently merged in ngtcp2. + ... when the tests want "connection refused". -- ngtcp2: move the h3 initing to immediately after the rx key +- KNOWN_BUGS: IDN tests failing on Windows - To fix a segfault and to better deal with 0-RTT + Closes #3747 + +Dan Fandrich (9 Oct 2019) +- cirrus: Increase the git clone depth. - Assisted-by: Tatsuhiro Tsujikawa + If more commits are submitted to master between the time of triggering + the first Cirrus build and the time the final build gets started, the + desired commit is no longer at HEAD and the build will error out. + [skip ci] -- [Alessandro Ghedini brought this change] +Daniel Stenberg (9 Oct 2019) +- docs: make sure the --no-progress-meter docs file is in dist too - quiche: register debug callback once and earlier - - The quiche debug callback is global and can only be initialized once, so - make sure we don't do it multiple times (e.g. if multiple requests are - executed). +- docs: document it as --no-progress-meter instead of the reverse - In addition this initializes the callback before the connection is - created, so we get logs for the handshake as well. + Follow-up to 93373a960c3bb4 - Closes #4236 + Reported-by: infinnovation-dev on github + Fixes #4474 + Closes #4475 -- ssh: add a generic Curl_ssh_version function for SSH backends +Dan Fandrich (9 Oct 2019) +- cirrus: Switch the FreeBSD 11.x build to 11.3 and add a 13.0 build. - Closes #4235 - -- base64: check for SSH, not specific SSH backends - -- vssh: move ssh init/cleanup functions into backend code - -- vssh: create directory for SSH backend code + Also, select the images using image_family to get the latest snapshots + automatically. + [skip ci] -- TODO/ROADMAP: remove "refuse downgrade redirects" and HTTP/3 +Daniel Stenberg (8 Oct 2019) +- curl: --no-progress-meter - HTTP3 is now already in full progress + New option that allows a user to ONLY switch off curl's progress meter + and leave everything else in "talkative" mode. - Downgrade redirects can be achived almost exactly like that by setting - CURLOPT_REDIR_PROTOCOLS. - -- RELEASE-NOTES: synced + Reported-by: Piotr Komborski + Fixes #4422 + Closes #4470 -- travis: add a quiche build +- TODO: Consult %APPDATA% also for .netrc - Closes #4207 + Closes #4016 -- http: fix use of credentials from URL when using HTTP proxy - - When a username and password are provided in the URL, they were wrongly - removed from the stored URL so that subsequent uses of the same URL - wouldn't find the crendentials. This made doing HTTP auth with multiple - connections (like Digest) mishave. +- CURLOPT_TIMEOUT.3: remove the mention of "minutes" - Regression from 46e164069d1a5230 (7.62.0) + ... just say that limiting operations risk aborting otherwise fine + working transfers. If that means seconds, minutes or hours, we leave to + the user. - Test case 335 added to verify. + Reported-by: Martin Gartner + Closes #4469 + +- [Andrei Valeriu BICA brought this change] + + docs: added multi-event.c example - Reported-by: Mike Crowe + Similar to multi-uv.c but using libevent 2. This is a simpler libevent + integration example then hiperfifo.c. - Fixes #4228 - Closes #4229 + Closes #4471 -- [Mike Crowe brought this change] +Jay Satiro (5 Oct 2019) +- [Nicolas brought this change] - tests: Replace outdated test case numbering documentation + ldap: fix OOM error on missing query string - Tests are no longer grouped by numeric range[1]. Let's stop saying that - and provide some alternative advice for numbering tests. + - Allow missing queries, don't return NO_MEMORY error in such a case. - [1] https://curl.haxx.se/mail/lib-2019-08/0043.html + It is acceptable for there to be no specified query string, for example: - Closes #4227 - -- travis: reduce number of torture tests in 'coverage' + curl ldap://ldap.forumsys.com - ... to make it complete in time. This cut seems not almost not affect - the coverage percentage and yet completes within 35 minutes on travis - where the previous runs recently always timed out after 50. + A regression bug in 1b443a7 caused this issue. - Closes #4223 - -- [Igor Makarov brought this change] - - configure: use -lquiche to link to quiche + This is a partial fix for #4261. - Closes #4226 - -- ngtcp2: provide the callbacks as a static struct + Bug: https://github.com/curl/curl/issues/4261#issuecomment-525543077 + Reported-by: Jojojov@users.noreply.github.com + Analyzed-by: Samuel Surtees - ... instead of having them in quicsocket + Closes https://github.com/curl/curl/pull/4467 -- [Tatsuhiro Tsujikawa brought this change] +- [Paul B. Omta brought this change] - ngtcp2: add missing nghttp3_conn_add_write_offset call + build: Remove unused HAVE_LIBSSL and HAVE_LIBCRYPTO defines - Closes #4225 - -- [Tatsuhiro Tsujikawa brought this change] - - ngtcp2: deal with stream close - -- [Tatsuhiro Tsujikawa brought this change] - - ngtcp2: Consume QUIC STREAM data properly + Closes https://github.com/curl/curl/pull/4460 -- [Tatsuhiro Tsujikawa brought this change] +Daniel Stenberg (5 Oct 2019) +- RELEASE-NOTES: synced - ngtcp2: don't reinitialize SSL on Retry +- [Stian Soiland-Reyes brought this change] -- multi: getsock improvements for QUIC connecting + curl: ensure HTTP 429 triggers --retry + + This completes #3794. + + Also make sure the new tests from #4195 are enabled + + Closes #4465 -- connect: connections are persistent by default for HTTP/3 +Marcel Raad (4 Oct 2019) +- [apique brought this change] -- quiche: happy eyeballs + winbuild: add ENABLE_UNICODE option - Closes #4220 - -- ngtcp2: do QUIC connections happy-eyeballs friendly + Fixes https://github.com/curl/curl/issues/4308 + Closes https://github.com/curl/curl/pull/4309 -- curl_version: bump string buffer size to 250 +Daniel Stenberg (4 Oct 2019) +- ngtcp2: adapt to API change - With HTTP/3 libs and plenty TLS libs, I manged to hit the limit (which - causes a truncated output). + Closes #4457 -- CURLOPT_ALTSVC.3: use a "" file name to not load from a file +- cookies: change argument type for Curl_flush_cookies + + The second argument is really a 'bool' so use that and pass in TRUE/FALSE + to make it clear. + + Closes #4455 -Jay Satiro (14 Aug 2019) -- vauth: Use CURLE_AUTH_ERROR for auth function errors +- http2: move state-init from creation to pre-transfer - - Add new error code CURLE_AUTH_ERROR. + To make sure that the HTTP/2 state is initialized correctly for + duplicated handles. It would otherwise easily generate "spurious" + PRIORITY frames to get sent over HTTP/2 connections when duplicated easy + handles were used. - Prior to this change auth function errors were signaled by - CURLE_OUT_OF_MEMORY and CURLE_RECV_ERROR, and neither one was - technically correct. + Reported-by: Daniel Silverstone + Fixes #4303 + Closes #4442 + +- urlapi: fix use-after-free bug - Ref: https://github.com/curl/curl/pull/3848 + Follow-up from 2c20109a9b5d04 - Co-authored-by: Dominik Hölzl + Added test 663 to verify. - Closes https://github.com/curl/curl/pull/3864 + Reported by OSS-Fuzz + Bug: https://crbug.com/oss-fuzz/17954 + + Closes #4453 -Daniel Stenberg (13 Aug 2019) -- curl_version_info: make the quic_version a const +- [Paul Dreik brought this change] + + cookie: avoid harmless use after free - Follow-up from 1a2df1518ad8653f + This fix removes a use after free which can be triggered by + the internal cookie fuzzer, but otherwise is probably + impossible to trigger from an ordinary application. - Closes #4222 - -- examples: add http3.c, altsvc.c and http3-present.c + The following program reproduces it: - Closes #4221 - -Peter Wu (13 Aug 2019) -- nss: use TLSv1.3 as default if supported + curl_global_init(CURL_GLOBAL_DEFAULT); + CURL* handle=curl_easy_init(); + CookieInfo* info=Curl_cookie_init(handle,NULL,NULL,false); + curl_easy_setopt(handle, CURLOPT_COOKIEJAR, "/dev/null"); + Curl_flush_cookies(handle, true); + Curl_cookie_cleanup(info); + curl_easy_cleanup(handle); + curl_global_cleanup(); - SSL_VersionRangeGetDefault returns (TLSv1.0, TLSv1.2) as supported - range in NSS 3.45. It looks like the intention is to raise the minimum - version rather than lowering the maximum, so adjust accordingly. Note - that the caller (nss_setup_connect) initializes the version range to - (TLSv1.0, TLSv1.3), so there is no need to check for >= TLSv1.0 again. + This was found through fuzzing. - Closes #4187 - Reviewed-by: Daniel Stenberg - Reviewed-by: Kamil Dudka + Closes #4454 -Daniel Stenberg (13 Aug 2019) -- quic.h: remove unused proto +- [Denis Chaplygin brought this change] -- curl_version_info.3: mentioned ALTSVC and HTTP3 + docs: add note on failed handles not being counted by curl_multi_perform - ... and sorted the list alphabetically + Closes #4446 -- lib/quic.c: unused - removed +- CURLMOPT_MAX_CONCURRENT_STREAMS.3: fix SEE ALSO typo -- CURLOPT_ALTSVC_CTRL.3: remove CURLALTSVC_ALTUSED +- [Niall O'Reilly brought this change] + + ESNI: initial build/setup - Follow-up to 98c3f148 that removed it from the header file + Closes #4011 -- [Junho Choi brought this change] +- RELEASE-NOTES: synced - docs/HTTP3: simplify quiche build instruction +- redirect: when following redirects to an absolute URL, URL encode it - Use --recursive to get boringssl in one line + ... to make it handle for example (RFC violating) embeded spaces. - Closes #4219 + Reported-by: momala454 on github + Fixes #4445 + Closes #4447 -- altsvc: make it use h3-22 with ngtcp2 as well +- urlapi: fix URL encoding when setting a full URL -- ngtcp2: initial h3 request work - - Closes #4217 +- tool_operate: rename functions to make more sense -- curl_version_info: offer quic (and h3) library info +- curl: create easy handles on-demand and not ahead of time - Closes #4216 - -- HTTP3: use ngtcp2's draft-22 branch + This should again enable crazy-large download ranges of the style + [1-10000000] that otherwise easily ran out of memory starting in 7.66.0 + when this new handle allocating scheme was introduced. + + Reported-by: Peter Sumatra + Fixes #4393 + Closes #4438 -- RELEASE-NOTES: synced +- [Kunal Ekawde brought this change] -- CURLOPT_READFUNCTION.3: provide inline example + CURLMOPT_MAX_CONCURRENT_STREAMS: new setopt - ... instead of mentioning one in another place - -- [Tatsuhiro Tsujikawa brought this change] + Closes #4410 - ngtcp2: send HTTP/3 request with nghttp3 +- chunked-encoding: stop hiding the CURLE_BAD_CONTENT_ENCODING error - This commit makes sending HTTP/3 request with nghttp3 work. It - minimally receives HTTP response and calls nghttp3 callbacks, but no - processing is made at the moment. + Unknown content-encoding would get returned as CURLE_WRITE_ERROR if the + response is chunked-encoded. - Closes #4215 - -- nghttp3: initial h3 template code added + Reported-by: Ilya Kosarev + Fixes #4310 + Closes #4449 -- nghttp3: required when ngtcp2 is used for QUIC +Marcel Raad (1 Oct 2019) +- checksrc: fix uninitialized variable warning - - checked for by configure - - updated docs/HTTP3.md - - shown in the version string + The loop doesn't need to be executed without a file argument. - Closes #4210 - -- [Eric Wong brought this change] + Closes https://github.com/curl/curl/pull/4444 - asyn-thread: issue CURL_POLL_REMOVE before closing socket - - This avoids EBADF errors from EPOLL_CTL_DEL operations in the - ephiperfifo.c example. EBADF is dangerous in multi-threaded - applications where I rely on epoll_ctl to operate on the same - epoll description from different threads. +- urlapi: fix unused variable warning - Follow-up to eb9a604f8d7db8 + `dest` is only used with `ENABLE_IPV6`. - Bug: https://curl.haxx.se/mail/lib-2019-08/0026.html - Closes #4211 + Closes https://github.com/curl/curl/pull/4444 -- [Carlo Marcelo Arenas Belón brought this change] +- lib: silence conversion warnings + + Closes https://github.com/curl/curl/pull/4444 - configure: avoid undefined check_for_ca_bundle +- AppVeyor: add 32-bit MinGW-w64 build - instead of using a "greater than 0" test, check for variable being - set, as it is always set to 1, and could be left unset if non of - OPENSSL MBEDTLS GNUTLS WOLFSSL is being configured for. + With WinSSL and testing enabled so that it would have detected most of + the warnings fixed in [0] and [1]. - Closes #4213 - -- [Tatsuhiro Tsujikawa brought this change] - - ngtcp2: Send ALPN h3-22 + [0] https://github.com/curl/curl/pull/4398 + [1] https://github.com/curl/curl/pull/4415 - Closes #4212 - -- [Tatsuhiro Tsujikawa brought this change] - - ngtcp2: use ngtcp2_settings_default and specify initial_ts - -- curl_global_init_mem.3: mention it was added in 7.12.0 - -- [Tatsuhiro Tsujikawa brought this change] + Closes https://github.com/curl/curl/pull/4433 - ngtcp2: make the QUIC handshake work +- AppVeyor: remove MSYS2_ARG_CONV_EXCL for winbuild - Closes #4209 + It's only used for MSYS2 with MinGW. + + Closes -- [Alex Mayorga brought this change] +Daniel Stenberg (30 Sep 2019) +- [Emil Engler brought this change] - HTTP3.md: Update quiche build instructions - - Added cloning for quiche and BoringSSL and modified the build - instructions so they work on a clean folder. + git: add tests/server/disabled to .gitignore - Closes #4208 + Closes #4441 -- CURLOPT_H3: removed +- altsvc: accept quoted ma and persist values - There's no use for this anymore and it was never in a release. + As mandated by the spec. Test 1654 is extended to verify. - Closes #4206 + Closes #4443 -- http3: make connection reuse work - - Closes #4204 +- mailmap: a Lucas fix -- quiche: add SSLKEYLOGFILE support +Alessandro Ghedini (29 Sep 2019) +- [Lucas Pardue brought this change] -- cleanup: s/curl_debug/curl_dbg_debug in comments and docs - - Leftovers from the function rename back in 76b63489495 - - Reported-by: Gisle Vanem - Bug: https://github.com/curl/curl/commit/f3e0f071b14fcb46a453f69bdf4e062bcaacf362#com - mitcomment-34601751 - - Closes #4203 + quiche: update HTTP/3 config creation to new API -- RELEASE-NOTES: synced +Daniel Stenberg (29 Sep 2019) +- BINDINGS: PureBasic, Net::Curl for perl and Nim -- alt-svc: add protocol version selection masking - - So that users can mask in/out specific HTTP versions when Alt-Svc is - used. - - - Removed "h2c" and updated test case accordingly - - Changed how the altsvc struct is laid out - - Added ifdefs to make the unittest run even in a quiche-tree +- BINDINGS: Kapito is an Erlang library, basically a binding + +- BINDINGS: added clj-curl - Closes #4201 + Reported-by: Lucas Severo + +- [Jay Satiro brought this change] -- http3: fix the HTTP/3 in the request, make alt-svc set right versions + docs: disambiguate CURLUPART_HOST is for host name (ie no port) - Closes #4200 + Closes #4424 -- alt-svc: send Alt-Used: in redirected requests +- cookies: using a share with cookies shouldn't enable the cookie engine - RFC 7838 section 5: + The 'share object' only sets the storage area for cookies. The "cookie + engine" still needs to be enabled or activated using the normal cookie + options. - When using an alternative service, clients SHOULD include an Alt-Used - header field in all requests. + This caused the curl command line tool to accidentally use cookies + without having been told to, since curl switched to using shared cookies + in 7.66.0. - Removed CURLALTSVC_ALTUSED again (feature is still EXPERIMENTAL thus - this is deemed ok). + Test 1166 verifies - You can disable sending this header just like you disable any other HTTP - header in libcurl. + Updated test 506 - Closes #4199 + Fixes #4429 + Closes #4434 -- CURLOPT_HTTP_VERSION: seting this to 3 forces HTTP/3 use directly - - Even though it cannot fall-back to a lower HTTP version automatically. The - safer way to upgrade remains via CURLOPT_ALTSVC. - - CURLOPT_H3 no longer has any bits that do anything and might be removed - before we remove the experimental label. - - Updated the curl tool accordingly to use "--http3". - - Closes #4197 +- setopt: handle ALTSVC set to NULL -- docs/ALTSVC: remove what works and the experimental explanation - - Also, put the TODO items at the bottom. +- RELEASE-NOTES: synced + +- [grdowns brought this change] + + INSTALL: add vcpkg installation instructions - Closes #4198 + Closes #4435 -- docs/EXPERIMENTAL: explain what it means and what's experimental now +- [Zenju brought this change] -- curl: make use of CURLINFO_RETRY_AFTER when retrying + FTP: add test for FTPFILE_NOCWD: Avoid redundant CWDs - If a Retry-After: header was used in the response, that value overrides - other retry timing options. + Add libtest 661 - Fixes #3794 - Closes #4195 + Closes #4417 -- curl: use CURLINFO_PROTOCOL to check for HTTP(s) +- [Zenju brought this change] + + FTP: url-decode path before evaluation - ... instead of CURLINFO_EFFECTIVE_URL to avoid string operations. + Closes #4428 -- CURLINFO_RETRY_AFTER: parse the Retry-After header value +Marcel Raad (27 Sep 2019) +- tests: fix narrowing conversion warnings - This is only the libcurl part that provides the information. There's no - user of the parsed value. This change includes three new tests for the - parser. + `timediff_t` is 64 bits wide also on 32-bit systems since + commit b1616dad8f0. - Ref: #3794 + Closes https://github.com/curl/curl/pull/4415 -- docs/ALTSVC.md: first basic file format description +Jay Satiro (27 Sep 2019) +- [julian brought this change] -- curl: have -w's 'http_version' show '3' for HTTP/3 + vtls: Fix comment typo about macosx-version-min compiler flag - Closes #4196 + Closes https://github.com/curl/curl/pull/4425 -- curl.h: add CURL_HTTP_VERSION_3 to the version enum +Daniel Stenberg (26 Sep 2019) +- [Yechiel Kalmenson brought this change] + + README: minor grammar fix - It can't be set for CURLOPT_HTTP_VERSION, but it can be extracted with - CURLINFO_HTTP_VERSION. + Closes #4431 -- quiche: make use of the connection timeout API properly +- [Spezifant brought this change] -- quiche: make POSTFIELDS posts work + HTTP3: fix prefix parameter for ngtcp2 build + + Closes #4430 -- quiche: improved error handling and memory cleanups +- quiche: don't close connection at end of stream! -- quiche: flush egress in h3_stream_recv() too +- quiche: set 'drain' when returning without having drained the queues -- RELEASE-NOTES: synced +- Revert "FTP: url-decode path before evaluation" + + This reverts commit 2f036a72d543e96128bd75cb0fedd88815fd42e2. -Jay Satiro (6 Aug 2019) -- [Patrick Monnerat brought this change] +- HTTP3: merged and simplified the two 'running' sections - os400: take care of CURLOPT_SASL_AUTHZID in curl_easy_setopt_ccsid(). +- HTTP3: show an --alt-svc using example too + +- [Zenju brought this change] + + FTP: url-decode path before evaluation - Ref: https://github.com/curl/curl/issues/3653 - Ref: https://github.com/curl/curl/pull/3790 + Closes #4423 + +- openssl: use strerror on SSL_ERROR_SYSCALL - NOTE: This commit was cherry-picked and is part of a series of commits - that added the authzid feature for upcoming 7.66.0. The series was - temporarily reverted in db8ec1f so that it would not ship in a 7.65.x - patch release. + Instead of showing the somewhat nonsensical errno number, use strerror() + to provide a more relatable error message. - Closes https://github.com/curl/curl/pull/4186 + Closes #4411 -- tests: Fix the line endings for the SASL alt-auth tests +- HTTP3: update quic.aiortc.org + add link to server list - - Change data and protocol sections to CRLF line endings. + Reported-by: Jeremy Lainé + +Jay Satiro (26 Sep 2019) +- url: don't set appconnect time for non-ssl/non-ssh connections - Prior to this change the tests would fail or hang, which is because - certain sections such as protocol require CRLF line endings. + Prior to this change non-ssl/non-ssh connections that were reused set + TIMER_APPCONNECT [1]. Arguably that was incorrect since no SSL/SSH + handshake took place. - Follow-up to grandparent commit which added the tests. + [1]: TIMER_APPCONNECT is publicly known as CURLINFO_APPCONNECT_TIME in + libcurl and %{time_appconnect} in the curl tool. It is documented as + "the time until the SSL/SSH handshake is completed". - Ref: https://github.com/curl/curl/issues/3653 - Ref: https://github.com/curl/curl/pull/3790 + Reported-by: Marcel Hernandez - NOTE: This commit was cherry-picked and is part of a series of commits - that added the authzid feature for upcoming 7.66.0. The series was - temporarily reverted in db8ec1f so that it would not ship in a 7.65.x - patch release. + Ref: https://github.com/curl/curl/issues/3760 - Closes https://github.com/curl/curl/pull/4186 - -- [Steve Holme brought this change] + Closes https://github.com/curl/curl/pull/3773 - examples: Added SASL PLAIN authorisation identity (authzid) examples - - Ref: https://github.com/curl/curl/issues/3653 - Ref: https://github.com/curl/curl/pull/3790 +Daniel Stenberg (25 Sep 2019) +- ngtcp2: remove fprintf() calls - NOTE: This commit was cherry-picked and is part of a series of commits - that added the authzid feature for upcoming 7.66.0. The series was - temporarily reverted in db8ec1f so that it would not ship in a 7.65.x - patch release. + - convert some of them to H3BUF() calls to infof() + - remove some of them completely + - made DEBUG_HTTP3 defined only if CURLDEBUG is set for now - Closes https://github.com/curl/curl/pull/4186 + Closes #4421 -- [Steve Holme brought this change] +- [Jay Satiro brought this change] - curl: --sasl-authzid added to support CURLOPT_SASL_AUTHZID from the tool - - Ref: https://github.com/curl/curl/issues/3653 - Ref: https://github.com/curl/curl/pull/3790 + url: fix the NULL hostname compiler warning case - NOTE: This commit was cherry-picked and is part of a series of commits - that added the authzid feature for upcoming 7.66.0. The series was - temporarily reverted in db8ec1f so that it would not ship in a 7.65.x - patch release. + Closes #4403 + +- [Jay Satiro brought this change] + + travis: move the go install to linux-only - Closes https://github.com/curl/curl/pull/4186 + ... to repair the build again + Closes #4403 -- [Steve Holme brought this change] +- altsvc: correct the #ifdef for the ngtcp2 backend - sasl: Implement SASL authorisation identity via CURLOPT_SASL_AUTHZID +- altsvc: save h3 as h3-23 - Added the ability for the calling program to specify the authorisation - identity (authzid), the identity to act as, in addition to the - authentication identity (authcid) and password when using SASL PLAIN - authentication. + Follow-up to d176a2c7e5 + +- urlapi: question mark within fragment is still fragment - Fixes #3653 - Closes #3790 + The parser would check for a query part before fragment, which caused it + to do wrong when the fragment contains a question mark. - NOTE: This commit was cherry-picked and is part of a series of commits - that added the authzid feature for upcoming 7.66.0. The series was - temporarily reverted in db8ec1f so that it would not ship in a 7.65.x - patch release. + Extended test 1560 to verify. - Closes https://github.com/curl/curl/pull/4186 - -Daniel Stenberg (6 Aug 2019) -- docs/HTTP3: refreshed as it is now in master and HTTP/3 can be tested + Reported-by: Alex Konev + Fixes #4412 + Closes #4413 -- [Yiming Jing brought this change] +- [Alex Samorukov brought this change] - mesalink: implement client authentication + HTTP3.md: move -p for mkdir, remove -j for make - Closes #4184 + - mkdir on OSX/Darwin requires `-p` argument before dir + + - portabbly figuring out number of cores is an exercise for somewhere + else + + Closes #4407 -- curl_multi_poll: a sister to curl_multi_wait() that waits more +Patrick Monnerat (24 Sep 2019) +- os400: getpeername() and getsockname() return ebcdic AF_UNIX sockaddr, - Repeatedly we see problems where using curl_multi_wait() is difficult or - just awkward because if it has no file descriptor to wait for - internally, it returns immediately and leaves it to the caller to wait - for a small amount of time in order to avoid occasional busy-looping. + As libcurl now uses these 2 system functions, wrappers are needed on os400 + to convert returned AF_UNIX sockaddrs to ascii. - This is often missed or misunderstood, leading to underperforming - applications. + This is a follow-up to commit 7fb54ef. + See also #4037. + Closes #4214 + +Jay Satiro (24 Sep 2019) +- [Lucas Pardue brought this change] + + strcase: fix raw lowercasing the letter X - This change introduces curl_multi_poll() as a replacement drop-in - function that accepts the exact same set of arguments. This function - works identically to curl_multi_wait() - EXCEPT - for the case when - there's nothing to wait for internally, as then this function will by - itself wait for a "suitable" short time before it returns. This - effectiely avoids all risks of busy-looping and should also make it less - likely that apps "over-wait". + Casing mistake in Curl_raw_tolower 'X' wasn't lowercased as 'x' prior to + this change. - This also changes the curl tool to use this funtion internally when - doing parallel transfers and changes curl_easy_perform() to use it - internally. + Follow-up to 0023fce which added the function several days ago. + + Ref: https://github.com/curl/curl/pull/4401#discussion_r327396546 - Closes #4163 + Closes https://github.com/curl/curl/pull/4408 -- quiche:h3_stream_recv return 0 at end of stream +Daniel Stenberg (23 Sep 2019) +- http2: Expression 'stream->stream_id != - 1' is always true - ... and remove some verbose messages we don't need. Made transfers from - facebook.com work better. - -- altsvc: make quiche use h3-22 now + PVS-Studio warning + Fixes #4402 -- quiche: show the actual version number +- http2: A value is being subtracted from the unsigned variable + + PVS-Studio warning + Fixes #4402 -- quiche: first working HTTP/3 request +- libssh: part of conditional expression is always true: !result - - enable debug log - - fix use of quiche API - - use download buffer - - separate header/body + PVS-Studio warning + Fixed #4402 + +- libssh: part of conditional expression is always true - Closes #4193 + PVS-Studio warning + Fixes #4402 -- http09: disable HTTP/0.9 by default in both tool and library +- libssh: The expression is excessive or contains a misprint - As the plan has been laid out in DEPRECATED. Update docs accordingly and - verify in test 1174. Now requires the option to be set to allow HTTP/0.9 - responses. + PVS-Studio warning + Fixes #4402 + +- quiche: The expression must be surrounded by parentheses - Closes #4191 + PVS-Studio warning + Fixes #4402 -- quiche: initial h3 request send/receive +- vauth: The parameter 'status' must be surrounded by parentheses + + PVS-Studio warning + Fixes #4402 -- lib/Makefile.am: make checksrc run in vquic too +- [Paul Dreik brought this change] -- altsvc: fix removal of expired cache entry + doh: allow only http and https in debug mode - Closes #4192 + Otherwise curl may be told to use for instance pop3 to + communicate with the doh server, which most likely + is not what you want. + + Found through fuzzing. + + Closes #4406 -- RELEASE-NOTES: synced +- [Paul Dreik brought this change] -Steve Holme (4 Aug 2019) -- md4: Use our own MD4 implementation when no crypto libraries are available + doh: return early if there is no time left - Closes #3780 + Closes #4406 -- md4: No need to include Curl_md4.h for each TLS library +- [Barry Pollard brought this change] -- md4: No need for the NTLM code to call Curl_md4it() for each TLS library + http: lowercase headernames for HTTP/2 and HTTP/3 - As the NTLM code no longer calls any of TLS libraries' specific MD4 - functions, there is no need to call this function for each #ifdef. + Closes #4401 + Fixes #4400 -- md4: Move the mbed TLS MD4 implementation out of the NTLM code +Marcel Raad (23 Sep 2019) +- vtls: fix narrowing conversion warnings + + Curl_timeleft returns `timediff_t`, which is 64 bits wide also on + 32-bit systems since commit b1616dad8f0. + + Closes https://github.com/curl/curl/pull/4398 -- md4: Move the WinCrypt implementation out of the NTLM code +Daniel Stenberg (23 Sep 2019) +- [Joel Depooter brought this change] -- md4: Move the SecureTransport implementation out of the NTLM code + winbuild: Add manifest to curl.exe for proper OS version detection + + This is a small fix to commit ebd213270a017a6830928ee2e1f4a9cabc799898 + in pull request #1221. That commit added the CURL_EMBED_MANIFEST flag to + CURL_RC_FLAGS. However, later in the file CURL_RC_FLAGS is + overwritten. The fix is to append values to CURL_RC_FLAGS instead of + overwriting + + Closes #4399 -- md4: Use the Curl_md4it() function for OpenSSL based NTLM +- RELEASE-NOTES: synced -- md4: Move the GNU TLS gcrypt MD4 implementation out of the NTLM code +Marcel Raad (22 Sep 2019) +- openssl: fix compiler warning with LibreSSL + + It was already fixed for BoringSSL in commit a0f8fccb1e0. + LibreSSL has had the second argument to SSL_CTX_set_min_proto_version + as uint16_t ever since the function was added in [0]. + + [0] https://github.com/libressl-portable/openbsd/commit/56f107201baefb5533486d665a58d8f57fd3aeda + + Closes https://github.com/curl/curl/pull/4397 -- md4: Move the GNU TLS Nettle MD4 implementation out of the NTLM code +Daniel Stenberg (22 Sep 2019) +- curl: exit the create_transfers loop on errors + + When looping around the ranges and given URLs to create transfers, all + errors should exit the loop and return. Previously it would keep + looping. + + Reported-by: SumatraPeter on github + Bug: #4393 + Closes #4396 -Jay Satiro (4 Aug 2019) -- OS400: Add CURLOPT_H3 symbols +Jay Satiro (21 Sep 2019) +- socks: Fix destination host shown on SOCKS5 error - Follow-up to 3af0e76 which added experimental H3 support. + Prior to this change when a server returned a socks5 connect error then + curl would parse the destination address:port from that data and show it + to the user as the destination: - Closes https://github.com/curl/curl/pull/4185 + curld -v --socks5 10.0.3.1:1080 http://google.com:99 + * SOCKS5 communication to google.com:99 + * SOCKS5 connect to IPv4 172.217.12.206 (locally resolved) + * Can't complete SOCKS5 connection to 253.127.0.0:26673. (1) + curl: (7) Can't complete SOCKS5 connection to 253.127.0.0:26673. (1) + + That's incorrect because the address:port included in the connect error + is actually a bind address:port (typically unused) and not the + destination address:port. This fix changes curl to show the destination + information that curl sent to the server instead: + + curld -v --socks5 10.0.3.1:1080 http://google.com:99 + * SOCKS5 communication to google.com:99 + * SOCKS5 connect to IPv4 172.217.7.14:99 (locally resolved) + * Can't complete SOCKS5 connection to 172.217.7.14:99. (1) + curl: (7) Can't complete SOCKS5 connection to 172.217.7.14:99. (1) + + curld -v --socks5-hostname 10.0.3.1:1080 http://google.com:99 + * SOCKS5 communication to google.com:99 + * SOCKS5 connect to google.com:99 (remotely resolved) + * Can't complete SOCKS5 connection to google.com:99. (1) + curl: (7) Can't complete SOCKS5 connection to google.com:99. (1) + + Ref: https://tools.ietf.org/html/rfc1928#section-6 + + Closes https://github.com/curl/curl/pull/4394 -Daniel Stenberg (3 Aug 2019) -- url: make use of new HTTP version if alt-svc has one +Daniel Stenberg (21 Sep 2019) +- travis: enable ngtcp2 h3-23 builds -- url: set conn->transport to default TCP at init time +- altsvc: both backends run h3-23 now + + Closes #4395 -- altsvc: with quiche, use the quiche h3 alpn string +- http: fix warning on conversion from int to bit - Closes #4183 + Follow-up from 03ebe66d70 -- alt-svc: more liberal ALPN name parsing +- urldata: use 'bool' for the bit type on MSVC compilers - Allow pretty much anything to be part of the ALPN identifier. In - particular minus, which is used for "h3-20" (in-progress HTTP/3 - versions) etc. + Closes #4387 + Fixes #4379 + +- appveyor: upgrade VS2017 to VS2019 - Updated test 356. - Closes #4182 + Closes #4383 -- quiche: use the proper HTTP/3 ALPN +- [Zenju brought this change] -- quiche: add failf() calls for two error cases + FTP: FTPFILE_NOCWD: avoid redundant CWDs - To aid debugging + Closes #4382 + +- cookie: pass in the correct cookie amount to qsort() - Closes #4181 + As the loop discards cookies without domain set. This bug would lead to + qsort() trying to sort uninitialized pointers. We have however not found + it a security problem. + + Reported-by: Paul Dreik + Closes #4386 -- mailmap: added Kyohei Kadota +- [Paul Dreik brought this change] -Kamil Dudka (1 Aug 2019) -- http_negotiate: improve handling of gss_init_sec_context() failures + urlapi: avoid index underflow for short ipv6 hostnames - If HTTPAUTH_GSSNEGOTIATE was used for a POST request and - gss_init_sec_context() failed, the POST request was sent - with empty body. This commit also restores the original - behavior of `curl --fail --negotiate`, which was changed - by commit 6c6035532383e300c712e4c1cd9fdd749ed5cf59. + If the input hostname is "[", hlen will underflow to max of size_t when + it is subtracted with 2. - Add regression tests 2077 and 2078 to cover this. + hostname[hlen] will then cause a warning by ubsanitizer: - Fixes #3992 - Closes #4171 - -Daniel Stenberg (1 Aug 2019) -- mailmap: added 4 more names + runtime error: addition of unsigned offset to 0x overflowed to + 0x - Evgeny Grin, Peter Pih, Anton Malov and Marquis de Muesli - -- mailmap: add Giorgos Oikonomou - -- src/makefile: fix uncompressed hugehelp.c generation + I think that in practice, the generated code will work, and the output + of hostname[hlen] will be the first character "[". - Regression from 5cf5d57ab9 (7.64.1) + This can be demonstrated by the following program (tested in both clang + and gcc, with -O3) - Fixed-by: Lance Ware - Fixes #4176 - Closes #4177 - -- appveyor: pass on -k to make - -- timediff: make it 64 bit (if possible) even with 32 bit time_t + int main() { + char* hostname=strdup("["); + size_t hlen = strlen(hostname); - ... to make it hold microseconds too. + hlen-=2; + hostname++; + printf("character is %d\n",+hostname[hlen]); + free(hostname-1); + } - Fixes #4165 - Closes #4168 - -- ROADMAP: parallel transfers are merged now - -- getenv: support up to 4K environment variable contents on windows + I found this through fuzzing, and even if it seems harmless, the proper + thing is to return early with an error. - Reported-by: Michal Čaplygin - Fixes #4174 - Closes #4175 + Closes #4389 -- [Kyohei Kadota brought this change] +- [Tatsuhiro Tsujikawa brought this change] - plan9: add support for running on Plan 9 + ngtcp2: compile with latest ngtcp2 + nghttp3 draft-23 - Closes #3701 + Closes #4392 -- [Kyohei Kadota brought this change] +- THANKS-filter: deal with my typos 'Jat' => 'Jay' - ntlm: explicit type casting +- travis: use go master + + ... as the boringssl builds needs a very recent version + + Co-authored-by: Jat Satiro + Closes #4361 -- [Justin brought this change] +- tool_operate: removed unused variable 'done' + + Fixes warning detected by PVS-Studio + Fixes #4374 - curl.h: fix outdated comment +- tool_operate: Expression 'config->resume_from' is always true - Closes #4167 + Fixes warning detected by PVS-Studio + Fixes #4374 -- curl: remove outdated comment +- tool_getparam: remove duplicate switch case - Turned bad with commit b8894085000 + Fixes warning detected by PVS-Studio + Fixes #4374 + +- libssh2: part of conditional expression is always true: !result - Reported-by: niallor on github - Fixes #4172 - Closes #4173 + Fixes warning detected by PVS-Studio + Fixes #4374 -- cleanup: remove the 'numsocks' argument used in many places +- urlapi: Expression 'storep' is always true - It was used (intended) to pass in the size of the 'socks' array that is - also passed to these functions, but was rarely actually checked/used and - the array is defined to a fixed size of MAX_SOCKSPEREASYHANDLE entries - that should be used instead. + Fixes warning detected by PVS-Studio + Fixes #4374 + +- urlapi: 'scheme' is always true - Closes #4169 + Fixes warning detected by PVS-Studio + Fixes #4374 -- readwrite_data: repair setting the TIMER_STARTTRANSFER stamp +- urlapi: part of conditional expression is always true: (relurl[0] == '/') - Regression, broken in commit 65eb65fde64bd5f (curl 7.64.1) + Fixes warning detected by PVS-Studio + Fixes #4374 + +- setopt: store CURLOPT_RTSP_SERVER_CSEQ correctly - Reported-by: Jonathan Cardoso Machado - Assisted-by: Jay Satiro + Fixes bug detected by PVS-Studio + Fixes #4374 + +- mime: make Curl_mime_duppart() assert if called without valid dst - Fixes #4136 - Closes #4162 + Fixes warning detected by PVS-Studio + Fixes #4374 -- mailmap: Amit Katyal +- http_proxy: part of conditional expression is always true: !error + + Fixes warning detected by PVS-Studio + Fixes #4374 -- asyn-thread: removed unused variable +- imap: merged two case-branches performing the same action - Follow-up to eb9a604f. Mistake caused by me when I edited the commit - before push... + Fixes warning detected by PVS-Studio + Fixes #4374 -- RELEASE-NOTES: synced +- multi: value '2L' is assigned to a boolean + + Fixes warning detected by PVS-Studio + Fixes #4374 -- [Amit Katyal brought this change] +- easy: part of conditional expression is always true: !result + + Fixes warning detected by PVS-Studio + Fixes #4374 - asyn-thread: create a socketpair to wait on +- netrc: part of conditional expression is always true: !done - Closes #4157 + Fixes warning detected by PVS-Studio + Fixes #4374 -- curl: cap the maximum allowed values for retry time arguments +- version: Expression 'left > 1' is always true - ... to avoid integer overflows later when multiplying with 1000 to - convert seconds to milliseconds. + Fixes warning detected by PVS-Studio + Fixes #4374 + +- url: remove dead code - Added test 1269 to verify. + Fixes warning detected by PVS-Studio + Fixes #4374 + +- url: part of expression is always true: (bundle->multiuse == 0) - Reported-by: Jason Lee - Closes #4166 + Fixes warning detected by PVS-Studio + Fixes #4374 -- progress: reset download/uploaded counter +- ftp: the conditional expression is always true - ... to make CURLOPT_MAX_RECV_SPEED_LARGE and - CURLOPT_MAX_SEND_SPEED_LARGE work correctly on subsequent transfers that - reuse the same handle. + ... both !result and (ftp->transfer != FTPTRANSFER_BODY)! - Fixed-by: Ironbars13 on github - Fixes #4084 - Closes #4161 + Fixes warning detected by PVS-Studio + Fixes #4374 -- http2_recv: trigger another read when the last data is returned +- ftp: Expression 'ftpc->wait_data_conn' is always false - ... so that end-of-stream is detected properly. + Fixes warning detected by PVS-Studio + Fixes #4374 + +- ftp: Expression 'ftpc->wait_data_conn' is always true - Reported-by: Tom van der Woerdt - Fixes #4043 - Closes #4160 + Fixes warning detected by PVS-Studio + Fixes #4374 -- curl: avoid uncessary libcurl timeouts (in parallel mode) +- ftp: part of conditional expression is always true: !result - When curl_multi_wait() returns OK without file descriptors to wait for, - it might already have done a long timeout. + Fixes warning detected by PVS-Studio + Fixes #4374 + +- http: fix Expression 'http->postdata' is always false - Closes #4159 + Fixes warning detected by PVS-Studio + Fixes #4374 + Reported-by: Valerii Zapodovnikov -- [Balazs Kovacsics brought this change] +- [Niall O'Reilly brought this change] - HTTP: use chunked Transfer-Encoding for HTTP_POST if size unknown - - If using the read callback for HTTP_POST, and POSTFIELDSIZE is not set, - automatically add a Transfer-Encoding: chunked header, same as it is - already done for HTTP_PUT, HTTP_POST_FORM and HTTP_POST_MIME. Update - test 1514 according to the new behaviour. + doh: avoid truncating DNS QTYPE to lower octet - Closes #4138 + Closes #4381 -Jay Satiro (29 Jul 2019) -- [Daniel Stenberg brought this change] +- [Jens Finkhaeuser brought this change] - winbuild: add vquic to list of build directories - - This fixes the winbuild build method which broke several days ago - when experimental quic support was added in 3af0e76. + urlapi: CURLU_NO_AUTHORITY allows empty authority/host part - Reported-by: Michael Lee + CURLU_NO_AUTHORITY is intended for use with unknown schemes (i.e. not + "file:///") to override cURL's default demand that an authority exists. - Fixes https://github.com/curl/curl/issues/4158 + Closes #4349 -- easy: resize receive buffer on easy handle reset +- version: next release will be 7.67.0 + +- RELEASE-NOTES: synced + +- url: only reuse TLS connections with matching pinning - - In curl_easy_reset attempt to resize the receive buffer to its default - size. If realloc fails then continue using the previous size. + If the requests have different CURLOPT_PINNEDPUBLICKEY strings set, the + connection should not be reused. - Prior to this change curl_easy_reset did not properly handle resetting - the receive buffer (data->state.buffer). It reset the variable holding - its size (data->set.buffer_size) to the default size (READBUFFER_SIZE) - but then did not actually resize the buffer. If a user resized the - buffer by using CURLOPT_BUFFERSIZE to set the size smaller than the - default, later called curl_easy_reset and attempted to reuse the handle - then a heap overflow would very likely occur during that handle's next - transfer. + Bug: https://curl.haxx.se/mail/lib-2019-09/0061.html + Reported-by: Sebastian Haglund - Reported-by: Felix Hädicke + Closes #4347 + +- README: add OSS-Fuzz badge [skip ci] - Fixes https://github.com/curl/curl/issues/4143 - Closes https://github.com/curl/curl/pull/4145 + Closes #4380 -- [Brad Spencer brought this change] +Michael Kaufmann (18 Sep 2019) +- http: merge two "case" statements - examples: Avoid reserved names in hiperfifo examples +Daniel Stenberg (18 Sep 2019) +- [Zenju brought this change] + + FTP: remove trailing slash from path for LIST/MLSD - - Trade in __attribute__((unused)) for the classic (void)x to silence - unused symbols. + Closes #4348 + +- mime: when disabled, avoid C99 macro - Because the classic way is not gcc specific. Also because the prior - method mapped to symbol _Unused, which starts with _ and a capital - letter which is reserved. + Closes #4368 + +- url: cleanup dangling DOH request headers too - Assisted-by: The Infinnovation team + Follow-up to 9bc44ff64d9081 - Bug: https://github.com/curl/curl/issues/4120#issuecomment-512542108 + Credit to OSS-Fuzz + Bug: https://crbug.com/oss-fuzz/17269 - Closes https://github.com/curl/curl/pull/4153 - -Daniel Stenberg (25 Jul 2019) -- RELEASE-NOTES: synced + Closes #4372 -- [Felix Hädicke brought this change] +- [Christoph M. Becker brought this change] - ssh-libssh: do not specify O_APPEND when not in append mode + http2: relax verification of :authority in push promise requests - Specifying O_APPEND in conjunction with O_TRUNC and O_CREAT does not - make much sense. And this combination of flags is not accepted by all - SFTP servers (at least not Apache SSHD). + If the :authority pseudo header field doesn't contain an explicit port, + we assume it is valid for the default port, instead of rejecting the + request for all ports. - Fixes #4147 - Closes #4148 - -- [Gergely Nagy brought this change] + Ref: https://curl.haxx.se/mail/lib-2019-09/0041.html + + Closes #4365 - multi: call detach_connection before Curl_disconnect +- doh: clean up dangling DOH handles and memory on easy close - Curl_disconnect bails out if conn->easyq is not empty, detach_connection - needs to be called first to remove the current easy from the queue. + If you set the same URL for target as for DoH (and it isn't a DoH + server), like "https://example.com" in both, the easy handles used for + the DoH requests could be left "dangling" and end up not getting freed. - Fixes #4144 - Closes #4151 + Reported-by: Paul Dreik + Closes #4366 -Jay Satiro (23 Jul 2019) -- tool_operate: fix implicit call to easysrc_cleanup +- unit1655: make it C90 compliant - easysrc_cleanup is only defined when CURL_DISABLE_LIBCURL_OPTION is not - defined, and prior to this change would be called regardless. + Unclear why this was not detected in the CI. + + Follow-up to b7666027296a + +- smb: check for full size message before reading message details - Bug: https://github.com/curl/curl/pull/3804#issuecomment-513922637 - Reported-by: Marcel Raad + To avoid reading of uninitialized data. - Closes https://github.com/curl/curl/pull/4142 + Assisted-by: Max Dymond + Bug: https://crbug.com/oss-fuzz/16907 + Closes #4363 -Daniel Stenberg (22 Jul 2019) -- curl:create_transfers check return code from curl_easy_setopt +- quiche: persist connection details - From commit b8894085 + ... like we do for other protocols at connect time. This makes "curl -I" + and other things work. - Pointed out by Coverity CID 1451703 + Reported-by: George Liu + Fixes #4358 + Closes #4360 + +- openssl: fix warning with boringssl and SSL_CTX_set_min_proto_version - Closes #4134 + Follow-up to ffe34b7b59 + Closes #4359 -- HTTP3: initial (experimental) support +- [Paul Dreik brought this change] + + doh: fix undefined behaviour and open up for gcc and clang optimization - USe configure --with-ngtcp2 or --with-quiche + The undefined behaviour is annoying when running fuzzing with + sanitizers. The codegen is the same, but the meaning is now not up for + dispute. See https://cppinsights.io/s/516a2ff4 - Using either option will enable a HTTP3 build. - Co-authored-by: Alessandro Ghedini + By incrementing the pointer first, both gcc and clang recognize this as + a bswap and optimizes it to a single instruction. See + https://godbolt.org/z/994Zpx - Closes #3500 + Closes #4350 -- curl: remove dead code +- [Paul Dreik brought this change] + + doh: fix (harmless) buffer overrun - The loop never loops (since b889408500), pointed out by Coverity (CID - 1451702) + Added unit test case 1655 to verify. + Close #4352 - Closes #4133 + the code correctly finds the flaws in the old code, + if one temporarily restores doh.c to the old version. -- docs/PARALLEL-TRANSFERS: correct the version number +Alessandro Ghedini (15 Sep 2019) +- docs: remove trailing ':' from section names in CURLOPT_TRAILER* man -- docs/PARALLEL-TRANSFERS: added +- docs: fix typo in CURLOPT_HTTP_VERSION man -- curl: support parallel transfers - - This is done by making sure each individual transfer is first added to a - linked list as then they can be performed serially, or at will, in - parallel. - - Closes #3804 +GitHub (14 Sep 2019) +- [Daniel Stenberg brought this change] -- docs/MANUAL.md: converted to markdown from plain text - - ... will make it render as a nicer web page. + CI: inintial github action job - Closes #4131 + First shot at a CI build on github actions -- curl_version_info: provide nghttp2 details +Daniel Stenberg (13 Sep 2019) +- appveyor: add a winbuild - Introducing CURLVERSION_SIXTH with nghttp2 info. + Assisted-by: Marcel Raad + Assisted-by: Jay Satiro - Closes #4121 - -- bump: start working on 7.66.0 + Closes #4324 -- source: remove names from source comments +- FTP: allow "rubbish" prepended to the SIZE response - Several reasons: + This is a protocol violation but apparently there are legacy proprietary + servers doing this. - - we can't add everyone who's helping out so its unfair to just a few - selected ones. - - we already list all helpers in THANKS and in RELEASE-NOTES for each - release - - we don't want to give the impression that some parts of the code is - "owned" or "controlled" by specific persons + Added test 336 and 337 to verify. - Assisted-by: Daniel Gustafsson - Closes #4129 - -Version 7.65.3 (19 Jul 2019) + Reported-by: Philippe Marguinaud + Closes #4339 -Daniel Stenberg (19 Jul 2019) -- RELEASE-NOTES: 7.65.3 +- [Zenju brought this change] -- THANKS: 7.65.3 status + FTP: skip CWD to entry dir when target is absolute + + Closes #4332 -- progress: make the progress meter appear again +Kamil Dudka (13 Sep 2019) +- curl: fix memory leaked by parse_metalink() - Fix regression caused by 21080e1 + This commit fixes a regression introduced by curl-7_65_3-5-gb88940850. + Detected by tests 2005, 2008, 2009, 2010, 2011, and 2012 with valgrind + and libmetalink enabled. - Reported-by: Chih-Hsuan Yen - Fixes #4122 - Closes #4124 - -- version: bump to 7.65.3 - -- RELEASE-NOTES: Contributors or now 1990 - -Version 7.65.2 (17 Jul 2019) - -Daniel Stenberg (17 Jul 2019) -- RELEASE-NOTES: 7.65.2 + Closes #4326 -- THANKS: add contributors from 7.65.2 +Daniel Stenberg (13 Sep 2019) +- parsedate: still provide the name arrays when disabled + + If FILE or FTP are enabled, since they also use them! + + Reported-by: Roland Hieber + Fixes #4325 + Closes #4343 -Jay Satiro (17 Jul 2019) -- [aasivov brought this change] +- [Gilles Vollant brought this change] - cmake: Fix finding Brotli on case-sensitive file systems + curl:file2string: load large files much faster - - Find package "Brotli" instead of "BROTLI" since the former is the - casing used for CMake/FindBrotli.cmake, and otherwise find_package - may fail on a case-sensitive file system. + ... by using a more efficient realloc scheme. - Fixes https://github.com/curl/curl/issues/4117 + Bug: https://curl.haxx.se/mail/lib-2019-09/0045.html + Closes #4336 -- CURLOPT_RANGE.3: Caution against using it for HTTP PUT +- openssl: close_notify on the FTP data connection doesn't mean closure - AFAICT CURLOPT_RANGE does not support ranged HTTP PUT uploads so I've - cautioned against using it for that purpose and included a workaround. + For FTPS transfers, curl gets close_notify on the data connection + without that being a signal to close the control connection! - Bug: https://curl.haxx.se/mail/lib-2019-04/0075.html - Reported-by: Christopher Head + Regression since 3f5da4e59a556fc (7.65.0) - Closes https://github.com/curl/curl/issues/3814 + Reported-by: Zenju on github + Reviewed-by: Jay Satiro + Fixes #4329 + Closes #4340 -- [Stefano Simonelli brought this change] +- [Jimmy Gaussen brought this change] - CURLOPT_SEEKDATA.3: fix variable name + docs/HTTP3: fix `--with-ssl` ngtcp2 configure flag - Closes https://github.com/curl/curl/pull/4118 + Closes #4338 -- [Giorgos Oikonomou brought this change] +- RELEASE-NOTES: synced - CIPHERS.md: Explain Schannel error SEC_E_ALGORITHM_MISMATCH - - If the SSL backend is Schannel and the user specifies an Schannel CALG_ - that is not supported by the protocol or the server then curl returns - CURLE_SSL_CONNECT_ERROR (35) SEC_E_ALGORITHM_MISMATCH. - - Fixes https://github.com/curl/curl/issues/3389 - Closes https://github.com/curl/curl/pull/4106 +- curlver: bump to 7.66.1 -- [Daniel Gustafsson brought this change] +- [Zenju brought this change] - nss: inspect returnvalue of token check + setopt: make it easier to add new enum values - PK11_IsPresent() checks for the token for the given slot is available, - and sets needlogin flags for the PK11_Authenticate() call. Should it - return false, we should however treat it as an error and bail out. + ... by using the *_LAST define names better. - Closes https://github.com/curl/curl/pull/4110 + Closes #4321 -- docs: Explain behavior change in --tlsv1. options since 7.54 - - Since 7.54 --tlsv1. options use the specified version or later, however - older versions of curl documented it as using just the specified version - which may or may not have happened depending on the TLS library. - Document this discrepancy to allay confusion for users familiar with the - old documentation that expect just the specified version. +- asyn-thread: s/AF_LOCAL/AF_UNIX for Solaris - Fixes https://github.com/curl/curl/issues/4097 - Closes https://github.com/curl/curl/pull/4119 + Reported-by: Dagobert Michelsen + Fixes #4328 + Closes #4333 -- libcurl: Restrict redirect schemes (follow-up) +- [Bernhard Walle brought this change] + + winbuild/MakefileBuild.vc: Add vssh - - Allow FTPS on redirect. + Without that modification, the Windows build using the makefiles doesn't + work. - - Update default allowed redirect protocols in documentation. + Signed-off-by: Bernhard Walle - Follow-up to 6080ea0. + Fixes #4322 + Closes #4323 + +Bernhard Walle (11 Sep 2019) +- winbuild/MakefileBuild.vc: Fix line endings - Ref: https://github.com/curl/curl/pull/4094 + The file had mixed line endings. - Closes https://github.com/curl/curl/pull/4115 + Signed-off-by: Bernhard Walle -Daniel Stenberg (16 Jul 2019) -- test1173: make it also check all libcurl option man pages +Jay Satiro (11 Sep 2019) +- ldap: Stop using wide char version of ldapp_err2string - ... and adjust those that cause errors + Despite ldapp_err2string being documented by MS as returning a + PCHAR (char *), when UNICODE it is mapped to ldap_err2stringW and + returns PWCHAR (wchar_t *). - Closes #4116 - -- curl: only accept COLUMNS less than 10000 + We have lots of code that expects ldap_err2string to return char *, + most of it failf used like this: - ... as larger values would rather indicate something silly (and could - potentially cause buffer problems). + failf(data, "LDAP local: Some error: %s", ldap_err2string(rc)); - Reported-by: pendrek at hackerone - Closes #4114 + Closes https://github.com/curl/curl/pull/4272 -- dist: add manpage-syntax.pl - - follow-up to 7fb66c403 +Version 7.66.0 (10 Sep 2019) -- test1173: detect some basic man page format mistakes +Daniel Stenberg (10 Sep 2019) +- RELEASE-NOTES: curl 7.66.0 + +- THANKS: from the 7.66.0 release + +- curl: make sure the parallel transfers do them all - Triggered by PR #4111 + The logic could erroneously break the loop too early before all + transfers had been transferred. - Closes #4113 + Reported-by: Tom van der Woerdt + Fixes #4316 + Closes #4317 -Jay Satiro (15 Jul 2019) -- [Bjarni Ingi Gislason brought this change] +- urlapi: one colon is enough for the strspn() input (typo) - docs: Fix missing lines caused by undefined macros - - - Escape apostrophes at line start. - - Some lines begin with a "'" (apostrophe, single quote), which is then - interpreted as a control character in *roff. +- urlapi: verify the IPv6 numerical address - Such lines are interpreted as being a call to a macro, and if - undefined, the lines are removed from the output. + It needs to parse correctly. Otherwise it could be tricked into letting + through a-f using host names that libcurl would then resolve. Like + '[ab.be]'. - Bug: https://bugs.debian.org/926352 - Signed-off-by: Bjarni Ingi Gislason + Reported-by: Thomas Vegas + Closes #4315 + +- [Clément Notin brought this change] + + openssl: use SSL_CTX_set__proto_version() when available - Submitted-by: Alessandro Ghedini + OpenSSL 1.1.0 adds SSL_CTX_set__proto_version() that we now use + when available. Existing code is preserved for older versions of + OpenSSL. - Closes https://github.com/curl/curl/pull/4111 + Closes #4304 -Daniel Stenberg (14 Jul 2019) -- libcurl-security.3: update to new CURLOPT_REDIR_PROTOCOLS defaults - - follow-up to 6080ea098 +- [Clément Notin brought this change] -- [Linos Giannopoulos brought this change] + openssl: indent, re-organize and add comments - libcurl: Add testcase for gopher redirects - - The testcase ensures that redirects to CURLPROTO_GOPHER won't be - allowed, by default, in the future. Also, curl is being used - for convenience while keeping the testcases DRY. - - The expected error code is CURLE_UNSUPPORTED_PROTOCOL when the client is - redirected to CURLPROTO_GOPHER +- [migueljcrum brought this change] + + sspi: fix memory leaks - Signed-off-by: Linos Giannopoulos + Closes #4299 -- [Linos Giannopoulos brought this change] +- travis: disable ngtcp2 builds (again) - libcurl: Restrict redirect schemes - - All protocols except for CURLPROTO_FILE/CURLPROTO_SMB and their TLS - counterpart were allowed for redirect. This vastly broadens the - exploitation surface in case of a vulnerability such as SSRF [1], where - libcurl-based clients are forced to make requests to arbitrary hosts. +- Curl_fillreadbuffer: avoid double-free trailer buf on error - For instance, CURLPROTO_GOPHER can be used to smuggle any TCP-based - protocol by URL-encoding a payload in the URI. Gopher will open a TCP - connection and send the payload. + Reviewed-by: Jay Satiro + Reported-by: Thomas Vegas - Only HTTP/HTTPS and FTP are allowed. All other protocols have to be - explicitly enabled for redirects through CURLOPT_REDIR_PROTOCOLS. + Closes #4307 + +- tool_setopt: handle a libcurl build without netrc support - [1]: https://www.acunetix.com/blog/articles/server-side-request-forgery-vulnerability/ + Reported-by: codesniffer13 on github + Fixes #4302 + Closes #4305 + +- security:read_data fix bad realloc() - Signed-off-by: Linos Giannopoulos + ... that could end up a double-free - Closes #4094 + CVE-2019-5481 + Bug: https://curl.haxx.se/docs/CVE-2019-5481.html -- [Zenju brought this change] +- [Thomas Vegas brought this change] - openssl: define HAVE_SSL_GET_SHUTDOWN based on version number + tftp: Alloc maximum blksize, and use default unless OACK is received - Closes #4100 + Fixes potential buffer overflow from 'recvfrom()', should the server + return an OACK without blksize. + + Bug: https://curl.haxx.se/docs/CVE-2019-5482.html + CVE-2019-5482 -- [Peter Simonyi brought this change] +- [Thomas Vegas brought this change] - http: allow overriding timecond with custom header - - With CURLOPT_TIMECONDITION set, a header is automatically added (e.g. - If-Modified-Since). Allow this to be replaced or suppressed with - CURLOPT_HTTPHEADER. - - Fixes #4103 - Closes #4109 + tftp: return error when packet is too small for options -Jay Satiro (11 Jul 2019) -- [Juergen Hoetzel brought this change] +- KNOWN_BUGS/TODO: cleanup and remove outdated issues - smb: Use the correct error code for access denied on file open +- RELEASE-NOTES: synced + +- netrc: free 'home' on error - - Return CURLE_REMOTE_ACCESS_DENIED for SMB access denied on file open. + Follow-up to f9c7ba9096ec2 - Prior to this change CURLE_REMOTE_FILE_NOT_FOUND was returned instead. + Coverity CID 1453474 - Closes https://github.com/curl/curl/pull/4095 - -- [Daniel Gustafsson brought this change] + Closes #4291 - DEPRECATE: fixup versions and spelling +- urldata: avoid 'generic', use dedicated pointers - Correctly set the July 17 version to 7.65.2, and update spelling to - be consistent. Also fix a typo. + For the 'proto' union within the connectdata struct. - Closes https://github.com/curl/curl/pull/4107 - -- [Gisle Vanem brought this change] + Closes #4290 - system_win32: fix clang warning - - - Declare variable in header as extern. +- cleanup: move functions out of url.c and make them static - Bug: https://github.com/curl/curl/commit/48b9ea4#commitcomment-34084597 + Closes #4289 -Daniel Gustafsson (10 Jul 2019) -- headers: Remove no longer exported functions +- smtp: check for and bail out on too short EHLO response - There were a leftover few prototypes of Curl_ functions that we used to - export but no longer do, this removes those prototypes and cleans up any - comments still referring to them. + Otherwise, a three byte response would make the smtp_state_ehlo_resp() + function misbehave. - Curl_write32_le(), Curl_strcpy_url(), Curl_strlen_url(), Curl_up_free() - Curl_concat_url(), Curl_detach_connnection(), Curl_http_setup_conn() - were made static in 05b100aee247bb9bec8e9a1b0166496aa4248d1c. - Curl_http_perhapsrewind() made static in 574aecee208f79d391f10d57520b3. + Credit to OSS-Fuzz + Bug: https://crbug.com/oss-fuzz/16918 - For the remainder, I didn't trawl the Git logs hard enough to capture - their exact time of deletion, but they were all gone: Curl_splayprint(), - Curl_http2_send_request(), Curl_global_host_cache_dtor(), - Curl_scan_cache_used(), Curl_hostcache_destroy(), Curl_second_connect(), - Curl_http_auth_stage() and Curl_close_connections(). + Assisted-by: Max Dymond - Closes #4096 - Reviewed-by: Daniel Stenberg - -- CMake: fix typos and spelling - -- [Kyle Edwards brought this change] + Closes #4287 - CMake: Convert errant elseif() to else() +- smb: init *msg to NULL in smb_send_and_recv() - CMake interprets an elseif() with no arguments as elseif(FALSE), - resulting in the elseif() block not being executed. That is not what - was intended here. Change the empty elseif() to an else() as it was - intended. + ... it might otherwise return OK from this function leaving that pointer + uninitialized. - Closes #4101 - Reported-by: Artalus - Reviewed-by: Daniel Gustafsson - -- buildconf: fix header filename + Bug: https://crbug.com/oss-fuzz/16907 - The header file inclusion had a typo, it should be .h and not .hd. - Fix by renaming. + Closes #4286 + +- ROADMAP: updated after recent user poll - Fixes #4102 - Reported-by: AceCrow on Github + In rough prio order -- [Jan Chren brought this change] +- THANKS: remove duplicate - configure: fix --disable-code-coverage +- Curl_addr2string: take an addrlen argument too - This fixes the case when --disable-code-coverage supplied to ./configure - would result in coverage="yes" being set. + This allows the function to figure out if a unix domain socket has a + file name or not associated with it! When a socket is created with + socketpair(), as done in the fuzzer testing, the path struct member is + uninitialized and must not be accessed. - Closes #4099 - Reviewed-by: Daniel Gustafsson + Bug: https://crbug.com/oss-fuzz/16699 + + Closes #4283 -- cleanup: fix typo in comment +- [Rolf Eike Beer brought this change] -- RELEASE-NOTES: synced + CMake: remove needless newlines at end of gss variables -Jay Satiro (6 Jul 2019) -- [Daniel Gustafsson brought this change] +- [Rolf Eike Beer brought this change] - nss: support using libnss on macOS - - The file suffix for dynamically loadable objects on macOS is .dylib, - which need to be added for the module definitions in order to get the - NSS TLS backend to work properly on macOS. - - Closes https://github.com/curl/curl/pull/4046 + CI: remove duplicate configure flag for LGTM.com -- [Daniel Gustafsson brought this change] +- [Rolf Eike Beer brought this change] - nss: don't set unused parameter - - The value of the maxPTDs parameter to PR_Init() has since at least - NSPR 2.1, which was released sometime in 1998, been marked ignored - as is accordingly not used in the initialization code. Setting it - to a value when calling PR_Init() is thus benign, but indicates an - intent which may be misleading. Reset the value to zero to improve - clarity. + CMake: use platform dependent name for dlopen() library - Closes https://github.com/curl/curl/pull/4054 - -- [Daniel Gustafsson brought this change] + Closes #4279 - nss: only cache valid CRL entries +- quiche: expire when poll returned data - Change the logic around such that we only keep CRLs that NSS actually - ended up caching around for later deletion. If CERT_CacheCRL() fails - then there is little point in delaying the freeing of the CRL as it - is not used. + ... to make sure we continue draining the queue until empty - Closes https://github.com/curl/curl/pull/4053 - -- [Gergely Nagy brought this change] + Closes #4281 - lib: Use UTF-8 encoding in comments - - Some editors and IDEs assume that source files use UTF-8 file encodings. - It also fixes the build with MSVC when /utf-8 command line option is - used (this option is mandatory for some other open-source projects, this - is useful when using the same options is desired for building all - libraries of a project). +- quiche: decrease available buffer size, don't assign it! - Closes https://github.com/curl/curl/pull/4087 + Found-by: Jeremy Lainé -- [Caleb Raitto brought this change] +- RELEASE-NOTES: synced - CURLOPT_HEADEROPT.3: Fix example - - Fix an issue where example builds a curl_slist, but fails to actually - use it, or free it. - - Closes https://github.com/curl/curl/pull/4090 +- [Kyohei Kadota brought this change] + + curl: fix include conditions -- [Shankar Jadhavar brought this change] +- [Kyohei Kadota brought this change] - winbuild: Change Makefile to honor ENABLE_OPENSSL_AUTO_LOAD_CONFIG - - - Made changes so that ENABLE_OPENSSL_AUTO_LOAD_CONFIG will be honored. + plan9: fix installation instructions - - Also removed some ^M chars from file. + Closes #4276 + +- ngtcp2: on h3 stream close, call expire - Prior to this change while building on Windows platform even if we pass - the ENABLE_OPENSSL_AUTO_LOAD_CONFIG option with value as "no" it does - not set the CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG flag. + ... to trigger a new read to detect the stream close! - Closes https://github.com/curl/curl/pull/4086 + Closes #4275 -Daniel Stenberg (4 Jul 2019) -- doh-url.d: added in 7.62.0 +- [Tatsuhiro Tsujikawa brought this change] -Jay Satiro (30 Jun 2019) -- docs: Fix links to OpenSSL docs + ngtcp2: build latest ngtcp2 and ngtcp2_crypto_openssl - OpenSSL changed their manual locations and does not redirect to the new - locations. + Closes #4278 + +- ngtcp2: set flow control window to stream buffer size - Bug: https://curl.haxx.se/mail/lib-2019-06/0056.html - Reported-by: Daniel Stenberg + Closes #4274 -Daniel Stenberg (26 Jun 2019) -- [Gaël PORTAY brought this change] +- [Christopher Head brought this change] - curl_multi_wait.3: escape backslash in example - - The backslash in the character Line Feed must be escaped. - - The current man-page outputs the code as following: - - fprintf(stderr, "curl_multi failed, code %d.0, mc); - - The commit fixes it as follow: - - fprintf(stderr, "curl_multi failed, code %d\n", mc); + CURLOPT_HEADERFUNCTION.3: clarify - Closes #4079 + Closes #4273 -- openssl: disable engine if OPENSSL_NO_UI_CONSOLE is defined - - ... since that needs UI_OpenSSL() which isn't provided when OpenSSL is - built with OPENSSL_NO_UI_CONSOLE which happens when OpenSSL is built for - UWP (with "VC-WIN32-UWP"). +- CURLINFO docs: mention that in redirects times are added - Reported-by: Vasily Lobaskin - Fixes #4073 - Closes #4077 + Suggested-by: Brandon Dong + Fixes #4250 + Closes #4269 -- test1521: adapt to SLISTPOINT - - The header now has the slist-using options marked as SLISTPOINT so this - makes sure test 1521 understands that. +- travis: enable ngtcp2 builds again - Follow-up to ae99b4de1c443ae989 + Switched to the openssl-quic-draft-22 openssl branch. - Closes #4074 + Closes #4271 -- win32: make DLL loading a no-op for UWP - - Reported-by: Michael Brehm - Fixes #4060 - Closes #4072 +- HTTP3: switched openssl branch to use -- [1ocalhost brought this change] +- [Tatsuhiro Tsujikawa brought this change] - configure: fix typo '--disable-http-uath' + ngtcp2: Build with latest ngtcp2 and ngtcp2_crypto_openssl - Closes #4076 - -- [Niklas Hambüchen brought this change] + Closes #4270 - docs: fix string suggesting HTTP/2 is not the default - - Commit 25fd1057c9c86e3 made HTTP2 the default, and further down in the - man page that new default is mentioned, but the section at the top - contradicted it until now. +- http2: when marked for closure and wanted to close == OK - Also remove claim that setting the HTTP version is not sensible. + It could otherwise return an error even when closed correctly if GOAWAY + had been received previously. - Closes #4075 + Reported-by: Tom van der Woerdt + Fixes #4267 + Closes #4268 - RELEASE-NOTES: synced -- [Stephan Szabo brought this change] - - tests: update fixed IP for hostip/clientip split - - These tests give differences for me on linux when using a hostip - pointing to the external ip address for the local machine. +- build-openssl: fix build with Visual Studio 2019 - Closes #4070 + Reviewed-by: Marcel Raad + Contributed-by: osabc on github + Fixes #4188 + Closes #4266 -Daniel Gustafsson (24 Jun 2019) -- http: clarify header buffer size calculation +Kamil Dudka (26 Aug 2019) +- vauth: return CURLE_AUTH_ERROR on gss_init_sec_context() failure - The header buffer size calculation can from static analysis seem to - overlow as it performs an addition between two size_t variables and - stores the result in a size_t variable. Overflow is however guarded - against elsewhere since the input to the addition is regulated by - the maximum read buffer size. Clarify this with a comment since the - question was asked. + This is a follow-up to https://github.com/curl/curl/pull/3864 . - Reviewed-by: Daniel Stenberg + Closes #4224 -Daniel Stenberg (24 Jun 2019) -- KNOWN_BUGS: Don't clear digest for single realm +Daniel Stenberg (26 Aug 2019) +- KNOWN_BUGS: USE_UNIX_SOCKETS on Windows - Closes #3267 + Closes #4040 -- KNOWN_BUGS: Schannel disable CURLOPT_SSL_VERIFYPEER and verify hostname +- quiche: send the HTTP body correctly on callback uploads - Closes #3284 + Closes #4265 -- http2: call done_sending on end of upload - - To make sure a HTTP/2 stream registers the end of stream. +- travis: disable ngtcp2 builds (temporarily) - Bug #4043 made me find this problem but this fix doesn't correct the - reported issue. + Just too many API changes right now - Closes #4068 - -- [James Brown brought this change] + Closes #4264 - c-ares: honor port numbers in CURLOPT_DNS_SERVERS +- ngtcp2: add support for SSLKEYLOGFILE - By using ares_set_servers_ports_csv on new enough c-ares. + Closes #4260 + +- ngtcp2: improve h3 response receiving - Fixes #4066 - Closes #4067 + Closes #4259 -Daniel Gustafsson (24 Jun 2019) -- CURLMOPT_SOCKETFUNCTION.3: fix typo +- ngtcp2: use nghttp3_version() -Daniel Stenberg (24 Jun 2019) -- [Koen Dergent brought this change] +- ngtcp2: sync with upstream API changes + + Assisted-by: Tatsuhiro Tsujikawa - curl: skip CURLOPT_PROXY_CAPATH for disabled-proxy builds +- [Kyle Abramowitz brought this change] + + scp: fix directory name length used in memcpy - Closes #4061 + Fix read off end of array due to bad pointer math in getworkingpath for + SCP home directory case. + + Closes #4258 -- test153: fix content-length to avoid occasional hang +- http: the 'closed' struct field is used by both ngh2 and ngh3 - Closes #4065 + and remove 'header_recvbuf', not used for anything + + Reported-by: Jeremy Lainé + + Closes #4257 -- RELEASE-NOTES: synced +- ngtcp2: accept upload via callback + + Closes #4256 -- multi: enable multiplexing by default (again) +- defines: avoid underscore-prefixed defines - It was originally made default in d7c4213bd0c (7.62.0) but mistakenly - reverted in commit 2f44e94efb3d (7.65.0). Now enabled again. + Double-underscored or underscore plus uppercase letter at least. - Closes #4051 - -- typecheck: add 3 missing strings and a callback data pointer + ... as they're claimed to be reserved. - Closes #4050 + Reported-by: patnyb on github + + Fixes #4254 + Closes #4255 -- tests: add disable-scan.pl to dist +- travis: add a build using ngtcp2 + nghttp3 (and a patched OpenSSL) - follow-up from 29177f422a5 + Runs no tests - Closes #4059 + Closes #4253 -- http2: don't call stream-close on already closed streams +- travis: bump to using nghttp2 version 1.39.2 - Closes #4055 + Closes #4252 -Marcel Raad (20 Jun 2019) -- travis: enable alt-svc for coverage build +- [Gisle Vanem brought this change] + + docs/examples/curlx: fix errors - Closes + Initialise 'mimetype' and require the -p12 arg. + + Closes #4248 -- travis: enable libssh2 for coverage build +- cleanup: remove DOT_CHAR completely - It was enabled by default before commit c92d2e14cfb. + Follow-up to f9c7ba9096ec - Disable torture tests 600 and 601 because of - https://github.com/curl/curl/issues/1678. + The use of DOT_CHAR for ".ssh" was probably a mistake and is removed + now. - Closes + Pointed-out-by: Gisle Vanem + Bug: https://github.com/curl/curl/pull/4230#issuecomment-522960638 + + Closes #4247 -- travis: disable threaded resolver for coverage build +- spnego_sspi: add typecast to fix build warning - This enables more tests. + Reported in build "Win32 target on Debian Stretch (64-bit) - + i686-w64-mingw32 - gcc-20170516" - Closes + Closes #4245 -- travis: enable brotli for all xenial jobs +- openssl: build warning free with boringssl - There's no need for a separate job, and no need to build it from source - with Xenial. + Closes #4244 + +- curl: make --libcurl use CURL_HTTP_VERSION_3 - Closes + Closes #4243 -- travis: enable warnings-as-errors for coverage build +- ngtcp2: make postfields-set posts work - Closes + Closes #4242 -GitHub (20 Jun 2019) -- [Gisle Vanem brought this change] +- http: remove chunked-encoding and expect header use for HTTP/3 - system_win32: fix typo +- [Alessandro Ghedini brought this change] -Daniel Stenberg (20 Jun 2019) -- typecheck: CURLOPT_CONNECT_TO takes an slist too + configure: use pkg-config to detect quiche + + This removes the need to hard-code the quiche target path in + configure.ac. - Additionally, add an alias in curl.h for slist-using options so that - we can grep/parse those out at will. + This depends on https://github.com/cloudflare/quiche/pull/128 - Closes #4042 + Closes #4237 -- [Stephan Szabo brought this change] +- CURLOPT_SSL_VERIFYHOST: treat the value 1 as 2 + + For a long time (since 7.28.1) we've returned error when setting the + value to 1 to make applications notice that we stopped supported the old + behavior for 1. Starting now, we treat 1 and 2 exactly the same. + + Closes #4241 - tests: support non-localhost HOSTIP for dict/smb servers +- curl: use .curlrc (with a dot) on Windows as well - smbserver.py/dictserver.py were explicitly using localhost/127.0.0.1 for - binding the server which when we were running the tests with a separate - HOSTIP and CLIENTIP had failures verifying the server from the device we - were testing. + Fall-back to _curlrc if the dot-version is missing. - This changes them to take the address from runtests.py and default to - localhost/127.0.0.1 if none is given. + Co-Authored-By: Steve Holme - Closes #4048 - -- test1523: basic test of CURLOPT_LOW_SPEED_LIMIT + Closes #4230 -- configure: --disable-progress-meter +- netrc: make the code try ".netrc" on Windows as well - Builds libcurl without support for the built-in progress meter. + ... but fall back and try "_netrc" too if the dot version didn't work. - Closes #4023 + Co-Authored-By: Steve Holme -- curl: improved skip-setopt-options when built with disabled features +- ngtcp2: use ngtcp2_version() to get the run-time version - Reduces #ifdefs in src/tool_operate.c + ... which of course doesn't have to be the same used at build-time. - Follow-up from 4e86f2fc4e6 - Closes #3936 + Function just recently merged in ngtcp2. -Steve Holme (18 Jun 2019) -- netrc: Return the correct error code when out of memory +- ngtcp2: move the h3 initing to immediately after the rx key - Introduced in 763c5178. + To fix a segfault and to better deal with 0-RTT - Closes #4036 + Assisted-by: Tatsuhiro Tsujikawa -Daniel Stenberg (18 Jun 2019) -- config-os400: add getpeername and getsockname defines - - Reported-by: jonrumsey on github - Fixes #4037 - Closes #4039 +- [Alessandro Ghedini brought this change] -- runtests: keep logfiles around by default + quiche: register debug callback once and earlier - Make '-k' a no-op. The singletest function now clears the log directory - BEFORE each individual test and not after, which makes it possible to - always keep the logfiles around after a test has been run. No need to - specify -k anymore. Keeping the option parsing around to work with users - of old habits. + The quiche debug callback is global and can only be initialized once, so + make sure we don't do it multiple times (e.g. if multiple requests are + executed). - Some tests also didn't work properly when -k was used (since the old - logs would be kep when a new test starts) which this change also fixes. + In addition this initializes the callback before the connection is + created, so we get logs for the handshake as well. - Closes #4035 + Closes #4236 -- [Gergely Nagy brought this change] +- ssh: add a generic Curl_ssh_version function for SSH backends + + Closes #4235 - openssl: fix pubkey/signature algorithm detection in certinfo +- base64: check for SSH, not specific SSH backends + +- vssh: move ssh init/cleanup functions into backend code + +- vssh: create directory for SSH backend code + +- TODO/ROADMAP: remove "refuse downgrade redirects" and HTTP/3 - Certinfo gives the same result for all OpenSSL versions. - Also made printing RSA pubkeys consistent with older versions. + HTTP3 is now already in full progress - Reported-by: Michael Wallner - Fixes #3706 - Closes #4030 + Downgrade redirects can be achived almost exactly like that by setting + CURLOPT_REDIR_PROTOCOLS. -- conn_maxage: move the check to prune_dead_connections() - - ... and avoid the locking issue. +- RELEASE-NOTES: synced + +- travis: add a quiche build - Reported-by: Kunal Ekawde - Fixes #4029 - Closes #4032 + Closes #4207 -- tests: have runtests figure out disabled features +- http: fix use of credentials from URL when using HTTP proxy - ... so that runtests can skip individual test cases that test features - that are explicitly disabled in this build. This new logic is intended - for disabled features that aren't otherwise easily visible through the - curl_version_info() or other API calls. + When a username and password are provided in the URL, they were wrongly + removed from the stored URL so that subsequent uses of the same URL + wouldn't find the crendentials. This made doing HTTP auth with multiple + connections (like Digest) mishave. - tests/server/disabled is a newly built executable that will output a - list of disabled features. Outputs nothing for a default build. + Regression from 46e164069d1a5230 (7.62.0) - Closes #3950 - -- test188/189: fix Content-Length + Test case 335 added to verify. - This cures the flaky test results + Reported-by: Mike Crowe - Closes #4034 + Fixes #4228 + Closes #4229 -- [Thomas Gamper brought this change] +- [Mike Crowe brought this change] - winbuild: use WITH_PREFIX if given + tests: Replace outdated test case numbering documentation - Closes #4031 + Tests are no longer grouped by numeric range[1]. Let's stop saying that + and provide some alternative advice for numbering tests. + + [1] https://curl.haxx.se/mail/lib-2019-08/0043.html + + Closes #4227 -Daniel Gustafsson (17 Jun 2019) -- openssl: remove outdated comment +- travis: reduce number of torture tests in 'coverage' - OpenSSL used to call exit(1) on syntax errors in OPENSSL_config(), - which is why we switched to CONF_modules_load_file() and introduced - a comment stating why. This behavior was however changed in OpenSSL - commit abdd677125f3a9e3082f8c5692203590fdb9b860, so remove the now - outdated and incorrect comment. The mentioned commit also declares - OPENSSL_config() deprecated so keep the current coding. + ... to make it complete in time. This cut seems not almost not affect + the coverage percentage and yet completes within 35 minutes on travis + where the previous runs recently always timed out after 50. - Closes #4033 - Reviewed-by: Daniel Stenberg + Closes #4223 -Daniel Stenberg (16 Jun 2019) -- RELEASE-NOTES: synced +- [Igor Makarov brought this change] -Patrick Monnerat (16 Jun 2019) -- os400: make vsetopt() non-static as Curl_vsetopt() for os400 support. - - Use it in curl_easy_setopt_ccsid(). + configure: use -lquiche to link to quiche - Reported-by: jonrumsey on github - Fixes #3833 - Closes #4028 + Closes #4226 -Daniel Stenberg (15 Jun 2019) -- runtests: report single test time + total duration +- ngtcp2: provide the callbacks as a static struct - ... after each successful test. + ... instead of having them in quicsocket + +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: add missing nghttp3_conn_add_write_offset call - Closes #4027 + Closes #4225 -- multi: fix the transfer hash function +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: deal with stream close + +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: Consume QUIC STREAM data properly + +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: don't reinitialize SSL on Retry + +- multi: getsock improvements for QUIC connecting + +- connect: connections are persistent by default for HTTP/3 + +- quiche: happy eyeballs - Follow-up from 8b987cc7eb + Closes #4220 + +- ngtcp2: do QUIC connections happy-eyeballs friendly + +- curl_version: bump string buffer size to 250 - Reported-by: Tom van der Woerdt - Fixes #4018 - Closes #4024 + With HTTP/3 libs and plenty TLS libs, I manged to hit the limit (which + causes a truncated output). -- unit1654: cleanup on memory failure +- CURLOPT_ALTSVC.3: use a "" file name to not load from a file + +Jay Satiro (14 Aug 2019) +- vauth: Use CURLE_AUTH_ERROR for auth function errors - ... to make it handle torture tests properly. + - Add new error code CURLE_AUTH_ERROR. - Reported-by: Marcel Raad - Fixes #4021 - Closes #4022 - -Marcel Raad (13 Jun 2019) -- krb5: fix compiler warning + Prior to this change auth function errors were signaled by + CURLE_OUT_OF_MEMORY and CURLE_RECV_ERROR, and neither one was + technically correct. - Even though the variable was used in a DEBUGASSERT, GCC 8 warned in - debug mode: - krb5.c:324:17: error: unused variable 'maj' [-Werror=unused-variable] + Ref: https://github.com/curl/curl/pull/3848 - Just suppress the warning and declare the variable unconditionally - instead of only for DEBUGBUILD (which also missed the check for - HAVE_ASSERT_H). + Co-authored-by: Dominik Hölzl - Closes https://github.com/curl/curl/pull/4020 + Closes https://github.com/curl/curl/pull/3864 -Daniel Stenberg (13 Jun 2019) -- quote.d: asterisk prefix works for SFTP as well +Daniel Stenberg (13 Aug 2019) +- curl_version_info: make the quic_version a const - Reported-by: Ben Voris - Fixes #4017 - Closes #4019 + Follow-up from 1a2df1518ad8653f + + Closes #4222 -- multi: fix the transfer hashes in the socket hash entries +- examples: add http3.c, altsvc.c and http3-present.c - - The transfer hashes weren't using the correct keys so removing entries - failed. + Closes #4221 + +Peter Wu (13 Aug 2019) +- nss: use TLSv1.3 as default if supported - - Simplified the iteration logic over transfers sharing the same socket and - they now simply are set to expire and thus get handled in the "regular" - timer loop instead. + SSL_VersionRangeGetDefault returns (TLSv1.0, TLSv1.2) as supported + range in NSS 3.45. It looks like the intention is to raise the minimum + version rather than lowering the maximum, so adjust accordingly. Note + that the caller (nss_setup_connect) initializes the version range to + (TLSv1.0, TLSv1.3), so there is no need to check for >= TLSv1.0 again. - Reported-by: Tom van der Woerdt - Fixes #4012 - Closes #4014 + Closes #4187 + Reviewed-by: Daniel Stenberg + Reviewed-by: Kamil Dudka -Jay Satiro (12 Jun 2019) -- [Cliff Crosland brought this change] +Daniel Stenberg (13 Aug 2019) +- quic.h: remove unused proto - url: Fix CURLOPT_MAXAGE_CONN time comparison - - Old connections are meant to expire from the connection cache after - CURLOPT_MAXAGE_CONN seconds. However, they actually expire after 1000x - that value. This occurs because a time value measured in milliseconds is - accidentally divided by 1M instead of by 1,000. +- curl_version_info.3: mentioned ALTSVC and HTTP3 - Closes https://github.com/curl/curl/pull/4013 + ... and sorted the list alphabetically -Daniel Stenberg (11 Jun 2019) -- test1165: verify that CURL_DISABLE_ symbols are in sync - - between configure.ac and source code. They should be possible to switch - on/off in configure AND be used in source code. +- lib/quic.c: unused - removed -- configure: remove CURL_DISABLE_TLS_SRP - - It isn't used by code so stop providing the define. +- CURLOPT_ALTSVC_CTRL.3: remove CURLALTSVC_ALTUSED - Closes #4010 + Follow-up to 98c3f148 that removed it from the header file -- Revert "cmake: add SMB to list of disabled protocols if HTTP_ONLY is specified" +- [Junho Choi brought this change] + + docs/HTTP3: simplify quiche build instruction - This reverts commit 36738caeb78603ce24e3ea089a167b8c216fb938. + Use --recursive to get boringssl in one line - Apparently several of the appveyor windows builds broke. + Closes #4219 -- [sergey-raevskiy brought this change] +- altsvc: make it use h3-22 with ngtcp2 as well - cmake: add SMB to list of disabled protocols if HTTP_ONLY is specified +- ngtcp2: initial h3 request work - Reviewed-by: Jakub Zakrzewski - Closes #3770 + Closes #4217 + +- curl_version_info: offer quic (and h3) library info + + Closes #4216 + +- HTTP3: use ngtcp2's draft-22 branch - RELEASE-NOTES: synced -- http2: remove CURL_DISABLE_TYPECHECK define +- CURLOPT_READFUNCTION.3: provide inline example - ... in http2-less builds as it served no use. + ... instead of mentioning one in another place -- configure: more --disable switches to toggle off individual features +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: send HTTP/3 request with nghttp3 - ... actual support in the code for disabling these has already landed. + This commit makes sending HTTP/3 request with nghttp3 work. It + minimally receives HTTP response and calls nghttp3 callbacks, but no + processing is made at the moment. - Closes #4009 + Closes #4215 -- wolfssl: fix key pinning build error - - follow-up from deb9462ff2de8 +- nghttp3: initial h3 template code added -- CURLMOPT_SOCKETFUNCTION.3: clarified +- nghttp3: required when ngtcp2 is used for QUIC - Moved away the callback explanation from curl_multi_socket_action.3 and - expanded it somewhat. + - checked for by configure + - updated docs/HTTP3.md + - shown in the version string - Closes #4006 + Closes #4210 -- wolfssl: fixup for SNI use +- [Eric Wong brought this change] + + asyn-thread: issue CURL_POLL_REMOVE before closing socket - follow-up from deb9462ff2de8 + This avoids EBADF errors from EPOLL_CTL_DEL operations in the + ephiperfifo.c example. EBADF is dangerous in multi-threaded + applications where I rely on epoll_ctl to operate on the same + epoll description from different threads. - Closes #4007 + Follow-up to eb9a604f8d7db8 + + Bug: https://curl.haxx.se/mail/lib-2019-08/0026.html + Closes #4211 -- CURLOPT_CAINFO.3: polished wording +- [Carlo Marcelo Arenas Belón brought this change] + + configure: avoid undefined check_for_ca_bundle - Clarify the functionality when built to use Schannel and Secure - Transport and stop calling it the "recommended" or "preferred" way and - instead rather call it the default. + instead of using a "greater than 0" test, check for variable being + set, as it is always set to 1, and could be left unset if non of + OPENSSL MBEDTLS GNUTLS WOLFSSL is being configured for. - Removed the reference to the ssl comparison table as it isn't necessary. + Closes #4213 + +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: Send ALPN h3-22 - Reported-by: Richard Alcock - Bug: https://curl.haxx.se/mail/lib-2019-06/0019.html - Closes #4005 + Closes #4212 -GitHub (10 Jun 2019) -- [Daniel Stenberg brought this change] +- [Tatsuhiro Tsujikawa brought this change] + + ngtcp2: use ngtcp2_settings_default and specify initial_ts + +- curl_global_init_mem.3: mention it was added in 7.12.0 + +- [Tatsuhiro Tsujikawa brought this change] - SECURITY.md: created + ngtcp2: make the QUIC handshake work - Brief security policy description for use/display on github. + Closes #4209 + +- [Alex Mayorga brought this change] -Daniel Gustafsson (10 Jun 2019) -- tool_cb_prg: Fix integer overflow in progress bar + HTTP3.md: Update quiche build instructions - Commit 61faa0b420c236480bc9ef6fd52b4ecc1e0f8d17 fixed the progress bar - width calculation to avoid integer overflow, but failed to account for - the fact that initial_size is initialized to -1 when the file size is - retrieved from the remote on an upload, causing another signed integer - overflow. Fix by separately checking for this case before the width - calculation. + Added cloning for quiche and BoringSSL and modified the build + instructions so they work on a clean folder. - Closes #3984 - Reported-by: Brian Carpenter (Geeknik Labs) - Reviewed-by: Daniel Stenberg + Closes #4208 -Daniel Stenberg (10 Jun 2019) -- wolfssl: refer to it as wolfSSL only - - Remove support for, references to and use of "cyaSSL" from the source - and docs. wolfSSL is the current name and there's no point in keeping - references to ancient history. +- CURLOPT_H3: removed - Assisted-by: Daniel Gustafsson + There's no use for this anymore and it was never in a release. - Closes #3903 - -- RELEASE-NOTES: synced + Closes #4206 -- bindlocal: detect and avoid IP version mismatches in bind() +- http3: make connection reuse work - Reported-by: Alex Grebenschikov - Fixes #3993 - Closes #4002 + Closes #4204 + +- quiche: add SSLKEYLOGFILE support -- multi: make sure 'data' can present in several sockhash entries +- cleanup: s/curl_debug/curl_dbg_debug in comments and docs - Since more than one socket can be used by each transfer at a given time, - each sockhash entry how has its own hash table with transfers using that - socket. + Leftovers from the function rename back in 76b63489495 - In addition, the sockhash entry can now be marked 'blocked = TRUE'" - which then makes the delete function just set 'removed = TRUE' instead - of removing it "for real", as a way to not rip out the carpet under the - feet of a parent function that iterates over the transfers of that same - sockhash entry. + Reported-by: Gisle Vanem + Bug: https://github.com/curl/curl/commit/f3e0f071b14fcb46a453f69bdf4e062bcaacf362#com + mitcomment-34601751 - Reported-by: Tom van der Woerdt - Fixes #3961 - Fixes #3986 - Fixes #3995 - Fixes #4004 - Closes #3997 + Closes #4203 -- [Sorcus brought this change] +- RELEASE-NOTES: synced - libcurl-tutorial.3: Fix small typo (mutipart -> multipart) +- alt-svc: add protocol version selection masking - Fixed-by: MrSorcus on github - Closes #4000 - -- unpause: trigger a timeout for event-based transfers + So that users can mask in/out specific HTTP versions when Alt-Svc is + used. - ... so that timeouts or other state machine actions get going again - after a changing pause state. For example, if the last delivery was - paused there's no pending socket activity. + - Removed "h2c" and updated test case accordingly + - Changed how the altsvc struct is laid out + - Added ifdefs to make the unittest run even in a quiche-tree - Reported-by: sstruchtrup on github - Fixes #3994 - Closes #4001 + Closes #4201 -Marcel Raad (9 Jun 2019) -- travis: use xenial LLVM package for scan-build +- http3: fix the HTTP/3 in the request, make alt-svc set right versions - I missed that in commit 99a49d6. + Closes #4200 -- travis: update scan-build job to xenial +- alt-svc: send Alt-Used: in redirected requests - Closes https://github.com/curl/curl/pull/3999 - -Daniel Stenberg (8 Jun 2019) -- bump: start working on 7.65.2 - -Marcel Raad (5 Jun 2019) -- examples/htmltitle: use C++ casts between pointer types + RFC 7838 section 5: - Compilers and static analyzers warn about using C-style casts here. + When using an alternative service, clients SHOULD include an Alt-Used + header field in all requests. - Closes https://github.com/curl/curl/pull/3975 - -- examples/fopen: fix comparison + Removed CURLALTSVC_ALTUSED again (feature is still EXPERIMENTAL thus + this is deemed ok). - As want is size_t, (file->buffer_pos - want) is unsigned, so checking - if it's less than zero makes no sense. - Check if file->buffer_pos is less than want instead to avoid the - unsigned integer wraparound. + You can disable sending this header just like you disable any other HTTP + header in libcurl. - Closes https://github.com/curl/curl/pull/3975 + Closes #4199 -- build: fix Codacy warnings +- CURLOPT_HTTP_VERSION: seting this to 3 forces HTTP/3 use directly - Reduce variable scopes and remove redundant variable stores. + Even though it cannot fall-back to a lower HTTP version automatically. The + safer way to upgrade remains via CURLOPT_ALTSVC. - Closes https://github.com/curl/curl/pull/3975 - -- sws: remove unused variables + CURLOPT_H3 no longer has any bits that do anything and might be removed + before we remove the experimental label. - Unused since commit 2f44e94. + Updated the curl tool accordingly to use "--http3". - Closes https://github.com/curl/curl/pull/3975 - -Version 7.65.1 (4 Jun 2019) - -Daniel Stenberg (4 Jun 2019) -- RELEASE-NOTES: 7.65.1 - -- THANKS: new contributors from 7.65.1 - -Steve Holme (4 Jun 2019) -- [Frank Gevaerts brought this change] + Closes #4197 - ssl: Update outdated "openssl-only" comments for supported backends +- docs/ALTSVC: remove what works and the experimental explanation - These are for features that used to be openssl-only but were expanded - over time to support other SSL backends. + Also, put the TODO items at the bottom. - Closes #3985 + Closes #4198 -Daniel Stenberg (4 Jun 2019) -- curl_share_setopt.3: improve wording [ci ship] - - Reported-by: Carlos ORyan +- docs/EXPERIMENTAL: explain what it means and what's experimental now -Steve Holme (4 Jun 2019) -- tool_parsecfg: Use correct return type for GetModuleFileName() +- curl: make use of CURLINFO_RETRY_AFTER when retrying - GetModuleFileName() returns a DWORD which is a typedef of an unsigned - long and not an int. + If a Retry-After: header was used in the response, that value overrides + other retry timing options. - Closes #3980 + Fixes #3794 + Closes #4195 -Daniel Stenberg (3 Jun 2019) -- TODO: "at least N milliseconds between requests" [ci skip] +- curl: use CURLINFO_PROTOCOL to check for HTTP(s) - Suggested-by: dkwolfe4 on github - Closes #3920 + ... instead of CURLINFO_EFFECTIVE_URL to avoid string operations. -Steve Holme (2 Jun 2019) -- tests/server/.gitignore: Add socksd to the ignore list +- CURLINFO_RETRY_AFTER: parse the Retry-After header value - Missed in 04fd6755. + This is only the libcurl part that provides the information. There's no + user of the parsed value. This change includes three new tests for the + parser. - Closes #3978 + Ref: #3794 + +- docs/ALTSVC.md: first basic file format description -- tool_parsecfg: Fix control flow issue (DEADCODE) +- curl: have -w's 'http_version' show '3' for HTTP/3 - Follow-up to 8144ba38. + Closes #4196 + +- curl.h: add CURL_HTTP_VERSION_3 to the version enum - Detected by Coverity CID 1445663 - Closes #3976 + It can't be set for CURLOPT_HTTP_VERSION, but it can be extracted with + CURLINFO_HTTP_VERSION. -Daniel Stenberg (2 Jun 2019) -- [Sergey Ogryzkov brought this change] +- quiche: make use of the connection timeout API properly - NTLM: reset proxy "multipass" state when CONNECT request is done - - Closes #3972 +- quiche: make POSTFIELDS posts work -- test334: verify HTTP 204 response with chunked coding header - - Verifies that a bodyless response don't parse this content-related - header. +- quiche: improved error handling and memory cleanups -- [Michael Kaufmann brought this change] +- quiche: flush egress in h3_stream_recv() too - http: don't parse body-related headers bodyless responses - - Responses with status codes 1xx, 204 or 304 don't have a response body. For - these, don't parse these headers: - - - Content-Encoding - - Content-Length - - Content-Range - - Last-Modified - - Transfer-Encoding +- RELEASE-NOTES: synced + +Jay Satiro (6 Aug 2019) +- [Patrick Monnerat brought this change] + + os400: take care of CURLOPT_SASL_AUTHZID in curl_easy_setopt_ccsid(). - This change ensures that HTTP/2 upgrades work even if a - "Content-Length: 0" or a "Transfer-Encoding: chunked" header is present. + Ref: https://github.com/curl/curl/issues/3653 + Ref: https://github.com/curl/curl/pull/3790 - Co-authored-by: Daniel Stenberg - Closes #3702 - Fixes #3968 - Closes #3977 - -- tls13-docs: mention it is only for OpenSSL >= 1.1.1 + NOTE: This commit was cherry-picked and is part of a series of commits + that added the authzid feature for upcoming 7.66.0. The series was + temporarily reverted in db8ec1f so that it would not ship in a 7.65.x + patch release. - Reported-by: Jay Satiro - Co-authored-by: Jay Satiro - Fixes #3938 - Closes #3946 + Closes https://github.com/curl/curl/pull/4186 -- dump-header.d: spell out that no headers == empty file [ci skip] +- tests: Fix the line endings for the SASL alt-auth tests - Reported-by: wesinator at github - Fixes #3964 - Closes #3974 - -- singlesocket: use separate variable for inner loop + - Change data and protocol sections to CRLF line endings. - An inner loop within the singlesocket() function wrongly re-used the - variable for the outer loop which then could cause an infinite - loop. Change to using a separate variable! + Prior to this change the tests would fail or hang, which is because + certain sections such as protocol require CRLF line endings. - Reported-by: Eric Wu - Fixes #3970 - Closes #3973 - -- RELEASE-NOTES: synced - -- [Josie Huddleston brought this change] - - http2: Stop drain from being permanently set on + Follow-up to grandparent commit which added the tests. - Various functions called within Curl_http2_done() can have the - side-effect of setting the Easy connection into drain mode (by calling - drain_this()). However, the last time we unset this for a transfer (by - calling drained_transfer()) is at the beginning of Curl_http2_done(). - If the Curl_easy is reused for another transfer, it is then stuck in - drain mode permanently, which in practice makes it unable to write any - data in the new transfer. + Ref: https://github.com/curl/curl/issues/3653 + Ref: https://github.com/curl/curl/pull/3790 - This fix moves the last call to drained_transfer() to later in - Curl_http2_done(), after the functions that could potentially call for a - drain. + NOTE: This commit was cherry-picked and is part of a series of commits + that added the authzid feature for upcoming 7.66.0. The series was + temporarily reverted in db8ec1f so that it would not ship in a 7.65.x + patch release. - Fixes #3966 - Closes #3967 - Reported-by: Josie-H + Closes https://github.com/curl/curl/pull/4186 + +- [Steve Holme brought this change] -Steve Holme (29 May 2019) -- conncache: Remove the DEBUGASSERT on length check + examples: Added SASL PLAIN authorisation identity (authzid) examples + + Ref: https://github.com/curl/curl/issues/3653 + Ref: https://github.com/curl/curl/pull/3790 - We trust the calling code as this is an internal function. + NOTE: This commit was cherry-picked and is part of a series of commits + that added the authzid feature for upcoming 7.66.0. The series was + temporarily reverted in db8ec1f so that it would not ship in a 7.65.x + patch release. - Closes #3962 + Closes https://github.com/curl/curl/pull/4186 -Jay Satiro (29 May 2019) -- [Gisle Vanem brought this change] +- [Steve Holme brought this change] - system_win32: fix function prototype + curl: --sasl-authzid added to support CURLOPT_SASL_AUTHZID from the tool - - Change if_nametoindex parameter type from char * to const char *. + Ref: https://github.com/curl/curl/issues/3653 + Ref: https://github.com/curl/curl/pull/3790 - Follow-up to 09eef8af from this morning. + NOTE: This commit was cherry-picked and is part of a series of commits + that added the authzid feature for upcoming 7.66.0. The series was + temporarily reverted in db8ec1f so that it would not ship in a 7.65.x + patch release. - Bug: https://github.com/curl/curl/commit/09eef8af#r33716067 + Closes https://github.com/curl/curl/pull/4186 -Marcel Raad (29 May 2019) -- appveyor: add Visual Studio solution build - - Closes https://github.com/curl/curl/pull/3941 +- [Steve Holme brought this change] -- appveyor: add support for other build systems - - Introduce BUILD_SYSTEM variable, which is currently always CMake. + sasl: Implement SASL authorisation identity via CURLOPT_SASL_AUTHZID - Closes https://github.com/curl/curl/pull/3941 - -Steve Holme (29 May 2019) -- url: Load if_nametoindex() dynamically from iphlpapi.dll on Windows + Added the ability for the calling program to specify the authorisation + identity (authzid), the identity to act as, in addition to the + authentication identity (authcid) and password when using SASL PLAIN + authentication. - This fixes the static dependency on iphlpapi.lib and allows curl to - build for targets prior to Windows Vista. + Fixes #3653 + Closes #3790 - This partially reverts 170bd047. + NOTE: This commit was cherry-picked and is part of a series of commits + that added the authzid feature for upcoming 7.66.0. The series was + temporarily reverted in db8ec1f so that it would not ship in a 7.65.x + patch release. - Fixes #3960 - Closes #3958 + Closes https://github.com/curl/curl/pull/4186 -Daniel Stenberg (29 May 2019) -- http: fix "error: equality comparison with extraneous parentheses" +Daniel Stenberg (6 Aug 2019) +- docs/HTTP3: refreshed as it is now in master and HTTP/3 can be tested -- parse_proxy: make sure portptr is initialized - - Reported-by: Benbuck Nason - - fixes #3959 +- [Yiming Jing brought this change] -- url: default conn->port to the same as conn->remote_port - - ... so that it has a sensible value when ConnectionExists() is called which - needs it set to differentiate host "bundles" correctly on port number! - - Also, make conncache:hashkey() use correct port for bundles that are proxy vs - host connections. - - Probably a regression from 7.62.0 + mesalink: implement client authentication - Reported-by: Tom van der Woerdt - Fixes #3956 - Closes #3957 + Closes #4184 -- conncache: make "bundles" per host name when doing proxy tunnels - - Only HTTP proxy use where multiple host names can be used over the same - connection should use the proxy host name for bundles. +- curl_multi_poll: a sister to curl_multi_wait() that waits more - Reported-by: Tom van der Woerdt - Fixes #3951 - Closes #3955 - -- multi: track users of a socket better + Repeatedly we see problems where using curl_multi_wait() is difficult or + just awkward because if it has no file descriptor to wait for + internally, it returns immediately and leaves it to the caller to wait + for a small amount of time in order to avoid occasional busy-looping. - They need to be removed from the socket hash linked list with more care. + This is often missed or misunderstood, leading to underperforming + applications. - When sh_delentry() is called to remove a sockethash entry, remove all - individual transfers from the list first. To enable this, each Curl_easy struct - now stores a pointer to the sockethash entry to know how to remove itself. + This change introduces curl_multi_poll() as a replacement drop-in + function that accepts the exact same set of arguments. This function + works identically to curl_multi_wait() - EXCEPT - for the case when + there's nothing to wait for internally, as then this function will by + itself wait for a "suitable" short time before it returns. This + effectiely avoids all risks of busy-looping and should also make it less + likely that apps "over-wait". - Reported-by: Tom van der Woerdt and Kunal Ekawde + This also changes the curl tool to use this funtion internally when + doing parallel transfers and changes curl_easy_perform() to use it + internally. - Fixes #3952 - Fixes #3904 - Closes #3953 + Closes #4163 -Steve Holme (28 May 2019) -- curl-win32.h: Enable Unix Domain Sockets based on the Windows SDK version - - Microsoft added support for Unix Domain Sockets in Windows 10 1803 - (RS4). Rather than expect the user to enable Unix Domain Sockets by - uncommenting the #define that was added in 0fd6221f we use the RS4 - pre-processor variable that is present in newer versions of the - Windows SDK. +- quiche:h3_stream_recv return 0 at end of stream - Closes #3939 + ... and remove some verbose messages we don't need. Made transfers from + facebook.com work better. -Daniel Stenberg (28 May 2019) -- [Jonas Vautherin brought this change] +- altsvc: make quiche use h3-22 now - cmake: support CMAKE_OSX_ARCHITECTURES when detecting SIZEOF variables - - Closes #3945 +- quiche: show the actual version number -Marcel Raad (27 May 2019) -- HAProxy tests: add keywords +- quiche: first working HTTP/3 request - Add the proxy and haproxy keywords in order to be able to exclude or - run these specific tests. + - enable debug log + - fix use of quiche API + - use download buffer + - separate header/body - Closes https://github.com/curl/curl/pull/3949 - -Daniel Stenberg (27 May 2019) -- [Maksim Stsepanenka brought this change] + Closes #4193 - tests: make test 1420 and 1406 work with rtsp-disabled libcurl +- http09: disable HTTP/0.9 by default in both tool and library - Closes #3948 - -Kamil Dudka (27 May 2019) -- [Hubert Kario brought this change] - - nss: allow to specify TLS 1.3 ciphers if supported by NSS + As the plan has been laid out in DEPRECATED. Update docs accordingly and + verify in test 1174. Now requires the option to be set to allow HTTP/0.9 + responses. - Closes #3916 + Closes #4191 -Daniel Stenberg (26 May 2019) -- RELEASE-NOTES: synced +- quiche: initial h3 request send/receive -- [Jay Satiro brought this change] +- lib/Makefile.am: make checksrc run in vquic too - Revert all SASL authzid (new feature) commits - - - Revert all commits related to the SASL authzid feature since the next - release will be a patch release, 7.65.1. - - Prior to this change CURLOPT_SASL_AUTHZID / --sasl-authzid was destined - for the next release, assuming it would be a feature release 7.66.0. - However instead the next release will be a patch release, 7.65.1 and - will not contain any new features. - - After the patch release after the reverted commits can be restored by - using cherry-pick: - - git cherry-pick a14d72c a9499ff 8c1cc36 c2a8d52 0edf690 - - Details for all reverted commits: - - Revert "os400: take care of CURLOPT_SASL_AUTHZID in curl_easy_setopt_ccsid()." - - This reverts commit 0edf6907ae37e2020722e6f61229d8ec64095b0a. - - Revert "tests: Fix the line endings for the SASL alt-auth tests" - - This reverts commit c2a8d52a1356a722ff9f4aeb983cd4eaf80ef221. - - Revert "examples: Added SASL PLAIN authorisation identity (authzid) examples" - - This reverts commit 8c1cc369d0c7163c6dcc91fd38edfea1f509ae75. - - Revert "curl: --sasl-authzid added to support CURLOPT_SASL_AUTHZID from the tool" - - This reverts commit a9499ff136d89987af885e2d7dff0a066a3e5817. - - Revert "sasl: Implement SASL authorisation identity via CURLOPT_SASL_AUTHZID" +- altsvc: fix removal of expired cache entry - This reverts commit a14d72ca2fec5d4eb5a043936e4f7ce08015c177. + Closes #4192 -- [dbrowndan brought this change] +- RELEASE-NOTES: synced - FAQ: more minor updates and spelling fixes +Steve Holme (4 Aug 2019) +- md4: Use our own MD4 implementation when no crypto libraries are available - Closes #3937 + Closes #3780 -- RELEASE-NOTES: synced +- md4: No need to include Curl_md4.h for each TLS library -- sectransp: handle errSSLPeerAuthCompleted from SSLRead() +- md4: No need for the NTLM code to call Curl_md4it() for each TLS library - Reported-by: smuellerDD on github - Fixes #3932 - Closes #3933 - -GitHub (24 May 2019) -- [Gisle Vanem brought this change] + As the NTLM code no longer calls any of TLS libraries' specific MD4 + functions, there is no need to call this function for each #ifdef. - Fix typo. +- md4: Move the mbed TLS MD4 implementation out of the NTLM code -Daniel Stenberg (23 May 2019) -- tool_setopt: for builds with disabled-proxy, skip all proxy setopts() - - Reported-by: Marcel Raad - Fixes #3926 - Closes #3929 +- md4: Move the WinCrypt implementation out of the NTLM code -Steve Holme (23 May 2019) -- winbuild: Use two space indentation - - Closes #3930 +- md4: Move the SecureTransport implementation out of the NTLM code -GitHub (23 May 2019) -- [Gisle Vanem brought this change] +- md4: Use the Curl_md4it() function for OpenSSL based NTLM - tool_parse_cfg: Avoid 2 fopen() for WIN32 - - Using the memdebug.h mem-leak feature, I noticed 2 calls like: - FILE tool_parsecfg.c:70 fopen("c:\Users\Gisle\AppData\Roaming\_curlrc","rt") - FILE tool_parsecfg.c:114 fopen("c:\Users\Gisle\AppData\Roaming\_curlrc","rt") - - No need for 'fopen(), 'fclose()' and a 'fopen()' yet again. +- md4: Move the GNU TLS gcrypt MD4 implementation out of the NTLM code -Daniel Stenberg (23 May 2019) -- md4: include the mbedtls config.h to get the MD4 info +- md4: Move the GNU TLS Nettle MD4 implementation out of the NTLM code -- md4: build correctly with openssl without MD4 +Jay Satiro (4 Aug 2019) +- OS400: Add CURLOPT_H3 symbols - Reported-by: elsamuko at github - Fixes #3921 - Closes #3922 - -Patrick Monnerat (23 May 2019) -- os400: take care of CURLOPT_SASL_AUTHZID in curl_easy_setopt_ccsid(). + Follow-up to 3af0e76 which added experimental H3 support. + + Closes https://github.com/curl/curl/pull/4185 -Daniel Stenberg (23 May 2019) -- .github/FUNDING: mention our opencollective "home" [ci skip] +Daniel Stenberg (3 Aug 2019) +- url: make use of new HTTP version if alt-svc has one -Marcel Raad (23 May 2019) -- [Zenju brought this change] +- url: set conn->transport to default TCP at init time - config-win32: add support for if_nametoindex and getsockname +- altsvc: with quiche, use the quiche h3 alpn string - Closes https://github.com/curl/curl/pull/3923 + Closes #4183 -Jay Satiro (23 May 2019) -- tests: Fix the line endings for the SASL alt-auth tests - - - Change data and protocol sections to CRLF line endings. - - Prior to this change the tests would fail or hang, which is because - certain sections such as protocol require CRLF line endings. +- alt-svc: more liberal ALPN name parsing - Follow-up to a9499ff from today which added the tests. + Allow pretty much anything to be part of the ALPN identifier. In + particular minus, which is used for "h3-20" (in-progress HTTP/3 + versions) etc. - Ref: https://github.com/curl/curl/pull/3790 + Updated test 356. + Closes #4182 -Daniel Stenberg (23 May 2019) -- url: fix bad #ifdef - - Regression since e91e48161235272ff485. - - Reported-by: Tom Greenslade - Fixes #3924 - Closes #3925 +- quiche: use the proper HTTP/3 ALPN -- Revert "progress: CURL_DISABLE_PROGRESS_METER" - - This reverts commit 3b06e68b7734cb10a555f9d7e804dd5d808236a4. - - Clearly this change wasn't good enough as it broke CURLOPT_LOW_SPEED_LIMIT + - CURLOPT_LOW_SPEED_TIME +- quiche: add failf() calls for two error cases - Reported-by: Dave Reisner + To aid debugging - Fixes #3927 - Closes #3928 - -Steve Holme (22 May 2019) -- examples: Added SASL PLAIN authorisation identity (authzid) examples + Closes #4181 -- curl: --sasl-authzid added to support CURLOPT_SASL_AUTHZID from the tool +- mailmap: added Kyohei Kadota -- sasl: Implement SASL authorisation identity via CURLOPT_SASL_AUTHZID +Kamil Dudka (1 Aug 2019) +- http_negotiate: improve handling of gss_init_sec_context() failures - Added the ability for the calling program to specify the authorisation - identity (authzid), the identity to act as, in addition to the - authentication identity (authcid) and password when using SASL PLAIN - authentication. + If HTTPAUTH_GSSNEGOTIATE was used for a POST request and + gss_init_sec_context() failed, the POST request was sent + with empty body. This commit also restores the original + behavior of `curl --fail --negotiate`, which was changed + by commit 6c6035532383e300c712e4c1cd9fdd749ed5cf59. - Fixed #3653 - Closes #3790 - -Marc Hoersken (22 May 2019) -- tests: add support to test against OpenSSH for Windows + Add regression tests 2077 and 2078 to cover this. - Testing against OpenSSH for Windows requires v7.7.0.0 or newer - due to the use of AllowUsers and DenyUsers. For more info see: - https://github.com/PowerShell/Win32-OpenSSH/wiki/sshd_config - -Daniel Stenberg (22 May 2019) -- bump: start on the next release + Fixes #3992 + Closes #4171 -Marcel Raad (22 May 2019) -- examples: fix "clarify calculation precedence" warnings +Daniel Stenberg (1 Aug 2019) +- mailmap: added 4 more names - Closes https://github.com/curl/curl/pull/3919 + Evgeny Grin, Peter Pih, Anton Malov and Marquis de Muesli -- hiperfifo: remove unused variable - - Closes https://github.com/curl/curl/pull/3919 +- mailmap: add Giorgos Oikonomou -- examples: remove dead variable stores +- src/makefile: fix uncompressed hugehelp.c generation - Closes https://github.com/curl/curl/pull/3919 - -- examples: reduce variable scopes + Regression from 5cf5d57ab9 (7.64.1) - Closes https://github.com/curl/curl/pull/3919 + Fixed-by: Lance Ware + Fixes #4176 + Closes #4177 -- http2-download: fix format specifier - - Closes https://github.com/curl/curl/pull/3919 +- appveyor: pass on -k to make -Daniel Stenberg (22 May 2019) -- PolarSSL: deprecate support step 1. Removed from configure. - - Also removed mentions from most docs. +- timediff: make it 64 bit (if possible) even with 32 bit time_t - Discussed: https://curl.haxx.se/mail/lib-2019-05/0045.html + ... to make it hold microseconds too. - Closes #3888 + Fixes #4165 + Closes #4168 -- configure/cmake: check for if_nametoindex() - - - adds the check to cmake - - - fixes the configure check to work for cross-compiled windows builds - - Closes #3917 +- ROADMAP: parallel transfers are merged now -- parse_proxy: use the IPv6 zone id if given - - If the proxy string is given as an IPv6 numerical address with a zone - id, make sure to use that for the connect to the proxy. +- getenv: support up to 4K environment variable contents on windows - Reported-by: Edmond Yu + Reported-by: Michal Čaplygin + Fixes #4174 + Closes #4175 + +- [Kyohei Kadota brought this change] + + plan9: add support for running on Plan 9 - Fixes #3482 - Closes #3918 + Closes #3701 -Version 7.65.0 (22 May 2019) +- [Kyohei Kadota brought this change] -Daniel Stenberg (22 May 2019) -- RELEASE-NOTES: 7.65.0 release + ntlm: explicit type casting -- THANKS: from the 7.65.0 release-notes +- [Justin brought this change] -- url: convert the zone id from a IPv6 URL to correct scope id + curl.h: fix outdated comment - Reported-by: GitYuanQu on github - Fixes #3902 - Closes #3914 + Closes #4167 -- configure: detect getsockname and getpeername on windows too - - Made detection macros for these two functions in the same style as other - functions possibly in winsock in the hope this will work better to - detect these functions when cross-compiling for Windows. +- curl: remove outdated comment - Follow-up to e91e4816123 + Turned bad with commit b8894085000 - Fixes #3913 - Closes #3915 + Reported-by: niallor on github + Fixes #4172 + Closes #4173 -Marcel Raad (21 May 2019) -- examples: remove unused variables +- cleanup: remove the 'numsocks' argument used in many places - Fixes Codacy/CppCheck warnings. + It was used (intended) to pass in the size of the 'socks' array that is + also passed to these functions, but was rarely actually checked/used and + the array is defined to a fixed size of MAX_SOCKSPEREASYHANDLE entries + that should be used instead. - Closes + Closes #4169 -Daniel Gustafsson (21 May 2019) -- udpateconninfo: mark variable unused - - When compiling without getpeername() or getsockname(), the sockfd - paramter to Curl_udpateconninfo() became unused after commit e91e481612 - added ifdef guards. +- readwrite_data: repair setting the TIMER_STARTTRANSFER stamp - Closes #3910 - Fixes https://curl.haxx.se/dev/log.cgi?id=20190520172441-32196 - Reviewed-by: Marcel Raad, Daniel Stenberg - -- ftp: move ftp_ccc in under featureflag + Regression, broken in commit 65eb65fde64bd5f (curl 7.64.1) - Commit e91e48161235272ff485ff32bd048c53af731f43 moved ftp_ccc in under - the FTP featureflag in the UserDefined struct, but vtls callsites were - still using it unprotected. + Reported-by: Jonathan Cardoso Machado + Assisted-by: Jay Satiro - Closes #3912 - Fixes: https://curl.haxx.se/dev/log.cgi?id=20190520044705-29865 - Reviewed-by: Daniel Stenberg, Marcel Raad + Fixes #4136 + Closes #4162 + +- mailmap: Amit Katyal -Daniel Stenberg (20 May 2019) -- curl: report error for "--no-" on non-boolean options +- asyn-thread: removed unused variable - Reported-by: Olen Andoni - Fixes #3906 - Closes #3907 + Follow-up to eb9a604f. Mistake caused by me when I edited the commit + before push... -- [Guy Poizat brought this change] +- RELEASE-NOTES: synced - mbedtls: enable use of EC keys - - Closes #3892 +- [Amit Katyal brought this change] -- lib1560: add tests for parsing URL with too long scheme + asyn-thread: create a socketpair to wait on - Ref: #3905 - -- [Omar Ramadan brought this change] + Closes #4157 - urlapi: increase supported scheme length to 40 bytes +- curl: cap the maximum allowed values for retry time arguments + + ... to avoid integer overflows later when multiplying with 1000 to + convert seconds to milliseconds. - The longest currently registered URI scheme at IANA is 36 bytes long. + Added test 1269 to verify. - Closes #3905 - Closes #3900 + Reported-by: Jason Lee + Closes #4166 -Marcel Raad (20 May 2019) -- lib: reduce variable scopes +- progress: reset download/uploaded counter - Fixes Codacy/CppCheck warnings. + ... to make CURLOPT_MAX_RECV_SPEED_LARGE and + CURLOPT_MAX_SEND_SPEED_LARGE work correctly on subsequent transfers that + reuse the same handle. - Closes https://github.com/curl/curl/pull/3872 + Fixed-by: Ironbars13 on github + Fixes #4084 + Closes #4161 -- tool_formparse: remove redundant assignment +- http2_recv: trigger another read when the last data is returned - Just initialize word_begin with the correct value. + ... so that end-of-stream is detected properly. - Closes https://github.com/curl/curl/pull/3873 + Reported-by: Tom van der Woerdt + Fixes #4043 + Closes #4160 -- ssh: move variable declaration to where it's used +- curl: avoid uncessary libcurl timeouts (in parallel mode) - This way, we need only one call to free. + When curl_multi_wait() returns OK without file descriptors to wait for, + it might already have done a long timeout. - Closes https://github.com/curl/curl/pull/3873 + Closes #4159 + +- [Balazs Kovacsics brought this change] -- ssh-libssh: remove unused variable + HTTP: use chunked Transfer-Encoding for HTTP_POST if size unknown - sock was only used to be assigned to fd_read. + If using the read callback for HTTP_POST, and POSTFIELDSIZE is not set, + automatically add a Transfer-Encoding: chunked header, same as it is + already done for HTTP_PUT, HTTP_POST_FORM and HTTP_POST_MIME. Update + test 1514 according to the new behaviour. - Closes https://github.com/curl/curl/pull/3873 + Closes #4138 -Daniel Stenberg (20 May 2019) -- test332: verify the blksize fix +Jay Satiro (29 Jul 2019) +- [Daniel Stenberg brought this change] -- tftp: use the current blksize for recvfrom() + winbuild: add vquic to list of build directories - bug: https://curl.haxx.se/docs/CVE-2019-5436.html - Reported-by: l00p3r on hackerone - CVE-2019-5436 - -Daniel Gustafsson (19 May 2019) -- version: make ssl_version buffer match for multi_ssl + This fixes the winbuild build method which broke several days ago + when experimental quic support was added in 3af0e76. - When running a multi TLS backend build the version string needs more - buffer space. Make the internal ssl_buffer stack buffer match the one - in Curl_multissl_version() to allow for the longer string. For single - TLS backend builds there is no use in extended to buffer. This is a - fallout from #3863 which fixes up the multi_ssl string generation to - avoid a buffer overflow when the buffer is too small. + Reported-by: Michael Lee - Closes #3875 - Reviewed-by: Daniel Stenberg + Fixes https://github.com/curl/curl/issues/4158 -Steve Holme (18 May 2019) -- http_ntlm_wb: Handle auth for only a single request +- easy: resize receive buffer on easy handle reset - Currently when the server responds with 401 on NTLM authenticated - connection (re-used) we consider it to have failed. However this is - legitimate and may happen when for example IIS is set configured to - 'authPersistSingleRequest' or when the request goes thru a proxy (with - 'via' header). + - In curl_easy_reset attempt to resize the receive buffer to its default + size. If realloc fails then continue using the previous size. - Implemented by imploying an additional state once a connection is - re-used to indicate that if we receive 401 we need to restart - authentication. + Prior to this change curl_easy_reset did not properly handle resetting + the receive buffer (data->state.buffer). It reset the variable holding + its size (data->set.buffer_size) to the default size (READBUFFER_SIZE) + but then did not actually resize the buffer. If a user resized the + buffer by using CURLOPT_BUFFERSIZE to set the size smaller than the + default, later called curl_easy_reset and attempted to reuse the handle + then a heap overflow would very likely occur during that handle's next + transfer. - Missed in fe6049f0. - -- http_ntlm_wb: Cleanup handshake after clean NTLM failure + Reported-by: Felix Hädicke - Missed in 50b87c4e. + Fixes https://github.com/curl/curl/issues/4143 + Closes https://github.com/curl/curl/pull/4145 -- http_ntlm_wb: Return the correct error on receiving an empty auth message +- [Brad Spencer brought this change] + + examples: Avoid reserved names in hiperfifo examples - Missed in fe20826b as it wasn't implemented in http.c in b4d6db83. + - Trade in __attribute__((unused)) for the classic (void)x to silence + unused symbols. - Closes #3894 - -Daniel Stenberg (18 May 2019) -- curl: make code work with protocol-disabled libcurl + Because the classic way is not gcc specific. Also because the prior + method mapped to symbol _Unused, which starts with _ and a capital + letter which is reserved. - Closes #3844 - -- libcurl: #ifdef away more code for disabled features/protocols - -- progress: CURL_DISABLE_PROGRESS_METER + Assisted-by: The Infinnovation team + + Bug: https://github.com/curl/curl/issues/4120#issuecomment-512542108 + + Closes https://github.com/curl/curl/pull/4153 -- hostip: CURL_DISABLE_SHUFFLE_DNS +Daniel Stenberg (25 Jul 2019) +- RELEASE-NOTES: synced -- netrc: CURL_DISABLE_NETRC +- [Felix Hädicke brought this change] -Viktor Szakats (16 May 2019) -- docs: Markdown and misc improvements [ci skip] + ssh-libssh: do not specify O_APPEND when not in append mode - Approved-by: Daniel Stenberg - Closes #3896 - -- docs/RELEASE-PROCEDURE: link to live iCalendar [ci skip] + Specifying O_APPEND in conjunction with O_TRUNC and O_CREAT does not + make much sense. And this combination of flags is not accepted by all + SFTP servers (at least not Apache SSHD). - Ref: https://github.com/curl/curl/commit/0af41b40b2c7bd379b2251cbe7cd618e21fa0ea1#commitcomment-33563135 - Approved-by: Daniel Stenberg - Closes #3895 + Fixes #4147 + Closes #4148 -Daniel Stenberg (16 May 2019) -- travis: add an osx http-only build - - Closes #3887 +- [Gergely Nagy brought this change] -- cleanup: remove FIXME and TODO comments + multi: call detach_connection before Curl_disconnect - They serve very little purpose and mostly just add noise. Most of them - have been around for a very long time. I read them all before removing - or rephrasing them. + Curl_disconnect bails out if conn->easyq is not empty, detach_connection + needs to be called first to remove the current easy from the queue. - Ref: #3876 - Closes #3883 + Fixes #4144 + Closes #4151 -- curl: don't set FTP options for FTP-disabled builds - - ... since libcurl has started to be totally unaware of options for - disabled protocols they now return error. +Jay Satiro (23 Jul 2019) +- tool_operate: fix implicit call to easysrc_cleanup - Bug: https://github.com/curl/curl/commit/c9c5304dd4747cbe75d2f24be85920d572fcb5b8#commitcomment-33533937 + easysrc_cleanup is only defined when CURL_DISABLE_LIBCURL_OPTION is not + defined, and prior to this change would be called regardless. + Bug: https://github.com/curl/curl/pull/3804#issuecomment-513922637 Reported-by: Marcel Raad - Closes #3886 + + Closes https://github.com/curl/curl/pull/4142 -Steve Holme (16 May 2019) -- http_ntlm_wb: Move the type-2 message processing into a dedicated function +Daniel Stenberg (22 Jul 2019) +- curl:create_transfers check return code from curl_easy_setopt - This brings the code inline with the other HTTP authentication mechanisms. + From commit b8894085 - Closes #3890 - -Daniel Stenberg (15 May 2019) -- RELEASE-NOTES: synced - -- docs/RELEASE-PROCEDURE: updated coming releases dates [ci skip] - -- CURLOPT_READFUNCTION.3: see also CURLOPT_UPLOAD_BUFFERSIZE [ci skip] + Pointed out by Coverity CID 1451703 - Reported-by: Roy Bellingan - Bug: #3885 + Closes #4134 -- parse_proxy: use the URL parser API +- HTTP3: initial (experimental) support + + USe configure --with-ngtcp2 or --with-quiche - As we treat a given proxy as a URL we should use the unified URL parser - to extract the parts out of it. + Using either option will enable a HTTP3 build. + Co-authored-by: Alessandro Ghedini - Closes #3878 + Closes #3500 -Steve Holme (15 May 2019) -- http_negotiate: Move the Negotiate state out of the negotiatedata structure +- curl: remove dead code - Given that this member variable is not used by the SASL based protocols - there is no need to have it here. + The loop never loops (since b889408500), pointed out by Coverity (CID + 1451702) - Closes #3882 + Closes #4133 -- http_ntlm: Move the NTLM state out of the ntlmdata structure - - Given that this member variable is not used by the SASL based protocols - there is no need to have it here. +- docs/PARALLEL-TRANSFERS: correct the version number -- url: Move the negotiate state type into a dedicated enum +- docs/PARALLEL-TRANSFERS: added -- url: Remove duplicate clean up of the winbind variables in conn_shutdown() +- curl: support parallel transfers - Given that Curl_disconnect() calls Curl_http_auth_cleanup_ntlm() prior - to calling conn_shutdown() and it in turn performs this, there is no - need to perform the same action in conn_shutdown(). + This is done by making sure each individual transfer is first added to a + linked list as then they can be performed serially, or at will, in + parallel. - Closes #3881 + Closes #3804 -Daniel Stenberg (14 May 2019) -- urlapi: require a non-zero host name length when parsing URL +- docs/MANUAL.md: converted to markdown from plain text - Updated test 1560 to verify. + ... will make it render as a nicer web page. - Closes #3880 + Closes #4131 -- configure: error out if OpenSSL wasn't detected when asked for +- curl_version_info: provide nghttp2 details - If --with-ssl is used and configure still couldn't enable SSL this - creates an error instead of just silently ignoring the fact. + Introducing CURLVERSION_SIXTH with nghttp2 info. - Suggested-by: Isaiah Norton - Fixes #3824 - Closes #3830 - -Daniel Gustafsson (14 May 2019) -- imap: Fix typo in comment + Closes #4121 -Steve Holme (14 May 2019) -- url: Remove unnecessary initialisation from allocate_conn() - - No need to set variables to zero as calloc() does this for us. - - Closes #3879 +- bump: start working on 7.66.0 -Daniel Stenberg (14 May 2019) -- CURLOPT_CAINFO.3: with Schannel, you want Windows 8 or later [ci skip] +- source: remove names from source comments - Clues-provided-by: Jay Satiro - Clues-provided-by: Jeroen Ooms - Fixes #3711 - Closes #3874 - -Daniel Gustafsson (13 May 2019) -- vtls: fix potential ssl_buffer stack overflow + Several reasons: - In Curl_multissl_version() it was possible to overflow the passed in - buffer if the generated version string exceeded the size of the buffer. - Fix by inverting the logic, and also make sure to not exceed the local - buffer during the string generation. + - we can't add everyone who's helping out so its unfair to just a few + selected ones. + - we already list all helpers in THANKS and in RELEASE-NOTES for each + release + - we don't want to give the impression that some parts of the code is + "owned" or "controlled" by specific persons - Closes #3863 - Reported-by: nevv on HackerOne/curl - Reviewed-by: Jay Satiro - Reviewed-by: Daniel Stenberg - -Daniel Stenberg (13 May 2019) -- RELEASE-NOTES: synced - -- appveyor: also build "/ci" branches like travis - -- pingpong: disable more when no pingpong enabled + Assisted-by: Daniel Gustafsson + Closes #4129 -- proxy: acknowledge DISABLE_PROXY more +Version 7.65.3 (19 Jul 2019) -- parsedate: CURL_DISABLE_PARSEDATE +Daniel Stenberg (19 Jul 2019) +- RELEASE-NOTES: 7.65.3 -- sasl: only enable if there's a protocol enabled using it +- THANKS: 7.65.3 status -- mime: acknowledge CURL_DISABLE_MIME +- progress: make the progress meter appear again + + Fix regression caused by 21080e1 + + Reported-by: Chih-Hsuan Yen + Fixes #4122 + Closes #4124 -- wildcard: disable from build when FTP isn't present +- version: bump to 7.65.3 -- http: CURL_DISABLE_HTTP_AUTH +- RELEASE-NOTES: Contributors or now 1990 -- base64: build conditionally if there are users +Version 7.65.2 (17 Jul 2019) -- doh: CURL_DISABLE_DOH +Daniel Stenberg (17 Jul 2019) +- RELEASE-NOTES: 7.65.2 -Steve Holme (12 May 2019) -- auth: Rename the various authentication clean up functions - - For consistency and to a avoid confusion. - - Closes #3869 +- THANKS: add contributors from 7.65.2 -Daniel Stenberg (12 May 2019) -- [Jay Satiro brought this change] +Jay Satiro (17 Jul 2019) +- [aasivov brought this change] - docs/INSTALL: fix broken link [ci skip] + cmake: Fix finding Brotli on case-sensitive file systems - Reported-by: Joombalaya on github - Fixes #3818 - -Marcel Raad (12 May 2019) -- easy: fix another "clarify calculation precedence" warning + - Find package "Brotli" instead of "BROTLI" since the former is the + casing used for CMake/FindBrotli.cmake, and otherwise find_package + may fail on a case-sensitive file system. - I missed this one in commit 6b3dde7fe62ea5a557fd1fd323fac2bcd0c2e9be. + Fixes https://github.com/curl/curl/issues/4117 -- build: fix "clarify calculation precedence" warnings - - Codacy/CppCheck warns about this. Consistently use parentheses as we - already do in some places to silence the warning. +- CURLOPT_RANGE.3: Caution against using it for HTTP PUT - Closes https://github.com/curl/curl/pull/3866 - -- cmake: restore C89 compatibility of CurlTests.c + AFAICT CURLOPT_RANGE does not support ranged HTTP PUT uploads so I've + cautioned against using it for that purpose and included a workaround. - I broke it in d1b5cf830bfe169745721b21245d2217d2c2453e and - 97de97daefc2ed084c91eff34af2426f2e55e134. + Bug: https://curl.haxx.se/mail/lib-2019-04/0075.html + Reported-by: Christopher Head - Reported-by: Viktor Szakats - Ref: https://github.com/curl/curl/commit/97de97daefc2ed084c91eff34af2426f2e55e134#commitcomment-33499044 - Closes https://github.com/curl/curl/pull/3868 + Closes https://github.com/curl/curl/issues/3814 -Steve Holme (11 May 2019) -- http_ntlm: Corrected the name of the include guard - - Missed in f0bdd72c. - - Closes #3867 +- [Stefano Simonelli brought this change] -- http_digest: Don't expose functions when HTTP and Crypto Auth are disabled + CURLOPT_SEEKDATA.3: fix variable name - Closes #3861 - -- http_negotiate: Don't expose functions when HTTP is disabled - -Daniel Stenberg (11 May 2019) -- SECURITY-PROCESS: fix links [ci skip] + Closes https://github.com/curl/curl/pull/4118 -Marcel Raad (11 May 2019) -- CMake: suppress unused variable warnings - - I missed these in commit d1b5cf830bfe169745721b21245d2217d2c2453e. +- [Giorgos Oikonomou brought this change] -Daniel Stenberg (11 May 2019) -- doh: disable DOH for the cases it doesn't work - - Due to limitations in Curl_resolver_wait_resolv(), it doesn't work for - DOH resolves. This fix disables DOH for those. + CIPHERS.md: Explain Schannel error SEC_E_ALGORITHM_MISMATCH - Limitation added to KNOWN_BUGS. + If the SSL backend is Schannel and the user specifies an Schannel CALG_ + that is not supported by the protocol or the server then curl returns + CURLE_SSL_CONNECT_ERROR (35) SEC_E_ALGORITHM_MISMATCH. - Fixes #3850 - Closes #3857 + Fixes https://github.com/curl/curl/issues/3389 + Closes https://github.com/curl/curl/pull/4106 -Jay Satiro (11 May 2019) -- checksrc.bat: Ignore snprintf warnings in docs/examples - - .. because we allow snprintf use in docs/examples. - - Closes https://github.com/curl/curl/pull/3862 +- [Daniel Gustafsson brought this change] -Steve Holme (10 May 2019) -- vauth: Fix incorrect function description for Curl_auth_user_contains_domain() + nss: inspect returnvalue of token check - ...and misalignment of these comments. From a78c61a4. + PK11_IsPresent() checks for the token for the given slot is available, + and sets needlogin flags for the PK11_Authenticate() call. Should it + return false, we should however treat it as an error and bail out. - Closes #3860 + Closes https://github.com/curl/curl/pull/4110 -Jay Satiro (10 May 2019) -- Revert "multi: support verbose conncache closure handle" - - This reverts commit b0972bc. - - - No longer show verbose output for the conncache closure handle. +- docs: Explain behavior change in --tlsv1. options since 7.54 - The offending commit was added so that the conncache closure handle - would inherit verbose mode from the user's easy handle. (Note there is - no way for the user to set options for the closure handle which is why - that was necessary.) Other debug settings such as the debug function - were not also inherited since we determined that could lead to crashes - if the user's per-handle private data was used on an unexpected handle. + Since 7.54 --tlsv1. options use the specified version or later, however + older versions of curl documented it as using just the specified version + which may or may not have happened depending on the TLS library. + Document this discrepancy to allay confusion for users familiar with the + old documentation that expect just the specified version. - The reporter here says he has a debug function to capture the verbose - output, and does not expect or want any output to stderr; however - because the conncache closure handle does not inherit the debug function - the verbose output for that handle does go to stderr. + Fixes https://github.com/curl/curl/issues/4097 + Closes https://github.com/curl/curl/pull/4119 + +- libcurl: Restrict redirect schemes (follow-up) - There are other plausible scenarios as well such as the user redirects - stderr on their handle, which is also not inherited since it could lead - to crashes when used on an unexpected handle. + - Allow FTPS on redirect. - Short of allowing the user to set options for the conncache closure - handle I don't think there's much we can safely do except no longer - inherit the verbose setting. + - Update default allowed redirect protocols in documentation. - Bug: https://curl.haxx.se/mail/lib-2019-05/0021.html - Reported-by: Kristoffer Gleditsch + Follow-up to 6080ea0. - Ref: https://github.com/curl/curl/pull/3598 - Ref: https://github.com/curl/curl/pull/3618 + Ref: https://github.com/curl/curl/pull/4094 - Closes https://github.com/curl/curl/pull/3856 + Closes https://github.com/curl/curl/pull/4115 -Steve Holme (10 May 2019) -- ntlm: Fix misaligned function comments for Curl_auth_ntlm_cleanup() +Daniel Stenberg (16 Jul 2019) +- test1173: make it also check all libcurl option man pages - From 6012fa5a. + ... and adjust those that cause errors - Closes #3858 - -Daniel Stenberg (9 May 2019) -- BUG-BOUNTY: minor formatting fixes [ci skip] - -- RELEASE-NOTES: synced + Closes #4116 -- BUG-BOUNTY.md: add the Dropbox "bonus" extra payout ability [ci skip] +- curl: only accept COLUMNS less than 10000 - Closes #3839 - -Kamil Dudka (9 May 2019) -- http_negotiate: do not treat failure of gss_init_sec_context() as fatal + ... as larger values would rather indicate something silly (and could + potentially cause buffer problems). - Fixes #3726 - Closes #3849 + Reported-by: pendrek at hackerone + Closes #4114 -- spnego_gssapi: fix return code on gss_init_sec_context() failure +- dist: add manpage-syntax.pl - Fixes #3726 - Closes #3849 + follow-up to 7fb66c403 -Steve Holme (9 May 2019) -- gen_resp_file.bat: Removed unnecessary @ from all but the first command +- test1173: detect some basic man page format mistakes - There is need to use @ on every command once echo has been turned off. + Triggered by PR #4111 - Closes #3854 + Closes #4113 -Jay Satiro (8 May 2019) -- http: Ignore HTTP/2 prior knowledge setting for HTTP proxies - - - Do not switch to HTTP/2 for an HTTP proxy that is not tunnelling to - the destination host. +Jay Satiro (15 Jul 2019) +- [Bjarni Ingi Gislason brought this change] + + docs: Fix missing lines caused by undefined macros - We already do something similar for HTTPS proxies by not sending h2. [1] + - Escape apostrophes at line start. - Prior to this change setting CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE would - incorrectly use HTTP/2 to talk to the proxy, which is not something we - support (yet?). Also it's debatable whether or not that setting should - apply to HTTP/2 proxies. + Some lines begin with a "'" (apostrophe, single quote), which is then + interpreted as a control character in *roff. - [1]: https://github.com/curl/curl/commit/17c5d05 + Such lines are interpreted as being a call to a macro, and if + undefined, the lines are removed from the output. - Bug: https://github.com/curl/curl/issues/3570 - Bug: https://github.com/curl/curl/issues/3832 + Bug: https://bugs.debian.org/926352 + Signed-off-by: Bjarni Ingi Gislason - Closes https://github.com/curl/curl/pull/3853 - -Marcel Raad (8 May 2019) -- travis: update mesalink build to xenial + Submitted-by: Alessandro Ghedini - Closes https://github.com/curl/curl/pull/3842 - -Daniel Stenberg (8 May 2019) -- [Ricky Leverence brought this change] + Closes https://github.com/curl/curl/pull/4111 - OpenSSL: Report -fips in version if OpenSSL is built with FIPS - - Older versions of OpenSSL report FIPS availabilty via an OPENSSL_FIPS - define. It uses this define to determine whether to publish -fips at - the end of the version displayed. Applications that utilize the version - reported by OpenSSL will see a mismatch if they compare it to what curl - reports, as curl is not modifying the version in the same way. This - change simply adds a check to see if OPENSSL_FIPS is defined, and will - alter the reported version to match what OpenSSL itself provides. This - only appears to be applicable in versions of OpenSSL <1.1.1 +Daniel Stenberg (14 Jul 2019) +- libcurl-security.3: update to new CURLOPT_REDIR_PROTOCOLS defaults - Closes #3771 + follow-up to 6080ea098 -Kamil Dudka (7 May 2019) -- [Frank Gevaerts brought this change] +- [Linos Giannopoulos brought this change] - nss: allow fifos and character devices for certificates. + libcurl: Add testcase for gopher redirects - Currently you can do things like --cert <(cat ./cert.crt) with (at least) the - openssl backend, but that doesn't work for nss because is_file rejects fifos. + The testcase ensures that redirects to CURLPROTO_GOPHER won't be + allowed, by default, in the future. Also, curl is being used + for convenience while keeping the testcases DRY. - I don't actually know if this is sufficient, nss might do things internally - (like seeking back) that make this not work, so actual testing is needed. + The expected error code is CURLE_UNSUPPORTED_PROTOCOL when the client is + redirected to CURLPROTO_GOPHER - Closes #3807 + Signed-off-by: Linos Giannopoulos -Daniel Gustafsson (6 May 2019) -- test2100: Fix typos in test description +- [Linos Giannopoulos brought this change] -Daniel Stenberg (6 May 2019) -- ssh: define USE_SSH if SSH is enabled (any backend) + libcurl: Restrict redirect schemes + + All protocols except for CURLPROTO_FILE/CURLPROTO_SMB and their TLS + counterpart were allowed for redirect. This vastly broadens the + exploitation surface in case of a vulnerability such as SSRF [1], where + libcurl-based clients are forced to make requests to arbitrary hosts. - Closes #3846 - -Steve Holme (5 May 2019) -- winbuild: Add our standard copyright header to the winbuild batch files - -- makedebug: Fix ERRORLEVEL detection after running where.exe + For instance, CURLPROTO_GOPHER can be used to smuggle any TCP-based + protocol by URL-encoding a payload in the URI. Gopher will open a TCP + connection and send the payload. - Closes #3838 - -Daniel Stenberg (5 May 2019) -- urlapi: add CURLUPART_ZONEID to set and get + Only HTTP/HTTPS and FTP are allowed. All other protocols have to be + explicitly enabled for redirects through CURLOPT_REDIR_PROTOCOLS. - The zoneid can be used with IPv6 numerical addresses. + [1]: https://www.acunetix.com/blog/articles/server-side-request-forgery-vulnerability/ - Updated test 1560 to verify. + Signed-off-by: Linos Giannopoulos - Closes #3834 + Closes #4094 -- [Taiyu Len brought this change] +- [Zenju brought this change] - WRITEFUNCTION: add missing set_in_callback around callback + openssl: define HAVE_SSL_GET_SHUTDOWN based on version number - Closes #3837 - -- RELEASE-NOTES: synced + Closes #4100 -- CURLMOPT_TIMERFUNCTION.3: warn about the recursive risk [ci skip] - - Reported-by: Ricardo Gomes - - Bug: #3537 - Closes #3836 +- [Peter Simonyi brought this change] -- CURLOPT_CHUNK_BGN_FUNCTION.3: document the struct and time value + http: allow overriding timecond with custom header - The time field in the curl_fileinfo struct will always be zero. No code - was ever implemented to actually convert the date string to a time_t. + With CURLOPT_TIMECONDITION set, a header is automatically added (e.g. + If-Modified-Since). Allow this to be replaced or suppressed with + CURLOPT_HTTPHEADER. - Fixes #3829 - Closes #3835 - -- OS400/ccsidcurl.c: code style fixes + Fixes #4103 + Closes #4109 -- OS400/ccsidcurl: replace use of Curl_vsetopt - - (and make the code style comply) - - Fixes #3833 +Jay Satiro (11 Jul 2019) +- [Juergen Hoetzel brought this change] -- urlapi: strip off scope id from numerical IPv6 addresses + smb: Use the correct error code for access denied on file open - ... to make the host name "usable". Store the scope id and put it back - when extracting a URL out of it. + - Return CURLE_REMOTE_ACCESS_DENIED for SMB access denied on file open. - Also makes curl_url_set() syntax check CURLUPART_HOST. + Prior to this change CURLE_REMOTE_FILE_NOT_FOUND was returned instead. - Fixes #3817 - Closes #3822 + Closes https://github.com/curl/curl/pull/4095 -- RELEASE-NOTES: synced +- [Daniel Gustafsson brought this change] -- multiif.h: remove unused protos - - ... for functions related to pipelining. Those functions were removed in - 2f44e94efb3df. + DEPRECATE: fixup versions and spelling - Closes #3828 - -- [Yiming Jing brought this change] - - travis: mesalink: temporarily disable test 3001 + Correctly set the July 17 version to 7.65.2, and update spelling to + be consistent. Also fix a typo. - ... due to SHA-1 signatures in test certs - -- [Yiming Jing brought this change] + Closes https://github.com/curl/curl/pull/4107 - travis: upgrade the MesaLink TLS backend to v1.0.0 - - Closes #3823 - Closes #3776 +- [Gisle Vanem brought this change] -- ConnectionExists: improve non-multiplexing use case - - - better log output + system_win32: fix clang warning - - make sure multiplex is enabled for it to be used - -- multi: provide Curl_multiuse_state to update information + - Declare variable in header as extern. - As soon as a TLS backend gets ALPN conformation about the specific HTTP - version it can now set the multiplex situation for the "bundle" and - trigger moving potentially queued up transfers to the CONNECT state. + Bug: https://github.com/curl/curl/commit/48b9ea4#commitcomment-34084597 -- process_pending_handles: mark queued transfers as previously pending +Daniel Gustafsson (10 Jul 2019) +- headers: Remove no longer exported functions - With transfers being queued up, we only move one at a a time back to the - CONNECT state but now we mark moved transfers so that when a moved - transfer is confirmed "successful" (it connected) it will trigger the - move of another pending transfer. Previously, it would otherwise wait - until the transfer was done before doing this. This makes queued up - pending transfers get processed (much) faster. - -- http: mark bundle as not for multiuse on < HTTP/2 response + There were a leftover few prototypes of Curl_ functions that we used to + export but no longer do, this removes those prototypes and cleans up any + comments still referring to them. - Fixes #3813 - Closes #3815 - -Daniel Gustafsson (1 May 2019) -- cookie: Guard against possible NULL ptr deref + Curl_write32_le(), Curl_strcpy_url(), Curl_strlen_url(), Curl_up_free() + Curl_concat_url(), Curl_detach_connnection(), Curl_http_setup_conn() + were made static in 05b100aee247bb9bec8e9a1b0166496aa4248d1c. + Curl_http_perhapsrewind() made static in 574aecee208f79d391f10d57520b3. - In case the name pointer isn't set (due to memory pressure most likely) - we need to skip the prefix matching and reject with a badcookie to avoid - a possible NULL pointer dereference. + For the remainder, I didn't trawl the Git logs hard enough to capture + their exact time of deletion, but they were all gone: Curl_splayprint(), + Curl_http2_send_request(), Curl_global_host_cache_dtor(), + Curl_scan_cache_used(), Curl_hostcache_destroy(), Curl_second_connect(), + Curl_http_auth_stage() and Curl_close_connections(). - Closes #3820 #3821 - Reported-by: Jonathan Moerman + Closes #4096 Reviewed-by: Daniel Stenberg -Patrick Monnerat (30 Apr 2019) -- os400: Add CURLOPT_MAXAGE_CONN to ILE/RPG bindings - -Kamil Dudka (29 Apr 2019) -- nss: provide more specific error messages on failed init - - Closes #3808 - -Daniel Stenberg (29 Apr 2019) -- [Reed Loden brought this change] +- CMake: fix typos and spelling - docs: minor polish to the bug bounty / security docs - - Closes #3811 +- [Kyle Edwards brought this change] -- CURL_MAX_INPUT_LENGTH: largest acceptable string input size - - This limits all accepted input strings passed to libcurl to be less than - CURL_MAX_INPUT_LENGTH (8000000) bytes, for these API calls: - curl_easy_setopt() and curl_url_set(). + CMake: Convert errant elseif() to else() - The 8000000 number is arbitrary picked and is meant to detect mistakes - or abuse, not to limit actual practical use cases. By limiting the - acceptable string lengths we also reduce the risk of integer overflows - all over. + CMake interprets an elseif() with no arguments as elseif(FALSE), + resulting in the elseif() block not being executed. That is not what + was intended here. Change the empty elseif() to an else() as it was + intended. - NOTE: This does not apply to `CURLOPT_POSTFIELDS`. + Closes #4101 + Reported-by: Artalus + Reviewed-by: Daniel Gustafsson + +- buildconf: fix header filename - Test 1559 verifies. + The header file inclusion had a typo, it should be .h and not .hd. + Fix by renaming. - Closes #3805 + Fixes #4102 + Reported-by: AceCrow on Github -- [Tseng Jun brought this change] +- [Jan Chren brought this change] - curlver.h: use parenthesis in CURL_VERSION_BITS macro + configure: fix --disable-code-coverage - Closes #3809 + This fixes the case when --disable-code-coverage supplied to ./configure + would result in coverage="yes" being set. + + Closes #4099 + Reviewed-by: Daniel Gustafsson -Marcel Raad (27 Apr 2019) -- [Simon Warta brought this change] +- cleanup: fix typo in comment - cmake: rename CMAKE_USE_DARWINSSL to CMAKE_USE_SECTRANSP - - Closes https://github.com/curl/curl/pull/3769 +- RELEASE-NOTES: synced -Steve Holme (23 Apr 2019) -- ntlm: Missed pre-processor || (or) during rebase for cd15acd0 +Jay Satiro (6 Jul 2019) +- [Daniel Gustafsson brought this change] -- ntlm: Support the NT response in the type-3 when OpenSSL doesn't include MD4 + nss: support using libnss on macOS - Just like we do for mbed TLS, use our local implementation of MD4 when - OpenSSL doesn't support it. This allows a type-3 message to include the - NT response. - -Daniel Gustafsson (23 Apr 2019) -- INTERNALS: fix misindentation of ToC item + The file suffix for dynamically loadable objects on macOS is .dylib, + which need to be added for the module definitions in order to get the + NSS TLS backend to work properly on macOS. - Kerberos was incorrectly indented as a subsection under FTP, which is - incorrect as they are both top level sections. A fix for this was first - attempted in commit fef38a0898322f285401c5ff2f5e7c90dbf3be63 but that - was a few paddles short of being complete. + Closes https://github.com/curl/curl/pull/4046 -- [Aron Bergman brought this change] +- [Daniel Gustafsson brought this change] - INTERNALS: Add structs to ToC + nss: don't set unused parameter - Add the subsections under "Structs in libcurl" to the table of contents. + The value of the maxPTDs parameter to PR_Init() has since at least + NSPR 2.1, which was released sometime in 1998, been marked ignored + as is accordingly not used in the initialization code. Setting it + to a value when calling PR_Init() is thus benign, but indicates an + intent which may be misleading. Reset the value to zero to improve + clarity. - Reviewed-by: Daniel Stenberg - Reviewed-by: Daniel Gustafsson + Closes https://github.com/curl/curl/pull/4054 -- [Aron Bergman brought this change] +- [Daniel Gustafsson brought this change] - INTERNALS: Add code highlighting + nss: only cache valid CRL entries - Make all struct members under the Curl_handler section - print in monospace font. + Change the logic around such that we only keep CRLs that NSS actually + ended up caching around for later deletion. If CERT_CacheCRL() fails + then there is little point in delaying the freeing of the CRL as it + is not used. - Closes #3801 - Reviewed-by: Daniel Stenberg - Reviewed-by: Daniel Gustafsson + Closes https://github.com/curl/curl/pull/4053 -Daniel Stenberg (22 Apr 2019) -- docs/BUG-BOUNTY: bug bounty time [skip ci] - - Introducing the curl bug bounty program on hackerone. We now recommend - filing security issues directly in the hackerone ticket system which - only is readable to curl security team members. - - Assisted-by: Daniel Gustafsson - - Closes #3488 +- [Gergely Nagy brought this change] -Steve Holme (22 Apr 2019) -- sasl: Don't send authcid as authzid for the PLAIN mechanism as per RFC 4616 + lib: Use UTF-8 encoding in comments + + Some editors and IDEs assume that source files use UTF-8 file encodings. + It also fixes the build with MSVC when /utf-8 command line option is + used (this option is mandatory for some other open-source projects, this + is useful when using the same options is desired for building all + libraries of a project). - RFC 4616 specifies the authzid is optional in the client authentication - message and that the server will derive the authorisation identity - (authzid) from the authentication identity (authcid) when not specified - by the client. + Closes https://github.com/curl/curl/pull/4087 -Jay Satiro (22 Apr 2019) -- [Gisle Vanem brought this change] +- [Caleb Raitto brought this change] - memdebug: fix variable name - - Follow-up to 76b6348 which renamed logfile as curl_dbg_logfile. + CURLOPT_HEADEROPT.3: Fix example - Ref: https://github.com/curl/curl/commit/76b6348#r33259088 - -Steve Holme (21 Apr 2019) -- vauth/cleartext: Don't send the authzid if it is empty + Fix an issue where example builds a curl_slist, but fails to actually + use it, or free it. - Follow up to 762a292f. - -Daniel Stenberg (21 Apr 2019) -- test 196,197,198: add 'retry' keyword [skip ci] + Closes https://github.com/curl/curl/pull/4090 -- RELEASE-NOTES: synced +- [Shankar Jadhavar brought this change] -- CURLOPT_MAXAGE_CONN: set the maximum allowed age for conn reuse + winbuild: Change Makefile to honor ENABLE_OPENSSL_AUTO_LOAD_CONFIG + + - Made changes so that ENABLE_OPENSSL_AUTO_LOAD_CONFIG will be honored. - ... and disconnect too old ones instead of trying to reuse. + - Also removed some ^M chars from file. - Default max age is set to 118 seconds. + Prior to this change while building on Windows platform even if we pass + the ENABLE_OPENSSL_AUTO_LOAD_CONFIG option with value as "no" it does + not set the CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG flag. - Ref: #3722 - Closes #3782 + Closes https://github.com/curl/curl/pull/4086 -Daniel Gustafsson (20 Apr 2019) -- [Po-Chuan Hsieh brought this change] +Daniel Stenberg (4 Jul 2019) +- doh-url.d: added in 7.62.0 - altsvc: Fix building with cookies disables +Jay Satiro (30 Jun 2019) +- docs: Fix links to OpenSSL docs - ALTSVC requires Curl_get_line which is defined in lib/cookie.c inside a #if - check of HTTP and COOKIES. That makes Curl_get_line undefined if COOKIES is - disabled. Fix by splitting out the function into a separate file which can - be included where needed. + OpenSSL changed their manual locations and does not redirect to the new + locations. - Closes #3717 - Reviewed-by: Daniel Gustafsson - Reviewed-by: Marcel Raad + Bug: https://curl.haxx.se/mail/lib-2019-06/0056.html + Reported-by: Daniel Stenberg -Daniel Stenberg (20 Apr 2019) -- test1002: correct the name [skip ci] +Daniel Stenberg (26 Jun 2019) +- [Gaël PORTAY brought this change] -- test660: verify CONNECT_ONLY with IMAP + curl_multi_wait.3: escape backslash in example - which basically just makes sure LOGOUT is *not* issued on disconnect - -- Curl_disconnect: treat all CONNECT_ONLY connections as "dead" + The backslash in the character Line Feed must be escaped. - Since the connection has been used by the "outside" we don't know the - state of it anymore and curl should not use it anymore. + The current man-page outputs the code as following: - Bug: https://curl.haxx.se/mail/lib-2019-04/0052.html + fprintf(stderr, "curl_multi failed, code %d.0, mc); - Closes #3795 - -- multi: fix the statenames (follow-up fix from 2f44e94efb3df8e) + The commit fixes it as follow: - The list of names must be in sync with the defined states in the header - file! - -Steve Holme (16 Apr 2019) -- openvms: Remove pre-processors for Windows as VMS cannot support them - -- openvms: Remove pre-processor for SecureTransport as VMS cannot support it + fprintf(stderr, "curl_multi failed, code %d\n", mc); - Fixes #3768 - Closes #3785 - -Jay Satiro (16 Apr 2019) -- TODO: Add issue link to an existing entry - -Daniel Stenberg (16 Apr 2019) -- RELEASE-NOTES: synced + Closes #4079 -Jay Satiro (16 Apr 2019) -- tool_help: Warn if curl and libcurl versions do not match - - .. because functionality may be affected if the versions differ. - - This commit implements TODO 18.7 "warning if curl version is not in sync - with libcurl version". - - Ref: https://github.com/curl/curl/blob/curl-7_64_1/docs/TODO#L1028-L1033 +- openssl: disable engine if OPENSSL_NO_UI_CONSOLE is defined - Closes https://github.com/curl/curl/pull/3774 - -Steve Holme (16 Apr 2019) -- md5: Update the function signature following d84da52d - -- md5: Forgot to update the code alignment in d84da52d - -- md5: Return CURLcode from the internally accessible functions + ... since that needs UI_OpenSSL() which isn't provided when OpenSSL is + built with OPENSSL_NO_UI_CONSOLE which happens when OpenSSL is built for + UWP (with "VC-WIN32-UWP"). - Following 28f826b3 to return CURLE_OK instead of numeric 0. + Reported-by: Vasily Lobaskin + Fixes #4073 + Closes #4077 -Daniel Gustafsson (15 Apr 2019) -- tests: Run global cleanup at end of tests +- test1521: adapt to SLISTPOINT - Make sure to run curl_global_cleanup() when shutting down the test - suite to release any resources allocated in the SSL setup. This is - clearly visible when running tests with PolarSSL where the thread - lock calloc() memory which isn't released when not running cleanup. - Below is an excerpt from the autobuild logs: + The header now has the slist-using options marked as SLISTPOINT so this + makes sure test 1521 understands that. - ==12368== 96 bytes in 1 blocks are possibly lost in loss record 1 of 2 - ==12368== at 0x4837B65: calloc (vg_replace_malloc.c:752) - ==12368== by 0x11A76E: curl_dbg_calloc (memdebug.c:205) - ==12368== by 0x145CDF: Curl_polarsslthreadlock_thread_setup - (polarssl_threadlock.c:54) - ==12368== by 0x145B37: Curl_polarssl_init (polarssl.c:865) - ==12368== by 0x14129D: Curl_ssl_init (vtls.c:171) - ==12368== by 0x118B4C: global_init (easy.c:158) - ==12368== by 0x118BF5: curl_global_init (easy.c:221) - ==12368== by 0x118D0B: curl_easy_init (easy.c:299) - ==12368== by 0x114E96: test (lib1906.c:32) - ==12368== by 0x115495: main (first.c:174) + Follow-up to ae99b4de1c443ae989 - Closes #3783 - Reviewed-by: Marcel Raad - Reviewed-by: Daniel Stenberg + Closes #4074 -Marcel Raad (15 Apr 2019) -- travis: use mbedtls from Xenial - - No need to build it from source anymore. +- win32: make DLL loading a no-op for UWP - Closes https://github.com/curl/curl/pull/3779 + Reported-by: Michael Brehm + Fixes #4060 + Closes #4072 -- travis: use libpsl from Xenial - - This makes building libpsl and libidn2 from source unnecessary and - removes the need for the autopoint and libunistring-dev packages. - - Closes https://github.com/curl/curl/pull/3779 +- [1ocalhost brought this change] -Daniel Stenberg (15 Apr 2019) -- runtests: start socksd like other servers - - ... without a $srcdir prefix. Triggered by the failures in several - autobuilds. + configure: fix typo '--disable-http-uath' - Closes #3781 + Closes #4076 -Daniel Gustafsson (14 Apr 2019) -- socksd: Fix typos - - Reviewed-by: Daniel Stenberg +- [Niklas Hambüchen brought this change] -- socksd: Properly decorate static variables + docs: fix string suggesting HTTP/2 is not the default - Mark global variables static to avoid compiler warning in Clang when - using -Wmissing-variable-declarations. + Commit 25fd1057c9c86e3 made HTTP2 the default, and further down in the + man page that new default is mentioned, but the section at the top + contradicted it until now. - Closes #3778 - Reviewed-by: Daniel Stenberg - -Steve Holme (14 Apr 2019) -- md(4|5): Fixed indentation oddities with the importation of replacement code + Also remove claim that setting the HTTP version is not sensible. - The indentation from 211d5329 and 57d6d253 was a little strange as - parts didn't align correctly, uses 4 spaces rather than 2. Checked - the indentation of the original source so it aligns, albeit, using - curl style. + Closes #4075 -- md5: Code style to return CURLE_OK rather than numeric 0 +- RELEASE-NOTES: synced -- md5: Corrected code style for some pointer arguments +- [Stephan Szabo brought this change] -Marcel Raad (13 Apr 2019) -- travis: update some builds to xenial + tests: update fixed IP for hostip/clientip split - Xenial comes with more up-to-date software versions and more available - packages, some of which we currently build from source. Unfortunately, - some builds would fail with Xenial because of assertion failures in - Valgrind when using OpenSSL, so leave these at Trusty. + These tests give differences for me on linux when using a hostip + pointing to the external ip address for the local machine. - Closes https://github.com/curl/curl/pull/3777 + Closes #4070 -Daniel Stenberg (13 Apr 2019) -- test: make tests and test scripts use socksd for SOCKS +Daniel Gustafsson (24 Jun 2019) +- http: clarify header buffer size calculation - Make all SOCKS tests use socksd instead of ssh. - -- socksd: new SOCKS 4+5 server for tests + The header buffer size calculation can from static analysis seem to + overlow as it performs an addition between two size_t variables and + stores the result in a size_t variable. Overflow is however guarded + against elsewhere since the input to the addition is regulated by + the maximum read buffer size. Clarify this with a comment since the + question was asked. - Closes #3752 + Reviewed-by: Daniel Stenberg -- singleipconnect: show port in the verbose "Trying ..." message +Daniel Stenberg (24 Jun 2019) +- KNOWN_BUGS: Don't clear digest for single realm - To aid debugging better. - -- [tmilburn brought this change] + Closes #3267 - CURLOPT_ADDRESS_SCOPE: fix range check and more - - Commit 9081014 fixed most of the confusing issues between scope id and - scope however 844896d added bad limits checking assuming that the scope - is being set and not the scope id. - - I have fixed the documentation so it all refers to scope ids. - - In addition Curl_if2ip refered to the scope id as remote_scope_id which - is incorrect, so I renamed it to local_scope_id. - - Adjusted-by: Daniel Stenberg +- KNOWN_BUGS: Schannel disable CURLOPT_SSL_VERIFYPEER and verify hostname - Closes #3655 - Closes #3765 - Fixes #3713 + Closes #3284 -- urlapi: stricter CURLUPART_PORT parsing - - Only allow well formed decimal numbers in the input. +- http2: call done_sending on end of upload - Document that the number MUST be between 1 and 65535. + To make sure a HTTP/2 stream registers the end of stream. - Add tests to test 1560 to verify the above. + Bug #4043 made me find this problem but this fix doesn't correct the + reported issue. - Ref: https://github.com/curl/curl/issues/3753 - Closes #3762 + Closes #4068 -Jay Satiro (13 Apr 2019) -- [Jan Ehrhardt brought this change] +- [James Brown brought this change] - winbuild: Support MultiSSL builds - - - Remove the lines in winbuild/Makefile.vc that generate an error with - multiple SSL backends. + c-ares: honor port numbers in CURLOPT_DNS_SERVERS - - Add /DCURL_WITH_MULTI_SSL in winbuild/MakefileBuild.vc if multiple SSL - backends are set. + By using ares_set_servers_ports_csv on new enough c-ares. - Closes https://github.com/curl/curl/pull/3772 + Fixes #4066 + Closes #4067 -Daniel Stenberg (12 Apr 2019) -- travis: remove mesalink builds (temporarily?) - - Since the mesalink build started to fail on travis, even though we build - a fixed release version, we disable it to prevent it from blocking - progress. - - Closes #3767 +Daniel Gustafsson (24 Jun 2019) +- CURLMOPT_SOCKETFUNCTION.3: fix typo -- openssl: mark connection for close on TLS close_notify +Daniel Stenberg (24 Jun 2019) +- [Koen Dergent brought this change] + + curl: skip CURLOPT_PROXY_CAPATH for disabled-proxy builds - Without this, detecting and avoid reusing a closed TLS connection - (without a previous GOAWAY) when doing HTTP/2 is tricky. + Closes #4061 + +- test153: fix content-length to avoid occasional hang - Reported-by: Tom van der Woerdt - Fixes #3750 - Closes #3763 + Closes #4065 - RELEASE-NOTES: synced -Steve Holme (11 Apr 2019) -- vauth/cleartext: Update the PLAIN login function signature to match RFC 4616 +- multi: enable multiplexing by default (again) - Functionally this doesn't change anything as we still use the username - for both the authorisation identity and the authentication identity. + It was originally made default in d7c4213bd0c (7.62.0) but mistakenly + reverted in commit 2f44e94efb3d (7.65.0). Now enabled again. - Closes #3757 + Closes #4051 -Daniel Stenberg (11 Apr 2019) -- test1906: verify CURLOPT_CURLU + CURLOPT_PORT usage +- typecheck: add 3 missing strings and a callback data pointer - Based-on-code-by: Poul T Lomholt + Closes #4050 -- url: always clone the CUROPT_CURLU handle - - Since a few code paths actually update that data. +- tests: add disable-scan.pl to dist - Fixes #3753 - Closes #3761 + follow-up from 29177f422a5 - Reported-by: Poul T Lomholt + Closes #4059 -- CURLOPT_DNS_USE_GLOBAL_CACHE: remove - - Remove the code too. The functionality has been disabled in code since - 7.62.0. Setting this option will from now on simply be ignored and have - no function. +- http2: don't call stream-close on already closed streams - Closes #3654 + Closes #4055 -Marcel Raad (11 Apr 2019) -- travis: install libgnutls28-dev only for --with-gnutls build - - Reduces the time needed for the other jobs a little. +Marcel Raad (20 Jun 2019) +- travis: enable alt-svc for coverage build - Closes https://github.com/curl/curl/pull/3721 + Closes -- travis: install libnss3-dev only for --with-nss build - - Reduces the time needed for the other jobs a little. +- travis: enable libssh2 for coverage build - Closes https://github.com/curl/curl/pull/3721 - -- travis: install libssh2-dev only for --with-libssh2 build + It was enabled by default before commit c92d2e14cfb. - Reduces the time needed for the other jobs a little. + Disable torture tests 600 and 601 because of + https://github.com/curl/curl/issues/1678. - Closes https://github.com/curl/curl/pull/3721 + Closes -- travis: install libssh-dev only for --with-libssh build +- travis: disable threaded resolver for coverage build - Reduces the time needed for the other jobs a little. + This enables more tests. - Closes https://github.com/curl/curl/pull/3721 + Closes -- travis: install krb5-user only for --with-gssapi build +- travis: enable brotli for all xenial jobs - Reduces the time needed for the other jobs a little. + There's no need for a separate job, and no need to build it from source + with Xenial. - Closes https://github.com/curl/curl/pull/3721 + Closes -- travis: install lcov only for the coverage job - - Reduces the time needed for the other jobs a little. +- travis: enable warnings-as-errors for coverage build - Closes https://github.com/curl/curl/pull/3721 + Closes -- travis: install clang only when needed - - This reduces the GCC job runtimes a little and it's needed to - selectively update clang builds to xenial. - - Closes https://github.com/curl/curl/pull/3721 +GitHub (20 Jun 2019) +- [Gisle Vanem brought this change] -- AppVeyor: enable testing for WinSSL build - - Closes https://github.com/curl/curl/pull/3725 + system_win32: fix typo -- build: fix Codacy/CppCheck warnings +Daniel Stenberg (20 Jun 2019) +- typecheck: CURLOPT_CONNECT_TO takes an slist too - - remove unused variables - - declare conditionally used variables conditionally - - suppress unused variable warnings in the CMake tests - - remove dead variable stores - - consistently use WIN32 macro to detect Windows + Additionally, add an alias in curl.h for slist-using options so that + we can grep/parse those out at will. - Closes https://github.com/curl/curl/pull/3739 + Closes #4042 + +- [Stephan Szabo brought this change] -- polarssl_threadlock: remove conditionally unused code + tests: support non-localhost HOSTIP for dict/smb servers - Make functions no-ops if neither both USE_THREADS_POSIX and - HAVE_PTHREAD_H nor both USE_THREADS_WIN32 and HAVE_PROCESS_H are - defined. Previously, if only one of them was defined, there was either - code compiled that did nothing useful or the wrong header included for - the functions used. + smbserver.py/dictserver.py were explicitly using localhost/127.0.0.1 for + binding the server which when we were running the tests with a separate + HOSTIP and CLIENTIP had failures verifying the server from the device we + were testing. - Also, move POLARSSL_MUTEX_T define to implementation file as it's not - used externally. + This changes them to take the address from runtests.py and default to + localhost/127.0.0.1 if none is given. - Closes https://github.com/curl/curl/pull/3739 + Closes #4048 -- lib557: initialize variables - - These variables are only conditionally initialized. - - Closes https://github.com/curl/curl/pull/3739 +- test1523: basic test of CURLOPT_LOW_SPEED_LIMIT -- lib509: add missing include for strdup +- configure: --disable-progress-meter - Closes https://github.com/curl/curl/pull/3739 + Builds libcurl without support for the built-in progress meter. + + Closes #4023 -- README.md: fix no-consecutive-blank-lines Codacy warning +- curl: improved skip-setopt-options when built with disabled features - Consistently use one blank line between blocks. + Reduces #ifdefs in src/tool_operate.c - Closes https://github.com/curl/curl/pull/3739 + Follow-up from 4e86f2fc4e6 + Closes #3936 -- tests/server/util: fix Windows Unicode build +Steve Holme (18 Jun 2019) +- netrc: Return the correct error code when out of memory - Always use the ANSI version of FormatMessage as we don't have the - curl_multibyte gear available here. + Introduced in 763c5178. - Closes https://github.com/curl/curl/pull/3758 - -Daniel Stenberg (11 Apr 2019) -- curl_easy_getinfo.3: fix minor formatting mistake + Closes #4036 -Daniel Gustafsson (11 Apr 2019) -- xattr: skip unittest on unsupported platforms +Daniel Stenberg (18 Jun 2019) +- config-os400: add getpeername and getsockname defines - The stripcredentials unittest fails to compile on platforms without - xattr support, for example the Solaris member in the buildfarm which - fails with the following: + Reported-by: jonrumsey on github + Fixes #4037 + Closes #4039 + +- runtests: keep logfiles around by default - CC unit1621-unit1621.o - CC ../libtest/unit1621-first.o - CCLD unit1621 - Undefined first referenced - symbol in file - stripcredentials unit1621-unit1621.o - goto problem 2 - ld: fatal: symbol referencing errors. No output written to .libs/unit1621 - collect2: error: ld returned 1 exit status - gmake[2]: *** [Makefile:996: unit1621] Error 1 + Make '-k' a no-op. The singletest function now clears the log directory + BEFORE each individual test and not after, which makes it possible to + always keep the logfiles around after a test has been run. No need to + specify -k anymore. Keeping the option parsing around to work with users + of old habits. - Fix by excluding the test on such platforms by using the reverse - logic from where stripcredentials() is defined. + Some tests also didn't work properly when -k was used (since the old + logs would be kep when a new test starts) which this change also fixes. - Closes #3759 - Reviewed-by: Daniel Stenberg + Closes #4035 -Steve Holme (11 Apr 2019) -- emailL Added reference to RFC8314 for implicit TLS +- [Gergely Nagy brought this change] -- README: Schannel, stop calling it "winssl" + openssl: fix pubkey/signature algorithm detection in certinfo + + Certinfo gives the same result for all OpenSSL versions. + Also made printing RSA pubkeys consistent with older versions. - Stick to "Schannel" everywhere - follow up to 180501cb. + Reported-by: Michael Wallner + Fixes #3706 + Closes #4030 -Jakub Zakrzewski (10 Apr 2019) -- cmake: clear CMAKE_REQUIRED_LIBRARIES after each use +- conn_maxage: move the check to prune_dead_connections() - This fixes GSSAPI builds with the libraries in a non-standard location. - The testing for recv() were failing because it failed to link - the Kerberos libraries, which are not needed for this or subsequent - tests. + ... and avoid the locking issue. - fixes #3743 - closes #3744 + Reported-by: Kunal Ekawde + Fixes #4029 + Closes #4032 -- cmake: avoid linking executable for some tests with cmake 3.6+ +- tests: have runtests figure out disabled features - With CMAKE_TRY_COMPILE_TARGET_TYPE set to STATIC_LIBRARY, the try_compile() - (which is used by check_c_source_compiles()) will build static library - instead of executable. This avoids linking additional libraries in and thus - speeds up those checks a little. + ... so that runtests can skip individual test cases that test features + that are explicitly disabled in this build. This new logic is intended + for disabled features that aren't otherwise easily visible through the + curl_version_info() or other API calls. - This commit also avoids #3743 (GSSAPI build errors) on itself with cmake - 3.6 or above. That issue was fixed separately for all versions. + tests/server/disabled is a newly built executable that will output a + list of disabled features. Outputs nothing for a default build. - Ref: #3744 + Closes #3950 -- cmake: minor cleanup - - - Remove nneeded include_regular_expression. - It was setting what is already a default. - - - Remove duplicated include. +- test188/189: fix Content-Length - - Don't check for pre-3.0.0 CMake version. - We already require at least 3.0.0, so it's just clutter. + This cures the flaky test results - Ref: #3744 - -Steve Holme (8 Apr 2019) -- build-openssl.bat: Fixed support for OpenSSL v1.1.0+ - -- build-openssl.bat: Perfer the use of if statements rather than goto (where possible) - -- build-openssl.bat: Perform the install for each build type directly after the build - -- build-openssl.bat: Split the install of static and shared build types - -- build-openssl.bat: Split the building of static and shared build types - -- build-openssl.bat: Move the installation into a separate function - -- build-openssl.bat: Move the build step into a separate function + Closes #4034 -- build-openssl.bat: Move the OpenSSL configuration into a separate function +- [Thomas Gamper brought this change] -- build-openssl.bat: Fixed the BUILD_CONFIG variable not being initialised + winbuild: use WITH_PREFIX if given - Should the parent environment set this variable then the build might - not be performed as the user intended. - -Daniel Stenberg (8 Apr 2019) -- socks: fix error message + Closes #4031 -- config.d: clarify that initial : and = might need quoting [skip ci] +Daniel Gustafsson (17 Jun 2019) +- openssl: remove outdated comment + + OpenSSL used to call exit(1) on syntax errors in OPENSSL_config(), + which is why we switched to CONF_modules_load_file() and introduced + a comment stating why. This behavior was however changed in OpenSSL + commit abdd677125f3a9e3082f8c5692203590fdb9b860, so remove the now + outdated and incorrect comment. The mentioned commit also declares + OPENSSL_config() deprecated so keep the current coding. - Fixes #3738 - Closes #3749 + Closes #4033 + Reviewed-by: Daniel Stenberg +Daniel Stenberg (16 Jun 2019) - RELEASE-NOTES: synced - - bumped to 7.65.0 for next release -- socks5: user name and passwords must be shorter than 256 - - bytes... since the protocol needs to store the length in a single byte field. +Patrick Monnerat (16 Jun 2019) +- os400: make vsetopt() non-static as Curl_vsetopt() for os400 support. - Reported-by: XmiliaH on github - Fixes #3737 - Closes #3740 - -- [Jakub Zakrzewski brought this change] - - test: urlapi: urlencode characters above 0x7f correctly - -- [Jakub Zakrzewski brought this change] - - urlapi: urlencode characters above 0x7f correctly + Use it in curl_easy_setopt_ccsid(). - fixes #3741 - Closes #3742 - -- [Even Rouault brought this change] + Reported-by: jonrumsey on github + Fixes #3833 + Closes #4028 - multi_runsingle(): fix use-after-free - - Fixes #3745 - Closes #3746 - - The following snippet - ``` +Daniel Stenberg (15 Jun 2019) +- runtests: report single test time + total duration - int main() - { - CURL* hCurlHandle = curl_easy_init(); - curl_easy_setopt(hCurlHandle, CURLOPT_URL, "http://example.com"); - curl_easy_setopt(hCurlHandle, CURLOPT_PROXY, "1"); - curl_easy_perform(hCurlHandle); - curl_easy_cleanup(hCurlHandle); - return 0; - } - ``` - triggers the following Valgrind warning + ... after each successful test. - ``` - ==4125== Invalid read of size 8 - ==4125== at 0x4E7D1EE: Curl_llist_remove (llist.c:97) - ==4125== by 0x4E7EF5C: detach_connnection (multi.c:798) - ==4125== by 0x4E80545: multi_runsingle (multi.c:1451) - ==4125== by 0x4E8197C: curl_multi_perform (multi.c:2072) - ==4125== by 0x4E766A0: easy_transfer (easy.c:625) - ==4125== by 0x4E76915: easy_perform (easy.c:719) - ==4125== by 0x4E7697C: curl_easy_perform (easy.c:738) - ==4125== by 0x4008BE: main (in /home/even/curl/test) - ==4125== Address 0x9b3d1d0 is 1,120 bytes inside a block of size 1,600 free'd - ==4125== at 0x4C2ECF0: free (vg_replace_malloc.c:530) - ==4125== by 0x4E62C36: conn_free (url.c:756) - ==4125== by 0x4E62D34: Curl_disconnect (url.c:818) - ==4125== by 0x4E48DF9: Curl_once_resolved (hostip.c:1097) - ==4125== by 0x4E8052D: multi_runsingle (multi.c:1446) - ==4125== by 0x4E8197C: curl_multi_perform (multi.c:2072) - ==4125== by 0x4E766A0: easy_transfer (easy.c:625) - ==4125== by 0x4E76915: easy_perform (easy.c:719) - ==4125== by 0x4E7697C: curl_easy_perform (easy.c:738) - ==4125== by 0x4008BE: main (in /home/even/curl/test) - ==4125== Block was alloc'd at - ==4125== at 0x4C2F988: calloc (vg_replace_malloc.c:711) - ==4125== by 0x4E6438E: allocate_conn (url.c:1654) - ==4125== by 0x4E685B4: create_conn (url.c:3496) - ==4125== by 0x4E6968F: Curl_connect (url.c:4023) - ==4125== by 0x4E802E7: multi_runsingle (multi.c:1368) - ==4125== by 0x4E8197C: curl_multi_perform (multi.c:2072) - ==4125== by 0x4E766A0: easy_transfer (easy.c:625) - ==4125== by 0x4E76915: easy_perform (easy.c:719) - ==4125== by 0x4E7697C: curl_easy_perform (easy.c:738) - ==4125== by 0x4008BE: main (in /home/even/curl/test) - ``` + Closes #4027 + +- multi: fix the transfer hash function - This has been bisected to commit 2f44e94 + Follow-up from 8b987cc7eb - Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=14109 - Credit to OSS Fuzz + Reported-by: Tom van der Woerdt + Fixes #4018 + Closes #4024 -- pipelining: removed +- unit1654: cleanup on memory failure - As previously planned and documented in DEPRECATE.md, all pipelining - code is removed. + ... to make it handle torture tests properly. - Closes #3651 - -- [cclauss brought this change] + Reported-by: Marcel Raad + Fixes #4021 + Closes #4022 - tests: make Impacket (SMB server) Python 3 compatible +Marcel Raad (13 Jun 2019) +- krb5: fix compiler warning - Closes #3731 - Fixes #3289 - -Marcel Raad (6 Apr 2019) -- [Simon Warta brought this change] - - cmake: set SSL_BACKENDS + Even though the variable was used in a DEBUGASSERT, GCC 8 warned in + debug mode: + krb5.c:324:17: error: unused variable 'maj' [-Werror=unused-variable] - This groups all SSL backends into the feature "SSL" and sets the - SSL_BACKENDS analogue to configure.ac + Just suppress the warning and declare the variable unconditionally + instead of only for DEBUGBUILD (which also missed the check for + HAVE_ASSERT_H). - Closes https://github.com/curl/curl/pull/3736 + Closes https://github.com/curl/curl/pull/4020 -- [Simon Warta brought this change] +Daniel Stenberg (13 Jun 2019) +- quote.d: asterisk prefix works for SFTP as well + + Reported-by: Ben Voris + Fixes #4017 + Closes #4019 - cmake: don't run SORT on empty list +- multi: fix the transfer hashes in the socket hash entries + + - The transfer hashes weren't using the correct keys so removing entries + failed. - In case of an empty list, SORTing leads to the cmake error "list - sub-command SORT requires list to be present." + - Simplified the iteration logic over transfers sharing the same socket and + they now simply are set to expire and thus get handled in the "regular" + timer loop instead. - Closes https://github.com/curl/curl/pull/3736 + Reported-by: Tom van der Woerdt + Fixes #4012 + Closes #4014 -Daniel Gustafsson (5 Apr 2019) -- [Eli Schwartz brought this change] +Jay Satiro (12 Jun 2019) +- [Cliff Crosland brought this change] - configure: fix default location for fish completions + url: Fix CURLOPT_MAXAGE_CONN time comparison - Fish defines a vendor completions directory for completions that are not - installed as part of the fish project itself, and the vendor completions - are preferred if they exist. This prevents trying to overwrite the - builtin curl.fish completion (or creating file conflicts in distro - packaging). + Old connections are meant to expire from the connection cache after + CURLOPT_MAXAGE_CONN seconds. However, they actually expire after 1000x + that value. This occurs because a time value measured in milliseconds is + accidentally divided by 1M instead of by 1,000. - Prefer the pkg-config defined location exported by fish, if it can be - found, and fall back to the correct directory defined by most systems. + Closes https://github.com/curl/curl/pull/4013 + +Daniel Stenberg (11 Jun 2019) +- test1165: verify that CURL_DISABLE_ symbols are in sync - Closes #3723 - Reviewed-by: Daniel Gustafsson + between configure.ac and source code. They should be possible to switch + on/off in configure AND be used in source code. -Marcel Raad (5 Apr 2019) -- ftplistparser: fix LGTM alert "Empty block without comment" +- configure: remove CURL_DISABLE_TLS_SRP - Removing the block is consistent with line 954/957. + It isn't used by code so stop providing the define. - Closes https://github.com/curl/curl/pull/3732 + Closes #4010 -- transfer: fix LGTM alert "Comparison is always true" +- Revert "cmake: add SMB to list of disabled protocols if HTTP_ONLY is specified" - Just remove the redundant condition, which also makes it clear that - k->buf is always 0-terminated if this break is not hit. + This reverts commit 36738caeb78603ce24e3ea089a167b8c216fb938. - Closes https://github.com/curl/curl/pull/3732 + Apparently several of the appveyor windows builds broke. -Jay Satiro (4 Apr 2019) -- [Rikard Falkeborn brought this change] +- [sergey-raevskiy brought this change] - smtp: fix compiler warning + cmake: add SMB to list of disabled protocols if HTTP_ONLY is specified - - Fix clang string-plus-int warning. + Reviewed-by: Jakub Zakrzewski + Closes #3770 + +- RELEASE-NOTES: synced + +- http2: remove CURL_DISABLE_TYPECHECK define - Clang 8 warns about adding a string to an int does not append to the - string. Indeed it doesn't, but that was not the intention either. Use - array indexing as suggested to silence the warning. There should be no - functional changes. + ... in http2-less builds as it served no use. + +- configure: more --disable switches to toggle off individual features - (In other words clang warns about "foo"+2 but not &"foo"[2] so use the - latter.) + ... actual support in the code for disabling these has already landed. - smtp.c:1221:29: warning: adding 'int' to a string does not append to the - string [-Wstring-plus-int] - eob = strdup(SMTP_EOB + 2); - ~~~~~~~~~~~~~~~~^~~~ + Closes #4009 + +- wolfssl: fix key pinning build error - Closes https://github.com/curl/curl/pull/3729 + follow-up from deb9462ff2de8 diff --git a/release/src/router/curl/CMake/CurlSymbolHiding.cmake b/release/src/router/curl/CMake/CurlSymbolHiding.cmake index 224755a314c..8e5fd67a0ab 100644 --- a/release/src/router/curl/CMake/CurlSymbolHiding.cmake +++ b/release/src/router/curl/CMake/CurlSymbolHiding.cmake @@ -11,13 +11,7 @@ if(CURL_HIDDEN_SYMBOLS) set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") elseif(CMAKE_COMPILER_IS_GNUCC) - if(NOT CMAKE_VERSION VERSION_LESS 2.8.10) - set(GCC_VERSION ${CMAKE_C_COMPILER_VERSION}) - else() - execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - endif() - if(NOT GCC_VERSION VERSION_LESS 3.4) + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4) # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact set(SUPPORTS_SYMBOL_HIDING TRUE) set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") diff --git a/release/src/router/curl/CMake/FindCARES.cmake b/release/src/router/curl/CMake/FindCARES.cmake index 723044a6442..3d1bae6dcff 100644 --- a/release/src/router/curl/CMake/FindCARES.cmake +++ b/release/src/router/curl/CMake/FindCARES.cmake @@ -7,34 +7,16 @@ # also defined, but not for general use are # CARES_LIBRARY, where to find the c-ares library. -find_path(CARES_INCLUDE_DIR ares.h - /usr/local/include - /usr/include - ) +find_path(CARES_INCLUDE_DIR ares.h) set(CARES_NAMES ${CARES_NAMES} cares) find_library(CARES_LIBRARY NAMES ${CARES_NAMES} - PATHS /usr/lib /usr/local/lib ) -if(CARES_LIBRARY AND CARES_INCLUDE_DIR) - set(CARES_LIBRARIES ${CARES_LIBRARY}) - set(CARES_FOUND "YES") -else() - set(CARES_FOUND "NO") -endif() - - -if(CARES_FOUND) - if(NOT CARES_FIND_QUIETLY) - message(STATUS "Found c-ares: ${CARES_LIBRARIES}") - endif() -else() - if(CARES_FIND_REQUIRED) - message(FATAL_ERROR "Could not find c-ares library") - endif() -endif() +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CARES + REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR) mark_as_advanced( CARES_LIBRARY diff --git a/release/src/router/curl/CMake/FindLibSSH2.cmake b/release/src/router/curl/CMake/FindLibSSH2.cmake index 84822dba74d..91e17c1db15 100644 --- a/release/src/router/curl/CMake/FindLibSSH2.cmake +++ b/release/src/router/curl/CMake/FindLibSSH2.cmake @@ -5,31 +5,18 @@ # LIBSSH2_INCLUDE_DIR - the libssh2 include directory # LIBSSH2_LIBRARY - the libssh2 library name -if(LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) - set(LibSSH2_FIND_QUIETLY TRUE) -endif() - -find_path(LIBSSH2_INCLUDE_DIR libssh2.h -) +find_path(LIBSSH2_INCLUDE_DIR libssh2.h) -find_library(LIBSSH2_LIBRARY NAMES ssh2 -) +find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2) if(LIBSSH2_INCLUDE_DIR) - file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9][0-9][0-9].*") - - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MAJOR "${libssh2_version_str}") - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MINOR "${libssh2_version_str}") - string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_PATCH "${libssh2_version_str}") - - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MAJOR "${LIBSSH2_VERSION_MAJOR}") - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MINOR "${LIBSSH2_VERSION_MINOR}") - string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_PATCH "${LIBSSH2_VERSION_PATCH}") - - set(LIBSSH2_VERSION "${LIBSSH2_VERSION_MAJOR}.${LIBSSH2_VERSION_MINOR}.${LIBSSH2_VERSION_PATCH}") + file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"") + string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1" LIBSSH2_VERSION "${libssh2_version_str}") endif() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LibSSH2 DEFAULT_MSG LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY ) +find_package_handle_standard_args(LibSSH2 + REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR + VERSION_VAR LIBSSH2_VERSION) -mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY LIBSSH2_VERSION_MAJOR LIBSSH2_VERSION_MINOR LIBSSH2_VERSION_PATCH LIBSSH2_VERSION) +mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY) diff --git a/release/src/router/curl/CMake/FindNGHTTP2.cmake b/release/src/router/curl/CMake/FindNGHTTP2.cmake index 348b9612dfa..5138e99999e 100644 --- a/release/src/router/curl/CMake/FindNGHTTP2.cmake +++ b/release/src/router/curl/CMake/FindNGHTTP2.cmake @@ -10,9 +10,9 @@ find_package_handle_standard_args(NGHTTP2 REQUIRED_VARS NGHTTP2_LIBRARY NGHTTP2_INCLUDE_DIR - FAIL_MESSAGE - "Could NOT find NGHTTP2" ) set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR}) set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY}) + +mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES) diff --git a/release/src/router/curl/CMake/OtherTests.cmake b/release/src/router/curl/CMake/OtherTests.cmake index c1c9aa32ab5..8b150290c73 100644 --- a/release/src/router/curl/CMake/OtherTests.cmake +++ b/release/src/router/curl/CMake/OtherTests.cmake @@ -32,7 +32,7 @@ int main(void) { return 0; }" curl_cv_recv) if(curl_cv_recv) - if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown") + if(NOT DEFINED curl_cv_func_recv_args OR curl_cv_func_recv_args STREQUAL "unknown") foreach(recv_retv "int" "ssize_t" ) foreach(recv_arg1 "SOCKET" "int" ) foreach(recv_arg2 "char *" "void *" ) @@ -81,7 +81,7 @@ if(curl_cv_recv) string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}") endif() - if("${curl_cv_func_recv_args}" STREQUAL "unknown") + if(curl_cv_func_recv_args STREQUAL "unknown") message(FATAL_ERROR "Cannot find proper types to use for recv args") endif() else() diff --git a/release/src/router/curl/CMake/Utilities.cmake b/release/src/router/curl/CMake/Utilities.cmake index 5cb1d449754..ffc411ae98b 100644 --- a/release/src/router/curl/CMake/Utilities.cmake +++ b/release/src/router/curl/CMake/Utilities.cmake @@ -2,12 +2,11 @@ # Returns a list of arguments that evaluate to true function(count_true output_count_var) - set(lst) + set(lst_len 0) foreach(option_var IN LISTS ARGN) if(${option_var}) - list(APPEND lst ${option_var}) + math(EXPR lst_len "${lst_len} + 1") endif() endforeach() - list(LENGTH lst lst_len) set(${output_count_var} ${lst_len} PARENT_SCOPE) endfunction() diff --git a/release/src/router/curl/CMakeLists.txt b/release/src/router/curl/CMakeLists.txt index cb78921e129..73b053b3157 100644 --- a/release/src/router/curl/CMakeLists.txt +++ b/release/src/router/curl/CMakeLists.txt @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -38,7 +38,8 @@ # To check: # (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not. # (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options. -cmake_minimum_required(VERSION 3.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.0...3.16 FATAL_ERROR) + set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") include(Utilities) include(Macros) @@ -49,7 +50,7 @@ project(CURL C) message(WARNING "the curl cmake build system is poorly maintained. Be aware") -file(READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS) +file(STRINGS ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS REGEX "#define LIBCURL_VERSION( |_NUM )") string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" CURL_VERSION ${CURL_VERSION_H_CONTENTS}) string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) @@ -79,7 +80,18 @@ option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) if(WIN32) option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF) option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON) + set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string") + if(CURL_TARGET_WINDOWS_VERSION) + add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}) + elseif(ENABLE_INET_PTON) + # _WIN32_WINNT_VISTA (0x0600) + add_definitions(-D_WIN32_WINNT=0x0600) + else() + # _WIN32_WINNT_WINXP (0x0501) + add_definitions(-D_WIN32_WINNT=0x0501) + endif() endif() +option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF) cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup" ON "NOT ENABLE_ARES" @@ -93,8 +105,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers -Wno-pedantic-ms-format) # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new # test result in. - check_c_compiler_flag(${_CCOPT} OPT${_CCOPT}) - if(OPT${_CCOPT}) + string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname) + check_c_compiler_flag(${_CCOPT} ${_optvarname}) + if(${_optvarname}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}") endif() endforeach() @@ -123,7 +136,6 @@ if(ENABLE_ARES) set(USE_ARES 1) find_package(CARES REQUIRED) list(APPEND CURL_LIBS ${CARES_LIBRARY}) - set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) endif() include(CurlSymbolHiding) @@ -172,6 +184,7 @@ if(HTTP_ONLY) set(CURL_DISABLE_RTSP ON) set(CURL_DISABLE_POP3 ON) set(CURL_DISABLE_IMAP ON) + set(CURL_DISABLE_SMB ON) set(CURL_DISABLE_SMTP ON) set(CURL_DISABLE_GOPHER ON) endif() @@ -285,7 +298,7 @@ if(WIN32) endif() # check SSL libraries -# TODO support GNUTLS, POLARSSL, CYASSL +# TODO support GnuTLS and WolfSSL if(APPLE) option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF) @@ -412,6 +425,10 @@ if(USE_NGHTTP2) list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) endif() +if(WIN32) + set(USE_WIN32_CRYPTO ON) +endif() + if(NOT CURL_DISABLE_LDAP) if(WIN32) option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) @@ -923,20 +940,7 @@ check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) - -# symbol exists in win32, but function does not. -if(WIN32) - if(ENABLE_INET_PTON) - check_function_exists(inet_pton HAVE_INET_PTON) - # _WIN32_WINNT_VISTA (0x0600) - add_definitions(-D_WIN32_WINNT=0x0600) - else() - # _WIN32_WINNT_WINXP (0x0501) - add_definitions(-D_WIN32_WINNT=0x0501) - endif() -else() - check_function_exists(inet_pton HAVE_INET_PTON) -endif() +check_symbol_exists(inet_pton "${CURL_INCLUDES}" HAVE_INET_PTON) check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR) if(HAVE_FSETXATTR) @@ -1160,6 +1164,23 @@ if(CURL_WERROR) endif() endif() +if(CURL_LTO) + if(CMAKE_VERSION VERSION_LESS 3.9) + message(FATAL_ERROR "Requested LTO but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9") + endif() + + cmake_policy(SET CMP0069 NEW) + + include(CheckIPOSupported) + check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT CURL_LTO_ERROR LANGUAGES C) + if(CURL_HAS_LTO) + message(STATUS "LTO supported and enabled") + else() + message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}") + endif() +endif() + + # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). function(transform_makefile_inc INPUT_FILE OUTPUT_FILE) file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) @@ -1199,14 +1220,22 @@ if(BUILD_TESTING) add_subdirectory(tests) endif() +# NTLM support requires crypto function adaptions from various SSL libs +# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS +if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO)) + set(use_ntlm ON) +else() + set(use_ntlm OFF) +endif() + # Helper to populate a list (_items) with a label when conditions (the remaining # args) are satisfied -function(_add_if label) - # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection +macro(_add_if label) + # needs to be a macro to allow this indirection if(${ARGN}) - set(_items ${_items} "${label}" PARENT_SCOPE) + set(_items ${_items} "${label}") endif() -endfunction() +endmacro() # Clear list and try to detect available features set(_items) @@ -1228,15 +1257,14 @@ _add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) # NTLM support requires crypto function adaptions from various SSL libs # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS -if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_SECTRANSP OR USE_MBEDTLS OR USE_NSS)) - _add_if("NTLM" 1) - # TODO missing option (autoconf: --enable-ntlm-wb) - _add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) -endif() +_add_if("NTLM" use_ntlm) +# TODO missing option (autoconf: --enable-ntlm-wb) +_add_if("NTLM_WB" use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP _add_if("TLS-SRP" USE_TLS_SRP) # TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header _add_if("HTTP2" USE_NGHTTP2) +_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS)) string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") message(STATUS "Enabled features: ${SUPPORT_FEATURES}") @@ -1261,6 +1289,8 @@ _add_if("POP3" NOT CURL_DISABLE_POP3) _add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) _add_if("IMAP" NOT CURL_DISABLE_IMAP) _add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) +_add_if("SMB" NOT CURL_DISABLE_SMB AND use_ntlm) +_add_if("SMBS" NOT CURL_DISABLE_SMB AND SSL_ENABLED AND use_ntlm) _add_if("SMTP" NOT CURL_DISABLE_SMTP) _add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) _add_if("SCP" USE_LIBSSH2) diff --git a/release/src/router/curl/Makefile.in b/release/src/router/curl/Makefile.in index d49d7001f8c..cadf9f24b2b 100644 --- a/release/src/router/curl/Makefile.in +++ b/release/src/router/curl/Makefile.in @@ -43,7 +43,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -447,6 +447,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -663,19 +664,18 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c \ - vtls/wolfssl.c vtls/schannel.c vtls/schannel_verify.c \ - vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c \ - vtls/bearssl.c + vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ + vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ + vtls/mesalink.c vtls/bearssl.c -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ - vtls/wolfssl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \ - vtls/mbedtls.h vtls/mesalink.h vtls/bearssl.h +LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ + vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ + vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ + vtls/bearssl.h LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h -LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c +LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ @@ -695,7 +695,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_multibyte.c hostcheck.c conncache.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ - doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c + doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -716,7 +716,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ - curl_get_line.h altsvc.h quic.h socketpair.h + curl_get_line.h altsvc.h quic.h socketpair.h rename.h LIB_RCFILES = libcurl.rc CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ diff --git a/release/src/router/curl/README b/release/src/router/curl/README index c439dab9e73..490faca1637 100644 --- a/release/src/router/curl/README +++ b/release/src/router/curl/README @@ -21,6 +21,8 @@ README curl binaries or other binaries that involve libcurl, you might enjoy the LICENSE-MIXING document. + All of those documents and more can be found in the docs/ directory. + CONTACT If you have problems, questions, ideas or suggestions, please contact us diff --git a/release/src/router/curl/RELEASE-NOTES b/release/src/router/curl/RELEASE-NOTES index 7a121127151..ef3e38d14ab 100644 --- a/release/src/router/curl/RELEASE-NOTES +++ b/release/src/router/curl/RELEASE-NOTES @@ -1,146 +1,40 @@ -curl and libcurl 7.68.0 +curl and libcurl 7.69.1 - Public curl releases: 188 - Command line options: 229 - curl_easy_setopt() options: 269 + Public curl releases: 190 + Command line options: 230 + curl_easy_setopt() options: 270 Public functions in libcurl: 82 - Contributors: 2088 - -This release includes the following changes: - - o TLS: add BearSSL vtls implementation [37] - o XFERINFOFUNCTION: support CURL_PROGRESSFUNC_CONTINUE [36] - o curl: add --etag-compare and --etag-save [31] - o curl: add --parallel-immediate [29] - o multi: add curl_multi_wakeup() [38] - o openssl: CURLSSLOPT_NO_PARTIALCHAIN can disable partial cert chains [45] + Contributors: 2133 This release includes the following bugfixes: - o CVE-2019-15601: file: on Windows, refuse paths that start with \\ [106] - o Azure Pipelines: add several builds - o CMake: add support for building with the NSS vtls backend [43] - o CURL-DISABLE: initial docs for the CURL_DISABLE_* defines [19] - o CURLOPT_HEADERFUNCTION.3: Document that size is always 1 [100] - o CURLOPT_QUOTE.3: fix typos [78] - o CURLOPT_READFUNCTION.3: fix the example [107] - o CURLOPT_URL.3: "curl supports SMB version 1 (only)" - o CURLOPT_VERBOSE.3: see also ERRORBUFFER - o HISTORY: added cmake, HTTP/3 and parallel downloads with curl - o HISTORY: the SMB(S) support landed in 2014 - o INSTALL.md: provide Android build instructions [10] - o KNOWN_BUGS: Connection information when using TCP Fast Open [85] - o KNOWN_BUGS: LDAP on Windows doesn't work correctly [86] - o KNOWN_BUGS: TLS session cache doesn't work with TFO [56] - o OPENSOCKETFUNCTION.3: correct the purpose description [48] - o TrackMemory tests: always remove CR before LF [111] - o altsvc: bump to h3-24 [6] - o altsvc: make the save function ignore NULL filenames [67] - o build: Disable Visual Studio warning "conditional expression is constant" [49] - o build: fix for CURL_DISABLE_DOH [2] - o checksrc.bat: Add a check for vquic and vssh directories [40] - o checksrc: repair the copyrightyear check [25] - o cirrus-ci: enable clang sanitizers on freebsd 13 [60] - o cirrus: Drop the FreeBSD 10.4 build - o config-win32: cpu-machine-OS for Windows on ARM [13] - o configure: avoid unportable `==' test(1) operator [1] - o configure: enable IPv6 support without `getaddrinfo` [44] - o configure: fix typo in help text [4] - o conncache: CONNECT_ONLY connections assumed always in-use [71] - o conncache: fix multi-thread use of shared connection cache [61] - o copyrights: fix copyright year range [25] - o create_conn: prefer multiplexing to using new connections [76] - o curl -w: handle a blank input file correctly [105] - o curl.h: add two missing defines for "pre ISO C" compilers [75] - o curl/parseconfig: fix mem-leak [81] - o curl/parseconfig: use curl_free() to free memory allocated by libcurl [80] - o curl: cleanup multi handle on failure [103] - o curl: fix --upload-file . hangs if delay in STDIN [35] - o curl: fix -T globbing [16] - o curl: improved cleanup in upload error path [69] - o curl: make a few char pointers point to const char instead [95] - o curl: properly free mimepost data [104] - o curl: show better error message when no homedir is found [47] - o curl: show error for --http3 if libcurl lacks support [108] - o curl_setup_once: consistently use WHILE_FALSE in macros [54] - o define: remove HAVE_ENGINE_LOAD_BUILTIN_ENGINES, not used anymore [83] - o docs: Change 'experiemental' to 'experimental' [30] - o docs: TLS SRP doesn't work with TLS 1.3 [87] - o docs: fix several typos [62] - o docs: mention CURL_MAX_INPUT_LENGTH restrictions [109] - o doh: improved both encoding and decoding [11] - o doh: make it behave when built without proxy support [68] - o examples/postinmemory.c: Call curl_global_cleanup always [101] - o examples/url2file.c: corrected erroneous comment [102] - o examples: add multi-poll.c [14] - o global_init: undo the "intialized" bump in case of failure [52] - o hostip: suppress compiler warning [64] - o http_ntlm: Remove duplicate NSS initialisation [55] - o lib: Move lib/ssh.h -> lib/vssh/ssh.h [9] - o lib: fix compiler warnings with `CURL_DISABLE_VERBOSE_STRINGS` [93] - o lib: fix warnings found when porting to NuttX [99] - o lib: remove ASSIGNWITHINCONDITION exceptions, use our code style [84] - o lib: remove erroneous +x file permission on some c files [99] - o libssh2: add support for ECDSA and ed25519 knownhost keys [89] - o multi.h: remove INITIAL_MAX_CONCURRENT_STREAMS from public header [110] - o multi: free sockhash on OOM [63] - o multi_poll: avoid busy-loop when called without easy handles attached [15] - o ngtcp2: Support the latest update key callback type [92] - o ngtcp2: fix thread-safety bug in error-handling [33] - o ngtcp2: free used resources on disconnect [7] - o ngtcp2: handle key updates as ngtcp2 master branch tells us [8] - o ngtcp2: increase QUIC window size when data is consumed [12] - o ngtcp2: use overflow buffer for extra HTTP/3 data [5] - o ntlm: USE_WIN32_CRYPTO check removed to get USE_NTLM2SESSION set [3] - o ntlm_wb: fix double-free in OOM [65] - o openssl: Revert to less sensitivity for SYSCALL errors [26] - o openssl: improve error message for SYSCALL during connect [27] - o openssl: prevent recursive function calls from ctx callbacks [18] - o openssl: retrieve reported LibreSSL version at runtime [50] - o openssl: set X509_V_FLAG_PARTIAL_CHAIN by default [46] - o parsedate: offer a getdate_capped() alternative [53] - o pause: avoid updating socket if done was already called [22] - o projects: Fix Visual Studio projects SSH builds [41] - o projects: Fix Visual Studio wolfSSL configurations - o quiche: reject HTTP/3 headers in the wrong order [17] - o remove_handle: clear expire timers after multi_done() [20] - o runtests: --repeat=[num] to repeat tests [91] - o runtests: introduce --shallow to reduce huge torture tests [70] - o schannel: fix --tls-max for when min is --tlsv1 or default [39] - o setopt: Fix ALPN / NPN user option when built without HTTP2 [42] - o strerror: Add Curl_winapi_strerror for Win API specific errors [51] - o strerror: Fix an error looking up some Windows error strings - o strerror: Fix compiler warning "empty expression" [79] - o system.h: fix for MCST lcc compiler [23] - o test/sws: search for "Testno:" header unconditionally if no testno [73] - o test1175: verify symbols-in-versions and libcurl-errors.3 in sync [28] - o test1270: a basic -w redirect_url test [82] - o test1456: remove the use of a fixed local port number [77] - o test1558: use double slash after file: [21] - o test1560: require IPv6 for IPv6 aware URL parsing [24] - o tests/lib1557: fix mem-leak in OOM [66] - o tests/lib1559: fix mem-leak in OOM [66] - o tests/lib1591: free memory properly on OOM, in the trailers callback [90] - o tests/unit1607: fix mem-leak in OOM [66] - o tests/unit1609: fix mem-leak in OOM [66] - o tests/unit1620: fix bad free in OOM [66] - o tests: Change NTLM tests to require SSL [96] - o tests: Fix bounce requests with truncated writes [94] - o tests: fix build with `CURL_DISABLE_DOH` [64] - o tests: fix permissions of ssh keys in WSL [58] - o tests: make it possible to set executable extensions [58] - o tests: make sure checksrc runs on header files too - o tests: set LC_ALL=en_US.UTF-8 instead of blank in several tests [74] - o tests: use DoH feature for DoH tests [64] - o tests: use \r\n for log messages in WSL [58] - o tool_operate: fix mem leak when failed config parse [98] - o travis: Fix error detection [97] - o travis: abandon coveralls, it is not reliable [57] - o travis: build ngtcp2 with --enable-lib-only [32] - o travis: export the CC/CXX variables when set [34] - o vtls: make BearSSL possible to set with CURL_SSL_BACKEND [72] - o winbuild: Define CARES_STATICLIB when WITH_CARES=static [59] - o winbuild: Document CURL_STATICLIB requirement for static libcurl [88] + o ares: store dns parameters for duphandle [20] + o cirrus-ci: disable the FreeBSD 13 builds [3] + o curl_share_setopt.3: Note sharing cookies doesn't enable the engine [11] + o lib1564: reduce number of mid-wait wakeup calls [16] + o libssh: Fix matching user-specified MD5 hex key [7] + o MANUAL: update a dict-using command line + o mime: do not perform more than one read in a row [18] + o mime: fix the binary encoder to handle large data properly [17] + o mime: latch last read callback status [19] + o multi: skip EINTR check on wakeup socket if it was closed [12] + o pause: bail out on bad input [8] + o pause: force a connection recheck after unpausing (take 2) [5] + o pause: return early for calls that don't change pause state [10] + o runtests.1: rephrase how to specify what tests to run [2] + o runtests: fix missing use of exe_ext helper function + o seek: fix fall back for missing ftruncate on Windows [4] + o sftp: fix segfault regression introduced by #4747 in 7.69.0 [22] + o sha256: Added SecureTransport implementation [15] + o sha256: Added WinCrypt implementation [15] + o socks4: fix host resolve regression [14] + o socks5: host name resolv regression fix [6] + o tests/server: fix missing use of exe_ext helper function [24] + o tests: fix static ip:port instead of dynamic values being used [23] + o tests: make sleeping portable by avoiding select [1] + o unit1612: fix the inclusion and compilation of the HMAC unit test [9] + o urldata: remove the 'stream_was_rewound' connectdata struct member [13] + o version: make curl_version* thread-safe without using global context [21] This release includes the following known bugs: @@ -149,137 +43,38 @@ This release includes the following known bugs: This release would not have looked like this without help, code, reports and advice from friends like these: - 3dyd on github, Anderson Sasaki, Andreas Falkenhahn, Andrew Ishchuk, - bdry on github, Bjoern Franke, Brian Carpenter, bxac on github, - Bylon2 on github, Christian Schmitz, Christopher Head, Christopher Reid, - Christoph M. Becker, Cynthia Coan, Dan Fandrich, Daniel Gustafsson, - Daniel Stenberg, David Benjamin, Emil Engler, Fernando Muñoz, Frank Gevaerts, - Geeknik Labs, Gergely Nagy, Gisle Vanem, JanB on github, Javier Blazquez, - Jeff Mears, Jeffrey Walton, John Schroeder, Kamil Dudka, - kouzhudong on github, Kunal Ekawde, Leonardo Taccari, Marc Aldorasi, - Marcel Raad, marc-groundctl on github, Marc Hörsken, Maros Priputen, - Massimiliano Fantuzzi, Max Kellermann, Melissa Mears, Michael Forney, - Michael Vittiglio, Mohammad Hasbini, Niall O'Reilly, Paul Groke, - Paul Hoffman, Paul Joyce, Paulo Roberto Tomasi, Pavel Löbl, Pavel Pavlov, - Peter Wu, Ram Krushna Mishra, Ray Satiro, Richard Alcock, Richard Bowker, - Rickard Hallerbäck, Santino Keupp, sayrer on github, Shailesh Kapse, - Simon Warta, SLDiggie on github, Steve Holme, Tatsuhiro Tsujikawa, - Tom van der Woerdt, Victor Magierski, Vlastimil Ovčáčík, Wyatt O'Day, - Xiang Xiao, Xiaoyin Liu, - (70 contributors) + amishmm on github, Anders Berg, Andy Fiddaman, Christopher Reid, + Dan Fandrich, Daniel Stenberg, Ernst Sjöstrand, fds242 on github, + Fedor Korotkov, Felipe Gasper, Jim Fuller, Marcel Raad, Marc Hörsken, + MrdUkk on github, Patrick Monnerat, Ray Satiro, RuurdBeerstra on github, + Steve Holme, vitaha85 on github, + (19 contributors) Thanks! (and sorry if I forgot to mention someone) References to bug reports and discussions on issues: - [1] = https://curl.haxx.se/bug/?i=4567 - [2] = https://curl.haxx.se/bug/?i=4565 - [3] = https://curl.haxx.se/bug/?i=3704 - [4] = https://curl.haxx.se/bug/?i=4570 - [5] = https://curl.haxx.se/bug/?i=4525 - [6] = https://curl.haxx.se/bug/?i=4604 - [7] = https://curl.haxx.se/bug/?i=4614 - [8] = https://curl.haxx.se/bug/?i=4612 - [9] = https://curl.haxx.se/bug/?i=4609 - [10] = https://curl.haxx.se/bug/?i=4606 - [11] = https://curl.haxx.se/bug/?i=4598 - [12] = https://curl.haxx.se/bug/?i=4600 - [13] = https://curl.haxx.se/bug/?i=4590 - [14] = https://curl.haxx.se/bug/?i=4596 - [15] = https://curl.haxx.se/bug/?i=4594 - [16] = https://curl.haxx.se/bug/?i=4588 - [17] = https://curl.haxx.se/bug/?i=4571 - [18] = https://curl.haxx.se/bug/?i=4585 - [19] = https://curl.haxx.se/bug/?i=4545 - [20] = https://curl.haxx.se/bug/?i=4575 - [21] = https://curl.haxx.se/bug/?i=4554 - [22] = https://curl.haxx.se/bug/?i=4563 - [23] = https://curl.haxx.se/bug/?i=4576 - [24] = https://curl.haxx.se/bug/?i=4556 - [25] = https://curl.haxx.se/bug/?i=4549 - [26] = https://curl.haxx.se/bug/?i=4624 - [27] = https://curl.haxx.se/bug/?i=4593 - [28] = https://curl.haxx.se/bug/?i=4628 - [29] = https://curl.haxx.se/bug/?i=4500 - [30] = https://curl.haxx.se/bug/?i=4618 - [31] = https://curl.haxx.se/bug/?i=4543 - [32] = https://curl.haxx.se/bug/?i=4646 - [33] = https://curl.haxx.se/bug/?i=4645 - [34] = https://curl.haxx.se/bug/?i=4637 - [35] = https://curl.haxx.se/bug/?i=2051 - [36] = https://curl.haxx.se/bug/?i=4599 - [37] = https://curl.haxx.se/bug/?i=4597 - [38] = https://curl.haxx.se/bug/?i=4418 - [39] = https://curl.haxx.se/bug/?i=4633 - [40] = https://curl.haxx.se/bug/?i=4607 - [41] = https://curl.haxx.se/bug/?i=4492 - [42] = https://curl.haxx.se/bug/?i=4668 - [43] = https://curl.haxx.se/bug/?i=4663 - [44] = https://curl.haxx.se/bug/?i=4662 - [45] = https://curl.haxx.se/bug/?i=4665 - [46] = https://curl.haxx.se/mail/lib-2019-11/0094.html - [47] = https://curl.haxx.se/bug/?i=4644 - [48] = https://curl.haxx.se/mail/lib-2019-12/0007.html - [49] = https://curl.haxx.se/bug/?i=4658 - [50] = https://curl.haxx.se/bug/?i=2425 - [51] = https://curl.haxx.se/bug/?i=4550 - [52] = https://curl.haxx.se/bug/?i=4636 - [53] = https://curl.haxx.se/bug/?i=4152 - [54] = https://curl.haxx.se/bug/?i=4649 - [55] = https://curl.haxx.se/bug/?i=3935 - [56] = https://curl.haxx.se/bug/?i=4301 - [57] = https://curl.haxx.se/bug/?i=4694 - [58] = https://curl.haxx.se/bug/?i=3899 - [59] = https://curl.haxx.se/bug/?i=4688 - [60] = https://curl.haxx.se/bug/?i=4557 - [61] = https://curl.haxx.se/bug/?i=4544 - [62] = https://curl.haxx.se/bug/?i=4680 - [63] = https://curl.haxx.se/bug/?i=4713 - [64] = https://curl.haxx.se/bug/?i=4692 - [65] = https://curl.haxx.se/bug/?i=4710 - [66] = https://curl.haxx.se/bug/?i=4709 - [67] = https://curl.haxx.se/bug/?i=4707 - [68] = https://curl.haxx.se/bug/?i=4704 - [69] = https://curl.haxx.se/bug/?i=4705 - [70] = https://curl.haxx.se/bug/?i=4699 - [71] = https://curl.haxx.se/bug/?i=4369 - [72] = https://curl.haxx.se/bug/?i=4698 - [73] = https://curl.haxx.se/bug/?i=4744 - [74] = https://curl.haxx.se/bug/?i=4738 - [75] = https://curl.haxx.se/bug/?i=4739 - [76] = https://curl.haxx.se/bug/?i=4732 - [77] = https://curl.haxx.se/bug/?i=4733 - [78] = https://curl.haxx.se/bug/?i=4736 - [79] = https://github.com/curl/curl/commit/5b22e1a#r36458547 - [80] = https://curl.haxx.se/bug/?i=4730 - [81] = https://curl.haxx.se/bug/?i=4731 - [82] = https://curl.haxx.se/bug/?i=4728 - [83] = https://curl.haxx.se/bug/?i=4725 - [84] = https://curl.haxx.se/bug/?i=4683 - [85] = https://curl.haxx.se/bug/?i=4296 - [86] = https://curl.haxx.se/bug/?i=4261 - [87] = https://curl.haxx.se/bug/?i=4262 - [88] = https://curl.haxx.se/bug/?i=4721 - [89] = https://curl.haxx.se/bug/?i=4714 - [90] = https://curl.haxx.se/bug/?i=4720 - [91] = https://curl.haxx.se/bug/?i=4715 - [92] = https://curl.haxx.se/bug/?i=4735 - [93] = https://curl.haxx.se/bug/?i=4775 - [94] = https://github.com/curl/curl/pull/4717#issuecomment-570240785 - [95] = https://curl.haxx.se/bug/?i=4771 - [96] = https://curl.haxx.se/bug/?i=4768 - [97] = https://curl.haxx.se/bug/?i=3730 - [98] = https://curl.haxx.se/bug/?i=4767 - [99] = https://curl.haxx.se/bug/?i=4756 - [100] = https://curl.haxx.se/bug/?i=4758 - [101] = https://curl.haxx.se/bug/?i=4751 - [102] = https://curl.haxx.se/bug/?i=4745 - [103] = https://curl.haxx.se/bug/?i=4772 - [104] = https://curl.haxx.se/bug/?i=4781 - [105] = https://curl.haxx.se/bug/?i=4786 - [106] = https://curl.haxx.se/docs/CVE-2019-15601.html - [107] = https://curl.haxx.se/bug/?i=4787 - [108] = https://curl.haxx.se/bug/?i=4785 - [109] = https://curl.haxx.se/bug/?i=4783 - [110] = https://curl.haxx.se/bug/?i=4790 - [111] = https://curl.haxx.se/bug/?i=4788 + [1] = https://curl.haxx.se/bug/?i=5035 + [2] = https://curl.haxx.se/bug/?i=5033 + [3] = https://curl.haxx.se/bug/?i=5028 + [4] = https://curl.haxx.se/bug/?i=5055 + [5] = https://curl.haxx.se/bug/?i=5049 + [6] = https://curl.haxx.se/bug/?i=5053 + [7] = https://curl.haxx.se/bug/?i=4971 + [8] = https://curl.haxx.se/bug/?i=5050 + [9] = https://curl.haxx.se/bug/?i=5024 + [10] = https://curl.haxx.se/bug/?i=5026 + [11] = https://curl.haxx.se/mail/lib-2020-03/0019.html + [12] = https://curl.haxx.se/bug/?i=5047 + [13] = https://curl.haxx.se/bug/?i=5046 + [14] = https://curl.haxx.se/bug/?i=5061 + [15] = https://curl.haxx.se/bug/?i=5030 + [16] = https://curl.haxx.se/bug/?i=5037 + [17] = https://curl.haxx.se/bug/?i=4860 + [18] = https://curl.haxx.se/bug/?i=4826 + [19] = https://curl.haxx.se/bug/?i=4813 + [20] = https://curl.haxx.se/bug/?i=4893 + [21] = https://curl.haxx.se/bug/?i=5010 + [22] = https://curl.haxx.se/bug/?i=5041 + [23] = https://curl.haxx.se/bug/?i=5065 + [24] = https://curl.haxx.se/bug/?i=5064 diff --git a/release/src/router/curl/acinclude.m4 b/release/src/router/curl/acinclude.m4 index 24dad39141e..3ad55c38859 100755 --- a/release/src/router/curl/acinclude.m4 +++ b/release/src/router/curl/acinclude.m4 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -2174,8 +2174,8 @@ AC_HELP_STRING([--without-ca-bundle], [Don't use a default CA bundle]), AC_ARG_WITH(ca-path, AC_HELP_STRING([--with-ca-path=DIRECTORY], [Path to a directory containing CA certificates stored individually, with \ -their filenames in a hash format. This option can be used with OpenSSL, \ -GnuTLS and PolarSSL backends. Refer to OpenSSL c_rehash for details. \ +their filenames in a hash format. This option can be used with the OpenSSL, \ +GnuTLS and mbedTLS backends. Refer to OpenSSL c_rehash for details. \ (example: /etc/certificates)]) AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]), [ @@ -2201,8 +2201,8 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]), capath="no" elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then dnl --with-ca-path given - if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1" -a "x$POLARSSL_ENABLED" != "x1"; then - AC_MSG_ERROR([--with-ca-path only works with OpenSSL, GnuTLS or PolarSSL]) + if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1" -a "x$MBEDTLS_ENABLED" != "x1"; then + AC_MSG_ERROR([--with-ca-path only works with OpenSSL, GnuTLS or mbedTLS]) fi capath="$want_capath" ca="no" diff --git a/release/src/router/curl/configure b/release/src/router/curl/configure index 34de9624868..d6d125f49f4 100755 --- a/release/src/router/curl/configure +++ b/release/src/router/curl/configure @@ -11,7 +11,7 @@ # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # -# Copyright (c) 1998 - 2019 Daniel Stenberg, +# Copyright (c) 1998 - 2020 Daniel Stenberg, # This configure script may be copied, distributed and modified under the # terms of the curl license; see COPYING for more details @@ -914,6 +914,7 @@ CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE CURL_LT_SHLIB_VERSIONED_FLAVOUR USE_LIBRTMP +USE_WOLFSSH USE_LIBSSH USE_LIBSSH2 LIBMETALINK_CPPFLAGS @@ -1189,6 +1190,7 @@ with_libpsl with_libmetalink with_libssh2 with_libssh +with_wolfssh with_librtmp enable_versioned_symbols with_winidn @@ -2048,9 +2050,9 @@ Optional Packages: --with-ca-path=DIRECTORY Path to a directory containing CA certificates stored individually, with their filenames in a hash - format. This option can be used with OpenSSL, GnuTLS - and PolarSSL backends. Refer to OpenSSL c_rehash for - details. (example: /etc/certificates) + format. This option can be used with the OpenSSL, + GnuTLS and mbedTLS backends. Refer to OpenSSL + c_rehash for details. (example: /etc/certificates) --without-ca-path Don't use a default CA path --with-ca-fallback Use the built in CA store of the SSL library --without-ca-fallback Don't use the built in CA store of the SSL library @@ -2059,14 +2061,19 @@ Optional Packages: installation root --without-libmetalink disable libmetalink detection --with-libssh2=PATH Where to look for libssh2, PATH points to the - LIBSSH2 installation; when possible, set the + libssh2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option - --with-libssh2 enable LIBSSH2 - --with-libssh=PATH Where to look for libssh, PATH points to the LIBSSH + --with-libssh2 enable libssh2 + --with-libssh=PATH Where to look for libssh, PATH points to the libssh installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option - --with-libssh enable LIBSSH + --with-libssh enable libssh + --with-wolfssh=PATH Where to look for wolfssh, PATH points to the + wolfSSH installation; when possible, set the + PKG_CONFIG_PATH environment variable instead of + using this option + --with-wolfssh enable wolfssh --with-librtmp=PATH Where to look for librtmp, PATH points to the LIBRTMP installation; when possible, set the PKG_CONFIG_PATH environment variable instead of @@ -2178,7 +2185,7 @@ Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -Copyright (c) 1998 - 2019 Daniel Stenberg, +Copyright (c) 1998 - 2020 Daniel Stenberg, This configure script may be copied, distributed and modified under the terms of the curl license; see COPYING for more details _ACEOF @@ -8769,7 +8776,7 @@ esac fi : ${AR=ar} -: ${AR_FLAGS=cru} +: ${AR_FLAGS=cr} @@ -10487,8 +10494,8 @@ int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR cru libconftest.a conftest.o" >&5 - $AR cru libconftest.a conftest.o 2>&5 + echo "$AR cr libconftest.a conftest.o" >&5 + $AR cr libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF @@ -25512,8 +25519,8 @@ fi ca="$want_ca" capath="no" elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then - if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1" -a "x$POLARSSL_ENABLED" != "x1"; then - as_fn_error $? "--with-ca-path only works with OpenSSL, GnuTLS or PolarSSL" "$LINENO" 5 + if test "x$OPENSSL_ENABLED" != "x1" -a "x$GNUTLS_ENABLED" != "x1" -a "x$MBEDTLS_ENABLED" != "x1"; then + as_fn_error $? "--with-ca-path only works with OpenSSL, GnuTLS or mbedTLS" "$LINENO" 5 fi capath="$want_capath" ca="no" @@ -26066,6 +26073,13 @@ $as_echo "$as_me: libmetalink library defective or too old" >&6;} fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext + if test "x$OPENSSL_ENABLED" != "x1" -a "x$USE_WINDOWS_SSPI" != "x1" \ + -a "x$GNUTLS_ENABLED" != "x1" -a "x$NSS_ENABLED" != "x1" \ + -a "x$SECURETRANSPORT_ENABLED" != "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: metalink support requires a compatible SSL/TLS backend" >&5 +$as_echo "$as_me: WARNING: metalink support requires a compatible SSL/TLS backend" >&2;} + want_metalink="no" + fi CPPFLAGS="$clean_CPPFLAGS" LDFLAGS="$clean_LDFLAGS" LIBS="$clean_LIBS" @@ -26107,6 +26121,16 @@ else fi +OPT_WOLFSSH=off + +# Check whether --with-wolfssh was given. +if test "${with_wolfssh+set}" = set; then : + withval=$with_wolfssh; OPT_WOLFSSH=$withval +else + OPT_WOLFSSH=no +fi + + if test X"$OPT_LIBSSH2" != Xno; then CLEANLDFLAGS="$LDFLAGS" CLEANCPPFLAGS="$CPPFLAGS" @@ -26595,6 +26619,81 @@ $as_echo "$as_me: Added $DIR_SSH to CURL_LIBRARY_PATH" >&6;} CPPFLAGS=$CLEANCPPFLAGS LIBS=$CLEANLIBS fi +elif test X"$OPT_WOLFSSH" != Xno; then + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test "$OPT_WOLFSSH" != yes; then + WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" + LDFLAGS="$LDFLAGS `$WOLFCONFIG --libs`" + CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wolfSSH_Init in -lwolfssh" >&5 +$as_echo_n "checking for wolfSSH_Init in -lwolfssh... " >&6; } +if ${ac_cv_lib_wolfssh_wolfSSH_Init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwolfssh $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#ifdef __cplusplus +extern "C" +#endif +char wolfSSH_Init (); +int main (void) +{ +return wolfSSH_Init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_wolfssh_wolfSSH_Init=yes +else + ac_cv_lib_wolfssh_wolfSSH_Init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wolfssh_wolfSSH_Init" >&5 +$as_echo "$ac_cv_lib_wolfssh_wolfSSH_Init" >&6; } +if test "x$ac_cv_lib_wolfssh_wolfSSH_Init" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBWOLFSSH 1 +_ACEOF + + LIBS="-lwolfssh $LIBS" + +fi + + + for ac_header in wolfssh/ssh.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "wolfssh/ssh.h" "ac_cv_header_wolfssh_ssh_h" "$ac_includes_default" +if test "x$ac_cv_header_wolfssh_ssh_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WOLFSSH_SSH_H 1 +_ACEOF + curl_ssh_msg="enabled (wolfSSH)" + WOLFSSH_ENABLED=1 + +$as_echo "#define USE_WOLFSSH 1" >>confdefs.h + + USE_WOLFSSH=1 + + +fi + +done + + fi @@ -27643,11 +27742,11 @@ $as_echo "$as_me: -L is $LD_H2" >&6;} CPPFLAGS="$CPPFLAGS $CPP_H2" LIBS="$LIB_H2 $LIBS" - # use nghttp2_option_set_no_recv_client_magic to require nghttp2 - # >= 1.0.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nghttp2_option_set_no_recv_client_magic in -lnghttp2" >&5 -$as_echo_n "checking for nghttp2_option_set_no_recv_client_magic in -lnghttp2... " >&6; } -if ${ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic+:} false; then : + # use nghttp2_session_set_local_window_size to require nghttp2 + # >= 1.12.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nghttp2_session_set_local_window_size in -lnghttp2" >&5 +$as_echo_n "checking for nghttp2_session_set_local_window_size in -lnghttp2... " >&6; } +if ${ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -27659,26 +27758,26 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char nghttp2_option_set_no_recv_client_magic (); +char nghttp2_session_set_local_window_size (); int main (void) { -return nghttp2_option_set_no_recv_client_magic (); +return nghttp2_session_set_local_window_size (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic=yes + ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size=yes else - ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic=no + ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic" >&5 -$as_echo "$ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic" >&6; } -if test "x$ac_cv_lib_nghttp2_nghttp2_option_set_no_recv_client_magic" = xyes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size" >&5 +$as_echo "$ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size" >&6; } +if test "x$ac_cv_lib_nghttp2_nghttp2_session_set_local_window_size" = xyes; then : for ac_header in nghttp2/nghttp2.h do : @@ -42941,6 +43040,10 @@ if test "x$USE_LIBSSH" = "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" fi +if test "x$USE_WOLFSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi if test "x$CURL_DISABLE_RTSP" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP" fi diff --git a/release/src/router/curl/configure.ac b/release/src/router/curl/configure.ac index dd149b7e39e..e7ad63925ec 100755 --- a/release/src/router/curl/configure.ac +++ b/release/src/router/curl/configure.ac @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -31,7 +31,7 @@ XC_OVR_ZZ60 CURL_OVERRIDE_AUTOCONF dnl configure script copyright -AC_COPYRIGHT([Copyright (c) 1998 - 2019 Daniel Stenberg, +AC_COPYRIGHT([Copyright (c) 1998 - 2020 Daniel Stenberg, This configure script may be copied, distributed and modified under the terms of the curl license; see COPYING for more details]) @@ -2770,6 +2770,12 @@ if test X"$OPT_LIBMETALINK" != Xno; then AC_MSG_NOTICE([libmetalink library defective or too old]) want_metalink="no" ]) + if test "x$OPENSSL_ENABLED" != "x1" -a "x$USE_WINDOWS_SSPI" != "x1" \ + -a "x$GNUTLS_ENABLED" != "x1" -a "x$NSS_ENABLED" != "x1" \ + -a "x$SECURETRANSPORT_ENABLED" != "x1"; then + AC_MSG_WARN([metalink support requires a compatible SSL/TLS backend]) + want_metalink="no" + fi CPPFLAGS="$clean_CPPFLAGS" LDFLAGS="$clean_LDFLAGS" LIBS="$clean_LIBS" @@ -2795,17 +2801,23 @@ dnl ********************************************************************** dnl Default to compiler & linker defaults for LIBSSH2 files & libraries. OPT_LIBSSH2=off AC_ARG_WITH(libssh2,dnl -AC_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the LIBSSH2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) -AC_HELP_STRING([--with-libssh2], [enable LIBSSH2]), +AC_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the libssh2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AC_HELP_STRING([--with-libssh2], [enable libssh2]), OPT_LIBSSH2=$withval, OPT_LIBSSH2=no) OPT_LIBSSH=off AC_ARG_WITH(libssh,dnl -AC_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to the LIBSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) -AC_HELP_STRING([--with-libssh], [enable LIBSSH]), +AC_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to the libssh installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AC_HELP_STRING([--with-libssh], [enable libssh]), OPT_LIBSSH=$withval, OPT_LIBSSH=no) +OPT_WOLFSSH=off +AC_ARG_WITH(wolfssh,dnl +AC_HELP_STRING([--with-wolfssh=PATH],[Where to look for wolfssh, PATH points to the wolfSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AC_HELP_STRING([--with-wolfssh], [enable wolfssh]), + OPT_WOLFSSH=$withval, OPT_WOLFSSH=no) + if test X"$OPT_LIBSSH2" != Xno; then dnl backup the pre-libssh2 variables CLEANLDFLAGS="$LDFLAGS" @@ -2952,6 +2964,28 @@ elif test X"$OPT_LIBSSH" != Xno; then CPPFLAGS=$CLEANCPPFLAGS LIBS=$CLEANLIBS fi +elif test X"$OPT_WOLFSSH" != Xno; then + dnl backup the pre-wolfssh variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + + if test "$OPT_WOLFSSH" != yes; then + WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" + LDFLAGS="$LDFLAGS `$WOLFCONFIG --libs`" + CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" + fi + + AC_CHECK_LIB(wolfssh, wolfSSH_Init) + + AC_CHECK_HEADERS(wolfssh/ssh.h, + curl_ssh_msg="enabled (wolfSSH)" + WOLFSSH_ENABLED=1 + AC_DEFINE(USE_WOLFSSH, 1, [if wolfSSH is in use]) + AC_SUBST(USE_WOLFSSH, [1]) + ) + fi dnl ********************************************************************** @@ -3351,9 +3385,9 @@ if test X"$want_h2" != Xno; then CPPFLAGS="$CPPFLAGS $CPP_H2" LIBS="$LIB_H2 $LIBS" - # use nghttp2_option_set_no_recv_client_magic to require nghttp2 - # >= 1.0.0 - AC_CHECK_LIB(nghttp2, nghttp2_option_set_no_recv_client_magic, + # use nghttp2_session_set_local_window_size to require nghttp2 + # >= 1.12.0 + AC_CHECK_LIB(nghttp2, nghttp2_session_set_local_window_size, [ AC_CHECK_HEADERS(nghttp2/nghttp2.h, curl_h2_msg="enabled (nghttp2)" @@ -3695,9 +3729,9 @@ if test X"$want_quiche" != Xno; then LIBS=$CLEANLIBS ) else - dnl no nghttp3 pkg-config found, deal with it + dnl no quiche pkg-config found, deal with it if test X"$want_quiche" != Xdefault; then - dnl To avoid link errors, we do not allow --with-nghttp3 without + dnl To avoid link errors, we do not allow --with-quiche without dnl a pkgconfig file AC_MSG_ERROR([--with-quiche was specified but could not find quiche pkg-config file.]) fi @@ -4761,6 +4795,10 @@ if test "x$USE_LIBSSH" = "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" fi +if test "x$USE_WOLFSSH" = "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" +fi if test "x$CURL_DISABLE_RTSP" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP" fi diff --git a/release/src/router/curl/docs/DEPRECATE.md b/release/src/router/curl/docs/DEPRECATE.md index 4f4ef8ab6a4..26877c48aa7 100644 --- a/release/src/router/curl/docs/DEPRECATE.md +++ b/release/src/router/curl/docs/DEPRECATE.md @@ -5,32 +5,8 @@ email the curl-library mailing list as soon as possible and explain to us why this is a problem for you and how your use case can't be satisfied properly using a work around. -## PolarSSL +## Past removals -The polarssl TLS library has not had an update in over three years. The last -release was done on [January 7 -2016](https://tls.mbed.org/tech-updates/releases). This library has been -superseded by the mbedTLS library, which is the current incarnation of -PolarSSL. curl has supported mbedTLS since 2015. - -It seems unlikely that this library is a good choice for users to get proper -TLS security and support today and at the same time there are plenty of good -and updated alternatives. - -I consider it likely that the existing users of curl + polarssl out there are -stuck on old curl versions and when they eventually manage to update curl they -should also be able to update their TLS library. - -### State - -In the curl 7.65.2 release (July 17, 2019) the ability to build with this TLS -backend is removed from the configure script. The code remains and can be -built and used going forward, but it has to be manually enabled in a build (or -the configure removal reverted). - -### Removal - -The support for PolarSSL and all code for it will be completely removed from -the curl code base six months after it ships disabled in configure in a -release. In the release on or near February 27, 2020. (possibly called curl -7.70.0). + - Pipelining + - axTLS + - PolarSSL diff --git a/release/src/router/curl/docs/GOVERNANCE.md b/release/src/router/curl/docs/GOVERNANCE.md index d49358b95e2..81747179b90 100644 --- a/release/src/router/curl/docs/GOVERNANCE.md +++ b/release/src/router/curl/docs/GOVERNANCE.md @@ -18,7 +18,8 @@ expects from us. There is no legal entity. The curl project is just a bunch of people scattered around the globe with the common goal to produce source code that creates -great products. +great products. We are not part of any umbrella organization and we are not +located in any specific country. We are totally independent. The copyrights in the project are owned by the individuals and organizations that wrote those parts of the code. @@ -36,6 +37,28 @@ If there is no obvious consensus, a maintainer who's knowledgeable in the specific area will take an "executive" decision that they think is the right for the project. +## Donations + +Donating plain money to curl is best done to curl's [Open Collective +fund](https://opencollective.com/curl). Open Collective is a US based +non-profit organization that holds on to funds for us. This fund is then used +for paying the curl security bug bounties, to reimburse project related +expenses etc. + +Donations to the project can also come in form of server hosting, providing +services and paying for people to work on curl related code etc. Usually, such +donations are services paid for directly by the sponsors. + +We grade sponsors in a few different levels and if they meet the criterias, +they can be mentioned on the Sponsors page on the curl web site. + +## Commercial Support + +The curl project does not do or offer commercial support. It only hosts +mailing lists, runs bug trackers etc to facilitate communication and work. + +However, Daniel works for wolfSSL and we offer commercial curl support there. + ## Key roles ### Maintainers @@ -108,8 +131,8 @@ within the area of personal expertise and experience. ### Recommendations -- please enable 2fa on your github account to reduce risk of malicious source - code tampering +- we require two-factor authentication enabled on your github account to + reduce risk of malicious source code tampering - consider enabling signed git commits for additional verification of changes ### Merge advice diff --git a/release/src/router/curl/docs/HTTP-COOKIES.md b/release/src/router/curl/docs/HTTP-COOKIES.md index 06790f8a7e4..31af9f6d9b9 100644 --- a/release/src/router/curl/docs/HTTP-COOKIES.md +++ b/release/src/router/curl/docs/HTTP-COOKIES.md @@ -43,6 +43,27 @@ When libcurl saves a cookiejar, it creates a file header of its own in which there is a URL mention that will link to the web version of this document. +## Cookie file format + + The cookie file format is text based and stores one cookie per line. Lines + that start with `#` are treated as comments. + + Each line that each specifies a single cookie consists of seven text fields + separated with TAB characters. A valid line must end with a newline + character. + +### Fields in the file + + Field number, what type and example data and the meaning of it: + + 0. string `example.com` - the domain name + 1. boolean `FALSE` - include subdomains + 2. string `/foobar/` - path + 3. boolean `TRUE` - send/receive over HTTPS only + 4. number `1462299217` - expires at - seconds since Jan 1st 1970, or 0 + 5. string `person` - name of the cookie + 6. string `daniel` - value of the cookie + ## Cookies with curl the command line tool curl has a full cookie "engine" built in. If you just activate it, you can diff --git a/release/src/router/curl/docs/HTTP3.md b/release/src/router/curl/docs/HTTP3.md index c77f7743db7..55bdd02637d 100644 --- a/release/src/router/curl/docs/HTTP3.md +++ b/release/src/router/curl/docs/HTTP3.md @@ -33,7 +33,7 @@ in the master branch using pull-requests, just like ordinary changes. Build (patched) OpenSSL - % git clone --depth 1 -b openssl-quic-draft-23 https://github.com/tatsuhiro-t/openssl + % git clone --depth 1 -b OpenSSL_1_1_1d-quic-draft-27 https://github.com/tatsuhiro-t/openssl % cd openssl % ./config enable-tls1_3 --prefix= % make @@ -65,7 +65,7 @@ Build curl % git clone https://github.com/curl/curl % cd curl % ./buildconf - % LDFLAGS="-Wl,-rpath,/lib" ./configure --with-ssl= --with-nghttp3= --with-ngtcp2= + % LDFLAGS="-Wl,-rpath,/lib" ./configure --with-ssl= --with-nghttp3= --with-ngtcp2= --enable-alt-svc % make # quiche version @@ -93,13 +93,13 @@ Build quiche: % cd ../.. % QUICHE_BSSL_PATH=$PWD/deps/boringssl cargo build --release --features pkg-config-meta -Clone and build curl: +Build curl: % cd .. % git clone https://github.com/curl/curl % cd curl % ./buildconf - % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-ssl=$PWD/../quiche/deps/boringssl/.openssl --with-quiche=$PWD/../quiche/target/release + % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-ssl=$PWD/../quiche/deps/boringssl/.openssl --with-quiche=$PWD/../quiche/target/release --enable-alt-svc % make ## Run diff --git a/release/src/router/curl/docs/INSTALL.md b/release/src/router/curl/docs/INSTALL.md index 380f3b38e0f..63d41421bf6 100644 --- a/release/src/router/curl/docs/INSTALL.md +++ b/release/src/router/curl/docs/INSTALL.md @@ -115,7 +115,6 @@ libressl. - GnuTLS: `--without-ssl --with-gnutls`. - wolfSSL: `--without-ssl --with-wolfssl` - NSS: `--without-ssl --with-nss` - - PolarSSL: `--without-ssl --with-polarssl` - mbedTLS: `--without-ssl --with-mbedtls` - schannel: `--without-ssl --with-schannel` - secure transport: `--without-ssl --with-secure-transport` diff --git a/release/src/router/curl/docs/INTERNALS.md b/release/src/router/curl/docs/INTERNALS.md index 9ae72289829..add8b417f38 100644 --- a/release/src/router/curl/docs/INTERNALS.md +++ b/release/src/router/curl/docs/INTERNALS.md @@ -95,9 +95,8 @@ Dependencies - MIT Kerberos 1.2.4 - GSKit V5R3M0 - NSS 3.14.x - - PolarSSL 1.3.0 - Heimdal ? - - nghttp2 1.0.0 + - nghttp2 1.12.0 Operating Systems ----------------- diff --git a/release/src/router/curl/docs/KNOWN_BUGS b/release/src/router/curl/docs/KNOWN_BUGS index 5fd230f861b..26f21dc676b 100644 --- a/release/src/router/curl/docs/KNOWN_BUGS +++ b/release/src/router/curl/docs/KNOWN_BUGS @@ -12,6 +12,7 @@ check the changelog of the current development status, as one or more of these problems may have been fixed or changed somewhat since this was written! 1. HTTP + 1.2 Multiple methods in a single WWW-Authenticate: header 1.3 STARTTRANSFER time is wrong for HTTP POSTs 1.4 multipart formposts file name encoding 1.5 Expect-100 meets 417 @@ -35,8 +36,8 @@ problems may have been fixed or changed somewhat since this was written! 3. Email protocols 3.1 IMAP SEARCH ALL truncated response 3.2 No disconnect command - 3.3 SMTP to multiple recipients - 3.4 POP3 expects "CRLF.CRLF" eob for some single-line responses + 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses + 3.4 AUTH PLAIN for SMTP is not working on all servers 4. Command line 4.1 -J and -O with %-encoded file names @@ -56,6 +57,7 @@ problems may have been fixed or changed somewhat since this was written! 5.8 configure finding libs in wrong directory 5.9 Utilize Requires.private directives in libcurl.pc 5.10 IDN tests failing on Windows / MSYS2 + 5.11 configure --with-gssapi with Heimdal is ignored on macOS 6. Authentication 6.1 NTLM authentication and unicode @@ -86,8 +88,6 @@ problems may have been fixed or changed somewhat since this was written! 9.1 SFTP doesn't do CURLOPT_POSTQUOTE correct 10. SOCKS - 10.1 SOCKS proxy connections are done blocking - 10.2 SOCKS don't support timeouts 10.3 FTPS over SOCKS 10.4 active FTP over a SOCKS @@ -115,6 +115,13 @@ problems may have been fixed or changed somewhat since this was written! 1. HTTP +1.2 Multiple methods in a single WWW-Authenticate: header + + The HTTP responses headers WWW-Authenticate: can provide information about + multiple authentication methods as multiple headers or as several methods + within a single header. The latter way, several methods in the same physical + line, is not supported by libcurl's parser. (For no good reason.) + 1.3 STARTTRANSFER time is wrong for HTTP POSTs Wrong STARTTRANSFER timer accounting for POST requests Timer works fine with @@ -143,7 +150,7 @@ problems may have been fixed or changed somewhat since this was written! 1.6 Unnecessary close when 401 received waiting for 100 libcurl closes the connection if an HTTP 401 reply is received while it is - waiting for the the 100-continue response. + waiting for the 100-continue response. https://curl.haxx.se/mail/lib-2008-08/0462.html 1.7 Deflate error after all content was received @@ -275,20 +282,18 @@ problems may have been fixed or changed somewhat since this was written! The disconnect commands (LOGOUT and QUIT) may not be sent by IMAP, POP3 and SMTP if a failure occurs during the authentication phase of a connection. -3.3 SMTP to multiple recipients - - When sending data to multiple recipients, curl will abort and return failure - if one of the recipients indicate failure (on the "RCPT TO" - command). Ordinary mail programs would proceed and still send to the ones - that can receive data. This is subject for change in the future. - https://curl.haxx.se/bug/view.cgi?id=1116 - -3.4 POP3 expects "CRLF.CRLF" eob for some single-line responses +3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses You have to tell libcurl not to expect a body, when dealing with one line response commands. Please see the POP3 examples and test cases which show this for the NOOP and DELE commands. https://curl.haxx.se/bug/?i=740 +3.4 AUTH PLAIN for SMTP is not working on all servers + + Specifying "--login-options AUTH=PLAIN" on the command line doesn't seem to + work correctly. + + See https://github.com/curl/curl/issues/4080 4. Command line @@ -433,6 +438,12 @@ problems may have been fixed or changed somewhat since this was written! https://github.com/curl/curl/issues/3747 +5.11 configure --with-gssapi with Heimdal is ignored on macOS + + ... unless you also pass --with-gssapi-libs + + https://github.com/curl/curl/issues/3841 + 6. Authentication 6.1 NTLM authentication and unicode @@ -615,21 +626,6 @@ problems may have been fixed or changed somewhat since this was written! 10. SOCKS -10.1 SOCKS proxy connections are done blocking - - Both SOCKS5 and SOCKS4 proxy connections are done blocking, which is very bad - when used with the multi interface. - -10.2 SOCKS don't support timeouts - - The SOCKS4 connection codes don't properly acknowledge (connect) timeouts. - According to bug #1556528, even the SOCKS5 connect code does not do it right: - https://curl.haxx.se/bug/view.cgi?id=604 - - When connecting to a SOCK proxy, the (connect) timeout is not properly - acknowledged after the actual TCP connect (during the SOCKS "negotiate" - phase). - 10.3 FTPS over SOCKS libcurl doesn't support FTPS over a SOCKS proxy. diff --git a/release/src/router/curl/docs/Makefile.in b/release/src/router/curl/docs/Makefile.in index 1e58d6f9b67..cc49ad7d8ab 100644 --- a/release/src/router/curl/docs/Makefile.in +++ b/release/src/router/curl/docs/Makefile.in @@ -394,6 +394,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/docs/RELEASE-PROCEDURE.md b/release/src/router/curl/docs/RELEASE-PROCEDURE.md index d203458bef4..f2b4343bdd3 100644 --- a/release/src/router/curl/docs/RELEASE-PROCEDURE.md +++ b/release/src/router/curl/docs/RELEASE-PROCEDURE.md @@ -61,12 +61,12 @@ celebrate curl release scheduling ======================= -Basics ------- +Release Cycle +------------- We do releases every 8 weeks on Wednesdays. If critical problems arise, we can insert releases outside of the schedule or we can move the release date - but -this is very rare. +this is rare. Each 8 week release cycle is split in two 4-week periods. @@ -78,20 +78,28 @@ Each 8 week release cycle is split in two 4-week periods. then only focus on fixing bugs and polishing things to make a solid coming release. +- After a regular procedure-following release (made on Wednesdays), the + feature window remains closed until the following Monday in case of special + actions or patch releases etc. + +If a future release date happens to end up on a "bad date", like in the middle +of common public holidays or when the lead release manager is away traveling, +the release date can be moved forwards or backwards a full week. This is then +advertised well in advance. + Coming dates ------------ Based on the description above, here are some planned release dates (at the time of this writing): -- January 8, 2020 (moved) -- February 27, 2020 -- April 22, 2020 -- June 17, 2020 -- August 12, 2020 -- October 7, 2020 -- December 2, 2020 -- January 27, 2021 +- March 4, 2020 (7.69.0) +- April 29, 2020 +- June 24, 2020 +- August 19, 2020 +- October 14, 2020 +- December 9, 2020 +- February 3, 2021 The above (and more) curl-related dates are published in [iCalendar format](https://calendar.google.com/calendar/ical/c9u5d64odop9js55oltfarjk6g%40group.calendar.google.com/public/basic.ics) diff --git a/release/src/router/curl/docs/ROADMAP.md b/release/src/router/curl/docs/ROADMAP.md index 1d47682bf28..7bd07196ffb 100644 --- a/release/src/router/curl/docs/ROADMAP.md +++ b/release/src/router/curl/docs/ROADMAP.md @@ -27,6 +27,13 @@ ESNI (Encrypted SNI) Initial work exists in https://github.com/curl/curl/pull/4011 +thread-safe `curl_global_init()` +-------------------------------- + + Fix the libcurl specific parts of the function to be thread-safe. Make sure + it can be thread-safe if built with thread-safe 3rd party libraries. + (probably can't include `curl_global_init_mem()` for obvious reasons) + tiny-curl --------- diff --git a/release/src/router/curl/docs/THANKS b/release/src/router/curl/docs/THANKS index af74c0bd6a9..53735cb6f5f 100644 --- a/release/src/router/curl/docs/THANKS +++ b/release/src/router/curl/docs/THANKS @@ -4,15 +4,15 @@ If you have contributed but are missing here, please let us know! -"Captain Basil" -"Spoon Man" 1ocalhost on github 3dyd on github Aaro Koskinen Aaron Oneal Aaron Orenstein Aaron Scarisbrick +aasivov on github Abram Pousada +accountantM on github AceCrow on Github Adam Barclay Adam Brown @@ -24,10 +24,13 @@ Adam Marcionek Adam Piggott Adam Sampson Adam Tkac +adnn on github Adrian Burcea Adrian Peniak Adrian Schuur Adriano Meirelles +afrind on github +ahodesuka on github Ajit Dhumale Akhil Kedia Aki Koskinen @@ -46,6 +49,7 @@ Ales Mlakar Ales Novak Alessandro Ghedini Alessandro Vesely +Alex aka WindEagle Alex Baines Alex Bligh Alex Chan @@ -63,7 +67,6 @@ Alex Rousskov Alex Samorukov Alex Suykov Alex Vinnik -Alex aka WindEagle Alexander Beedie Alexander Dyagilev Alexander Elgert @@ -88,12 +91,14 @@ Alfonso Martone Alfred Gebert Allen Pulsifer Alona Rossen +amishmm on github Amit Katyal Amol Pattekar Amr Shahin Anatol Belski Anatoli Tubman Anders Bakken +Anders Berg Anders Gustafsson Anders Havn Anders Roxell @@ -127,6 +132,7 @@ Andrej E Baranov Andrew Benham Andrew Biggs Andrew Bushnell +Andrew de los Reyes Andrew Francis Andrew Fuller Andrew Ishchuk @@ -134,16 +140,19 @@ Andrew Krieger Andrew Kurushin Andrew Lambert Andrew Moise +Andrew Potter Andrew Robbins Andrew Wansink -Andrew de los Reyes Andrey Labunets Andrii Moiseiev +Andrius Merkys Andrés García Andy Cedilnik +Andy Fiddaman Andy Serpa Andy Tsouladze Angus Mackay +anshnd on github Anthon Pang Anthony Avina Anthony Bryan @@ -159,6 +168,7 @@ Antoni Villalonga Antonio Larrosa Antony74 on github Antti Hätälä +arainchik on github Archangel_SDY on github Arkadiusz Miskiewicz Armel Asselin @@ -166,15 +176,18 @@ Arnaud Compan Arnaud Ebalard Arnaud Rebillout Aron Bergman +Aron Rotteveel Artak Galoyan Arthur Murray Arve Knudsen Arvid Norberg +asavah on github Ashish Shukla Ask Bjørn Hansen Askar Safin Ates Goral Augustus Saunders +Austin Green Avery Fay Axel Tillequin Ayoub Boudhar @@ -190,6 +203,8 @@ Bas Mevissen Bas van Schaik Bastien Bouclet Basuke Suzuki +baumanj on github +bdry on github Ben Boeckel Ben Darnell Ben Greear @@ -231,9 +246,11 @@ Bjorn Augustsson Bjorn Reese Björn Stenberg Blaise Potard +bnfp on github Bob Relyea Bob Richmond Bob Schader +bobmitchell1956 on github Bogdan Nicula Brad Burdick Brad Fitzpatrick @@ -242,6 +259,7 @@ Brad Hards Brad King Brad Spencer Bradford Bruce +bramus on github Brandon Casey Brandon Dong Brandon Wang @@ -262,11 +280,14 @@ Brock Noland Bru Rom Bruce Mitchener Bruce Stephens +Bruno de Carvalho Bruno Grasselli Bruno Thomsen -Bruno de Carvalho Bryan Henderson Bryan Kemp +bsammon on github +buzo-ffm on github +bxac on github Bylon2 on github Byrial Jensen Caleb Raitto @@ -274,6 +295,7 @@ Cameron Kaiser Cameron MacMinn Camille Moncelier Caolan McNamara +Captain Basil Carie Pointer Carlo Cannas Carlo Marcelo Arenas Belón @@ -283,6 +305,8 @@ Carlos ORyan Carsten Lange Casey O'Donnell Catalin Patulea +cbartl on github +cclauss on github Chad Monroe Chandrakant Bagul Charles Kerr @@ -330,11 +354,14 @@ Ciprian Badescu Claes Jakobsson Clarence Gardner Claudio Neves +clbr on github Clemens Gruber Cliff Crosland Clifford Wolf Clint Clayton Clément Notin +cmfrolick on github +codesniffer13 on github Cody Jones Cody Mack Colby Ranger @@ -347,10 +374,13 @@ Cory Benfield Cory Nelson Costya Shulyupin Craig A West +Craig Andrews Craig Davison -Craig Markwardt Craig de Stigter +Craig Markwardt +crazydef on github Cris Bailiff +Cristian Greco Cristian Rodríguez Curt Bogmine Cynthia Coan @@ -359,7 +389,9 @@ Cyrill Osterwalder Cédric Connes Cédric Deltheil D. Flinkmann +d912e3 on github Da-Yoon Chung +daboul on github Dag Ekengren Dagobert Michelsen Dair Grant @@ -379,6 +411,7 @@ Dan Nelson Dan Petitt Dan Torop Dan Zitter +Daniel at touchtunes Daniel Bankhead Daniel Black Daniel Cater @@ -391,6 +424,7 @@ Daniel Kahn Gillmor Daniel Krügler Daniel Lee Hwang Daniel Lublin +Daniel Marjamäki Daniel Melani Daniel Mentz Daniel Romero @@ -401,13 +435,13 @@ Daniel Silverstone Daniel Steinberg Daniel Stenberg Daniel Theron -Daniel at touchtunes Daphne Luong Dario Nieuwenhuis Dario Weißer Darryl House Darshan Mody Darío Hereñú +dasimx on github Dave Dribin Dave Halbakken Dave Hamilton @@ -435,6 +469,7 @@ David Kimdon David L. David Lang David LeBlanc +David Lopes David Lord David McCreedy David Odin @@ -451,6 +486,7 @@ David Walser David Woodhouse David Wright David Yan +dbrowndan on github Dengminwen Denis Chaplygin Denis Feklushkin @@ -458,6 +494,7 @@ Denis Ollier Dennis Clarke Derek Higgins Desmond O. Chang +destman on github Detlef Schmier Dheeraj Sangamkar Didier Brisebourg @@ -476,9 +513,12 @@ Dinar Dirk Eddelbuettel Dirk Feytons Dirk Manske +dkjjr89 on github +dkwolfe4 on github Dmitri Shubin Dmitri Tikhonov Dmitriy Sergeyev +dmitrmax on github Dmitry Bartsevich Dmitry Eremin-Solenikov Dmitry Falko @@ -488,6 +528,7 @@ Dmitry Mikhirev Dmitry Popov Dmitry Rechkin Dmitry S. Baikov +dnivras on github Dolbneff A.V Domenico Andreoli Dominick Meglio @@ -505,7 +546,9 @@ Douglas Mencken Douglas R. Horner Douglas Steinwand Dov Murik +dpull on github Drake Arconis +dtmsecurity on github Duane Cathey Duncan Mac-Vicar Prett Dustin Boswell @@ -520,6 +563,7 @@ Earnestly on github Eason-Yu on github Ebenezer Ikonne Ed Morley +Edgaras Janušauskas Edin Kadribasic Edmond Yu Eduard Bloch @@ -531,11 +575,14 @@ Eelco Dolstra Eetu Ojanen Egon Eckert Eldar Zaitov +elelel on github +elephoenix on github Eli Schwartz Elia Tufarolo Elliot Saba Ellis Pritchard Elmira A Semenova +elsamuko on github Emanuele Bovisio Emil Engler Emil Lerner @@ -581,6 +628,7 @@ Even Rouault Evert Pot Evgeny Grin Evgeny Turnaev +eXeC64 on github Eygene Ryabinkin Fabian Frank Fabian Hiernaux @@ -589,13 +637,17 @@ Fabian Ruff Fabrice Fontaine Fabrizio Ammollo Fahim Chandurwala +Faizur Rahman +fds242 on github Federico Bianchi Fedor Karpelevitch +Fedor Korotkov Feist Josselin +Felipe Gasper Felix Hädicke Felix Kaiser -Felix Yan Felix von Leitner +Felix Yan Feng Tu Fernando Muñoz Flavio Medeiros @@ -683,6 +735,7 @@ Grigory Entin Guenole Bescon Guido Berhoerster Guillaume Arluison +guitared on github Gunter Knauf Gustaf Hui Gustavo Grieco @@ -694,6 +747,7 @@ Götz Babin-Ebell Hagai Auro Haibo Huang Hamish Mackenzie +hamstergene on github Han Han Han Qiao Hang Kin Lau @@ -729,6 +783,7 @@ Hoi-Ho Chan Hongli Lai Howard Blaise Howard Chu +hsiao yi Hubert Kario Huzaifa Sidhpurwala Hzhijun @@ -750,8 +805,10 @@ Iida Yosiaki Ilguiz Latypov Ilja van Sprundel Ilya Kosarev +imilli on github Immanuel Gregoire Inca R +infinnovation-dev on github Ingmar Runge Ingo Ralf Blum Ingo Wilken @@ -763,7 +820,9 @@ Isaiah Norton Ishan SinghLevett Ithubg on github Ivan Avdeev +IvanoG on github Ivo Bellin Salarin +iz8mbw on github Jack Zhang Jackarain on github Jacky Lam @@ -773,6 +832,7 @@ Jacob Moshenko Jactry Zeng Jad Chamcham Jaime Fullaondo +jakirkham on github Jakub Wilk Jakub Zakrzewski James Atwill @@ -782,6 +842,7 @@ James Cheng James Clancy James Cone James Dury +James Fuller James Gallagher James Griffiths James Housley @@ -805,6 +866,7 @@ Jared Jennings Jared Lundell Jari Aalto Jari Sundell +jasal82 on github Jason Baietto Jason Glasgow Jason Juang @@ -861,6 +923,7 @@ Jesper Jensen Jesse Chisholm Jesse Noller Jesse Tan +jethrogb on github Jie He Jim Drash Jim Freeman @@ -872,6 +935,7 @@ Jiri Dvorak Jiri Hruska Jiri Jaburek Jiří Malák +jnbr on github Jocelyn Jaubert Joe Halpin Joe Malicki @@ -923,6 +987,7 @@ Jojojov on github Jon DeVree Jon Grubbs Jon Nelson +Jon Rumsey Jon Sargeant Jon Seymour Jon Spencer @@ -940,6 +1005,7 @@ Jonathan Hseu Jonathan Moerman Jonathan Nieder Jongki Suwandi +jonrumsey on github Joombalaya on github Joonas Kuorilehto Jose Alf @@ -947,6 +1013,7 @@ Jose Kahan Josef Wolf Josh Bialkowski Josh Kapell +joshhe on github Joshua Kwan Joshua Swink Josie Huddleston @@ -969,6 +1036,7 @@ Julien Chaffraix Julien Nabet Julien Royer Jun-ichiro itojun Hagino +jungle-boogie on github Junho Choi Jurij Smakov Juro Bystricky @@ -977,11 +1045,14 @@ Justin Ehlert Justin Fletcher Justin Karneges Justin Maggard +jveazey on github +jzinn on github János Fekete Jérémy Rocher Jörg Mueller-Tolk Jörn Hartroth K. R. Walker +ka7 on github Kai Engert Kai Noda Kai Sommerfeld @@ -1028,11 +1099,14 @@ Kobi Gurkan Koen Dergent Konstantin Isakov Konstantin Kushnir +kouzhudong on github +kreshano on github Kris Kennaway Krishnendu Majumdar Krister Johansen Kristian Gunstone Kristian Köhntopp +Kristian Mide Kristiyan Tsaklev Kristoffer Gleditsch Kunal Ekawde @@ -1044,6 +1118,7 @@ Kyle L. Huff Kyle Sallee Kyohei Kadota Kyselgov E.N +l00p3r on Hackerone Lachlan O'Dea Ladar Levison Lance Ware @@ -1073,11 +1148,13 @@ Len Krause Len Marinaccio Lenaic Lefever Lenny Rachitsky +Leo Neat Leon Breedt Leon Winter Leonardo Rosati Leonardo Taccari Liam Healy +lijian996 on github Lijo Antony Linas Vepstas Lindley French @@ -1106,6 +1183,7 @@ Ludovico Cavedon Ludwig Nussel Lukas Ruzicka Lukasz Czekierda +lukaszgn on github Luke Amery Luke Call Luke Dashjr @@ -1115,10 +1193,10 @@ Luz Paz Luật Nguyễn Lyman Epp Lyndon Hill -MAntoniak on github Maciej Karpiuk Maciej Puzio Maciej W. Rozycki +madblobfish on github Mahmoud Samir Fayed Maks Naumov Maksim Kuzevanov @@ -1127,6 +1205,7 @@ Mamoru Tasaka Mamta Upadhyay Mandy Wu Manfred Schwarb +MAntoniak on github Manuel Massing Marc Aldorasi Marc Boucher @@ -1138,6 +1217,7 @@ Marc Kleine-Budde Marc Renault Marc Schlatter Marc-Antoine Perennou +marc-groundctl on github Marcel Hernandez Marcel Raad Marcel Roelofs @@ -1197,6 +1277,7 @@ Martin Storsjö Martin Vejnár Marty Kuhrt Maruko +masbug on github Massimiliano Fantuzzi Massimiliano Ziccardi Massimo Callegari @@ -1235,6 +1316,8 @@ Maxim Perenesenko Maxim Prohorov Maxime Larocque Maxime Legros +mbeifuss on github +mccormickt12 on github Mehmet Bozkurt Mekonikum Melissa Mears @@ -1284,6 +1367,7 @@ Michel Promonet Michele Bini Miguel Angel Miguel Diaz +migueljcrum on github Mihai Ionescu Mikael Johansson Mikael Sennerholm @@ -1292,11 +1376,13 @@ Mike Bytnar Mike Crowe Mike Dobbs Mike Dowell +Mike Frysinger Mike Giancola Mike Hasselberg Mike Henshaw Mike Hommey Mike Mio +Mike Norton Mike Power Mike Protts Mike Revi @@ -1305,19 +1391,24 @@ Miloš Ljumović Mingliang Zhu Miroslav Franc Miroslav Spousta +Mischa Salle Mitz Wark +mkzero on github Mohamed Lrhazi Mohammad AlSaleh Mohammad Hasbini Mohun Biswas +momala454 on github +moohoorama on github Mostyn Bramley-Moore Moti Avrahami +MrdUkk on github MrSorcus on github Muz Dima Myk Taylor -NTMan on Github Nach M. S. Nagai H +naost3rn on github Nate Prewitt Nathan Coulter Nathan O'Sullivan @@ -1327,12 +1418,18 @@ Nathaniel Waisbrot Naveen Chandran Naveen Noel Neal Poole +nedres on github +neex on github Nehal J Wani +neheb on github Neil Bowers Neil Dunbar Neil Kolban Neil Spring +nevv on HackerOne/curl Niall O'Reilly +niallor on github +nianxuejie on github Nic Roets Nicholas Maniscalco Nick Draffen @@ -1342,10 +1439,12 @@ Nick Miyake Nick Zitzmann Nicklas Avén Nico Baggus +nico-abram on github Nicolas Berloquin Nicolas Croiset Nicolas François Nicolas Grekas +Nicolas Guillier Nicolas Morey-Chaisemartin Niels van Tongeren Nikita Schmidt @@ -1355,14 +1454,18 @@ Niklas Hambüchen Nikolai Kondrashov Nikos Mavrogiannopoulos Nikos Tsipinakis +niner on github Ning Dong Nir Soffer Nis Jorgensen +nk Nobuhiro Ban Nodak Sodak +nopjmp on github Norbert Frese Norbert Kett Norbert Novotny +NTMan on Github Octavio Schroeder Ofer Okhin Vasilij @@ -1371,6 +1474,7 @@ Olaf Flebbe Olaf Stüben Oleg Pudeyev Olen Andoni +olesteban on github Oli Kingshott Oliver Gondža Oliver Graute @@ -1379,15 +1483,18 @@ Oliver Schindler Olivier Berger Olivier Brunel Omar Ramadan +omau on github Orange Tsai Oren Souroujon Oren Tirosh Orgad Shaneh Ori Avtalion +osabc on github Oscar Koeroo Oscar Norlander Oskar Liljeblad Oumph on github +ovidiu-benea on github P R Schaffner Palo Markovic Paolo Mossino @@ -1398,6 +1505,8 @@ Pascal Terjan Pasha Kuznetsov Pasi Karkkainen Pat Ray +patelvivekv1993 on github +patnyb on github Patrice Guerin Patricia Muscalu Patrick Bihan-Faou @@ -1435,11 +1544,14 @@ Pavel Orehov Pavel Pavlov Pavel Raiskup Pavel Rochnyak +Pavel Volgarev Pavol Markovic Pawel A. Gajda Pawel Kierski Pedro Larroy +Pedro Monreal Pedro Neves +pendrek at hackerone Peng Li Per Lundberg Per Malmberg @@ -1492,6 +1604,7 @@ Pierre Brico Pierre Chapuis Pierre Joye Pierre Ynard +Pierre-Yves Bigourdan Piotr Dobrogost Piotr Komborski Po-Chuan Hsieh @@ -1502,6 +1615,7 @@ Prash Dush Praveen Pvs Priyanka Shah Przemysław Tomaszewski +pszemus on github Puneet Pawaia Quagmire Quanah Gibson-Mount @@ -1594,6 +1708,7 @@ Rob Ward Robert A. Monat Robert B. Harris Robert D. Young +Robert Dunaj Robert Foreman Robert Iakobashvili Robert Kolcun @@ -1637,6 +1752,7 @@ Ruslan Baratov Ruslan Gazizov Rutger Hofman Ruurd Beerstra +RuurdBeerstra on github Ryan Braud Ryan Chan Ryan Nelson @@ -1646,8 +1762,6 @@ Ryan Winograd Ryuichi KAWAMATA Rémy Léone S. Moonesamy -SBKarr on github -SLDiggie on github Salah-Eddin Shaban Salvador Dávila Salvatore Sorrentino @@ -1670,6 +1784,8 @@ Saran Neti Sascha Swiercy Saul good Saurav Babu +sayrer on github +SBKarr on github Scott Bailey Scott Barrett Scott Cantor @@ -1715,23 +1831,29 @@ Shmulik Regev Siddhartha Prakash Jain Sidney San Martín Siegfried Gyuricsko +silveja1 on github Simon Dick Simon H. Simon Josefsson Simon Legner Simon Liu Simon Warta +SLDiggie on github +smuellerDD on github Somnath Kundu Song Ma Sonia Subramanian Spacen Jasset Spezifant on github Spiridonoff A.V +Spoon Man Spork Schivago +sstruchtrup on github Stadler Stephan Stan van de Burgt Stanislav Ivochkin Stanislav Zidek +steelman on github Stefan Agner Stefan Bühler Stefan Eissing @@ -1745,6 +1867,7 @@ Stefan Tomanek Stefan Ulrich Stefano Simonelli Steinar H. Gunderson +steini2000 on github Stepan Broz Stephan Bergmann Stephan Lagerholm @@ -1773,26 +1896,29 @@ Steven M. Schweda Steven Parkes Stian Soiland-Reyes Stoned Elipot +stootill on github Stuart Henderson SumatraPeter on github Sune Ahlgren +Sunny Bean Sunny Purushe Sven Anders Sven Blumenstein Sven Neuhaus Sven Wegener Svyatoslav Mishyn +swalkaus at yahoo.com Sylvestre Ledru Symeon Paraschoudis Sébastien Willemijns T. Bharath T. Yamada -TJ Saunders Tae Hyoung Ahn Tae Wong Taiyu Len Taneli Vähäkangas Tanguy Fautre +tarek112 on github Tatsuhiro Tsujikawa Teemu Yli-Elsila Temprimus @@ -1801,6 +1927,7 @@ Terry Wu The Infinnovation team TheAssassin on github Theodore Dubois +tholin on github Thomas Braun Thomas Gamper Thomas Glanzmann @@ -1812,8 +1939,8 @@ Thomas Petazzoni Thomas Ruecker Thomas Schwinge Thomas Tonino -Thomas Vegas Thomas van Hesteren +Thomas Vegas Thorsten Schöning Tiit Pikma Till Maas @@ -1837,7 +1964,9 @@ Timotej Lazar Timothe Litt Timothy Polich Tinus van den Berg +TJ Saunders Tobias Blomberg +Tobias Hieta Tobias Hintze Tobias Lindgren Tobias Markus @@ -1860,9 +1989,9 @@ Tom Mueller Tom Regner Tom Seddon Tom Sparrow +Tom van der Woerdt Tom Wright Tom Zerucha -Tom van der Woerdt Tomas Hoger Tomas Jakobsson Tomas Mlcoch @@ -1873,16 +2002,19 @@ Tomas Tomecek Tomasz Kojm Tomasz Lacki Tommie Gannert +tommink[at]post.pl Tommy Tam Ton Voon Toni Moreno Tony Kelman +tonystz on Github Toon Verwaest Tor Arntsen Torben Dannhauer Torsten Foertsch Toshio Kuratomi Toshiyuki Maezawa +tpaukrt on github Traian Nicolescu Travis Burtrum Travis Obenhaus @@ -1901,6 +2033,7 @@ Ulrich Telle Ulrich Zadow Valentin David Valerii Zapodovnikov +vanillajonathan on github Vasiliy Faronov Vasily Lobaskin Vasy Okhin @@ -1921,6 +2054,7 @@ Vincent Le Normand Vincent Penquerc'h Vincent Sanders Vincent Torri +vitaha85 on github Vlad Grachov Vlad Ureche Vladimir Grishchenko @@ -1932,6 +2066,7 @@ Vojtech Minarik Vojtěch Král Volker Schmid Vsevolod Novikov +vshmuk on hackerone W. Mark Kubacki Waldek Kozba Walter J. Mack @@ -1941,6 +2076,7 @@ Wayne Haigh Wenchao Li Wenxiang Qian Werner Koch +wesinator on github Wesley Laxton Wesley Miaw Wez Furlong @@ -1950,6 +2086,8 @@ Will Dietz Willem Sparreboom William A. Rowe Jr William Ahern +wmsch on github +wncboy on github Wojciech Zwiefka Wouter Van Rooy Wu Yongzheng @@ -1968,10 +2106,12 @@ Yasuhiro Matsumoto Yechiel Kalmenson Yehezkel Horowitz Yehoshua Hershberg +ygthien on github Yi Huang Yiming Jing Yingwei Liu Yonggang Luo +youngchopin on github Yousuke Kimoto Yu Xin Yukihiro Kawada @@ -1982,6 +2122,7 @@ Yves Lejeune Zachary Seguin Zdenek Pavlas Zekun Ni +zelinchen on github Zenju on github Zero King Zhao Yisha @@ -1990,105 +2131,9 @@ Zhibiao Wu Zhouyihai Ding Zmey Petroff Zvi Har'El -aasivov on github -accountantM on github -adnn on github -afrind on github -ahodesuka on github -anshnd on github -arainchik on github -asavah on github -baumanj on github -bdry on github -bobmitchell1956 on github -bsammon on github -buzo-ffm on github -bxac on github -cbartl on github -cclauss on github -clbr on github -cmfrolick on github -codesniffer13 on github -d912e3 on github -daboul on github -dasimx on github -dbrowndan on github -destman on github -dkjjr89 on github -dkwolfe4 on github -dnivras on github -dpull on github -dtmsecurity on github -eXeC64 on github -elelel on github -elephoenix on github -elsamuko on github -guitared on github -hsiao yi -imilli on github -infinnovation-dev on github -iz8mbw on github -jakirkham on github -jasal82 on github -jnbr on github -jonrumsey on github -joshhe on github -jungle-boogie on github -jveazey on github -jzinn on github -ka7 on github -kouzhudong on github -kreshano on github -l00p3r on Hackerone -lijian996 on github -lukaszgn on github -madblobfish on github -marc-groundctl on github -masbug on github -mccormickt12 on github -migueljcrum on github -mkzero on github -momala454 on github -moohoorama on github -nedres on github -neex on github -neheb on github -nevv on HackerOne/curl -niallor on github -nianxuejie on github -nico-abram on github -niner on github -nk -nopjmp on github -olesteban on github -omau on github -osabc on github -ovidiu-benea on github -patelvivekv1993 on github -patnyb on github -pendrek at hackerone -pszemus on github -sayrer on github -silveja1 on github -smuellerDD on github -sstruchtrup on github -steelman on github -steini2000 on github -stootill on github -swalkaus at yahoo.com -tarek112 on github -tholin on github -tommink[at]post.pl -tonystz on Github -tpaukrt on github -vanillajonathan on github -wesinator on github -wmsch on github -wncboy on github -youngchopin on github -zelinchen on github zzq1015 on github İsmail Dönmez Łukasz Domeradzki Štefan Kremeň Никита Дорохин +加藤郁之 diff --git a/release/src/router/curl/docs/TODO b/release/src/router/curl/docs/TODO index 6f4919c236c..b288e4dbb44 100644 --- a/release/src/router/curl/docs/TODO +++ b/release/src/router/curl/docs/TODO @@ -87,6 +87,8 @@ 10. LDAP 10.1 SASL based authentication mechanisms + 10.2 CURLOPT_SSL_CTX_FUNCTION for LDAPS + 10.3 Paged searches on LDAP server 11. SMB 11.1 File listing support @@ -132,6 +134,7 @@ 18.1 sync 18.2 glob posts 18.3 prevent file overwriting + 18.4 --proxycommand 18.5 UTF-8 filenames in Content-Disposition 18.7 at least N milliseconds between requests 18.9 Choose the name of file in braces for complex URLs @@ -403,7 +406,6 @@ EWOULDBLOCK or similar. Blocking cases include: - Name resolves on non-windows unless c-ares or the threaded resolver is used - - SOCKS proxy handshakes - file:// transfers - TELNET transfers - The "DONE" operation (post transfer protocol-specific actions) for the @@ -603,6 +605,17 @@ be possible to use ldap_bind_s() instead specifying the security context information ourselves. +10.2 CURLOPT_SSL_CTX_FUNCTION for LDAPS + + CURLOPT_SSL_CTX_FUNCTION works perfectly for HTTPS and email protocols, but + it has no effect for LDAPS connections. + + https://github.com/curl/curl/issues/4108 + +10.3 Paged searches on LDAP server + + https://github.com/curl/curl/issues/4452 + 11. SMB 11.1 File listing support @@ -857,6 +870,16 @@ that doesn't exist on the server, just like --ftp-create-dirs. existing). So that index.html becomes first index.html.1 and then index.html.2 etc. +18.4 --proxycommand + + Allow the user to make curl run a command and use its stdio to make requests + and not do any network connection by itself. Example: + + curl --proxycommand 'ssh pi@raspberrypi.local -W 10.1.1.75 80' \ + http://some/otherwise/unavailable/service.php + + See https://github.com/curl/curl/issues/4941 + 18.5 UTF-8 filenames in Content-Disposition RFC 6266 documents how UTF-8 names can be passed to a client in the diff --git a/release/src/router/curl/docs/cmdline-opts/Makefile.in b/release/src/router/curl/docs/cmdline-opts/Makefile.in index 52c356cb4d8..52d2de9ce6a 100644 --- a/release/src/router/curl/docs/cmdline-opts/Makefile.in +++ b/release/src/router/curl/docs/cmdline-opts/Makefile.in @@ -306,6 +306,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/docs/cmdline-opts/alt-svc.d b/release/src/router/curl/docs/cmdline-opts/alt-svc.d index df10bf257a2..15877a2feea 100644 --- a/release/src/router/curl/docs/cmdline-opts/alt-svc.d +++ b/release/src/router/curl/docs/cmdline-opts/alt-svc.d @@ -14,4 +14,4 @@ Specify a "" file name (zero length) to avoid loading/saving and make curl just handle the cache in memory. If this option is used several times, curl will load contents from all the -files but the the last one will be used for saving. +files but the last one will be used for saving. diff --git a/release/src/router/curl/docs/cmdline-opts/create-dirs.d b/release/src/router/curl/docs/cmdline-opts/create-dirs.d index 49e22e75a8c..b09d96ca7fe 100644 --- a/release/src/router/curl/docs/cmdline-opts/create-dirs.d +++ b/release/src/router/curl/docs/cmdline-opts/create-dirs.d @@ -6,4 +6,6 @@ necessary local directory hierarchy as needed. This option creates the dirs mentioned with the --output option, nothing else. If the --output file name uses no dir or if the dirs it mentions already exist, no dir will be created. +Created dirs are made with mode 0750 on unix style file systems. + To create remote directories when using FTP or SFTP, try --ftp-create-dirs. diff --git a/release/src/router/curl/docs/cmdline-opts/data.d b/release/src/router/curl/docs/cmdline-opts/data.d index d18312aaaff..8b5200d34af 100644 --- a/release/src/router/curl/docs/cmdline-opts/data.d +++ b/release/src/router/curl/docs/cmdline-opts/data.d @@ -22,9 +22,8 @@ data pieces specified will be merged together with a separating chunk that looks like \&'name=daniel&skill=lousy'. If you start the data with the letter @, the rest should be a file name to -read the data from, or - if you want curl to read the data from -stdin. Multiple files can also be specified. Posting data from a file named -\&'foobar' would thus be done with --data @foobar. When --data is told to read -from a file like that, carriage returns and newlines will be stripped out. If -you don't want the @ character to have a special interpretation use --data-raw -instead. +read the data from, or - if you want curl to read the data from stdin. Posting +data from a file named \&'foobar' would thus be done with --data @foobar. When +--data is told to read from a file like that, carriage returns and newlines +will be stripped out. If you don't want the @ character to have a special +interpretation use --data-raw instead. diff --git a/release/src/router/curl/docs/cmdline-opts/form.d b/release/src/router/curl/docs/cmdline-opts/form.d index 0bbc3701f19..7f1aa31c3b4 100644 --- a/release/src/router/curl/docs/cmdline-opts/form.d +++ b/release/src/router/curl/docs/cmdline-opts/form.d @@ -33,11 +33,11 @@ form-field to which the file portrait.jpg will be the input: curl -F profile=@portrait.jpg https://example.com/upload.cgi -Example: send a your name and shoe size in two text fields to the server: +Example: send your name and shoe size in two text fields to the server: curl -F name=John -F shoesize=11 https://example.com/ -Example: send a your essay in a text field to the server. Send it as a plain +Example: send your essay in a text field to the server. Send it as a plain text field, but get the contents for it from a local file: curl -F "story= -Protocols: IMAP POP3 SMTP +Protocols: IMAP POP3 SMTP HTTP --- Specify the Bearer Token for OAUTH 2.0 server authentication. The Bearer Token is used in conjunction with the user name which can be specified as part of diff --git a/release/src/router/curl/docs/curl-config.1 b/release/src/router/curl/docs/curl-config.1 index ae247048c75..0868c415875 100644 --- a/release/src/router/curl/docs/curl-config.1 +++ b/release/src/router/curl/docs/curl-config.1 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl-config 1 "November 30, 2017" "Curl 7.68.0" "curl-config manual" +.TH curl-config 1 "November 30, 2017" "Curl 7.69.1" "curl-config manual" .SH NAME curl-config \- Get information about a libcurl installation diff --git a/release/src/router/curl/docs/examples/Makefile.in b/release/src/router/curl/docs/examples/Makefile.in index 897ad4926fc..6ef22eae35a 100644 --- a/release/src/router/curl/docs/examples/Makefile.in +++ b/release/src/router/curl/docs/examples/Makefile.in @@ -1136,6 +1136,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/docs/libcurl/Makefile.in b/release/src/router/curl/docs/libcurl/Makefile.in index 153bcad123a..4b8002fb5e1 100644 --- a/release/src/router/curl/docs/libcurl/Makefile.in +++ b/release/src/router/curl/docs/libcurl/Makefile.in @@ -576,6 +576,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/docs/libcurl/curl_easy_cleanup.3 b/release/src/router/curl/docs/libcurl/curl_easy_cleanup.3 index 834660e1157..15a60077c23 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_cleanup.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_cleanup.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_cleanup 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_cleanup 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_cleanup - End a libcurl easy handle diff --git a/release/src/router/curl/docs/libcurl/curl_easy_duphandle.3 b/release/src/router/curl/docs/libcurl/curl_easy_duphandle.3 index daba039d35a..8c2967c7b4c 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_duphandle.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_duphandle.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_duphandle 3 "March 01, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_duphandle 3 "March 01, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_duphandle - Clone a libcurl session handle diff --git a/release/src/router/curl/docs/libcurl/curl_easy_escape.3 b/release/src/router/curl/docs/libcurl/curl_easy_escape.3 index f5b6269ddbd..ba34d8ed0e3 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_escape.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_escape.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_escape 3 "August 12, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_escape 3 "August 12, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_escape - URL encodes the given string diff --git a/release/src/router/curl/docs/libcurl/curl_easy_getinfo.3 b/release/src/router/curl/docs/libcurl/curl_easy_getinfo.3 index b628e84bb83..b01f6c314a6 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_getinfo.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_getinfo.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_getinfo 3 "August 06, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_getinfo 3 "August 06, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_getinfo - extract information from a curl handle diff --git a/release/src/router/curl/docs/libcurl/curl_easy_init.3 b/release/src/router/curl/docs/libcurl/curl_easy_init.3 index fb84df01c08..a45e3194094 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_init.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_init.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_init 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_init 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_init - Start a libcurl easy session diff --git a/release/src/router/curl/docs/libcurl/curl_easy_pause.3 b/release/src/router/curl/docs/libcurl/curl_easy_pause.3 index 8364c32c277..61801fb977c 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_pause.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_pause.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_pause 3 "May 01, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_pause 3 "May 01, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_pause - pause and unpause a connection diff --git a/release/src/router/curl/docs/libcurl/curl_easy_perform.3 b/release/src/router/curl/docs/libcurl/curl_easy_perform.3 index fa1c8b95774..44c10d74222 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_perform.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_perform.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_perform 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_perform 3 "September 23, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_perform - perform a blocking file transfer diff --git a/release/src/router/curl/docs/libcurl/curl_easy_recv.3 b/release/src/router/curl/docs/libcurl/curl_easy_recv.3 index 9816578b6a7..170ae9dcca1 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_recv.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_recv.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_recv 3 "December 18, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_recv 3 "December 18, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_recv - receives raw data on an "easy" connection diff --git a/release/src/router/curl/docs/libcurl/curl_easy_reset.3 b/release/src/router/curl/docs/libcurl/curl_easy_reset.3 index 2474d4a51b0..89072ea8e0b 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_reset.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_reset.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_reset 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_reset 3 "February 09, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_reset - reset all options of a libcurl session handle @@ -34,7 +34,8 @@ default values. This puts back the handle to the same state as it was in when it was just created with \fIcurl_easy_init(3)\fP. It does not change the following information kept in the handle: live -connections, the Session ID cache, the DNS cache, the cookies and shares. +connections, the Session ID cache, the DNS cache, the cookies, the shares or +the alt-svc cache. .SH AVAILABILITY This function was added in libcurl 7.12.1 .SH RETURN VALUE diff --git a/release/src/router/curl/docs/libcurl/curl_easy_send.3 b/release/src/router/curl/docs/libcurl/curl_easy_send.3 index d4a7d0340d1..926bf94c79e 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_send.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_send.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_send 3 "December 18, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_send 3 "December 18, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_send - sends raw data over an "easy" connection diff --git a/release/src/router/curl/docs/libcurl/curl_easy_setopt.3 b/release/src/router/curl/docs/libcurl/curl_easy_setopt.3 index 8cb862110c5..97f231305b7 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_setopt.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_setopt.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_setopt 3 "January 05, 2020" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_setopt 3 "January 14, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_setopt \- set options for a curl easy handle @@ -358,6 +358,8 @@ Address of the sender. See \fICURLOPT_MAIL_FROM(3)\fP Address of the recipients. See \fICURLOPT_MAIL_RCPT(3)\fP .IP CURLOPT_MAIL_AUTH Authentication address. See \fICURLOPT_MAIL_AUTH(3)\fP +.IP CURLOPT_MAIL_RCPT_ALLLOWFAILS +Allow RCPT TO command to fail for some recipients. See \fICURLOPT_MAIL_RCPT_ALLLOWFAILS(3)\fP .SH TFTP OPTIONS .IP CURLOPT_TFTP_BLKSIZE TFTP block size. See \fICURLOPT_TFTP_BLKSIZE(3)\fP diff --git a/release/src/router/curl/docs/libcurl/curl_easy_strerror.3 b/release/src/router/curl/docs/libcurl/curl_easy_strerror.3 index bd623e44d4b..b6f1cbccf99 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_strerror.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_strerror.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_easy_strerror 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_strerror 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_strerror - return string describing error code diff --git a/release/src/router/curl/docs/libcurl/curl_easy_unescape.3 b/release/src/router/curl/docs/libcurl/curl_easy_unescape.3 index 901c73ca594..ba06e58601b 100644 --- a/release/src/router/curl/docs/libcurl/curl_easy_unescape.3 +++ b/release/src/router/curl/docs/libcurl/curl_easy_unescape.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_easy_unescape 3 "October 04, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_easy_unescape 3 "October 04, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_easy_unescape - URL decodes the given string diff --git a/release/src/router/curl/docs/libcurl/curl_escape.3 b/release/src/router/curl/docs/libcurl/curl_escape.3 index 20eb8b09eaa..9a9b58222c0 100644 --- a/release/src/router/curl/docs/libcurl/curl_escape.3 +++ b/release/src/router/curl/docs/libcurl/curl_escape.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_escape 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_escape 3 "March 02, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_escape - URL encodes the given string @@ -39,7 +39,7 @@ two-digit hexadecimal number). If the 'length' argument is set to 0, curl_escape() will use strlen() on the input 'url' string to find out the size. -You must curl_free() the returned string when you're done with it. +You must \fIcurl_free(3)\fP the returned string when you're done with it. .SH AVAILABILITY Since 7.15.4, \fIcurl_easy_escape(3)\fP should be used. This function will be removed in a future release. diff --git a/release/src/router/curl/docs/libcurl/curl_formadd.3 b/release/src/router/curl/docs/libcurl/curl_formadd.3 index b26087b13b4..d8bdf7459f4 100644 --- a/release/src/router/curl/docs/libcurl/curl_formadd.3 +++ b/release/src/router/curl/docs/libcurl/curl_formadd.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_formadd 3 "December 11, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_formadd 3 "December 11, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_formadd - add a section to a multipart/formdata HTTP POST diff --git a/release/src/router/curl/docs/libcurl/curl_formfree.3 b/release/src/router/curl/docs/libcurl/curl_formfree.3 index da7b2564bf2..f3ff7d7f4a6 100644 --- a/release/src/router/curl/docs/libcurl/curl_formfree.3 +++ b/release/src/router/curl/docs/libcurl/curl_formfree.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_formfree 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_formfree 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_formfree - free a previously build multipart/formdata HTTP POST chain diff --git a/release/src/router/curl/docs/libcurl/curl_formget.3 b/release/src/router/curl/docs/libcurl/curl_formget.3 index 6e959788555..7dee5d211b1 100644 --- a/release/src/router/curl/docs/libcurl/curl_formget.3 +++ b/release/src/router/curl/docs/libcurl/curl_formget.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_formget 3 "September 02, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_formget 3 "September 02, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_formget - serialize a previously built multipart/formdata HTTP POST chain diff --git a/release/src/router/curl/docs/libcurl/curl_free.3 b/release/src/router/curl/docs/libcurl/curl_free.3 index eb58b19a391..b928b1c349b 100644 --- a/release/src/router/curl/docs/libcurl/curl_free.3 +++ b/release/src/router/curl/docs/libcurl/curl_free.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_free 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_free 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_free - reclaim memory that has been obtained through a libcurl call diff --git a/release/src/router/curl/docs/libcurl/curl_getdate.3 b/release/src/router/curl/docs/libcurl/curl_getdate.3 index 6a27f1c49cf..05165a5d467 100644 --- a/release/src/router/curl/docs/libcurl/curl_getdate.3 +++ b/release/src/router/curl/docs/libcurl/curl_getdate.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_getdate 3 "January 18, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_getdate 3 "January 18, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_getdate - Convert a date string to number of seconds diff --git a/release/src/router/curl/docs/libcurl/curl_getenv.3 b/release/src/router/curl/docs/libcurl/curl_getenv.3 index 763e99a2c37..9d10569a595 100644 --- a/release/src/router/curl/docs/libcurl/curl_getenv.3 +++ b/release/src/router/curl/docs/libcurl/curl_getenv.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_getenv 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_getenv 3 "March 02, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_getenv - return value for environment name @@ -32,15 +32,15 @@ curl_getenv - return value for environment name curl_getenv() is a portable wrapper for the getenv() function, meant to emulate its behaviour and provide an identical interface for all operating systems libcurl builds on (including win32). + +You must \fIcurl_free(3)\fP the returned string when you're done with it. .SH AVAILABILITY This function will be removed from the public libcurl API in a near future. It will instead be made "available" by source code access only, and then as curlx_getenv(). .SH RETURN VALUE -If successful, curl_getenv() returns a pointer to the value of the specified -environment. The memory it refers to is malloc()ed so the application must -free() this when the data is no longer needed. When \fIcurl_getenv(3)\fP fails -to find the specified name, it returns a null pointer. +A pointer to a zero terminated string or NULL if it failed to find the +specified name. .SH NOTE Under unix operating systems, there isn't any point in returning an allocated memory, although other systems won't work properly if this isn't done. The diff --git a/release/src/router/curl/docs/libcurl/curl_global_cleanup.3 b/release/src/router/curl/docs/libcurl/curl_global_cleanup.3 index a1929cc8832..c31034f2303 100644 --- a/release/src/router/curl/docs/libcurl/curl_global_cleanup.3 +++ b/release/src/router/curl/docs/libcurl/curl_global_cleanup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_global_cleanup 3 "September 20, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_global_cleanup 3 "September 20, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_global_cleanup - global libcurl cleanup diff --git a/release/src/router/curl/docs/libcurl/curl_global_init.3 b/release/src/router/curl/docs/libcurl/curl_global_init.3 index 8e83dc520c1..56663a6549b 100644 --- a/release/src/router/curl/docs/libcurl/curl_global_init.3 +++ b/release/src/router/curl/docs/libcurl/curl_global_init.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_global_init 3 "April 17, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_global_init 3 "January 23, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_global_init - Global libcurl initialisation @@ -88,9 +88,11 @@ Initialise nothing extra. This sets no bit. A sensible default. It will init both SSL and Win32. Right now, this equals the functionality of the \fBCURL_GLOBAL_ALL\fP mask. .IP CURL_GLOBAL_ACK_EINTR -When this flag is set, curl will acknowledge EINTR condition when connecting -or when waiting for data. Otherwise, curl waits until full timeout -elapses. (Added in 7.30.0) +This bit has no point since 7.69.0 but its behavior is instead the default. + +Before 7.69.0: when this flag is set, curl will acknowledge EINTR condition +when connecting or when waiting for data. Otherwise, curl waits until full +timeout elapses. (Added in 7.30.0) .SH RETURN VALUE If this function returns non-zero, something went wrong and you cannot use the other curl functions. diff --git a/release/src/router/curl/docs/libcurl/curl_global_init_mem.3 b/release/src/router/curl/docs/libcurl/curl_global_init_mem.3 index 86936d89b09..5d4b7ee06ef 100644 --- a/release/src/router/curl/docs/libcurl/curl_global_init_mem.3 +++ b/release/src/router/curl/docs/libcurl/curl_global_init_mem.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_global_init_mem 3 "August 11, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_global_init_mem 3 "August 11, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_global_init_mem - Global libcurl initialisation with memory callbacks diff --git a/release/src/router/curl/docs/libcurl/curl_global_sslset.3 b/release/src/router/curl/docs/libcurl/curl_global_sslset.3 index 64642e4a9a9..d9bea324471 100644 --- a/release/src/router/curl/docs/libcurl/curl_global_sslset.3 +++ b/release/src/router/curl/docs/libcurl/curl_global_sslset.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_global_sslset 3 "November 07, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_global_sslset 3 "March 04, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_global_sslset - Select SSL backend to use with libcurl @@ -38,7 +38,7 @@ typedef enum { CURLSSLBACKEND_GNUTLS = 2, CURLSSLBACKEND_NSS = 3, CURLSSLBACKEND_GSKIT = 5, - CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_POLARSSL = 6, /* deprecated */ CURLSSLBACKEND_WOLFSSL = 7, CURLSSLBACKEND_SCHANNEL = 8, CURLSSLBACKEND_DARWINSSL = 9, diff --git a/release/src/router/curl/docs/libcurl/curl_mime_addpart.3 b/release/src/router/curl/docs/libcurl/curl_mime_addpart.3 index dad45f9ca99..ff6b998eb1f 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_addpart.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_addpart.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_addpart 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_addpart 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_addpart - append a new empty part to a mime structure diff --git a/release/src/router/curl/docs/libcurl/curl_mime_data.3 b/release/src/router/curl/docs/libcurl/curl_mime_data.3 index bea46f21a72..fd805b44761 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_data.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_data.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_data 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_data 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_data - set a mime part's body data from memory diff --git a/release/src/router/curl/docs/libcurl/curl_mime_data_cb.3 b/release/src/router/curl/docs/libcurl/curl_mime_data_cb.3 index a34abde1d8e..ac874e556b1 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_data_cb.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_data_cb.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_data_cb 3 "April 17, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_data_cb 3 "April 17, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_data_cb - set a callback-based data source for a mime part's body diff --git a/release/src/router/curl/docs/libcurl/curl_mime_encoder.3 b/release/src/router/curl/docs/libcurl/curl_mime_encoder.3 index c685899104a..b9ae2dae58a 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_encoder.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_encoder.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_encoder 3 "September 05, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_encoder 3 "September 05, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_encoder - set a mime part's encoder and content transfer encoding diff --git a/release/src/router/curl/docs/libcurl/curl_mime_filedata.3 b/release/src/router/curl/docs/libcurl/curl_mime_filedata.3 index 72762b02a94..913b502adb8 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_filedata.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_filedata.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_filedata 3 "April 17, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_filedata 3 "April 17, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_filedata - set a mime part's body data from a file contents diff --git a/release/src/router/curl/docs/libcurl/curl_mime_filename.3 b/release/src/router/curl/docs/libcurl/curl_mime_filename.3 index 2669cc57720..ee63aa7094f 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_filename.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_filename.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_filename 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_filename 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_filename - set a mime part's remote file name diff --git a/release/src/router/curl/docs/libcurl/curl_mime_free.3 b/release/src/router/curl/docs/libcurl/curl_mime_free.3 index e78454e41a6..26a3ab1e7bc 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_free.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_free.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_free 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_free 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_free - free a previously built mime structure diff --git a/release/src/router/curl/docs/libcurl/curl_mime_headers.3 b/release/src/router/curl/docs/libcurl/curl_mime_headers.3 index 47107b50498..11b15b990f9 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_headers.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_headers.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_headers 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_headers 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_headers - set a mime part's custom headers diff --git a/release/src/router/curl/docs/libcurl/curl_mime_init.3 b/release/src/router/curl/docs/libcurl/curl_mime_init.3 index 5998eaa95fb..5ef7f1cdd86 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_init.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_init.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_init 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_init 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_init - create a mime handle diff --git a/release/src/router/curl/docs/libcurl/curl_mime_name.3 b/release/src/router/curl/docs/libcurl/curl_mime_name.3 index d6ea794db3f..7266a86cbc4 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_name.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_name.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_name 3 "September 22, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_name 3 "September 22, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_name - set a mime part's name diff --git a/release/src/router/curl/docs/libcurl/curl_mime_subparts.3 b/release/src/router/curl/docs/libcurl/curl_mime_subparts.3 index ab19b2c83e1..5639e330d66 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_subparts.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_subparts.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_subparts 3 "September 05, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_subparts 3 "September 05, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_subparts - set subparts of a multipart mime part diff --git a/release/src/router/curl/docs/libcurl/curl_mime_type.3 b/release/src/router/curl/docs/libcurl/curl_mime_type.3 index 96ea102ab3a..a2842ba9af9 100644 --- a/release/src/router/curl/docs/libcurl/curl_mime_type.3 +++ b/release/src/router/curl/docs/libcurl/curl_mime_type.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_mime_type 3 "April 17, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_mime_type 3 "April 17, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_mime_type - set a mime part's content type diff --git a/release/src/router/curl/docs/libcurl/curl_mprintf.3 b/release/src/router/curl/docs/libcurl/curl_mprintf.3 index 4aa5782dba8..3f38ed2f60f 100644 --- a/release/src/router/curl/docs/libcurl/curl_mprintf.3 +++ b/release/src/router/curl/docs/libcurl/curl_mprintf.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_printf 3 "April 01, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_printf 3 "April 01, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf diff --git a/release/src/router/curl/docs/libcurl/curl_multi_add_handle.3 b/release/src/router/curl/docs/libcurl/curl_multi_add_handle.3 index dfe6e0da4f2..eba97c02dfd 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_add_handle.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_add_handle.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_add_handle 3 "June 30, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_add_handle 3 "June 30, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_add_handle - add an easy handle to a multi session diff --git a/release/src/router/curl/docs/libcurl/curl_multi_assign.3 b/release/src/router/curl/docs/libcurl/curl_multi_assign.3 index 0dcdcfdf1bc..5c25ae73e34 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_assign.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_assign.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_assign 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_assign 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_assign \- set data to associate with an internal socket diff --git a/release/src/router/curl/docs/libcurl/curl_multi_cleanup.3 b/release/src/router/curl/docs/libcurl/curl_multi_cleanup.3 index 1e31e78f992..3b84f4a8fc7 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_cleanup.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_cleanup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_cleanup 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_cleanup 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_cleanup - close down a multi session diff --git a/release/src/router/curl/docs/libcurl/curl_multi_fdset.3 b/release/src/router/curl/docs/libcurl/curl_multi_fdset.3 index b2655f07e26..201902f349f 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_fdset.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_fdset.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_fdset 3 "November 09, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_fdset 3 "November 09, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_fdset - extracts file descriptor information from a multi handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_info_read.3 b/release/src/router/curl/docs/libcurl/curl_multi_info_read.3 index 5bd8bea1629..505f17d38a0 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_info_read.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_info_read.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_info_read 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_info_read 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_info_read - read multi stack informationals diff --git a/release/src/router/curl/docs/libcurl/curl_multi_init.3 b/release/src/router/curl/docs/libcurl/curl_multi_init.3 index 0d357db3238..807fd6178d4 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_init.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_init.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_init 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_init 3 "September 23, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_init - create a multi handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_perform.3 b/release/src/router/curl/docs/libcurl/curl_multi_perform.3 index e83eafd973d..01129cca30c 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_perform.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_perform.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_perform 3 "October 31, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_perform 3 "October 31, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_perform - reads/writes available data from each easy handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_poll.3 b/release/src/router/curl/docs/libcurl/curl_multi_poll.3 index edf2ca69357..ee80acac6a8 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_poll.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_poll.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_poll 3 "November 17, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_poll 3 "November 17, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_poll - polls on all easy handles in a multi handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_remove_handle.3 b/release/src/router/curl/docs/libcurl/curl_multi_remove_handle.3 index 4d4c54058f6..c24b6e5bc23 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_remove_handle.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_remove_handle.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_remove_handle 3 "February 19, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_remove_handle 3 "February 19, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_remove_handle - remove an easy handle from a multi session diff --git a/release/src/router/curl/docs/libcurl/curl_multi_setopt.3 b/release/src/router/curl/docs/libcurl/curl_multi_setopt.3 index c05589c0957..3f2b3fe99c7 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_setopt.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_setopt.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_setopt 3 "September 24, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_setopt 3 "September 24, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_setopt \- set options for a curl multi handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_socket.3 b/release/src/router/curl/docs/libcurl/curl_multi_socket.3 index 43dc92dfb10..c86d2b835a7 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_socket.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_socket.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_socket 3 "June 30, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_socket 3 "June 30, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_socket \- reads/writes available data diff --git a/release/src/router/curl/docs/libcurl/curl_multi_socket_action.3 b/release/src/router/curl/docs/libcurl/curl_multi_socket_action.3 index bca4ee6f00e..280d0837a07 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_socket_action.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_socket_action.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_socket_action 3 "June 10, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_socket_action 3 "June 10, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_socket_action \- reads/writes available data given an action diff --git a/release/src/router/curl/docs/libcurl/curl_multi_strerror.3 b/release/src/router/curl/docs/libcurl/curl_multi_strerror.3 index 5cb898349ba..a50001f2e44 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_strerror.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_strerror.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_strerror 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_strerror 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_strerror - return string describing error code diff --git a/release/src/router/curl/docs/libcurl/curl_multi_timeout.3 b/release/src/router/curl/docs/libcurl/curl_multi_timeout.3 index 0149ef743fe..fd070de6a48 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_timeout.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_timeout.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_timeout 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_timeout 3 "September 23, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_timeout \- how long to wait for action before proceeding diff --git a/release/src/router/curl/docs/libcurl/curl_multi_wait.3 b/release/src/router/curl/docs/libcurl/curl_multi_wait.3 index d0c15397fa1..323a01c6711 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_wait.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_wait.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_wait 3 "November 28, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_wait 3 "November 28, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_wait - polls on all easy handles in a multi handle diff --git a/release/src/router/curl/docs/libcurl/curl_multi_wakeup.3 b/release/src/router/curl/docs/libcurl/curl_multi_wakeup.3 index 462b1a088bd..8c3a6c99d63 100644 --- a/release/src/router/curl/docs/libcurl/curl_multi_wakeup.3 +++ b/release/src/router/curl/docs/libcurl/curl_multi_wakeup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_multi_wakeup 3 "November 25, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_multi_wakeup 3 "November 25, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_multi_wakeup - wakes up a sleeping curl_multi_poll call diff --git a/release/src/router/curl/docs/libcurl/curl_share_cleanup.3 b/release/src/router/curl/docs/libcurl/curl_share_cleanup.3 index c5374bac4bd..66eb34aafae 100644 --- a/release/src/router/curl/docs/libcurl/curl_share_cleanup.3 +++ b/release/src/router/curl/docs/libcurl/curl_share_cleanup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_share_cleanup 3 "August 09, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_share_cleanup 3 "August 09, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_share_cleanup - Clean up a shared object diff --git a/release/src/router/curl/docs/libcurl/curl_share_init.3 b/release/src/router/curl/docs/libcurl/curl_share_init.3 index 65bd020dda3..509b65b96d9 100644 --- a/release/src/router/curl/docs/libcurl/curl_share_init.3 +++ b/release/src/router/curl/docs/libcurl/curl_share_init.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_share_init 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_share_init 3 "September 23, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_share_init - Create a shared object diff --git a/release/src/router/curl/docs/libcurl/curl_share_setopt.3 b/release/src/router/curl/docs/libcurl/curl_share_setopt.3 index 67eb2d4f1ff..698adab3a34 100644 --- a/release/src/router/curl/docs/libcurl/curl_share_setopt.3 +++ b/release/src/router/curl/docs/libcurl/curl_share_setopt.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_share_setopt 3 "June 04, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_share_setopt 3 "March 06, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_share_setopt - Set options for a shared object @@ -60,6 +60,8 @@ be set to one of the values described below. .RS .IP CURL_LOCK_DATA_COOKIE Cookie data will be shared across the easy handles using this shared object. +Note that this does not activate an easy handle's cookie handling. You can do +that separately by using \fICURLOPT_COOKIEFILE(3)\fP for example. .IP CURL_LOCK_DATA_DNS Cached DNS hosts will be shared across the easy handles using this shared object. Note that when you use the multi interface, all easy handles added to diff --git a/release/src/router/curl/docs/libcurl/curl_share_strerror.3 b/release/src/router/curl/docs/libcurl/curl_share_strerror.3 index ca31df87682..2f20d7d4010 100644 --- a/release/src/router/curl/docs/libcurl/curl_share_strerror.3 +++ b/release/src/router/curl/docs/libcurl/curl_share_strerror.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_share_strerror 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_share_strerror 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_share_strerror - return string describing error code diff --git a/release/src/router/curl/docs/libcurl/curl_slist_append.3 b/release/src/router/curl/docs/libcurl/curl_slist_append.3 index 26de8956899..45d5ff79b23 100644 --- a/release/src/router/curl/docs/libcurl/curl_slist_append.3 +++ b/release/src/router/curl/docs/libcurl/curl_slist_append.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_slist_append 3 "January 02, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_slist_append 3 "January 02, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_slist_append - add a string to an slist diff --git a/release/src/router/curl/docs/libcurl/curl_slist_free_all.3 b/release/src/router/curl/docs/libcurl/curl_slist_free_all.3 index 2473bcf221e..5efd12c00b7 100644 --- a/release/src/router/curl/docs/libcurl/curl_slist_free_all.3 +++ b/release/src/router/curl/docs/libcurl/curl_slist_free_all.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_slist_free_all 3 "September 23, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_slist_free_all 3 "September 23, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_slist_free_all - free an entire curl_slist list diff --git a/release/src/router/curl/docs/libcurl/curl_strequal.3 b/release/src/router/curl/docs/libcurl/curl_strequal.3 index 49ff4b20e0a..5fb46936b27 100644 --- a/release/src/router/curl/docs/libcurl/curl_strequal.3 +++ b/release/src/router/curl/docs/libcurl/curl_strequal.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_strequal 3 "June 29, 2017" "libcurl 7.68.0" "libcurl Manual" +.TH curl_strequal 3 "June 29, 2017" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_strequal, curl_strnequal - case insensitive string comparisons diff --git a/release/src/router/curl/docs/libcurl/curl_unescape.3 b/release/src/router/curl/docs/libcurl/curl_unescape.3 index 0220714514e..2e8c71e6509 100644 --- a/release/src/router/curl/docs/libcurl/curl_unescape.3 +++ b/release/src/router/curl/docs/libcurl/curl_unescape.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_unescape 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_unescape 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_unescape - URL decodes the given string diff --git a/release/src/router/curl/docs/libcurl/curl_url.3 b/release/src/router/curl/docs/libcurl/curl_url.3 index fc2f1acc229..1c3d7258a2d 100644 --- a/release/src/router/curl/docs/libcurl/curl_url.3 +++ b/release/src/router/curl/docs/libcurl/curl_url.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_url 3 "March 22, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_url 3 "March 22, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_url - returns a new CURLU handle diff --git a/release/src/router/curl/docs/libcurl/curl_url_cleanup.3 b/release/src/router/curl/docs/libcurl/curl_url_cleanup.3 index 0a197b8742a..ef34dbd5c1b 100644 --- a/release/src/router/curl/docs/libcurl/curl_url_cleanup.3 +++ b/release/src/router/curl/docs/libcurl/curl_url_cleanup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_url_cleanup 3 "September 08, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_url_cleanup 3 "September 08, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_url_cleanup - free a CURLU handle diff --git a/release/src/router/curl/docs/libcurl/curl_url_dup.3 b/release/src/router/curl/docs/libcurl/curl_url_dup.3 index 0e71eed3bf6..0a6fea86507 100644 --- a/release/src/router/curl/docs/libcurl/curl_url_dup.3 +++ b/release/src/router/curl/docs/libcurl/curl_url_dup.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_url_dup 3 "September 08, 2018" "libcurl 7.68.0" "libcurl Manual" +.TH curl_url_dup 3 "September 08, 2018" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_url_dup - duplicate a CURLU handle diff --git a/release/src/router/curl/docs/libcurl/curl_url_get.3 b/release/src/router/curl/docs/libcurl/curl_url_get.3 index 57b7432db1f..c8ce23e37fb 100644 --- a/release/src/router/curl/docs/libcurl/curl_url_get.3 +++ b/release/src/router/curl/docs/libcurl/curl_url_get.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_url_get 3 "September 25, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_url_get 3 "September 25, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_url_get - extract a part from a URL diff --git a/release/src/router/curl/docs/libcurl/curl_url_set.3 b/release/src/router/curl/docs/libcurl/curl_url_set.3 index 751af58da9e..60d62c08a7b 100644 --- a/release/src/router/curl/docs/libcurl/curl_url_set.3 +++ b/release/src/router/curl/docs/libcurl/curl_url_set.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_url_set 3 "January 05, 2020" "libcurl 7.68.0" "libcurl Manual" +.TH curl_url_set 3 "January 05, 2020" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_url_set - set a URL part diff --git a/release/src/router/curl/docs/libcurl/curl_version.3 b/release/src/router/curl/docs/libcurl/curl_version.3 index c8929c9da2f..79087dab1c2 100644 --- a/release/src/router/curl/docs/libcurl/curl_version.3 +++ b/release/src/router/curl/docs/libcurl/curl_version.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH curl_version 3 "February 03, 2016" "libcurl 7.68.0" "libcurl Manual" +.TH curl_version 3 "February 03, 2016" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_version - returns the libcurl version string diff --git a/release/src/router/curl/docs/libcurl/curl_version_info.3 b/release/src/router/curl/docs/libcurl/curl_version_info.3 index 8d67f94e1bd..4ecdab9cdb0 100644 --- a/release/src/router/curl/docs/libcurl/curl_version_info.3 +++ b/release/src/router/curl/docs/libcurl/curl_version_info.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH curl_version_info 3 "August 13, 2019" "libcurl 7.68.0" "libcurl Manual" +.TH curl_version_info 3 "August 13, 2019" "libcurl 7.69.1" "libcurl Manual" .SH NAME curl_version_info - returns run-time libcurl version info diff --git a/release/src/router/curl/docs/libcurl/libcurl-easy.3 b/release/src/router/curl/docs/libcurl/libcurl-easy.3 index 7282ad5ebf7..b555e2e286b 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-easy.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-easy.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl 3 "February 03, 2016" "libcurl 7.68.0" "libcurl easy interface" +.TH libcurl 3 "February 03, 2016" "libcurl 7.69.1" "libcurl easy interface" .SH NAME libcurl-easy \- easy interface overview diff --git a/release/src/router/curl/docs/libcurl/libcurl-env.3 b/release/src/router/curl/docs/libcurl/libcurl-env.3 index 7c952440898..19ba2ec0356 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-env.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-env.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl-env 3 "April 17, 2018" "libcurl 7.68.0" "libcurl environment variables" +.TH libcurl-env 3 "April 17, 2018" "libcurl 7.69.1" "libcurl environment variables" .SH NAME libcurl-env \- environment variables libcurl understands diff --git a/release/src/router/curl/docs/libcurl/libcurl-errors.3 b/release/src/router/curl/docs/libcurl/libcurl-errors.3 index 3f6a2a134eb..cf6198cb33e 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-errors.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-errors.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-errors 3 "November 17, 2019" "libcurl 7.68.0" "libcurl errors" +.TH libcurl-errors 3 "December 24, 2019" "libcurl 7.69.1" "libcurl errors" .SH NAME libcurl-errors \- error codes in libcurl @@ -148,7 +148,7 @@ Function not found. A required zlib function was not found. .IP "CURLE_ABORTED_BY_CALLBACK (42)" Aborted by callback. A callback returned "abort" to libcurl. .IP "CURLE_BAD_FUNCTION_ARGUMENT (43)" -Internal error. A function was called with a bad parameter. +A function was called with a bad parameter. .IP "CURLE_INTERFACE_FAILED (45)" Interface error. A specified outgoing interface could not be used. Set which interface to use for outgoing connections' source IP address with @@ -260,6 +260,9 @@ An authentication function returned an error. .IP "CURLE_HTTP3 (95)" A problem was detected in the HTTP/3 layer. This is somewhat generic and can be one out of several problems, see the error buffer for details. +.IP "CURLE_QUIC_CONNECT_ERROR (96)" +QUIC connection error. This error may be caused by an SSL library error. QUIC +is the protocol used for HTTP/3 transfers. .IP "CURLE_OBSOLETE*" These error codes will never be returned. They were used in an old libcurl version and are currently unused. @@ -300,6 +303,8 @@ second time. (Added in 7.32.1) An API function was called from inside a callback. .IP "CURLM_WAKEUP_FAILURE (9)" Wakeup is unavailable or failed. +.IP "CURLM_BAD_FUNCTION_ARGUMENT (10)" +A function was called with a bad parameter. .SH "CURLSHcode" The "share" interface will return a CURLSHcode to indicate when an error has occurred. Also consider \fIcurl_share_strerror(3)\fP. diff --git a/release/src/router/curl/docs/libcurl/libcurl-multi.3 b/release/src/router/curl/docs/libcurl/libcurl-multi.3 index 05c5f3c5dbc..7c2f2e638d0 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-multi.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-multi.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-multi 3 "November 28, 2019" "libcurl 7.68.0" "libcurl multi interface" +.TH libcurl-multi 3 "November 28, 2019" "libcurl 7.69.1" "libcurl multi interface" .SH NAME libcurl-multi \- how to use the multi interface diff --git a/release/src/router/curl/docs/libcurl/libcurl-security.3 b/release/src/router/curl/docs/libcurl/libcurl-security.3 index 8894546d585..6ec6c78b6f9 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-security.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-security.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-security 3 "July 16, 2019" "libcurl 7.68.0" "libcurl security" +.TH libcurl-security 3 "July 16, 2019" "libcurl 7.69.1" "libcurl security" .SH NAME libcurl-security \- security considerations when using libcurl diff --git a/release/src/router/curl/docs/libcurl/libcurl-share.3 b/release/src/router/curl/docs/libcurl/libcurl-share.3 index 396bb0dd9e5..36e5c985137 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-share.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-share.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl-share 3 "November 27, 2017" "libcurl 7.68.0" "libcurl share interface" +.TH libcurl-share 3 "November 27, 2017" "libcurl 7.69.1" "libcurl share interface" .SH NAME libcurl-share \- how to use the share interface diff --git a/release/src/router/curl/docs/libcurl/libcurl-symbols.3 b/release/src/router/curl/docs/libcurl/libcurl-symbols.3 index 7759c4a8705..ca578cc0ff5 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-symbols.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-symbols.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl-symbols 3 "Jan 8, 2020" "libcurl 7.41.0" "libcurl symbols" +.TH libcurl-symbols 3 "Mar 11, 2020" "libcurl 7.41.0" "libcurl symbols" .SH NAME libcurl-symbols \- libcurl symbol version information .SH "libcurl symbols" @@ -245,6 +245,8 @@ Introduced in 7.1 Introduced in 7.1 .IP CURLE_PEER_FAILED_VERIFICATION Introduced in 7.17.1 +.IP CURLE_QUIC_CONNECT_ERROR +Introduced in 7.69.0 .IP CURLE_QUOTE_ERROR Introduced in 7.17.0 .IP CURLE_RANGE_ERROR @@ -705,14 +707,14 @@ Introduced in 7.30.0 Introduced in 7.30.0 .IP CURLMOPT_MAXCONNECTS Introduced in 7.16.3 +.IP CURLMOPT_MAX_CONCURRENT_STREAMS +Introduced in 7.67.0 .IP CURLMOPT_MAX_HOST_CONNECTIONS Introduced in 7.30.0 .IP CURLMOPT_MAX_PIPELINE_LENGTH Introduced in 7.30.0 .IP CURLMOPT_MAX_TOTAL_CONNECTIONS Introduced in 7.30.0 -.IP CURLMOPT_MAX_CONCURRENT_STREAMS -Introduced in 7.67.0 .IP CURLMOPT_PIPELINING Introduced in 7.16.0 .IP CURLMOPT_PIPELINING_SERVER_BL @@ -739,6 +741,8 @@ Introduced in 7.9.6 Introduced in 7.32.1 .IP CURLM_BAD_EASY_HANDLE Introduced in 7.9.6 +.IP CURLM_BAD_FUNCTION_ARGUMENT +Introduced in 7.69.0 .IP CURLM_BAD_HANDLE Introduced in 7.9.6 .IP CURLM_BAD_SOCKET @@ -755,10 +759,12 @@ Introduced in 7.9.6 Introduced in 7.9.6 .IP CURLM_RECURSIVE_API_CALL Introduced in 7.59.0 -.IP CURLM_WAKEUP_FAILURE -Introduced in 7.68.0 .IP CURLM_UNKNOWN_OPTION Introduced in 7.15.4 +.IP CURLM_WAKEUP_FAILURE +Introduced in 7.68.0 +.IP CURLOPT +Introduced in 7.69.0 .IP CURLOPTTYPE_FUNCTIONPOINT Introduced in 7.1 .IP CURLOPTTYPE_LONG @@ -767,10 +773,10 @@ Introduced in 7.1 Introduced in 7.1 .IP CURLOPTTYPE_OFF_T Introduced in 7.11.0 -.IP CURLOPTTYPE_STRINGPOINT -Introduced in 7.46.0 .IP CURLOPTTYPE_SLISTPOINT Introduced in 7.65.2 +.IP CURLOPTTYPE_STRINGPOINT +Introduced in 7.46.0 .IP CURLOPT_ABSTRACT_UNIX_SOCKET Introduced in 7.53.0 .IP CURLOPT_ACCEPTTIMEOUT_MS @@ -1020,6 +1026,8 @@ Introduced in 7.25.0 Introduced in 7.20.0 .IP CURLOPT_MAIL_RCPT Introduced in 7.20.0 +.IP CURLOPT_MAIL_RCPT_ALLLOWFAILS +Introduced in 7.69.0 .IP CURLOPT_MAXAGE_CONN Introduced in 7.65.0 .IP CURLOPT_MAXCONNECTS @@ -1567,6 +1575,7 @@ Introduced in 7.34.0 Introduced in 7.34.0 .IP CURLSSLBACKEND_POLARSSL Introduced in 7.34.0 +Deprecated since 7.69.0 .IP CURLSSLBACKEND_QSOSSL Introduced in 7.34.0 .IP CURLSSLBACKEND_SCHANNEL @@ -1667,10 +1676,10 @@ Introduced in 7.62.0 Introduced in 7.62.0 .IP CURLU_NON_SUPPORT_SCHEME Introduced in 7.62.0 -.IP CURLU_NO_DEFAULT_PORT -Introduced in 7.62.0 .IP CURLU_NO_AUTHORITY Introduced in 7.67.0 +.IP CURLU_NO_DEFAULT_PORT +Introduced in 7.62.0 .IP CURLU_PATH_AS_IS Introduced in 7.62.0 .IP CURLU_URLDECODE @@ -1687,10 +1696,10 @@ Introduced in 7.16.1 Introduced in 7.10 .IP CURLVERSION_SECOND Introduced in 7.11.1 -.IP CURLVERSION_THIRD -Introduced in 7.12.0 .IP CURLVERSION_SIXTH Introduced in 7.66.0 +.IP CURLVERSION_THIRD +Introduced in 7.12.0 .IP CURL_CHUNK_BGN_FUNC_FAIL Introduced in 7.21.0 .IP CURL_CHUNK_BGN_FUNC_OK @@ -2023,6 +2032,8 @@ Introduced in 7.28.0 Introduced in 7.28.0 .IP CURL_WAIT_POLLPRI Introduced in 7.28.0 +.IP CURL_WIN32 +Introduced in 7.69.0 .IP CURL_WRITEFUNC_PAUSE Introduced in 7.18.0 .IP CURL_ZERO_TERMINATED diff --git a/release/src/router/curl/docs/libcurl/libcurl-thread.3 b/release/src/router/curl/docs/libcurl/libcurl-thread.3 index c96ad9a469e..b7ece2505d8 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-thread.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-thread.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-thread 3 "June 30, 2019" "libcurl 7.68.0" "libcurl thread safety" +.TH libcurl-thread 3 "June 30, 2019" "libcurl 7.69.1" "libcurl thread safety" .SH NAME libcurl-thread \- libcurl thread safety diff --git a/release/src/router/curl/docs/libcurl/libcurl-tutorial.3 b/release/src/router/curl/docs/libcurl/libcurl-tutorial.3 index 3189a933685..f9257173419 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-tutorial.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-tutorial.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-tutorial 3 "October 31, 2019" "libcurl 7.68.0" "libcurl programming" +.TH libcurl-tutorial 3 "October 31, 2019" "libcurl 7.69.1" "libcurl programming" .SH NAME libcurl-tutorial \- libcurl programming tutorial diff --git a/release/src/router/curl/docs/libcurl/libcurl-url.3 b/release/src/router/curl/docs/libcurl/libcurl-url.3 index 8a4a306f7ff..55b5dc7394a 100644 --- a/release/src/router/curl/docs/libcurl/libcurl-url.3 +++ b/release/src/router/curl/docs/libcurl/libcurl-url.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl 3 "September 10, 2018" "libcurl 7.68.0" "libcurl url interface" +.TH libcurl 3 "September 10, 2018" "libcurl 7.69.1" "libcurl url interface" .SH NAME libcurl-url \- URL interface overview diff --git a/release/src/router/curl/docs/libcurl/libcurl.3 b/release/src/router/curl/docs/libcurl/libcurl.3 index 3c308c1ccd2..8aea9de35f2 100644 --- a/release/src/router/curl/docs/libcurl/libcurl.3 +++ b/release/src/router/curl/docs/libcurl/libcurl.3 @@ -19,7 +19,7 @@ .\" * KIND, either express or implied. .\" * .\" ************************************************************************** -.TH libcurl 3 "July 15, 2017" "libcurl 7.68.0" "libcurl overview" +.TH libcurl 3 "July 15, 2017" "libcurl 7.69.1" "libcurl overview" .SH NAME libcurl \- client-side URL transfers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.3 index 3fb76978f0a..988b32e3e3e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_ACTIVESOCKET 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_ACTIVESOCKET 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_ACTIVESOCKET \- get the active socket diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.3 index e0400685fad..b1f1725c7eb 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_APPCONNECT_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_APPCONNECT_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_APPCONNECT_TIME \- get the time until the SSL/SSH handshake is completed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.3 index a49516bb2ba..3d28da06606 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_APPCONNECT_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_APPCONNECT_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_APPCONNECT_TIME_T \- get the time until the SSL/SSH handshake is completed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CERTINFO.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CERTINFO.3 index 9f4813f0083..c6c134dd840 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CERTINFO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CERTINFO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CERTINFO 3 "November 07, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CERTINFO 3 "November 07, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CERTINFO \- get the TLS certificate chain diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.3 index 9f3821047f5..220492a9034 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONDITION_UNMET 3 "February 23, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONDITION_UNMET 3 "February 23, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONDITION_UNMET \- get info on unmet time conditional diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME.3 index 4db592a3b04..356c3d0e928 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONNECT_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONNECT_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONNECT_TIME \- get the time until connect diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.3 index e4798ac2006..c7e937b1844 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONNECT_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONNECT_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONNECT_TIME_T \- get the time until connect diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 index e833852bf2a..87012d2496a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONTENT_LENGTH_DOWNLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONTENT_LENGTH_DOWNLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONTENT_LENGTH_DOWNLOAD \- get content-length of download diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 index 8b075d382b8..b23b86df2c6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONTENT_LENGTH_DOWNLOAD_T \- get content-length of download diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.3 index bacc7fe5607..0afb737e848 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONTENT_LENGTH_UPLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONTENT_LENGTH_UPLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONTENT_LENGTH_UPLOAD \- get the specified size of the upload diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 index 8e8acfc06f8..148cc45beda 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONTENT_LENGTH_UPLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONTENT_LENGTH_UPLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONTENT_LENGTH_UPLOAD_T \- get the specified size of the upload diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.3 index 6e8b4fe9e75..d15c0254dc8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_CONTENT_TYPE 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_CONTENT_TYPE 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_CONTENT_TYPE \- get Content-Type diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_COOKIELIST.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_COOKIELIST.3 index c50a7ae1201..545ede3906c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_COOKIELIST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_COOKIELIST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_COOKIELIST 3 "March 20, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_COOKIELIST 3 "February 15, 2020" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_COOKIELIST \- get all known cookies @@ -46,8 +46,8 @@ CURL *curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); - /* enable the cookie engine with a non-existing file */ - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "-"); + /* enable the cookie engine */ + curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); res = curl_easy_perform(curl); @@ -59,7 +59,7 @@ if(curl) { /* a linked list of cookies in cookie file format */ struct curl_slist *each = cookies; while(each) { - printf("%s", each->data); + printf("%s\\n", each->data); each = each->next; } /* we must free these cookies when we're done */ diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.3 index 1303617d466..1289c070fda 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_EFFECTIVE_URL 3 "May 04, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_EFFECTIVE_URL 3 "May 04, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_EFFECTIVE_URL \- get the last used URL diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME.3 index 5a0d67c3a06..c0887eaecc3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_FILETIME 3 "January 25, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_FILETIME 3 "January 25, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_FILETIME \- get the remote time of the retrieved document diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME_T.3 index f3e88ffefa3..63206bbcb3a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FILETIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_FILETIME 3 "January 25, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_FILETIME 3 "January 25, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_FILETIME_T \- get the remote time of the retrieved document diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.3 index ba434b64d5e..adc112e8298 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_FTP_ENTRY_PATH 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_FTP_ENTRY_PATH 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_FTP_ENTRY_PATH \- get entry path in FTP server diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HEADER_SIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HEADER_SIZE.3 index 35eded36f8f..817b6f89ea2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HEADER_SIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HEADER_SIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_HEADER_SIZE 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_HEADER_SIZE 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_HEADER_SIZE \- get size of retrieved headers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.3 index 52f6e4a7097..02f478be302 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_HTTPAUTH_AVAIL 3 "October 07, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_HTTPAUTH_AVAIL 3 "October 07, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_HTTPAUTH_AVAIL \- get available HTTP authentication methods diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.3 index 60436b7848d..717129c1024 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_HTTP_CONNECTCODE 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_HTTP_CONNECTCODE 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_HTTP_CONNECTCODE \- get the CONNECT response code diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_VERSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_VERSION.3 index 64e31b69d8f..a4c724c3677 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_VERSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_HTTP_VERSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_HTTP_VERSION 3 "August 07, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_HTTP_VERSION 3 "August 07, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_HTTP_VERSION \- get the http version used in the connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LASTSOCKET.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LASTSOCKET.3 index 0b955e086e7..96d8ed1663a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LASTSOCKET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LASTSOCKET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_LASTSOCKET 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_LASTSOCKET 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_LASTSOCKET \- get the last socket used diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_IP.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_IP.3 index a681c73816a..e74cb922c22 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_IP.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_IP.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_LOCAL_IP 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_LOCAL_IP 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_LOCAL_IP \- get local IP address of last connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_PORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_PORT.3 index c14eb1bd548..01612a30f91 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_PORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_LOCAL_PORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_LOCAL_PORT 3 "March 16, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_LOCAL_PORT 3 "March 16, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_LOCAL_PORT \- get the latest local port number diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.3 index 742a56fe2dc..9e8ed9826fa 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_NAMELOOKUP_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_NAMELOOKUP_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_NAMELOOKUP_TIME \- get the name lookup time diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.3 index 0eea0276796..bbe5432eabf 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_NAMELOOKUP_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_NAMELOOKUP_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_NAMELOOKUP_TIME_T \- get the name lookup time in microseconds diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.3 index 9a0de24cd32..341bb587f4a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_NUM_CONNECTS 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_NUM_CONNECTS 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_NUM_CONNECTS \- get number of created connections diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_OS_ERRNO.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_OS_ERRNO.3 index 63381adff57..b127641a0ba 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_OS_ERRNO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_OS_ERRNO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_OS_ERRNO 3 "November 07, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_OS_ERRNO 3 "November 07, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_OS_ERRNO \- get errno number from last connect failure diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.3 index 91f77ac25c3..f9d404ecff3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PRETRANSFER_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PRETRANSFER_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PRETRANSFER_TIME \- get the time until the file transfer start diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.3 index a6c827ef18a..34b6ae7a967 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PRETRANSFER_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PRETRANSFER_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PRETRANSFER_TIME_T \- get the time until the file transfer start diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_IP.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_IP.3 index 54c75c511cb..59f31ca1492 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_IP.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_IP.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PRIMARY_IP 3 "March 22, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PRIMARY_IP 3 "March 22, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PRIMARY_IP \- get IP address of last connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.3 index 542ffbe73be..8c85c21f330 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PRIMARY_PORT 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PRIMARY_PORT 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PRIMARY_PORT \- get the latest destination port number diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIVATE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIVATE.3 index aaf34fdfa21..43d957b160b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIVATE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PRIVATE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PRIVATE 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PRIVATE 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PRIVATE \- get the private pointer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROTOCOL.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROTOCOL.3 index 363410697bd..4e8e4e271af 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROTOCOL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROTOCOL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PROTOCOL 3 "April 27, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PROTOCOL 3 "April 27, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PROTOCOL \- get the protocol used in the connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.3 index 809a3759c91..d41a414f357 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PROXYAUTH_AVAIL 3 "October 07, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PROXYAUTH_AVAIL 3 "October 07, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PROXYAUTH_AVAIL \- get available HTTP proxy authentication methods diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 index 3edf5918364..25f9d4db747 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_PROXY_SSL_VERIFYRESULT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_PROXY_SSL_VERIFYRESULT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_PROXY_SSL_VERIFYRESULT \- get the result of the proxy certificate verification diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.3 index 5640fddac77..7acf8ea1eec 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_REDIRECT_COUNT 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_REDIRECT_COUNT 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_REDIRECT_COUNT \- get the number of redirects diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.3 index 03ba793645a..fc124aa7b0b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_REDIRECT_TIME 3 "May 17, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_REDIRECT_TIME 3 "May 17, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_REDIRECT_TIME \- get the time for all redirection steps diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.3 index cc797112e65..e60956b7e1a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_REDIRECT_TIME_T 3 "May 17, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_REDIRECT_TIME_T 3 "May 17, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_REDIRECT_TIME_T \- get the time for all redirection steps diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_URL.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_URL.3 index f1b3e7af894..f1d0b52d5ff 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_URL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REDIRECT_URL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_REDIRECT_URL 3 "June 24, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_REDIRECT_URL 3 "June 24, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_REDIRECT_URL \- get the URL a redirect would go to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.3 index e55433662ff..9637f7a91e7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_REQUEST_SIZE 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_REQUEST_SIZE 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_REQUEST_SIZE \- get size of sent request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3 index a5d852762b3..3c39ef6f577 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RESPONSE_CODE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RESPONSE_CODE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RESPONSE_CODE \- get the last response code diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RETRY_AFTER.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RETRY_AFTER.3 index 6dedb1c35a8..b8d52b61c2d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RETRY_AFTER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RETRY_AFTER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RETRY_AFTER 3 "August 06, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RETRY_AFTER 3 "February 29, 2020" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RETRY_AFTER \- returns the Retry-After retry delay @@ -34,7 +34,7 @@ HTTP server suggesets the client should wait until the next request is issued. The information from the "Retry-After:" header. While the HTTP header might contain a fixed date string, the -\fICURLINFO_RETRY_AFTER(3)\fP will alwaus return number of seconds to wait - +\fICURLINFO_RETRY_AFTER(3)\fP will always return number of seconds to wait - or zero if there was no header or the header couldn't be parsed. .SH DEFAULT Returns zero delay if there was no header. diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.3 index 01bc90d3e97..79dffe594ed 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RTSP_CLIENT_CSEQ 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RTSP_CLIENT_CSEQ 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RTSP_CLIENT_CSEQ \- get the next RTSP client CSeq diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.3 index 027a98b993b..bbee08f1c3f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RTSP_CSEQ_RECV 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RTSP_CSEQ_RECV 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RTSP_CSEQ_RECV \- get the recently received CSeq diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.3 index c1ba8fecc1f..a4297a330f1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RTSP_SERVER_CSEQ 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RTSP_SERVER_CSEQ 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RTSP_SERVER_CSEQ \- get the next RTSP server CSeq diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.3 index 5ad2ddbe253..6b5adee0fe7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_RTSP_SESSION_ID 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_RTSP_SESSION_ID 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_RTSP_SESSION_ID \- get RTSP session ID diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SCHEME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SCHEME.3 index 4ebde9a90f8..701e7da9096 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SCHEME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SCHEME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SCHEME 3 "April 08, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SCHEME 3 "April 08, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SCHEME \- get the URL scheme (sometimes called protocol) used in the connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.3 index daa0289fa45..16aa9d05469 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SIZE_DOWNLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SIZE_DOWNLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SIZE_DOWNLOAD \- get the number of downloaded bytes diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.3 index 1cf2ca73dca..a788bf834ec 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SIZE_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SIZE_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SIZE_DOWNLOAD_T \- get the number of downloaded bytes diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.3 index f8a9f7a5991..b48f3f5ed1b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SIZE_UPLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SIZE_UPLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SIZE_UPLOAD \- get the number of uploaded bytes diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.3 index 2c0eb5e80b3..522c35f11ef 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SIZE_UPLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SIZE_UPLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SIZE_UPLOAD_T \- get the number of uploaded bytes diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.3 index 0c6abc276ea..e7984d7f0b4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SPEED_DOWNLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SPEED_DOWNLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SPEED_DOWNLOAD \- get download speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.3 index 4b8b16d0acb..ec92dab6737 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SPEED_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SPEED_DOWNLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SPEED_DOWNLOAD_T \- get download speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.3 index 19968ee2d84..ac0d9523c83 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SPEED_UPLOAD 3 "June 15, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SPEED_UPLOAD 3 "June 15, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SPEED_UPLOAD \- get upload speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.3 index f8a3a5c5039..6f454604943 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SPEED_UPLOAD_T 3 "March 31, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SPEED_UPLOAD_T 3 "March 31, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SPEED_UPLOAD_T \- get upload speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_ENGINES.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_ENGINES.3 index 596465940b2..1195d8e9cf1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_ENGINES.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_ENGINES.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SSL_ENGINES 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SSL_ENGINES 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SSL_ENGINES \- get an slist of OpenSSL crypto-engines diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 index 65e98be41b2..7b89e0b6786 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_SSL_VERIFYRESULT 3 "March 21, 2018" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_SSL_VERIFYRESULT 3 "March 21, 2018" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_SSL_VERIFYRESULT \- get the result of the certificate verification diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.3 index 64c1c6baeb6..35ca6e7e3a8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_STARTTRANSFER_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_STARTTRANSFER_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_STARTTRANSFER_TIME \- get the time until the first byte is received diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.3 index 079cf57e003..554335f1298 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_STARTTRANSFER_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_STARTTRANSFER_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_STARTTRANSFER_TIME_T \- get the time until the first byte is received diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SESSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SESSION.3 index efc98d82ed6..b5e848b13a1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SESSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SESSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_TLS_SESSION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_TLS_SESSION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_TLS_SESSION \- get TLS session info diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.3 index 1c9714aed7d..9168a90f12d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_TLS_SSL_PTR 3 "July 16, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_TLS_SSL_PTR 3 "March 04, 2020" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_TLS_SESSION, CURLINFO_TLS_SSL_PTR \- get TLS session info @@ -55,11 +55,11 @@ struct curl_tlssessioninfo { The \fIbackend\fP struct member is one of the defines in the CURLSSLBACKEND_* series: CURLSSLBACKEND_NONE (when built without TLS support), -CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_DARWINSSL, -CURLSSLBACKEND_GNUTLS, CURLSSLBACKEND_GSKIT, CURLSSLBACKEND_MBEDTLS, -CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL, CURLSSLBACKEND_POLARSSL, -CURLSSLBACKEND_SCHANNEL or CURLSSLBACKEND_MESALINK. (Note that the OpenSSL -forks are all reported as just OpenSSL here.) +CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_DARWINSSL, CURLSSLBACKEND_GNUTLS, +CURLSSLBACKEND_GSKIT, CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, +CURLSSLBACKEND_OPENSSL, CURLSSLBACKEND_SCHANNEL or +CURLSSLBACKEND_MESALINK. (Note that the OpenSSL forks are all reported as just +OpenSSL here.) The \fIinternals\fP struct member will point to a TLS library specific pointer for the active ("in use") SSL connection, with the following underlying types: @@ -80,8 +80,6 @@ as well: .RS .IP mbedTLS mbedtls_ssl_context * -.IP PolarSSL -ssl_context * .IP "Secure Channel" CtxtHandle * .IP "Secure Transport" diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME.3 index 961f4e7ea86..4565057716a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_TOTAL_TIME 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_TOTAL_TIME 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_TOTAL_TIME \- get total time of previous transfer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.3 b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.3 index b247b989d39..a1f85e86a7e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLINFO_TOTAL_TIME_T 3 "August 26, 2019" "libcurl 7.68.0" "curl_easy_getinfo options" +.TH CURLINFO_TOTAL_TIME_T 3 "August 26, 2019" "libcurl 7.69.1" "curl_easy_getinfo options" .SH NAME CURLINFO_TOTAL_TIME_T \- get total time of previous transfer in microseconds diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 index decc8100a87..c05687a2801 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE \- chunk length threshold for pipelining diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 index aa2f88ad4cd..26d9486f0a4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE \- size threshold for pipelining penalty diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.3 index 0af783f3086..5f7550ffe8c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_MAXCONNECTS 3 "September 23, 2018" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_MAXCONNECTS 3 "September 23, 2018" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_MAXCONNECTS \- set size of connection cache diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.3 index a809a256be6..51d0f8733eb 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_MAX_HOST_CONNECTIONS 3 "May 27, 2017" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_MAX_HOST_CONNECTIONS 3 "May 27, 2017" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_MAX_HOST_CONNECTIONS \- set max number of connections to a single host diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.3 index 86977adf9a2..332804add7d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_MAX_PIPELINE_LENGTH 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_MAX_PIPELINE_LENGTH 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_MAX_PIPELINE_LENGTH \- maximum number of requests in a pipeline diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 index ed668be1464..5b7873f88bd 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_MAX_TOTAL_CONNECTIONS 3 "May 27, 2017" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_MAX_TOTAL_CONNECTIONS 3 "May 27, 2017" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_MAX_TOTAL_CONNECTIONS \- max simultaneously open connections diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING.3 index ff80c38dec7..de4f7c7c977 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_PIPELINING 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_PIPELINING 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_PIPELINING \- enable HTTP pipelining and multiplexing diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.3 index b583683f828..951776135d9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_PIPELINING_SERVER_BL 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_PIPELINING_SERVER_BL 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_PIPELINING_SERVER_BL \- pipelining server blacklist diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.3 index 583f6d9486a..bd3f13c5b20 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_PIPELINING_SITE_BL 3 "April 05, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_PIPELINING_SITE_BL 3 "April 05, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_PIPELINING_SITE_BL \- pipelining host blacklist diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHDATA.3 index 1b93c72ab5f..53936863b44 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_PUSHDATA 3 "May 27, 2017" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_PUSHDATA 3 "May 27, 2017" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_PUSHDATA \- pointer to pass to push callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 index 61f6785342f..cdbc834019d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_PUSHFUNCTION 3 "February 03, 2016" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_PUSHFUNCTION 3 "February 03, 2016" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_PUSHFUNCTION \- callback that approves or denies server pushes diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETDATA.3 index 97200ffa45d..0a2e74d41cc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_SOCKETDATA 3 "May 31, 2017" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_SOCKETDATA 3 "May 31, 2017" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_SOCKETDATA \- custom pointer passed to the socket callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.3 index 4973472dd0e..605cd9f87f7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_SOCKETFUNCTION 3 "June 24, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_SOCKETFUNCTION 3 "June 24, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_SOCKETFUNCTION \- callback informed about what to wait for diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERDATA.3 index 753a7fce878..c81a23c4f61 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_TIMERDATA 3 "May 27, 2017" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_TIMERDATA 3 "May 27, 2017" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_TIMERDATA \- custom pointer to pass to timer callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.3 index 8b381473df6..d04b2680044 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLMOPT_TIMERFUNCTION 3 "May 03, 2019" "libcurl 7.68.0" "curl_multi_setopt options" +.TH CURLMOPT_TIMERFUNCTION 3 "May 03, 2019" "libcurl 7.69.1" "curl_multi_setopt options" .SH NAME CURLMOPT_TIMERFUNCTION \- set callback to receive timeout values diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 index 7d97a285f65..1762993426a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ABSTRACT_UNIX_SOCKET 3 "January 09, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ABSTRACT_UNIX_SOCKET 3 "January 09, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ABSTRACT_UNIX_SOCKET \- set an abstract Unix domain socket diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.3 index a649c4ff7aa..cc13e842988 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ACCEPTTIMEOUT_MS 3 "March 06, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ACCEPTTIMEOUT_MS 3 "March 06, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ACCEPTTIMEOUT_MS \- timeout waiting for FTP server to connect back diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.3 index e06909328ce..deb469b7f3a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ACCEPT_ENCODING 3 "August 27, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ACCEPT_ENCODING 3 "August 27, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ACCEPT_ENCODING \- enables automatic decompression of HTTP downloads diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.3 index 53a1b489398..d91dbf1b9a7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ADDRESS_SCOPE 3 "March 07, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ADDRESS_SCOPE 3 "March 07, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ADDRESS_SCOPE \- set scope id for IPv6 addresses diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC.3 index cf8a144d4ed..d161c76ec42 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ALTSVC 3 "August 14, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ALTSVC 3 "August 14, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ALTSVC \- set alt-svc cache file name diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3 index f399ed54022..c713adb48b6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ALTSVC_CTRL 3 "August 13, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ALTSVC_CTRL 3 "February 11, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ALTSVC_CTRL \- control alt-svc behavior @@ -70,7 +70,10 @@ Accept alternative services offered over HTTP/3. This will only be used if libcurl was also built to actually support HTTP/3, otherwise this bit will be ignored. .SH DEFAULT -0. No Alt-Svc treatment. +Alt-Svc handling is disabled by default. If \fICURLOPT_ALTSVC(3)\fP is set, +\fICURLOPT_ALTSVC_CTRL(3)\fP has a default value corresponding to +CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2 and HTTP/3 bits are +only set if libcurl was built with support for those versions. .SH PROTOCOLS HTTPS .SH EXAMPLE diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_APPEND.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_APPEND.3 index 75337ee5fdb..219f6c1254f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_APPEND.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_APPEND.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_APPEND 3 "March 06, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_APPEND 3 "March 06, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_APPEND \- enable appending to the remote file diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_AUTOREFERER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_AUTOREFERER.3 index 847f46ad627..d90a7f406e9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_AUTOREFERER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_AUTOREFERER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_AUTOREFERER 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_AUTOREFERER 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_AUTOREFERER \- automatically update the referer header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_BUFFERSIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_BUFFERSIZE.3 index 8ae28649425..892de768f8a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_BUFFERSIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_BUFFERSIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_BUFFERSIZE 3 "May 13, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_BUFFERSIZE 3 "May 13, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_BUFFERSIZE \- set preferred receive buffer size diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAINFO.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAINFO.3 index 3e62a29d1c1..cceb6034457 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAINFO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAINFO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CAINFO 3 "June 10, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CAINFO 3 "June 10, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CAINFO \- path to Certificate Authority (CA) bundle diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAPATH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAPATH.3 index d03e5a41452..ac2d4f47d10 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAPATH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CAPATH.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CAPATH 3 "September 10, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CAPATH 3 "March 04, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CAPATH \- specify directory holding CA certificates @@ -55,9 +55,8 @@ if(curl) { } .fi .SH AVAILABILITY -This option is supported by the OpenSSL, GnuTLS, PolarSSL and mbedTLS -(since 7.56.0) backends. The NSS backend provides the option only for -backward compatibility. +This option is supported by the OpenSSL, GnuTLS and mbedTLS (since 7.56.0) +backends. The NSS backend provides the option only for backward compatibility. .SH RETURN VALUE CURLE_OK if supported; or an error such as: diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CERTINFO.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CERTINFO.3 index 88e9327c02a..860cb8ceb21 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CERTINFO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CERTINFO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CERTINFO 3 "January 29, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CERTINFO 3 "January 29, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CERTINFO \- request SSL certificate information diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.3 index f6a8f8c6bfa..9c8b327e81e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CHUNK_BGN_FUNCTION 3 "May 03, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CHUNK_BGN_FUNCTION 3 "May 03, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CHUNK_BGN_FUNCTION \- callback before a transfer with FTP wildcardmatch diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_DATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_DATA.3 index 18e0bdd80b5..008182c1e5d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_DATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_DATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CHUNK_DATA 3 "November 07, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CHUNK_DATA 3 "November 07, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CHUNK_DATA \- custom pointer to the FTP chunk callbacks diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.3 index f1fa6fea03a..4344502880d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CHUNK_END_FUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CHUNK_END_FUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CHUNK_END_FUNCTION \- callback after a transfer with FTP wildcardmatch diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.3 index 7d428d6f3e1..8b9ae5bc641 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CLOSESOCKETDATA 3 "November 07, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CLOSESOCKETDATA 3 "November 07, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CLOSESOCKETDATA \- pointer passed to the socket close callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.3 index 63face60459..24087ac5d7b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CLOSESOCKETFUNCTION 3 "November 07, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CLOSESOCKETFUNCTION 3 "November 07, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CLOSESOCKETFUNCTION \- callback to socket close replacement function diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.3 index 47ce9594ca5..0aae7f009e5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONNECTTIMEOUT 3 "October 03, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONNECTTIMEOUT 3 "October 03, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONNECTTIMEOUT \- timeout for the connect phase diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.3 index 49fb7c4f416..c62f69cfbc9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONNECTTIMEOUT_MS 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONNECTTIMEOUT_MS 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONNECTTIMEOUT_MS \- timeout for the connect phase diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.3 index 6905c57f26c..624e1ef45e5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONNECT_ONLY 3 "February 18, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONNECT_ONLY 3 "February 18, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONNECT_ONLY \- stop when connected to target server diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_TO.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_TO.3 index d99e2b34a93..f2139c12f22 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_TO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONNECT_TO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONNECT_TO 3 "May 05, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONNECT_TO 3 "May 05, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONNECT_TO \- Connect to a specific host and port instead of the URL's host and port diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 index 2c69ad19bd5..e723f32f5e7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONV_FROM_NETWORK_FUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONV_FROM_NETWORK_FUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONV_FROM_NETWORK_FUNCTION \- convert data from network to host encoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 index c2731ac1b15..468aed91953 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONV_FROM_UTF8_FUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONV_FROM_UTF8_FUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONV_FROM_UTF8_FUNCTION \- convert data from UTF8 to host encoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 index 1f8396747cc..de8ec439913 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CONV_TO_NETWORK_FUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CONV_TO_NETWORK_FUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CONV_TO_NETWORK_FUNCTION \- convert data to network from host encoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIE.3 index 9a5789c7472..577c88de50b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COOKIE 3 "December 21, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COOKIE 3 "December 21, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COOKIE \- set contents of HTTP Cookie header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEFILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEFILE.3 index db05c3bfeb8..312485d5929 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEFILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEFILE.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COOKIEFILE 3 "March 13, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COOKIEFILE 3 "January 10, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COOKIEFILE \- file name to read cookies from @@ -76,6 +76,10 @@ if(curl) { curl_easy_cleanup(curl); } .fi +.SH "Cookie file format" +The cookie file format and general cookie concepts in curl are described in +the HTTP-COOKIES.md file, also hosted online here: +https://curl.haxx.se/docs/http-cookies.html .SH AVAILABILITY As long as HTTP is supported .SH RETURN VALUE diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEJAR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEJAR.3 index 39e6b1d8840..4139ccfc66f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEJAR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIEJAR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COOKIEJAR 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COOKIEJAR 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COOKIEJAR \- file name to store cookies to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIELIST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIELIST.3 index f08feec111c..323f3add751 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIELIST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIELIST.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COOKIELIST 3 "April 26, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COOKIELIST 3 "January 10, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COOKIELIST \- add to or manipulate cookies held in memory @@ -105,6 +105,10 @@ curl_easy_perform(curl); /* cookies imported from cookies.txt */ curl_easy_cleanup(curl); /* cookies exported to cookies.txt */ .fi +.SH "Cookie file format" +The cookie file format and general cookie concepts in curl are described in +the HTTP-COOKIES.md file, also hosted online here: +https://curl.haxx.se/docs/http-cookies.html .SH AVAILABILITY ALL was added in 7.14.1 diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIESESSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIESESSION.3 index 34e2ea8022a..f21bc10f76e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIESESSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COOKIESESSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COOKIESESSION 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COOKIESESSION 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COOKIESESSION \- start a new cookie session diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.3 index 8edf6782f31..4ddc9c687d4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_COPYPOSTFIELDS 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_COPYPOSTFIELDS 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_COPYPOSTFIELDS \- have libcurl copy data to POST diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLF.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLF.3 index 0be030e0b35..3f45514c158 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLF.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLF.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CRLF 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CRLF 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CRLF \- enable/disable CRLF conversion diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLFILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLFILE.3 index 309434758a9..0ecab3e3e79 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLFILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CRLFILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CRLFILE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CRLFILE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CRLFILE \- specify a Certificate Revocation List file diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CURLU.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CURLU.3 index 9aa6de50b6e..014a17f0ea3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CURLU.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CURLU.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CURLU 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CURLU 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CURLU \- set URL with CURLU * diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.3 index 13e30d118e3..5e80828863b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_CUSTOMREQUEST 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_CUSTOMREQUEST 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_CUSTOMREQUEST \- custom string for request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGDATA.3 index 88165205bb7..207ba327abf 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DEBUGDATA 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DEBUGDATA 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DEBUGDATA \- custom pointer for debug callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.3 index 06567d64a6d..4129731b568 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DEBUGFUNCTION 3 "October 06, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DEBUGFUNCTION 3 "October 06, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DEBUGFUNCTION \- debug callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.3 index 391a8665e37..425fa4fd7e6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DEFAULT_PROTOCOL 3 "December 21, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DEFAULT_PROTOCOL 3 "December 21, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DEFAULT_PROTOCOL \- default protocol to use if the URL is missing a diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DIRLISTONLY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DIRLISTONLY.3 index 67b419f2e03..e2a33a037d4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DIRLISTONLY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DIRLISTONLY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DIRLISTONLY 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DIRLISTONLY 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DIRLISTONLY \- ask for names only in a directory listing diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 index e93ead4afdc..32d28586c09 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DISALLOW_USERNAME_IN_URL 3 "February 25, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DISALLOW_USERNAME_IN_URL 3 "February 25, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DISALLOW_USERNAME_IN_URL \- disallow specifying username in the url diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.3 index 7f50982b6c0..92e0a788256 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_CACHE_TIMEOUT 3 "December 09, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_CACHE_TIMEOUT 3 "December 09, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_CACHE_TIMEOUT \- set life-time for DNS cache entries diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.3 index e7f0be96ecf..15bf54486ae 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_INTERFACE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_INTERFACE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_INTERFACE \- set interface to speak DNS over diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.3 index 71172dcf3ec..386d374331e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_LOCAL_IP4 3 "December 10, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_LOCAL_IP4 3 "December 10, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_LOCAL_IP4 \- IPv4 address to bind DNS resolves to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.3 index e34b07b6979..3d819794a08 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_LOCAL_IP6 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_LOCAL_IP6 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_LOCAL_IP6 \- IPv6 address to bind DNS resolves to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SERVERS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SERVERS.3 index 67c064fc4af..72f474bbe9d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SERVERS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SERVERS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_SERVERS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_SERVERS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_SERVERS \- set preferred DNS servers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.3 index d84ed77e44b..c79a828d462 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_SHUFFLE_ADDRESSES 3 "March 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_SHUFFLE_ADDRESSES 3 "March 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_SHUFFLE_ADDRESSES \- Shuffle addresses when a hostname returns more than one diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.3 index 665ba6b6b93..db7cea2dcf0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DNS_USE_GLOBAL_CACHE 3 "March 07, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DNS_USE_GLOBAL_CACHE 3 "March 07, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DNS_USE_GLOBAL_CACHE \- enable/disable global DNS cache diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DOH_URL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DOH_URL.3 index 64675bfee8f..feedbdd2521 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_DOH_URL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_DOH_URL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_DOH_URL 3 "September 06, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_DOH_URL 3 "September 06, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_DOH_URL \- provide the DNS-over-HTTPS URL diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_EGDSOCKET.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_EGDSOCKET.3 index bd4e3e2f1c4..f081bb17c33 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_EGDSOCKET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_EGDSOCKET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_EGDSOCKET 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_EGDSOCKET 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_EGDSOCKET \- set EGD socket path diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ERRORBUFFER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ERRORBUFFER.3 index adbeb673e6d..ab261a3b954 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ERRORBUFFER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ERRORBUFFER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ERRORBUFFER 3 "March 13, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ERRORBUFFER 3 "March 13, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ERRORBUFFER \- set error buffer for error messages diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.3 index f2f455accba..1a89e7ec8d4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_EXPECT_100_TIMEOUT_MS 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_EXPECT_100_TIMEOUT_MS 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_EXPECT_100_TIMEOUT_MS \- timeout for Expect: 100-continue response diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FAILONERROR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FAILONERROR.3 index ec7b84d6615..14ee181b274 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FAILONERROR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FAILONERROR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FAILONERROR 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FAILONERROR 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FAILONERROR \- request failure on HTTP response >= 400 diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FILETIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FILETIME.3 index 0685b7a1295..938fa0e1890 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FILETIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FILETIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FILETIME 3 "April 03, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FILETIME 3 "April 03, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FILETIME \- get the modification time of the remote resource diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.3 index 1fb7ff1091a..a4724dffeed 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FNMATCH_DATA 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FNMATCH_DATA 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FNMATCH_DATA \- custom pointer to fnmatch callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.3 index d398d076c1f..34a0d6b2894 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FNMATCH_FUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FNMATCH_FUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FNMATCH_FUNCTION \- wildcard matching function callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.3 index 73043d37d6f..9181c8d2619 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FOLLOWLOCATION 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FOLLOWLOCATION 3 "January 28, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FOLLOWLOCATION \- follow HTTP 3xx redirects @@ -47,7 +47,7 @@ are also disabled. When following a Location:, the 3xx response code that redirected it also dictates which request method it will use in the subsequent request: For 301, -302 and 303 responses libcurl will switch method to GET unless +302 and 303 responses libcurl will switch method from POST to GET unless \fICURLOPT_POSTREDIR(3)\fP instructs libcurl otherwise. All other 3xx codes will make libcurl send the same method again. diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FORBID_REUSE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FORBID_REUSE.3 index 25be2d106b7..f7c59c1eb7e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FORBID_REUSE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FORBID_REUSE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FORBID_REUSE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FORBID_REUSE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FORBID_REUSE \- make connection get closed at once after use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.3 index 4b393440f65..dc0fdc57904 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FRESH_CONNECT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FRESH_CONNECT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FRESH_CONNECT \- force a new connection to be used diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPPORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPPORT.3 index 90d9284218b..8d5cec24086 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPPORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPPORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTPPORT 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTPPORT 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTPPORT \- make FTP transfer active diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.3 index 991f57afb26..9473b6f9afd 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTPSSLAUTH 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTPSSLAUTH 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTPSSLAUTH \- set order in which to attempt TLS vs SSL when using FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.3 index f2e64a3e336..9c624766c7c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_ACCOUNT 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_ACCOUNT 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_ACCOUNT \- set account info for FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 index 1946887f3df..4fbf873becf 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_ALTERNATIVE_TO_USER 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_ALTERNATIVE_TO_USER 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_ALTERNATIVE_TO_USER \- command to use instead of USER with FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.3 index ca9584f0fae..b7e9e7b8677 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_CREATE_MISSING_DIRS 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_CREATE_MISSING_DIRS 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_CREATE_MISSING_DIRS \- create missing dirs for FTP and SFTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.3 index fd6ee51adc7..3f378c852d0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_FILEMETHOD 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_FILEMETHOD 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_FILEMETHOD \- select directory traversing method for FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_RESPONSE_TIMEOUT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_RESPONSE_TIMEOUT.3 index 60ba657e305..067762cdf71 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_RESPONSE_TIMEOUT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_RESPONSE_TIMEOUT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_RESPONSE_TIMEOUT 3 "October 03, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_RESPONSE_TIMEOUT 3 "October 03, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_RESPONSE_TIMEOUT \- time allowed to wait for FTP response diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 index 5f234b479ec..82463877c31 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_SKIP_PASV_IP 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_SKIP_PASV_IP 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_SKIP_PASV_IP \- ignore the IP address in the PASV response diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.3 index 2951066866b..9d43995fe5c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_SSL_CCC 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_SSL_CCC 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_SSL_CCC \- switch off SSL again with FTP after auth diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.3 index 74025b2c59e..59b6a89f9d8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_USE_EPRT 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_USE_EPRT 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_USE_EPRT \- enable/disable use of EPRT with FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.3 index ba465af40ca..b41e22608e9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_USE_EPSV 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_USE_EPSV 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_USE_EPSV \- enable/disable use of EPSV diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.3 index 7d60f01c7a9..9518c248572 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_FTP_USE_PRET 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_FTP_USE_PRET 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_FTP_USE_PRET \- enable the PRET command diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.3 index b324c1afd23..28fcad2fb42 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_GSSAPI_DELEGATION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_GSSAPI_DELEGATION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_GSSAPI_DELEGATION \- set allowed GSS-API delegation diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 index 96cc794fff6..5699b786790 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS 3 "February 21, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS 3 "February 21, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS \- head start for ipv6 for happy eyeballs diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3 index 7a0e2dfd2b4..c7de929ad1b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HAPROXYPROTOCOL 3 "May 18, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HAPROXYPROTOCOL 3 "May 18, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HAPROXYPROTOCOL \- send HAProxy PROXY protocol v1 header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADER.3 index f1080825fb2..4eb463d94e6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HEADER 3 "October 03, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HEADER 3 "October 03, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HEADER \- pass headers to the data stream diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERDATA.3 index 84b900872bc..543250dd0a1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HEADERDATA 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HEADERDATA 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HEADERDATA \- pointer to pass to header callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.3 index d52f1902539..389141b8196 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HEADERFUNCTION 3 "December 26, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HEADERFUNCTION 3 "December 26, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HEADERFUNCTION \- callback that receives header data diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADEROPT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADEROPT.3 index a88e61f29d2..1c1870062ea 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADEROPT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HEADEROPT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HEADEROPT 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HEADEROPT 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HEADEROPT \- set how to send HTTP headers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.3 index 5980aa43337..008275af643 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTP09_ALLOWED 3 "August 05, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTP09_ALLOWED 3 "August 05, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTP09 \- allow HTTP/0.9 response diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.3 index b08422fc56d..657df0cee17 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTP200ALIASES 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTP200ALIASES 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTP200ALIASES \- specify alternative matches for HTTP 200 OK diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPAUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPAUTH.3 index 7921e504d65..0f1cdeac849 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPAUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPAUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTPAUTH 3 "June 15, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTPAUTH 3 "June 15, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTPAUTH \- set HTTP server authentication methods to try diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPGET.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPGET.3 index 28ce8e6e601..541d3a28bf5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPGET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPGET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTPGET 3 "May 21, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTPGET 3 "May 21, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTPGET \- ask for an HTTP GET request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 index cf22711e704..fe9097973e7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTPHEADER 3 "December 30, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTPHEADER 3 "December 30, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTPHEADER \- set custom HTTP headers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPOST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPOST.3 index d9e078ae836..74a869c7eda 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPOST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPOST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTPPOST 3 "September 02, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTPPOST 3 "September 02, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTPPOST \- specify the multipart formpost content diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.3 index 704baf1dfdd..fdf03b1021a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTPPROXYTUNNEL 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTPPROXYTUNNEL 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTPPROXYTUNNEL \- tunnel through HTTP proxy diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.3 index 5490e4b5794..25fc214acf4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTP_CONTENT_DECODING 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTP_CONTENT_DECODING 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTP_CONTENT_DECODING \- enable/disable HTTP content decoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.3 index 38bb5fb5c5a..faa60e02c2b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTP_TRANSFER_DECODING 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTP_TRANSFER_DECODING 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTP_TRANSFER_DECODING \- enable/disable HTTP transfer decoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_VERSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_VERSION.3 index eee18213741..0e7e141d11b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_VERSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_HTTP_VERSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_HTTP_VERSION 3 "September 14, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_HTTP_VERSION 3 "September 14, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_HTTP_VERSION \- specify HTTP protocol version to use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.3 index 0ccc348e90d..85ef3e5ef1f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_IGNORE_CONTENT_LENGTH 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_IGNORE_CONTENT_LENGTH 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_IGNORE_CONTENT_LENGTH \- ignore content length diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE.3 index cc29ba99655..362a1c3e43f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_INFILESIZE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_INFILESIZE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_INFILESIZE \- set size of the input file to send off diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.3 index 94e00224c6c..c6daf52656d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_INFILESIZE_LARGE 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_INFILESIZE_LARGE 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_INFILESIZE_LARGE \- set size of the input file to send off diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERFACE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERFACE.3 index f3bb986c7e7..c42740abd99 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERFACE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERFACE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_INTERFACE 3 "June 18, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_INTERFACE 3 "June 18, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_INTERFACE \- source interface for outgoing traffic diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.3 index 304133862f6..098f31cf034 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_INTERLEAVEDATA 3 "September 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_INTERLEAVEDATA 3 "September 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_INTERLEAVEDATA \- custom pointer passed to RTSP interleave callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.3 index 3177d3a4fc9..7596d97508e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_INTERLEAVEFUNCTION 3 "August 11, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_INTERLEAVEFUNCTION 3 "August 11, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_INTERLEAVEFUNCTION \- callback function for RTSP interleaved data diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLDATA.3 index c00a6eece37..1e3be16d380 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_IOCTLDATA 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_IOCTLDATA 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_IOCTLDATA \- custom pointer passed to I/O callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.3 index 1dc7a3f758a..f47e7cd521f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_IOCTLFUNCTION 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_IOCTLFUNCTION 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_IOCTLFUNCTION \- callback for I/O operations diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IPRESOLVE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IPRESOLVE.3 index 4fb1ef6880e..7aeb70e6f7a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_IPRESOLVE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_IPRESOLVE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_IPRESOLVE 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_IPRESOLVE 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_IPRESOLVE \- specify which IP protocol version to use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT.3 index 0833e06514e..52a484d4089 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_ISSUERCERT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_ISSUERCERT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_ISSUERCERT \- issuer SSL certificate filename diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.3 index 1a6e7d7fa18..d31f4889fd2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_KEEP_SENDING_ON_ERROR 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_KEEP_SENDING_ON_ERROR 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_KEEP_SENDING_ON_ERROR \- keep sending on early HTTP response >= 300 diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEYPASSWD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEYPASSWD.3 index eeffc519fae..37ed8216398 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEYPASSWD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KEYPASSWD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_KEYPASSWD 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_KEYPASSWD 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_KEYPASSWD \- set passphrase to private key diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KRBLEVEL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KRBLEVEL.3 index 24019bc25a8..58288fa17b7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_KRBLEVEL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_KRBLEVEL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_KRBLEVEL 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_KRBLEVEL 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_KRBLEVEL \- set FTP kerberos security level diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORT.3 index 83591a5d8d4..16ccf3ce0a6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_LOCALPORT 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_LOCALPORT 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_LOCALPORT \- set local port number to use for socket diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.3 index 62fe8097f02..08da5e62866 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_LOCALPORTRANGE 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_LOCALPORTRANGE 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_LOCALPORTRANGE \- number of additional local ports to try diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 index e2f06101bc7..eeba9db743b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_LOGIN_OPTIONS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_LOGIN_OPTIONS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_LOGIN_OPTIONS \- set login options diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.3 index f3710f3324c..1305ac6b22e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_LOW_SPEED_LIMIT 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_LOW_SPEED_LIMIT 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_LOW_SPEED_LIMIT \- set low speed limit in bytes per second diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.3 index 23f594ae455..0a48a2d5d01 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_LOW_SPEED_TIME 3 "May 06, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_LOW_SPEED_TIME 3 "May 06, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_LOW_SPEED_TIME \- set low speed limit time period diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_AUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_AUTH.3 index cea99da327a..f5674fe0e37 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_AUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_AUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAIL_AUTH 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAIL_AUTH 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAIL_AUTH \- SMTP authentication address diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_FROM.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_FROM.3 index 42ed27a3f28..294498dc974 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_FROM.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_FROM.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAIL_FROM 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAIL_FROM 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAIL_FROM \- SMTP sender address diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT.3 index a1ad5b9558c..1d5fc810886 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAIL_RCPT 3 "July 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAIL_RCPT 3 "July 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAIL_RCPT \- list of SMTP mail recipients diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 new file mode 100644 index 00000000000..80e844ac8c8 --- /dev/null +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 @@ -0,0 +1,72 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_MAIL_RCPT_ALLLOWFAILS 3 "January 14, 2020" "libcurl 7.69.1" "curl_easy_setopt options" + +.SH NAME +CURLOPT_MAIL_RCPT_ALLLOWFAILS \- allow RCPT TO command to fail for some recipients +.SH SYNOPSIS +.nf +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_RCPT_ALLLOWFAILS, + long allow); +.SH DESCRIPTION +If \fIallow\fP is set to 1L, allow RCPT TO command to fail for some recipients. + +When sending data to multiple recipients, by default curl will abort SMTP +conversation if at least one of the recipients causes RCPT TO command to +return an error. + +The default behavior can be changed by setting \fIignore\fP to 1L which will +make curl ignore errors and proceed with the remaining valid recipients. + +In case when all recipients cause RCPT TO command to fail, curl will abort SMTP +conversation and return the error received from to the last RCPT TO command. +.SH DEFAULT +0 +.SH PROTOCOLS +SMTP +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + struct curl_slist *list; + + /* Adding one valid and one invalid email address */ + list = curl_slist_append(NULL, "person@example.com"); + list = curl_slist_append(list, "invalidemailaddress"); + + curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/"); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS, 1L); + + ret = curl_easy_perform(curl); + curl_slist_free_all(list); + curl_easy_cleanup(curl); +} +.fi +.SH AVAILABILITY +Added in 7.69.0. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_MAIL_FROM "(3), " CURLOPT_MAIL_RCPT "(3), " diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.3 index 703298c3db5..2c5db3c0202 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAXAGE_CONN 3 "April 14, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAXAGE_CONN 3 "April 14, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAXAGE_CONN \- max idle time allowed for reusing a connection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXCONNECTS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXCONNECTS.3 index 5bfa22369fe..bfcf597f666 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXCONNECTS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXCONNECTS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAXCONNECTS 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAXCONNECTS 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAXCONNECTS \- maximum connection cache size diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 index 5306df267dd..173926284c0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAXFILESIZE 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAXFILESIZE 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAXFILESIZE \- maximum file size allowed to download diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 index 7e7a3631958..d98b22b7d32 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAXFILESIZE_LARGE 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAXFILESIZE_LARGE 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAXFILESIZE_LARGE \- maximum file size allowed to download diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXREDIRS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXREDIRS.3 index 0e7e91258e4..ddd90f1b92b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXREDIRS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAXREDIRS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAXREDIRS 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAXREDIRS 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAXREDIRS \- maximum number of redirects allowed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.3 index 8c0d5c4f967..a6049adaa68 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAX_RECV_SPEED_LARGE 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAX_RECV_SPEED_LARGE 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAX_RECV_SPEED_LARGE \- rate limit data download speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.3 index 664bcf341c3..ebe6b9f9cd9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MAX_SEND_SPEED_LARGE 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MAX_SEND_SPEED_LARGE 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MAX_SEND_SPEED_LARGE \- rate limit data upload speed diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MIMEPOST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MIMEPOST.3 index a7ad3dfdab4..b9a14a0b56a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_MIMEPOST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_MIMEPOST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_MIMEPOST 3 "September 04, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_MIMEPOST 3 "September 04, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_MIMEPOST \- set post/send data from mime structure diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC.3 index 71dd0b31444..87d14a6cdbd 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NETRC 3 "November 03, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NETRC 3 "November 03, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NETRC \- request that .netrc is used diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC_FILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC_FILE.3 index 50f25739970..4a3f470bc81 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC_FILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NETRC_FILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NETRC_FILE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NETRC_FILE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NETRC_FILE \- file name to read .netrc info from diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.3 index 81b4e7ea40f..b2b66dc8fc7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NEW_DIRECTORY_PERMS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NEW_DIRECTORY_PERMS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NEW_DIRECTORY_PERMS \- permissions for remotely created directories diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.3 index 9817a286760..e47c68faead 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NEW_FILE_PERMS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NEW_FILE_PERMS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NEW_FILE_PERMS \- permissions for remotely created files diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOBODY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOBODY.3 index 6ee6bc6ee12..e059b80ed69 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOBODY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOBODY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NOBODY 3 "June 21, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NOBODY 3 "June 21, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NOBODY \- do the download request without getting the body diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROGRESS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROGRESS.3 index 441567fa3dc..c906074354e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROGRESS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROGRESS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NOPROGRESS 3 "October 09, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NOPROGRESS 3 "October 09, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NOPROGRESS \- switch off the progress meter diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROXY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROXY.3 index 06d5613cf46..acab8c6f974 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROXY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOPROXY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NOPROXY 3 "August 24, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NOPROXY 3 "August 24, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NOPROXY \- disable proxy use for specific hosts diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOSIGNAL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOSIGNAL.3 index f7292b302a4..73600906003 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOSIGNAL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_NOSIGNAL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_NOSIGNAL 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_NOSIGNAL 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_NOSIGNAL \- skip all signal handling diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.3 index 6d27f5bca01..7b20bbcd3cc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_OPENSOCKETDATA 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_OPENSOCKETDATA 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_OPENSOCKETDATA \- custom pointer passed to open socket callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.3 index 93c9a9cfc0d..2a2e4d4c06c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_OPENSOCKETFUNCTION 3 "December 03, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_OPENSOCKETFUNCTION 3 "December 03, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_OPENSOCKETFUNCTION \- set callback for opening sockets diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PASSWORD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PASSWORD.3 index 327f4356ba7..24924ef6b3e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PASSWORD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PASSWORD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PASSWORD 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PASSWORD 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PASSWORD \- password to use in authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 index 7dafbf4f8e2..a695d4a2691 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PATH_AS_IS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PATH_AS_IS 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PATH_AS_IS 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PATH_AS_IS \- do not handle dot dot sequences diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 index bacdc0ebab5..732bc71cbd4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PINNEDPUBLICKEY 3 "June 02, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PINNEDPUBLICKEY 3 "June 02, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PINNEDPUBLICKEY \- set pinned public key diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PIPEWAIT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PIPEWAIT.3 index 3fee87b30a0..8b67537ed5e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PIPEWAIT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PIPEWAIT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PIPEWAIT 3 "May 01, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PIPEWAIT 3 "May 01, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PIPEWAIT \- wait for pipelining/multiplexing diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PORT.3 index 728353a1aa2..95f6c249f6f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PORT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PORT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PORT \- set remote port number to work with diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POST.3 index 3ab464e78b9..f41f799dbf5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POST 3 "July 22, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POST 3 "July 22, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POST \- request an HTTP POST diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDS.3 index b3e4a6606a3..0e3ab25cce3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POSTFIELDS 3 "May 21, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POSTFIELDS 3 "January 14, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POSTFIELDS \- specify data to POST to server @@ -55,8 +55,8 @@ the POST data from the read callback. If you want to send a zero-byte POST set Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header, and libcurl will add that header automatically if the POST is either known to -be larger than 1024 bytes or if the expected size is unknown. You can disable -this header with \fICURLOPT_HTTPHEADER(3)\fP as usual. +be larger than 1MB or if the expected size is unknown. You can disable this +header with \fICURLOPT_HTTPHEADER(3)\fP as usual. To make multipart/formdata posts (aka RFC2388-posts), check out the \fICURLOPT_HTTPPOST(3)\fP option combined with \fIcurl_formadd(3)\fP. diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.3 index efafd268edf..04f6cbea187 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POSTFIELDSIZE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POSTFIELDSIZE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POSTFIELDSIZE \- size of POST data pointed to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.3 index f18ddd20737..e670501aeb2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POSTFIELDSIZE_LARGE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POSTFIELDSIZE_LARGE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POSTFIELDSIZE_LARGE \- size of POST data pointed to diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTQUOTE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTQUOTE.3 index b7c94c6ed82..298d1e499a3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTQUOTE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTQUOTE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POSTQUOTE 3 "December 18, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POSTQUOTE 3 "December 18, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POSTQUOTE \- (S)FTP commands to run after the transfer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTREDIR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTREDIR.3 index 23931da0c5a..7430114dcde 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTREDIR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_POSTREDIR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_POSTREDIR 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_POSTREDIR 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_POSTREDIR \- how to act on an HTTP POST redirect diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PREQUOTE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PREQUOTE.3 index 98546cb3d12..e4d1973de7c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PREQUOTE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PREQUOTE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PREQUOTE 3 "December 18, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PREQUOTE 3 "December 18, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PREQUOTE \- commands to run before an FTP transfer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRE_PROXY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRE_PROXY.3 index 173a0c095ff..4f0ca6b8257 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRE_PROXY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRE_PROXY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PRE_PROXY 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PRE_PROXY 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PRE_PROXY \- set pre-proxy to use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRIVATE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRIVATE.3 index 888aee31d4d..7f38081dd78 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRIVATE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PRIVATE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PRIVATE 3 "December 08, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PRIVATE 3 "December 08, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PRIVATE \- store a private pointer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSDATA.3 index 33ccd16e253..1fc07080f97 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROGRESSDATA 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROGRESSDATA 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROGRESSDATA \- custom pointer passed to the progress callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.3 index af18a196a5e..e9784023819 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROGRESSFUNCTION 3 "November 26, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROGRESSFUNCTION 3 "November 26, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROGRESSFUNCTION \- callback to progress meter function diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 index 96cfa864103..20129d815c9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROTOCOLS 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROTOCOLS 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROTOCOLS \- set allowed protocols diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY.3 index bd650e40dbb..0483d0f36ff 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY 3 "August 24, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY 3 "August 24, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY \- set proxy to use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYAUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYAUTH.3 index 29be2e48342..4652b767a2a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYAUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYAUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYAUTH 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYAUTH 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYAUTH \- set HTTP proxy authentication methods to try diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYHEADER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYHEADER.3 index f987d40e565..3d19a717149 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYHEADER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYHEADER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYHEADER 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYHEADER 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYHEADER \- custom HTTP headers to pass to proxy diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.3 index 072e19d5427..f3cae9fb163 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYPASSWORD 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYPASSWORD 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYPASSWORD \- password to use with proxy authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPORT.3 index e01811a5cae..e4e6d758749 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYPORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYPORT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYPORT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYPORT \- port number the proxy listens on diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYTYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYTYPE.3 index 15e3f835b9a..ce9c12fd113 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYTYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYTYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYTYPE 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYTYPE 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYTYPE \- proxy protocol type diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.3 index cd3f2c8bda2..2898b962dd0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYUSERNAME 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYUSERNAME 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYUSERNAME \- user name to use for proxy authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.3 index e5b74b1df32..5dda3055f01 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXYUSERPWD 3 "May 30, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXYUSERPWD 3 "May 30, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXYUSERPWD \- user name and password to use for proxy authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 index 8f4b813adc9..09bed945ed7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_CAINFO 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_CAINFO 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_CAINFO \- path to proxy Certificate Authority (CA) bundle diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 index c889ed2138f..5152102a61b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_CAPATH 3 "May 15, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_CAPATH 3 "May 15, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_CAPATH \- specify directory holding proxy CA certificates diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 index 8dc8dadc577..018a7a7e4cc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_CRLFILE 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_CRLFILE 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_CRLFILE \- specify a proxy Certificate Revocation List file diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 index 3bd03d04912..1f71ee7d778 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_KEYPASSWD 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_KEYPASSWD 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_KEYPASSWD \- set passphrase to proxy private key diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.3 index 604b228ba0c..a72ebbaf95d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_PINNEDPUBLICKEY 3 "May 15, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_PINNEDPUBLICKEY 3 "May 15, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_PINNEDPUBLICKEY \- set pinned public key for https proxy diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.3 index a3eaa9a89de..13e338893e9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SERVICE_NAME 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SERVICE_NAME 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SERVICE_NAME \- proxy authentication service name diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 index d042023d8ec..31b8edb4ebc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSLCERT 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSLCERT 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSLCERT \- set SSL proxy client certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 index 853d57ced6a..757e6e719cb 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSLCERTTYPE 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSLCERTTYPE 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSLCERTTYPE \- specify type of the proxy client SSL certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 index 974e9467c09..ecba9d2b4b8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSLKEY 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSLKEY 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSLKEY \- specify private keyfile for TLS and SSL proxy client cert diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 index 0e9b004bd37..5c62937ef57 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSLKEYTYPE 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSLKEYTYPE 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSLKEYTYPE \- set type of the proxy private key file diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 index e832ce764cb..d3ac69efe9e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSLVERSION 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSLVERSION 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSLVERSION \- set preferred proxy TLS/SSL version diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 index aef74b7f521..ac243824380 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSL_CIPHER_LIST 3 "October 10, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSL_CIPHER_LIST 3 "October 10, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSL_CIPHER_LIST \- specify ciphers to use for proxy TLS diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 index 890d12e8340..24b45c8106e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSL_OPTIONS 3 "July 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSL_OPTIONS 3 "January 23, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSL_OPTIONS \- set proxy SSL behavior options @@ -29,25 +29,31 @@ CURLOPT_PROXY_SSL_OPTIONS \- set proxy SSL behavior options CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_OPTIONS, long bitmask); .SH DESCRIPTION -Pass a long with a bitmask to tell libcurl about specific SSL behaviors. - -\fICURLSSLOPT_ALLOW_BEAST\fP tells libcurl to not attempt to use any -workarounds for a security flaw in the SSL3 and TLS1.0 protocols. If this -option isn't used or this bit is set to 0, the SSL layer libcurl uses may use -a work-around for this flaw although it might cause interoperability problems -with some (older) SSL implementations. WARNING: avoiding this work-around -lessens the security, and by setting this option to 1 you ask for exactly -that. This option is only supported for DarwinSSL, NSS and OpenSSL. - -\fICURLSSLOPT_NO_REVOKE\fP tells libcurl to disable certificate revocation -checks for those SSL backends where such behavior is present. This option is -only supported for Schannel (the native Windows SSL library), with an -exception in the case of Windows' Untrusted Publishers blacklist which it -seems can't be bypassed. +Pass a long with a bitmask to tell libcurl about specific SSL +behaviors. Available bits: +.IP CURLSSLOPT_ALLOW_BEAST +Tells libcurl to not attempt to use any workarounds for a security flaw in the +SSL3 and TLS1.0 protocols. If this option isn't used or this bit is set to 0, +the SSL layer libcurl uses may use a work-around for this flaw although it +might cause interoperability problems with some (older) SSL +implementations. WARNING: avoiding this work-around lessens the security, and +by setting this option to 1 you ask for exactly that. This option is only +supported for DarwinSSL, NSS and OpenSSL. +.IP CURLSSLOPT_NO_REVOKE +Tells libcurl to disable certificate revocation checks for those SSL backends +where such behavior is present. This option is only supported for Schannel +(the native Windows SSL library), with an exception in the case of Windows' +Untrusted Publishers blacklist which it seems can't be bypassed. (Added in +7.44.0) +.IP CURLSSLOPT_NO_PARTIALCHAIN +Tells libcurl to not accept "partial" certificate chains, which it otherwise +does by default. This option is only supported for OpenSSL and will fail the +certificate verification if the chain ends with an intermediate certificate +and not with a root cert. (Added in 7.68.0) .SH DEFAULT 0 .SH PROTOCOLS -All +All TLS-based protocols .SH AVAILABLE Added in 7.52.0 .SH EXAMPLE diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 index 8e1ec4946a3..79d40f27a5d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSL_VERIFYHOST 3 "August 20, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSL_VERIFYHOST 3 "August 20, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSL_VERIFYHOST \- verify the proxy certificate's name against host diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 index f457565d6b2..53c7eb7aa3e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_SSL_VERIFYPEER 3 "December 16, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_SSL_VERIFYPEER 3 "December 16, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_SSL_VERIFYPEER \- verify the proxy's SSL certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.3 index f3a166cf767..bc1b8d4364d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_TLS13_CIPHERS 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_TLS13_CIPHERS 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_TLS13_CIPHERS \- ciphers suites for proxy TLS 1.3 diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 index 186f14e4c31..8e866311f45 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_TLSAUTH_PASSWORD 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_TLSAUTH_PASSWORD 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_TLSAUTH_PASSWORD \- password to use for proxy TLS authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 index 61257885592..b17506c15b5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_TLSAUTH_TYPE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_TLSAUTH_TYPE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_TLSAUTH_TYPE \- set proxy TLS authentication methods diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 index 9683d0f0990..17f1c742ad1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_TLSAUTH_USERNAME 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_TLSAUTH_USERNAME 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_TLSAUTH_USERNAME \- user name to use for proxy TLS authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.3 index a1a0afaae4d..444410b62b0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PROXY_TRANSFER_MODE 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PROXY_TRANSFER_MODE 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PROXY_TRANSFER_MODE \- append FTP transfer mode to URL for proxy diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PUT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PUT.3 index 6cc64464398..45502649778 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_PUT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_PUT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_PUT 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_PUT 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_PUT \- make an HTTP PUT request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_QUOTE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_QUOTE.3 index 94337bd77e8..e6d852bfda2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_QUOTE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_QUOTE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_QUOTE 3 "December 18, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_QUOTE 3 "December 18, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_QUOTE \- (S)FTP commands to run before transfer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANDOM_FILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANDOM_FILE.3 index acd09af9c42..542239c55e6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANDOM_FILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANDOM_FILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RANDOM_FILE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RANDOM_FILE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RANDOM_FILE \- specify a source for random data diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANGE.3 index 42f4bad8c9c..47e34c78d75 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RANGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RANGE 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RANGE 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RANGE \- set byte range to request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_READDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_READDATA.3 index f6e3b26a86b..b3ecfe8d08d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_READDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_READDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_READDATA 3 "August 11, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_READDATA 3 "August 11, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_READDATA \- custom pointer passed to the read callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_READFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_READFUNCTION.3 index fc15fa12521..fb091f54777 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_READFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_READFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_READFUNCTION 3 "January 06, 2020" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_READFUNCTION 3 "January 06, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_READFUNCTION \- read callback for data uploads diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 index 439d992782a..c7e320b678c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_REDIR_PROTOCOLS 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_REDIR_PROTOCOLS 3 "February 18, 2020" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_REDIR_PROTOCOLS \- set protocols allowed to redirect to @@ -76,7 +76,10 @@ CURLPROTO_TELNET CURLPROTO_TFTP .fi .SH DEFAULT -All protocols except for FILE, SCP and since 7.40.0 SMB and SMBS. +HTTP, HTTPS, FTP and FTPS (Since 7.65.2). + +Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 +SMB and SMBS. .SH PROTOCOLS All .SH EXAMPLE diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REFERER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REFERER.3 index 0fb1e0ae964..4251b1085ec 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REFERER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REFERER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_REFERER 3 "December 21, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_REFERER 3 "December 21, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_REFERER \- set the HTTP referer header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.3 index 0abcebe2d7f..f3acac1d441 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_REQUEST_TARGET 3 "June 21, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_REQUEST_TARGET 3 "June 21, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_REQUEST_TARGET \- specify an alternative target for this request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVE.3 index 89ecf9d7d0f..35740ebf2c3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RESOLVE 3 "May 30, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RESOLVE 3 "May 30, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RESOLVE \- provide custom host name to IP address resolves diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.3 index 407171224f9..fb478f4353f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RESOLVER_START_DATA 3 "February 14, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RESOLVER_START_DATA 3 "February 14, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RESOLVER_START_DATA \- custom pointer passed to the resolver start callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.3 index 7338f9e7d23..e577cd7d2f7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RESOLVER_START_FUNCTION 3 "February 14, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RESOLVER_START_FUNCTION 3 "February 14, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RESOLVER_START_FUNCTION \- set callback to be called before a new resolve request is started diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM.3 index cf83ca30eda..0809e8f7a08 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RESUME_FROM 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RESUME_FROM 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RESUME_FROM \- set a point to resume transfer from diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.3 index 680872fc483..c69b8153743 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RESUME_FROM_LARGE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RESUME_FROM_LARGE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RESUME_FROM_LARGE \- set a point to resume transfer from diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.3 index 98f554af24d..4f6ecde6998 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_CLIENT_CSEQ 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_CLIENT_CSEQ 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_CLIENT_CSEQ \- set the RTSP client CSEQ number diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.3 index bcf4a27115b..d46c5395f44 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_REQUEST 3 "July 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_REQUEST 3 "July 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_REQUEST \- specify RTSP request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.3 index deb6ca3fd5a..e56c32ca655 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_SERVER_CSEQ 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_SERVER_CSEQ 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_SERVER_CSEQ \- set the RTSP server CSEQ number diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.3 index d73d8211231..f8b5f0209cf 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_SESSION_ID 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_SESSION_ID 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_SESSION_ID \- set RTSP session ID diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.3 index 36f9cb60656..abfb5551d41 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_STREAM_URI 3 "July 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_STREAM_URI 3 "July 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_STREAM_URI \- set RTSP stream URI diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.3 index 5fd1bb9cc6f..ea87706045c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_RTSP_TRANSPORT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_RTSP_TRANSPORT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_RTSP_TRANSPORT \- set RTSP Transport: header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SASL_IR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SASL_IR.3 index d0fa781ed41..e17ecdb48f4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SASL_IR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SASL_IR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SASL_IR 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SASL_IR 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SASL_IR \- enable sending initial response in first packet diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKDATA.3 index 651eab80c1d..35fd2f84280 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SEEKDATA 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SEEKDATA 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SEEKDATA \- custom pointer passed to the seek callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.3 index 5d3372eaeba..e139afef49f 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SEEKFUNCTION 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SEEKFUNCTION 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SEEKFUNCTION \- user callback for seeking in input stream diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 index ab54e270274..d494aafad07 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SERVICE_NAME 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SERVICE_NAME 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SERVICE_NAME \- authentication service name diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SHARE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SHARE.3 index cbbe78e78c6..33cea0e5789 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SHARE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SHARE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SHARE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SHARE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SHARE \- specify share handle to use diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.3 index 14939de199d..6782db7a28e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SOCKOPTDATA 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SOCKOPTDATA 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SOCKOPTDATA \- custom pointer to pass to sockopt callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.3 index b5c96c67149..15f92dac1e2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SOCKOPTFUNCTION 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SOCKOPTFUNCTION 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SOCKOPTFUNCTION \- set callback for setting socket options diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.3 index 4f0171bf488..15cea0b0805 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SOCKS5_AUTH 3 "April 27, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SOCKS5_AUTH 3 "April 27, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SOCKS5_AUTH \- set allowed methods for SOCKS5 proxy authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.3 index ec3e5cef126..06f2995ecfd 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SOCKS5_GSSAPI_NEC 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SOCKS5_GSSAPI_NEC 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SOCKS5_GSSAPI_NEC \- set socks proxy gssapi negotiation protection diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 index 333523b19aa..0e735f8e241 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SOCKS5_GSSAPI_SERVICE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SOCKS5_GSSAPI_SERVICE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SOCKS5_GSSAPI_SERVICE \- SOCKS5 proxy authentication service name diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.3 index 6c46b43c835..60b4c489f1a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_AUTH_TYPES 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_AUTH_TYPES 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_AUTH_TYPES \- set desired auth types for SFTP and SCP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.3 index fd5556b2641..efc34f2aae6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_COMPRESSION 3 "August 10, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_COMPRESSION 3 "August 10, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_COMPRESSION \- enables compression / decompression of SSH traffic diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 index beafeb4ee75..027a794ebc3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 \- checksum of SSH server public key diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.3 index af8ce658d3b..0e578d347d2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_KEYDATA 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_KEYDATA 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_KEYDATA \- pointer to pass to the SSH key callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 index 8f87a4e0f1b..d0be2d1cd62 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_KEYFUNCTION 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_KEYFUNCTION 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_KEYFUNCTION \- callback for known host matching logic diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.3 index 1490ba4281f..e2364230901 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_KNOWNHOSTS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_KNOWNHOSTS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_KNOWNHOSTS \- file name holding the SSH known hosts diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.3 index 2cc754d38a6..0c0988912b0 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_PRIVATE_KEYFILE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_PRIVATE_KEYFILE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_PRIVATE_KEYFILE \- set private key file for SSH auth diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.3 index d0945758c5e..9597cf932a5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSH_PUBLIC_KEYFILE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSH_PUBLIC_KEYFILE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSH_PUBLIC_KEYFILE \- set public key file for SSH auth diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERT.3 index 841f251d680..ec9307e43b2 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLCERT 3 "January 29, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLCERT 3 "January 29, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLCERT \- set SSL client certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.3 index 3ae7aa88c29..fa2d3575c29 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLCERTTYPE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLCERTTYPE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLCERTTYPE \- specify type of the client SSL certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE.3 index 18264bdacc9..d14a6cfe79e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLENGINE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLENGINE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLENGINE \- set SSL engine identifier diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.3 index f19674425d1..728356a1ab9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLENGINE_DEFAULT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLENGINE_DEFAULT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLENGINE_DEFAULT \- make SSL engine default diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEY.3 index 3ede517249f..126e967dc13 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLKEY 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLKEY 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLKEY \- specify private keyfile for TLS and SSL client cert diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.3 index 8f9b27dc725..06e2bec7522 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLKEYTYPE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLKEYTYPE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLKEYTYPE \- set type of the private key file diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLVERSION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLVERSION.3 index fb21ce2a82e..37fe8c01005 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLVERSION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSLVERSION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSLVERSION 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSLVERSION 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSLVERSION \- set preferred TLS/SSL version diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3 index 8def7aeca40..00788f6b1ce 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_CIPHER_LIST 3 "October 10, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_CIPHER_LIST 3 "October 10, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_CIPHER_LIST \- specify ciphers to use for TLS diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.3 index 9876d8c3359..e79ce71274d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_CTX_DATA 3 "June 02, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_CTX_DATA 3 "June 02, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_CTX_DATA \- custom pointer passed to ssl_ctx callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.3 index c68d2eea8a9..bdab969e552 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_CTX_FUNCTION 3 "June 02, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_CTX_FUNCTION 3 "June 02, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_CTX_FUNCTION \- SSL context callback for OpenSSL, wolfSSL or mbedTLS diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.3 index 5dccf244b42..312db619a5e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_ENABLE_ALPN 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_ENABLE_ALPN 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_ENABLE_ALPN \- enable ALPN diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.3 index 76f7b8a32ee..f526eb3b41a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_ENABLE_NPN 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_ENABLE_NPN 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_ENABLE_NPN \- enable NPN diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 index 04e7bc7bf7f..e3cf848cb5b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_FALSESTART 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_FALSESTART 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_FALSESTART \- enable TLS false start diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 index 83e8e12b5b3..700666e73fc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_OPTIONS 3 "December 02, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_OPTIONS 3 "December 02, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_OPTIONS \- set SSL behavior options diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.3 index 6fb5b336e92..1a507765251 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_SESSIONID_CACHE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_SESSIONID_CACHE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_SESSIONID_CACHE \- enable/disable use of the SSL session-ID cache diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.3 index 901a9cc69d5..7a136000289 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_VERIFYHOST 3 "August 20, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_VERIFYHOST 3 "August 20, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_VERIFYHOST \- verify the certificate's name against host diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.3 index cce1cbbf7ed..22a61555902 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_VERIFYPEER 3 "June 24, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_VERIFYPEER 3 "June 24, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_VERIFYPEER \- verify the peer's SSL certificate diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 index d1f78f5fb24..1eccbf8edbb 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SSL_VERIFYSTATUS 3 "October 09, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SSL_VERIFYSTATUS 3 "October 09, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SSL_VERIFYSTATUS \- verify the certificate's status diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STDERR.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STDERR.3 index 470093d3366..b58c425e0b8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STDERR.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STDERR.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_STDERR 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_STDERR 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_STDERR \- redirect stderr to another stream diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.3 index f657ea5ec66..39ce26a397a 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_STREAM_DEPENDS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_STREAM_DEPENDS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_STREAM_DEPENDS \- set stream this transfer depends on diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.3 index ef0c6be93ca..ca2d1537ef7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_STREAM_DEPENDS_E 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_STREAM_DEPENDS_E 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_STREAM_DEPENDS_E \- set stream this transfer depends on exclusively diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.3 index a873e3aa575..a7a339fe33d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_STREAM_WEIGHT 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_STREAM_WEIGHT 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_STREAM_WEIGHT \- set numerical stream weight diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.3 index 8103ff4d862..d9ae4d49ca3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_SUPPRESS_CONNECT_HEADERS 3 "April 28, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_SUPPRESS_CONNECT_HEADERS 3 "April 28, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_SUPPRESS_CONNECT_HEADERS \- Suppress proxy CONNECT response headers from user callbacks diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.3 index 6233e4c72e7..50dc01f635e 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TCP_FASTOPEN 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TCP_FASTOPEN 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TCP_FASTOPEN \- enable TCP Fast Open diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.3 index ef424409253..39844348198 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TCP_KEEPALIVE 3 "February 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TCP_KEEPALIVE 3 "February 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TCP_KEEPALIVE \- enable TCP keep-alive probing diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.3 index 09042b9aa0c..eb896391baf 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TCP_KEEPIDLE 3 "January 02, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TCP_KEEPIDLE 3 "January 02, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TCP_KEEPIDLE \- set TCP keep-alive idle time wait diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.3 index a87705e377d..1220a57d7c1 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TCP_KEEPINTVL 3 "January 02, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TCP_KEEPINTVL 3 "January 02, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TCP_KEEPINTVL \- set TCP keep-alive interval diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_NODELAY.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_NODELAY.3 index 75c72e464bd..070a5f89dc3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_NODELAY.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TCP_NODELAY.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TCP_NODELAY 3 "January 15, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TCP_NODELAY 3 "January 15, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TCP_NODELAY \- set the TCP_NODELAY option diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.3 index 11f55484378..32ec29749b7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TELNETOPTIONS 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TELNETOPTIONS 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TELNETOPTIONS \- custom telnet options diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.3 index ab7b21531f1..6110f8472ee 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TFTP_BLKSIZE 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TFTP_BLKSIZE 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TFTP_BLKSIZE \- TFTP block size diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.3 index 25e42bb0cca..84ca0cad4be 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TFTP_NO_OPTIONS 3 "April 06, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TFTP_NO_OPTIONS 3 "April 06, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TFTP_NO_OPTIONS \- Do not send TFTP options requests. diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMECONDITION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMECONDITION.3 index 87fe8ed3c99..d7ab48e14a3 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMECONDITION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMECONDITION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TIMECONDITION 3 "April 03, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TIMECONDITION 3 "April 03, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TIMECONDITION \- select condition for a time request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT.3 index bbf19f6f8f2..6e57893a3e4 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TIMEOUT 3 "October 15, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TIMEOUT 3 "October 15, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TIMEOUT \- set maximum time the request is allowed to take diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.3 index 0a2b92077a6..ef42f4beea9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TIMEOUT_MS 3 "September 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TIMEOUT_MS 3 "September 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TIMEOUT_MS \- set maximum time the request is allowed to take diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE.3 index d47e690347b..81746ea6fed 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TIMEVALUE 3 "January 25, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TIMEVALUE 3 "January 25, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TIMEVALUE \- set time value for conditional diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.3 index 4581b44d718..90deb8f1785 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TIMEVALUE_LARGE 3 "January 25, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TIMEVALUE_LARGE 3 "January 25, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TIMEVALUE_LARGE \- set time value for conditional diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.3 index c00570c6e85..354a05fe2e9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TLS13_CIPHERS 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TLS13_CIPHERS 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TLS13_CIPHERS \- specify ciphers suites to use for TLS 1.3 diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.3 index 06f251528c7..989dc27412d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TLSAUTH_PASSWORD 3 "December 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TLSAUTH_PASSWORD 3 "December 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TLSAUTH_PASSWORD \- password to use for TLS authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.3 index 1a92eec1838..b1f5e7d5ba5 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TLSAUTH_TYPE 3 "December 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TLSAUTH_TYPE 3 "December 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TLSAUTH_TYPE \- set TLS authentication methods diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.3 index f702b9de0da..c90be9420ee 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TLSAUTH_USERNAME 3 "December 16, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TLSAUTH_USERNAME 3 "December 16, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TLSAUTH_USERNAME \- user name to use for TLS authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERDATA.3 index 4f20fdffd93..2e3befa1088 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TRAILERDATA 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TRAILERDATA 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TRAILERDATA \- Custom pointer passed to the trailing headers callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.3 index 36ea8935dff..8c887c9e666 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TRAILERFUNCTION 3 "October 31, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TRAILERFUNCTION 3 "October 31, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TRAILERFUNCTION \- Set callback for sending trailing headers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.3 index 087b273e53e..e6d34e212f6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TRANSFERTEXT 3 "May 31, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TRANSFERTEXT 3 "May 31, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TRANSFERTEXT \- request a text based transfer for FTP diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.3 index b266ef176d4..ec4c1557f5c 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_TRANSFER_ENCODING 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_TRANSFER_ENCODING 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_TRANSFER_ENCODING \- ask for HTTP Transfer Encoding diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 index 9084dc724f3..d29622b8cac 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_UNIX_SOCKET_PATH 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_UNIX_SOCKET_PATH 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_UNIX_SOCKET_PATH \- set Unix domain socket diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.3 index c7fb804699f..8aefd10da78 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_UNRESTRICTED_AUTH 3 "May 15, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_UNRESTRICTED_AUTH 3 "May 15, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_UNRESTRICTED_AUTH \- send credentials to other hosts too diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD.3 index 0600aa42189..79e684915f9 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_UPLOAD 3 "April 17, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_UPLOAD 3 "April 17, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_UPLOAD \- enable data upload diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.3 index f1515f8c94f..ec84baf6c25 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_UPLOAD_BUFFERSIZE 3 "August 18, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_UPLOAD_BUFFERSIZE 3 "August 18, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_UPLOAD_BUFFERSIZE \- set preferred upload buffer size diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_URL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_URL.3 index 0ff7654ec7a..22e58301bd8 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_URL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_URL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_URL 3 "December 18, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_URL 3 "December 18, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_URL \- provide the URL to use in the request diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERAGENT.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERAGENT.3 index f117d0644d0..316eeebdaeb 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERAGENT.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERAGENT.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_USERAGENT 3 "December 21, 2016" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_USERAGENT 3 "December 21, 2016" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_USERAGENT \- set HTTP user-agent header diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERNAME.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERNAME.3 index 3d966a54ab3..4db458ffd96 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERNAME.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERNAME.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_USERNAME 3 "May 05, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_USERNAME 3 "May 05, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_USERNAME \- user name to use in authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERPWD.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERPWD.3 index 362fcf01181..b4140353d46 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERPWD.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USERPWD.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_USERPWD 3 "August 24, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_USERPWD 3 "August 24, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_USERPWD \- user name and password to use in authentication diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USE_SSL.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USE_SSL.3 index 6fc9fe3762a..e821da6921d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_USE_SSL.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_USE_SSL.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_USE_SSL 3 "October 10, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_USE_SSL 3 "October 10, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_USE_SSL \- request using SSL / TLS for the transfer diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_VERBOSE.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_VERBOSE.3 index 8cdda5917ba..ad5828b98dc 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_VERBOSE.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_VERBOSE.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_VERBOSE 3 "December 04, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_VERBOSE 3 "December 04, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_VERBOSE \- set verbose mode on/off diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.3 index 700f8db6758..e37c781e42d 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_WILDCARDMATCH 3 "May 18, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_WILDCARDMATCH 3 "May 18, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_WILDCARDMATCH \- enable directory wildcard transfers diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEDATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEDATA.3 index fba489a4383..67734f463c6 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEDATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEDATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_WRITEDATA 3 "August 11, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_WRITEDATA 3 "August 11, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_WRITEDATA \- custom pointer passed to the write callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.3 index 5fbaf5b8126..e35972b6e0b 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_WRITEFUNCTION 3 "November 23, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_WRITEFUNCTION 3 "November 23, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_WRITEFUNCTION \- set callback for writing received data diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFODATA.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFODATA.3 index ef6c4e6583f..43565648a54 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFODATA.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFODATA.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_XFERINFODATA 3 "October 09, 2017" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_XFERINFODATA 3 "October 09, 2017" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_XFERINFODATA \- custom pointer passed to the progress callback diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.3 index 34cbff799c7..1bd33dc2517 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_XFERINFOFUNCTION 3 "November 26, 2019" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_XFERINFOFUNCTION 3 "November 26, 2019" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_XFERINFOFUNCTION \- callback to progress meter function diff --git a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 index b4b03292a9e..ffb2e2e52d7 100644 --- a/release/src/router/curl/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 +++ b/release/src/router/curl/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH CURLOPT_XOAUTH2_BEARER 3 "May 22, 2018" "libcurl 7.68.0" "curl_easy_setopt options" +.TH CURLOPT_XOAUTH2_BEARER 3 "May 22, 2018" "libcurl 7.69.1" "curl_easy_setopt options" .SH NAME CURLOPT_XOAUTH2_BEARER \- specify OAuth 2.0 access token diff --git a/release/src/router/curl/docs/libcurl/opts/Makefile.in b/release/src/router/curl/docs/libcurl/opts/Makefile.in index fa31d9d628d..49679c150c4 100644 --- a/release/src/router/curl/docs/libcurl/opts/Makefile.in +++ b/release/src/router/curl/docs/libcurl/opts/Makefile.in @@ -336,6 +336,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -585,6 +586,7 @@ man_MANS = \ CURLOPT_MAIL_AUTH.3 \ CURLOPT_MAIL_FROM.3 \ CURLOPT_MAIL_RCPT.3 \ + CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 \ CURLOPT_MAXAGE_CONN.3 \ CURLOPT_MAXCONNECTS.3 \ CURLOPT_MAXFILESIZE.3 \ diff --git a/release/src/router/curl/docs/libcurl/opts/Makefile.inc b/release/src/router/curl/docs/libcurl/opts/Makefile.inc index 93c4357d228..52bf422f471 100644 --- a/release/src/router/curl/docs/libcurl/opts/Makefile.inc +++ b/release/src/router/curl/docs/libcurl/opts/Makefile.inc @@ -188,6 +188,7 @@ man_MANS = \ CURLOPT_MAIL_AUTH.3 \ CURLOPT_MAIL_FROM.3 \ CURLOPT_MAIL_RCPT.3 \ + CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 \ CURLOPT_MAXAGE_CONN.3 \ CURLOPT_MAXCONNECTS.3 \ CURLOPT_MAXFILESIZE.3 \ diff --git a/release/src/router/curl/docs/libcurl/symbols-in-versions b/release/src/router/curl/docs/libcurl/symbols-in-versions index 18f04bd70a3..93930c43588 100644 --- a/release/src/router/curl/docs/libcurl/symbols-in-versions +++ b/release/src/router/curl/docs/libcurl/symbols-in-versions @@ -105,6 +105,7 @@ CURLE_OPERATION_TIMEOUTED 7.1 7.17.0 CURLE_OUT_OF_MEMORY 7.1 CURLE_PARTIAL_FILE 7.1 CURLE_PEER_FAILED_VERIFICATION 7.17.1 +CURLE_QUIC_CONNECT_ERROR 7.69.0 CURLE_QUOTE_ERROR 7.17.0 CURLE_RANGE_ERROR 7.17.0 CURLE_READ_ERROR 7.1 @@ -317,10 +318,10 @@ CURLKHTYPE_UNKNOWN 7.19.6 CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0 CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 7.30.0 CURLMOPT_MAXCONNECTS 7.16.3 +CURLMOPT_MAX_CONCURRENT_STREAMS 7.67.0 CURLMOPT_MAX_HOST_CONNECTIONS 7.30.0 CURLMOPT_MAX_PIPELINE_LENGTH 7.30.0 CURLMOPT_MAX_TOTAL_CONNECTIONS 7.30.0 -CURLMOPT_MAX_CONCURRENT_STREAMS 7.67.0 CURLMOPT_PIPELINING 7.16.0 CURLMOPT_PIPELINING_SERVER_BL 7.30.0 CURLMOPT_PIPELINING_SITE_BL 7.30.0 @@ -334,6 +335,7 @@ CURLMSG_DONE 7.9.6 CURLMSG_NONE 7.9.6 CURLM_ADDED_ALREADY 7.32.1 CURLM_BAD_EASY_HANDLE 7.9.6 +CURLM_BAD_FUNCTION_ARGUMENT 7.69.0 CURLM_BAD_HANDLE 7.9.6 CURLM_BAD_SOCKET 7.15.4 CURLM_CALL_MULTI_PERFORM 7.9.6 @@ -342,14 +344,15 @@ CURLM_INTERNAL_ERROR 7.9.6 CURLM_OK 7.9.6 CURLM_OUT_OF_MEMORY 7.9.6 CURLM_RECURSIVE_API_CALL 7.59.0 -CURLM_WAKEUP_FAILURE 7.68.0 CURLM_UNKNOWN_OPTION 7.15.4 +CURLM_WAKEUP_FAILURE 7.68.0 +CURLOPT 7.69.0 CURLOPTTYPE_FUNCTIONPOINT 7.1 CURLOPTTYPE_LONG 7.1 CURLOPTTYPE_OBJECTPOINT 7.1 CURLOPTTYPE_OFF_T 7.11.0 -CURLOPTTYPE_STRINGPOINT 7.46.0 CURLOPTTYPE_SLISTPOINT 7.65.2 +CURLOPTTYPE_STRINGPOINT 7.46.0 CURLOPT_ABSTRACT_UNIX_SOCKET 7.53.0 CURLOPT_ACCEPTTIMEOUT_MS 7.24.0 CURLOPT_ACCEPT_ENCODING 7.21.6 @@ -468,6 +471,7 @@ CURLOPT_LOW_SPEED_TIME 7.1 CURLOPT_MAIL_AUTH 7.25.0 CURLOPT_MAIL_FROM 7.20.0 CURLOPT_MAIL_RCPT 7.20.0 +CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0 CURLOPT_MAXAGE_CONN 7.65.0 CURLOPT_MAXCONNECTS 7.7 CURLOPT_MAXFILESIZE 7.10.8 @@ -732,7 +736,7 @@ CURLSSLBACKEND_MESALINK 7.62.0 CURLSSLBACKEND_NONE 7.34.0 CURLSSLBACKEND_NSS 7.34.0 CURLSSLBACKEND_OPENSSL 7.34.0 -CURLSSLBACKEND_POLARSSL 7.34.0 +CURLSSLBACKEND_POLARSSL 7.34.0 7.69.0 CURLSSLBACKEND_QSOSSL 7.34.0 - 7.38.1 CURLSSLBACKEND_SCHANNEL 7.34.0 CURLSSLBACKEND_SECURETRANSPORT 7.64.1 @@ -783,8 +787,8 @@ CURLU_DEFAULT_SCHEME 7.62.0 CURLU_DISALLOW_USER 7.62.0 CURLU_GUESS_SCHEME 7.62.0 CURLU_NON_SUPPORT_SCHEME 7.62.0 -CURLU_NO_DEFAULT_PORT 7.62.0 CURLU_NO_AUTHORITY 7.67.0 +CURLU_NO_DEFAULT_PORT 7.62.0 CURLU_PATH_AS_IS 7.62.0 CURLU_URLDECODE 7.62.0 CURLU_URLENCODE 7.62.0 @@ -793,8 +797,8 @@ CURLVERSION_FIRST 7.10 CURLVERSION_FOURTH 7.16.1 CURLVERSION_NOW 7.10 CURLVERSION_SECOND 7.11.1 -CURLVERSION_THIRD 7.12.0 CURLVERSION_SIXTH 7.66.0 +CURLVERSION_THIRD 7.12.0 CURL_CHUNK_BGN_FUNC_FAIL 7.21.0 CURL_CHUNK_BGN_FUNC_OK 7.21.0 CURL_CHUNK_BGN_FUNC_SKIP 7.21.0 @@ -956,5 +960,6 @@ CURL_VERSION_UNIX_SOCKETS 7.40.0 CURL_WAIT_POLLIN 7.28.0 CURL_WAIT_POLLOUT 7.28.0 CURL_WAIT_POLLPRI 7.28.0 +CURL_WIN32 7.69.0 CURL_WRITEFUNC_PAUSE 7.18.0 CURL_ZERO_TERMINATED 7.56.0 diff --git a/release/src/router/curl/include/Makefile.in b/release/src/router/curl/include/Makefile.in index affbe7205fc..863cac661cf 100644 --- a/release/src/router/curl/include/Makefile.in +++ b/release/src/router/curl/include/Makefile.in @@ -342,6 +342,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/include/curl/Makefile.in b/release/src/router/curl/include/curl/Makefile.in index 9213b6d3007..1fef5c5a9f8 100644 --- a/release/src/router/curl/include/curl/Makefile.in +++ b/release/src/router/curl/include/curl/Makefile.in @@ -329,6 +329,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/include/curl/curl.h b/release/src/router/curl/include/curl/curl.h index a9754fd6484..b7cb30a581b 100644 --- a/release/src/router/curl/include/curl/curl.h +++ b/release/src/router/curl/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -38,12 +38,12 @@ #include "system.h" /* determine things run-time */ /* - * Define WIN32 when build target is Win32 API + * Define CURL_WIN32 when build target is Win32 API */ -#if (defined(_WIN32) || defined(__WIN32__)) && \ - !defined(WIN32) && !defined(__SYMBIAN32__) -#define WIN32 +#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && \ + !defined(__SYMBIAN32__) +#define CURL_WIN32 #endif #include @@ -58,7 +58,7 @@ #include #include -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if defined(CURL_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2 inclusion if winsock.h already was @@ -79,11 +79,11 @@ #include #endif -#if !defined(WIN32) && !defined(_WIN32_WCE) +#if !defined(CURL_WIN32) && !defined(_WIN32_WCE) #include #endif -#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#if !defined(CURL_WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) #include #endif @@ -114,7 +114,7 @@ typedef void CURLSH; #ifdef CURL_STATICLIB # define CURL_EXTERN -#elif defined(WIN32) || defined(__SYMBIAN32__) || \ +#elif defined(CURL_WIN32) || defined(__SYMBIAN32__) || \ (__has_declspec_attribute(dllexport) && \ __has_declspec_attribute(dllimport)) # if defined(BUILDING_LIBCURL) @@ -130,7 +130,7 @@ typedef void CURLSH; #ifndef curl_socket_typedef /* socket typedef */ -#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +#if defined(CURL_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else @@ -609,6 +609,7 @@ typedef enum { CURLE_AUTH_ERROR, /* 94 - an authentication function returned an error */ CURLE_HTTP3, /* 95 - An HTTP/3 layer problem */ + CURLE_QUIC_CONNECT_ERROR, /* 96 - QUIC connection error */ CURL_LAST /* never use! */ } CURLcode; @@ -943,77 +944,58 @@ typedef enum { /* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the string options from the header file */ -/* name is uppercase CURLOPT_, - type is one of the defined CURLOPTTYPE_ - number is unique identifier */ -#ifdef CINIT -#undef CINIT -#endif -#ifdef CURL_ISOCPP -#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT -#define SLISTPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLOPT_/**/name = type + number -#endif +#define CURLOPT(na,t,nu) na = t + nu /* handy aliases that make no run-time difference */ #define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT #define CURLOPTTYPE_SLISTPOINT CURLOPTTYPE_OBJECTPOINT /* - * This macro-mania below setups the CURLOPT_[what] enum, to be used with - * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] - * word. + * All CURLOPT_* values. */ typedef enum { /* This is the FILE * or void * the regular output should be written to. */ - CINIT(WRITEDATA, OBJECTPOINT, 1), + CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_OBJECTPOINT, 1), /* The full URL to get/put */ - CINIT(URL, STRINGPOINT, 2), + CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2), /* Port number to connect to, if other than default. */ - CINIT(PORT, LONG, 3), + CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3), /* Name of proxy to use. */ - CINIT(PROXY, STRINGPOINT, 4), + CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4), /* "user:password;options" to use when fetching. */ - CINIT(USERPWD, STRINGPOINT, 5), + CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5), /* "user:password" to use with proxy. */ - CINIT(PROXYUSERPWD, STRINGPOINT, 6), + CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6), /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, STRINGPOINT, 7), + CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7), /* not used */ /* Specified file stream to upload from (use as input): */ - CINIT(READDATA, OBJECTPOINT, 9), + CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_OBJECTPOINT, 9), /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. */ - CINIT(ERRORBUFFER, OBJECTPOINT, 10), + CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10), /* Function that will be called to store the output (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11), /* Function that will be called to read the input (instead of fread). The * parameters will use fread() syntax, make sure to follow them. */ - CINIT(READFUNCTION, FUNCTIONPOINT, 12), + CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12), /* Time-out the read operation after this amount of seconds */ - CINIT(TIMEOUT, LONG, 13), + CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13), /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about * how large the file being sent really is. That allows better error @@ -1024,20 +1006,20 @@ typedef enum { * which takes an off_t type, allowing platforms with larger off_t * sizes to handle larger files. See below for INFILESIZE_LARGE. */ - CINIT(INFILESIZE, LONG, 14), + CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14), /* POST static input fields. */ - CINIT(POSTFIELDS, OBJECTPOINT, 15), + CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15), /* Set the referrer page (needed by some CGIs) */ - CINIT(REFERER, STRINGPOINT, 16), + CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16), /* Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ - CINIT(FTPPORT, STRINGPOINT, 17), + CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17), /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, STRINGPOINT, 18), + CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18), /* If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. @@ -1046,10 +1028,10 @@ typedef enum { */ /* Set the "low speed limit" */ - CINIT(LOW_SPEED_LIMIT, LONG, 19), + CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19), /* Set the "low speed time" */ - CINIT(LOW_SPEED_TIME, LONG, 20), + CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20), /* Set the continuation offset. * @@ -1057,48 +1039,48 @@ typedef enum { * off_t types, allowing for large file offsets on platforms which * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. */ - CINIT(RESUME_FROM, LONG, 21), + CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21), /* Set cookie in request: */ - CINIT(COOKIE, STRINGPOINT, 22), + CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22), /* This points to a linked list of headers, struct curl_slist kind. This list is also used for RTSP (in spite of its name) */ - CINIT(HTTPHEADER, SLISTPOINT, 23), + CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23), /* This points to a linked list of post entries, struct curl_httppost */ - CINIT(HTTPPOST, OBJECTPOINT, 24), + CURLOPT(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24), /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, STRINGPOINT, 25), + CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25), /* password for the SSL or SSH private key */ - CINIT(KEYPASSWD, STRINGPOINT, 26), + CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26), /* send TYPE parameter? */ - CINIT(CRLF, LONG, 27), + CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27), /* send linked-list of QUOTE commands */ - CINIT(QUOTE, SLISTPOINT, 28), + CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28), /* send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified */ - CINIT(HEADERDATA, OBJECTPOINT, 29), + CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_OBJECTPOINT, 29), /* point to a file to read the initial cookies from, also enables "cookie awareness" */ - CINIT(COOKIEFILE, STRINGPOINT, 31), + CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31), /* What version to specifically try to use. See CURL_SSLVERSION defines below. */ - CINIT(SSLVERSION, LONG, 32), + CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_LONG, 32), /* What kind of HTTP time condition to use, see defines */ - CINIT(TIMECONDITION, LONG, 33), + CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_LONG, 33), /* Time to use with the above condition. Specified in number of seconds since 1 Jan 1970 */ - CINIT(TIMEVALUE, LONG, 34), + CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34), /* 35 = OBSOLETE */ @@ -1106,37 +1088,58 @@ typedef enum { HTTP: DELETE, TRACE and others FTP: to use a different list command */ - CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36), /* FILE handle to use instead of stderr */ - CINIT(STDERR, OBJECTPOINT, 37), + CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37), /* 38 is not used */ /* send linked-list of post-transfer QUOTE commands */ - CINIT(POSTQUOTE, SLISTPOINT, 39), + CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39), + + /* OBSOLETE, do not use! */ + CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40), + + /* talk a lot */ + CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41), + + /* throw the header out too */ + CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42), + + /* shut off the progress meter */ + CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43), + + /* use HEAD to get http document */ + CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44), + + /* no output on http error codes >= 400 */ + CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45), - CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + /* this is an upload */ + CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46), - CINIT(VERBOSE, LONG, 41), /* talk a lot */ - CINIT(HEADER, LONG, 42), /* throw the header out too */ - CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ - CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ - CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ - CINIT(UPLOAD, LONG, 46), /* this is an upload */ - CINIT(POST, LONG, 47), /* HTTP POST method */ - CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + /* HTTP POST method */ + CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47), - CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + /* bare names when listing directories */ + CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48), + + /* Append instead of overwrite on upload! */ + CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50), /* Specify whether to read the user+password from the .netrc or the URL. * This must be one of the CURL_NETRC_* enums below. */ - CINIT(NETRC, LONG, 51), + CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_LONG, 51), + + /* use Location: Luke! */ + CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52), - CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + /* transfer data in text/ASCII format */ + CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53), - CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ - CINIT(PUT, LONG, 54), /* HTTP PUT */ + /* HTTP PUT */ + CURLOPT(CURLOPT_PUT, CURLOPTTYPE_LONG, 54), /* 55 = OBSOLETE */ @@ -1144,265 +1147,267 @@ typedef enum { * Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ - CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + CURLOPT(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56), /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION callbacks */ - CINIT(PROGRESSDATA, OBJECTPOINT, 57), + CURLOPT(CURLOPT_PROGRESSDATA, CURLOPTTYPE_OBJECTPOINT, 57), #define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA /* We want the referrer field set automatically when following locations */ - CINIT(AUTOREFERER, LONG, 58), + CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58), /* Port of the proxy, can be set in the proxy string as well with: "[host]:[port]" */ - CINIT(PROXYPORT, LONG, 59), + CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59), /* size of the POST input data, if strlen() is not good to use */ - CINIT(POSTFIELDSIZE, LONG, 60), + CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60), /* tunnel non-http operations through a HTTP proxy */ - CINIT(HTTPPROXYTUNNEL, LONG, 61), + CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61), /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, STRINGPOINT, 62), + CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62), /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but doesn't match one of these, 'private' will be used. */ - CINIT(KRBLEVEL, STRINGPOINT, 63), + CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ - CINIT(SSL_VERIFYPEER, LONG, 64), + CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, STRINGPOINT, 65), + CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65), /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ /* Maximum number of http redirects to follow */ - CINIT(MAXREDIRS, LONG, 68), + CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68), /* Pass a long set to 1 to get the date of the requested document (if possible)! Pass a zero to shut it off. */ - CINIT(FILETIME, LONG, 69), + CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69), /* This points to a linked list of telnet options */ - CINIT(TELNETOPTIONS, SLISTPOINT, 70), + CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70), /* Max amount of cached alive connections */ - CINIT(MAXCONNECTS, LONG, 71), + CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71), - CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + /* OBSOLETE, do not use! */ + CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72), /* 73 = OBSOLETE */ /* Set to explicitly use a new connection for the upcoming transfer. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ - CINIT(FRESH_CONNECT, LONG, 74), + CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74), /* Set to explicitly forbid the upcoming transfer's connection to be re-used when done. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ - CINIT(FORBID_REUSE, LONG, 75), + CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75), /* Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, STRINGPOINT, 76), + CURLOPT(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76), /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, STRINGPOINT, 77), + CURLOPT(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77), /* Time-out connect operations after this amount of seconds, if connects are OK within this time, then fine... This only aborts the connect phase. */ - CINIT(CONNECTTIMEOUT, LONG, 78), + CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78), /* Function that will be called to store headers (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79), /* Set this to force the HTTP request to get back to GET. Only really usable if POST, PUT or a custom request have been used first. */ - CINIT(HTTPGET, LONG, 80), + CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80), /* Set if we should verify the Common name from the peer certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches the * provided hostname. */ - CINIT(SSL_VERIFYHOST, LONG, 81), + CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81), /* Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, STRINGPOINT, 82), + CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82), /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83), /* Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ - CINIT(HTTP_VERSION, LONG, 84), + CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_LONG, 84), /* Specifically switch on or off the FTP engine's use of the EPSV command. By default, that one will always be attempted before the more traditional PASV command. */ - CINIT(FTP_USE_EPSV, LONG, 85), + CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, STRINGPOINT, 86), + CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86), /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, STRINGPOINT, 87), + CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, STRINGPOINT, 88), + CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88), /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, STRINGPOINT, 89), + CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89), /* set the crypto engine for the SSL-sub system as default the param has no meaning... */ - CINIT(SSLENGINE_DEFAULT, LONG, 90), + CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90), /* Non-zero value means to use the global dns cache */ - CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + /* DEPRECATED, do not use! */ + CURLOPT(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91), /* DNS cache timeout */ - CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92), /* send linked-list of pre-transfer QUOTE commands */ - CINIT(PREQUOTE, SLISTPOINT, 93), + CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93), /* set the debug function */ - CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94), /* set the data for the debug function */ - CINIT(DEBUGDATA, OBJECTPOINT, 95), + CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_OBJECTPOINT, 95), /* mark this as start of a cookie session */ - CINIT(COOKIESESSION, LONG, 96), + CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96), /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, STRINGPOINT, 97), + CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97), /* Instruct libcurl to use a smaller receive buffer */ - CINIT(BUFFERSIZE, LONG, 98), + CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98), /* Instruct libcurl to not use any signal/alarm handlers, even when using timeouts. This option is useful for multi-threaded applications. See libcurl-the-guide for more background information. */ - CINIT(NOSIGNAL, LONG, 99), + CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99), /* Provide a CURLShare for mutexing non-ts data */ - CINIT(SHARE, OBJECTPOINT, 100), + CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100), /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ - CINIT(PROXYTYPE, LONG, 101), + CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_LONG, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed. Before 7.21.6, this was known as CURLOPT_ENCODING */ - CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102), /* Set pointer to private data */ - CINIT(PRIVATE, OBJECTPOINT, 103), + CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103), /* Set aliases for HTTP 200 in the HTTP Response header */ - CINIT(HTTP200ALIASES, SLISTPOINT, 104), + CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104), /* Continue to send authentication (user+password) when following locations, even when hostname changed. This can potentially send off the name and password to whatever host the server decides. */ - CINIT(UNRESTRICTED_AUTH, LONG, 105), + CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105), /* Specifically switch on or off the FTP engine's use of the EPRT command ( it also disables the LPRT attempt). By default, those ones will always be attempted before the good old traditional PORT command. */ - CINIT(FTP_USE_EPRT, LONG, 106), + CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_USERPWD. Note that setting multiple bits may cause extra network round-trips. */ - CINIT(HTTPAUTH, LONG, 107), + CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_LONG, 107), /* Set the ssl context callback function, currently only for OpenSSL or WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument. The function must match the curl_ssl_ctx_callback prototype. */ - CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108), /* Set the userdata for the ssl context callback function's third argument */ - CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_OBJECTPOINT, 109), /* FTP Option that causes missing dirs to be created on the remote server. In 7.19.4 we introduced the convenience enums for this option using the CURLFTP_CREATE_DIR prefix. */ - CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. Note that setting multiple bits may cause extra network round-trips. */ - CINIT(PROXYAUTH, LONG, 111), + CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_LONG, 111), /* FTP option that changes the timeout, in seconds, associated with getting a response. This is different from transfer timeout time and essentially places a demand on the FTP server to acknowledge commands in a timely manner. */ - CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), + CURLOPT(CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112), #define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to tell libcurl to resolve names to those IP versions only. This only has affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ - CINIT(IPRESOLVE, LONG, 113), + CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_LONG, 113), /* Set this option to limit the size of a file that will be downloaded from an HTTP or FTP server. Note there is also _LARGE version which adds large file support for platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ - CINIT(MAXFILESIZE, LONG, 114), + CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114), /* See the comment for INFILESIZE above, but in short, specifies * the size of the file being uploaded. -1 means unknown. */ - CINIT(INFILESIZE_LARGE, OFF_T, 115), + CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115), - /* Sets the continuation offset. There is also a LONG version of this; - * look above for RESUME_FROM. + /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version + * of this; look above for RESUME_FROM. */ - CINIT(RESUME_FROM_LARGE, OFF_T, 116), + CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116), /* Sets the maximum size of data that will be downloaded from * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. */ - CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117), /* Set this option to the file name of your .netrc file you want libcurl to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ - CINIT(NETRC_FILE, STRINGPOINT, 118), + CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118), /* Enable SSL/TLS for FTP, pick one of: CURLUSESSL_TRY - try using SSL, proceed anyway otherwise CURLUSESSL_CONTROL - SSL for the control connection or fail CURLUSESSL_ALL - SSL for all communication or fail */ - CINIT(USE_SSL, LONG, 119), + CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_LONG, 119), /* The _LARGE version of the standard POSTFIELDSIZE option */ - CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120), /* Enable/disable the TCP Nagle algorithm */ - CINIT(TCP_NODELAY, LONG, 121), + CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121), /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 123 OBSOLETE. Gone in 7.16.0 */ @@ -1422,143 +1427,143 @@ typedef enum { CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL */ - CINIT(FTPSSLAUTH, LONG, 129), + CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_LONG, 129), - CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), - CINIT(IOCTLDATA, OBJECTPOINT, 131), + CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130), + CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_OBJECTPOINT, 131), /* 132 OBSOLETE. Gone in 7.16.0 */ /* 133 OBSOLETE. Gone in 7.16.0 */ /* zero terminated string for pass on to the FTP server when asked for "account" info */ - CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134), /* feed cookie into cookie engine */ - CINIT(COOKIELIST, STRINGPOINT, 135), + CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135), /* ignore Content-Length */ - CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136), /* Set to non-zero to skip the IP address received in a 227 PASV FTP server response. Typically used for FTP-SSL purposes but is not restricted to that. libcurl will then instead use the same IP address it used for the control connection. */ - CINIT(FTP_SKIP_PASV_IP, LONG, 137), + CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137), /* Select "file method" to use when doing FTP, see the curl_ftpmethod above. */ - CINIT(FTP_FILEMETHOD, LONG, 138), + CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_LONG, 138), /* Local port number to bind the socket to */ - CINIT(LOCALPORT, LONG, 139), + CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139), /* Number of ports to try, including the first one set with LOCALPORT. Thus, setting it to 1 will make no additional attempts but the first. */ - CINIT(LOCALPORTRANGE, LONG, 140), + CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140), /* no transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET */ - CINIT(CONNECT_ONLY, LONG, 141), + CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141), /* Function that will be called to convert from the network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + CURLOPT(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142), /* Function that will be called to convert to the network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + CURLOPT(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143), /* Function that will be called to convert from UTF8 (instead of using the iconv calls in libcurl) Note that this is used only for SSL certificate processing */ - CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + CURLOPT(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144), /* if the connection proceeds too quickly then need to slow it down */ /* limit-rate: maximum number of bytes per second to send or receive */ - CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), - CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145), + CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146), /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147), /* callback function for setting socket options */ - CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), - CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148), + CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_OBJECTPOINT, 149), /* set to 0 to disable session ID re-use for this transfer, default is enabled (== 1) */ - CINIT(SSL_SESSIONID_CACHE, LONG, 150), + CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150), /* allowed SSH authentication methods */ - CINIT(SSH_AUTH_TYPES, LONG, 151), + CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_LONG, 151), /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152), + CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153), /* Send CCC (Clear Command Channel) after authentication */ - CINIT(FTP_SSL_CCC, LONG, 154), + CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154), /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ - CINIT(TIMEOUT_MS, LONG, 155), - CINIT(CONNECTTIMEOUT_MS, LONG, 156), + CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155), + CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156), /* set to zero to disable the libcurl's decoding and thus pass the raw body data to the application even when it is encoded/compressed */ - CINIT(HTTP_TRANSFER_DECODING, LONG, 157), - CINIT(HTTP_CONTENT_DECODING, LONG, 158), + CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157), + CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158), /* Permission used when creating new files and directories on the remote server for protocols that support it, SFTP/SCP/FILE */ - CINIT(NEW_FILE_PERMS, LONG, 159), - CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159), + CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160), /* Set the behaviour of POST when redirecting. Values must be set to one of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ - CINIT(POSTREDIR, LONG, 161), + CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_LONG, 161), /* used by scp/sftp to verify the host's public key */ - CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162), /* Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning CURL_SOCKET_BAD. The callback should have type curl_opensocket_callback */ - CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), - CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163), + CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 164), /* POST volatile input fields. */ - CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165), /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ - CINIT(PROXY_TRANSFER_MODE, LONG, 166), + CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166), /* Callback function for seeking in the input stream */ - CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), - CINIT(SEEKDATA, OBJECTPOINT, 168), + CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167), + CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_OBJECTPOINT, 168), /* CRL file */ - CINIT(CRLFILE, STRINGPOINT, 169), + CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169), /* Issuer certificate */ - CINIT(ISSUERCERT, STRINGPOINT, 170), + CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170), /* (IPv6) Address scope */ - CINIT(ADDRESS_SCOPE, LONG, 171), + CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171), /* Collect certificate chain info and allow it to get retrievable with CURLINFO_CERTINFO after the transfer is complete. */ - CINIT(CERTINFO, LONG, 172), + CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172), /* "name" and "pwd" to use when fetching. */ - CINIT(USERNAME, STRINGPOINT, 173), - CINIT(PASSWORD, STRINGPOINT, 174), + CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173), + CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174), /* "name" and "pwd" to use with Proxy when fetching. */ - CINIT(PROXYUSERNAME, STRINGPOINT, 175), - CINIT(PROXYPASSWORD, STRINGPOINT, 176), + CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175), + CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176), /* Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For @@ -1567,102 +1572,103 @@ typedef enum { implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ - CINIT(NOPROXY, STRINGPOINT, 177), + CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177), /* block size for TFTP transfers */ - CINIT(TFTP_BLKSIZE, LONG, 178), + CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178), /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + /* DEPRECATED, do not use! */ + CURLOPT(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179), /* Socks Service */ - CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180), /* set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ - CINIT(PROTOCOLS, LONG, 181), + CURLOPT(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181), /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ - CINIT(REDIR_PROTOCOLS, LONG, 182), + CURLOPT(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182), /* set the SSH knownhost file name to use */ - CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ - CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184), /* set the SSH host key callback custom pointer */ - CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_OBJECTPOINT, 185), /* set the SMTP mail originator */ - CINIT(MAIL_FROM, STRINGPOINT, 186), + CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186), /* set the list of SMTP mail receiver(s) */ - CINIT(MAIL_RCPT, SLISTPOINT, 187), + CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187), /* FTP: send PRET before PASV */ - CINIT(FTP_USE_PRET, LONG, 188), + CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188), /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ - CINIT(RTSP_REQUEST, LONG, 189), + CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_LONG, 189), /* The RTSP session identifier */ - CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190), /* The RTSP stream URI */ - CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191), /* The Transport: header to use in RTSP requests */ - CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192), /* Manually initialize the client RTSP CSeq for this handle */ - CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193), /* Manually initialize the server RTSP CSeq for this handle */ - CINIT(RTSP_SERVER_CSEQ, LONG, 194), + CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194), /* The stream to pass to INTERLEAVEFUNCTION. */ - CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_OBJECTPOINT, 195), /* Let the application define a custom write method for RTP data */ - CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196), /* Turn on wildcard matching */ - CINIT(WILDCARDMATCH, LONG, 197), + CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197), /* Directory matching callback called before downloading of an individual file (chunk) started */ - CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198), /* Directory matching callback called after the file (chunk) was downloaded, or skipped */ - CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199), /* Change match (fnmatch-like) callback for wildcard matching */ - CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200), /* Let the application define custom chunk data pointer */ - CINIT(CHUNK_DATA, OBJECTPOINT, 201), + CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_OBJECTPOINT, 201), /* FNMATCH_FUNCTION user pointer */ - CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_OBJECTPOINT, 202), /* send linked-list of name:port:address sets */ - CINIT(RESOLVE, SLISTPOINT, 203), + CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203), /* Set a username for authenticated TLS */ - CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204), /* Set a password for authenticated TLS */ - CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205), /* Set authentication type for authenticated TLS */ - CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206), /* Set to 1 to enable the "TE:" header in HTTP requests to ask for compressed transfer-encoded responses. Set to 0 to disable the use of TE: @@ -1674,271 +1680,274 @@ typedef enum { option is set to 1. */ - CINIT(TRANSFER_ENCODING, LONG, 207), + CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207), /* Callback function for closing socket (instead of close(2)). The callback should have type curl_closesocket_callback */ - CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), - CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208), + CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 209), /* allow GSSAPI credential delegation */ - CINIT(GSSAPI_DELEGATION, LONG, 210), + CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_LONG, 210), /* Set the name servers to use for DNS resolution */ - CINIT(DNS_SERVERS, STRINGPOINT, 211), + CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211), /* Time-out accept operations (currently for FTP only) after this amount of milliseconds. */ - CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212), /* Set TCP keepalive */ - CINIT(TCP_KEEPALIVE, LONG, 213), + CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213), /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ - CINIT(TCP_KEEPIDLE, LONG, 214), - CINIT(TCP_KEEPINTVL, LONG, 215), + CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214), + CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215), /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ - CINIT(SSL_OPTIONS, LONG, 216), + CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_LONG, 216), /* Set the SMTP auth originator */ - CINIT(MAIL_AUTH, STRINGPOINT, 217), + CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217), /* Enable/disable SASL initial response */ - CINIT(SASL_IR, LONG, 218), + CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218), /* Function that will be called instead of the internal progress display * function. This function should be defined as the curl_xferinfo_callback * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ - CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219), /* The XOAUTH2 bearer token */ - CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220), /* Set the interface string to use as outgoing network * interface for DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_INTERFACE, STRINGPOINT, 221), + CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221), /* Set the local IPv4 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222), /* Set the local IPv6 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223), /* Set authentication options directly */ - CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224), /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ - CINIT(SSL_ENABLE_NPN, LONG, 225), + CURLOPT(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225), /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ - CINIT(SSL_ENABLE_ALPN, LONG, 226), + CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226), /* Time to wait for a response to a HTTP request containing an * Expect: 100-continue header before sending the data anyway. */ - CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227), /* This points to a linked list of headers used for proxy requests only, struct curl_slist kind */ - CINIT(PROXYHEADER, SLISTPOINT, 228), + CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228), /* Pass in a bitmask of "header options" */ - CINIT(HEADEROPT, LONG, 229), + CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_LONG, 229), /* The public key in DER form used to validate the peer public key this option is used only if SSL_VERIFYPEER is true */ - CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230), /* Path to Unix domain socket */ - CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231), /* Set if we should verify the certificate status. */ - CINIT(SSL_VERIFYSTATUS, LONG, 232), + CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), /* Set if we should enable TLS false start. */ - CINIT(SSL_FALSESTART, LONG, 233), + CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233), /* Do not squash dot-dot sequences */ - CINIT(PATH_AS_IS, LONG, 234), + CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234), /* Proxy Service Name */ - CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235), /* Service Name */ - CINIT(SERVICE_NAME, STRINGPOINT, 236), + CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236), /* Wait/don't wait for pipe/mutex to clarify */ - CINIT(PIPEWAIT, LONG, 237), + CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237), /* Set the protocol used when curl is given a URL without a protocol */ - CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238), /* Set stream weight, 1 - 256 (default is 16) */ - CINIT(STREAM_WEIGHT, LONG, 239), + CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239), /* Set stream dependency on another CURL handle */ - CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240), /* Set E-xclusive stream dependency on another CURL handle */ - CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241), /* Do not send any tftp option requests to the server */ - CINIT(TFTP_NO_OPTIONS, LONG, 242), + CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242), /* Linked-list of host:port:connect-to-host:connect-to-port, overrides the URL's host:port (only for the network layer) */ - CINIT(CONNECT_TO, SLISTPOINT, 243), + CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243), /* Set TCP Fast Open */ - CINIT(TCP_FASTOPEN, LONG, 244), + CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244), /* Continue to send data if the server responds early with an * HTTP status code >= 300 */ - CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245), /* The CApath or CAfile used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_CAINFO, STRINGPOINT, 246), + CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246), /* The CApath directory used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_CAPATH, STRINGPOINT, 247), + CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247), /* Set if we should verify the proxy in ssl handshake, set 1 to verify. */ - CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248), /* Set if we should verify the Common name from the proxy certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches * the provided hostname. */ - CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249), /* What version to specifically try to use for proxy. See CURL_SSLVERSION defines below. */ - CINIT(PROXY_SSLVERSION, LONG, 250), + CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_LONG, 250), /* Set a username for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251), /* Set a password for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252), /* Set authentication type for authenticated TLS for proxy */ - CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253), /* name of the file keeping your private SSL-certificate for proxy */ - CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for proxy */ - CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255), /* name of the file keeping your private SSL-key for proxy */ - CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for proxy */ - CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257), /* password for the SSL private key for proxy */ - CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258), /* Specify which SSL ciphers to use for proxy */ - CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259), /* CRL file for proxy */ - CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260), /* Enable/disable specific SSL features with a bitmask for proxy, see CURLSSLOPT_* */ - CINIT(PROXY_SSL_OPTIONS, LONG, 261), + CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261), /* Name of pre proxy to use. */ - CINIT(PRE_PROXY, STRINGPOINT, 262), + CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262), /* The public key in DER form used to validate the proxy public key this option is used only if PROXY_SSL_VERIFYPEER is true */ - CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263), /* Path to an abstract Unix domain socket */ - CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264), /* Suppress proxy CONNECT response headers from user callbacks */ - CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265), /* The request target, instead of extracted from the URL */ - CINIT(REQUEST_TARGET, STRINGPOINT, 266), + CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266), /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ - CINIT(SOCKS5_AUTH, LONG, 267), + CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267), /* Enable/disable SSH compression */ - CINIT(SSH_COMPRESSION, LONG, 268), + CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268), /* Post MIME data. */ - CINIT(MIMEPOST, OBJECTPOINT, 269), + CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269), /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of seconds since 1 Jan 1970. */ - CINIT(TIMEVALUE_LARGE, OFF_T, 270), + CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270), /* Head start in milliseconds to give happy eyeballs. */ - CINIT(HAPPY_EYEBALLS_TIMEOUT_MS, LONG, 271), + CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271), /* Function that will be called before a resolver request is made */ - CINIT(RESOLVER_START_FUNCTION, FUNCTIONPOINT, 272), + CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272), /* User data to pass to the resolver start callback. */ - CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273), + CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_OBJECTPOINT, 273), /* send HAProxy PROXY protocol header? */ - CINIT(HAPROXYPROTOCOL, LONG, 274), + CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274), /* shuffle addresses before use when DNS returns multiple */ - CINIT(DNS_SHUFFLE_ADDRESSES, LONG, 275), + CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275), /* Specify which TLS 1.3 ciphers suites to use */ - CINIT(TLS13_CIPHERS, STRINGPOINT, 276), - CINIT(PROXY_TLS13_CIPHERS, STRINGPOINT, 277), + CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276), + CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277), /* Disallow specifying username/login in URL. */ - CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278), + CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278), /* DNS-over-HTTPS URL */ - CINIT(DOH_URL, STRINGPOINT, 279), + CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279), /* Preferred buffer size to use for uploads */ - CINIT(UPLOAD_BUFFERSIZE, LONG, 280), + CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280), /* Time in ms between connection upkeep calls for long-lived connections. */ - CINIT(UPKEEP_INTERVAL_MS, LONG, 281), + CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281), /* Specify URL using CURL URL API. */ - CINIT(CURLU, OBJECTPOINT, 282), + CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282), /* add trailing data just after no more data is available */ - CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 283), + CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283), /* pointer to be passed to HTTP_TRAILER_FUNCTION */ - CINIT(TRAILERDATA, OBJECTPOINT, 284), + CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_OBJECTPOINT, 284), /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ - CINIT(HTTP09_ALLOWED, LONG, 285), + CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285), /* alt-svc control bitmask */ - CINIT(ALTSVC_CTRL, LONG, 286), + CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286), /* alt-svc cache file name to possibly read from/write to */ - CINIT(ALTSVC, STRINGPOINT, 287), + CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287), /* maximum age of a connection to consider it for reuse (in seconds) */ - CINIT(MAXAGE_CONN, LONG, 288), + CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288), /* SASL authorisation identity */ - CINIT(SASL_AUTHZID, STRINGPOINT, 289), + CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289), + + /* allow RCPT TO command to fail for some recipients */ + CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290), CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2220,52 +2229,35 @@ CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership); -/* Old form API. */ -/* name is uppercase CURLFORM_ */ -#ifdef CFINIT -#undef CFINIT -#endif - -#ifdef CURL_ISOCPP -#define CFINIT(name) CURLFORM_ ## name -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define CFINIT(name) CURLFORM_/**/name -#endif - typedef enum { - CFINIT(NOTHING), /********* the first one is unused ************/ - - /* */ - CFINIT(COPYNAME), - CFINIT(PTRNAME), - CFINIT(NAMELENGTH), - CFINIT(COPYCONTENTS), - CFINIT(PTRCONTENTS), - CFINIT(CONTENTSLENGTH), - CFINIT(FILECONTENT), - CFINIT(ARRAY), - CFINIT(OBSOLETE), - CFINIT(FILE), - - CFINIT(BUFFER), - CFINIT(BUFFERPTR), - CFINIT(BUFFERLENGTH), - - CFINIT(CONTENTTYPE), - CFINIT(CONTENTHEADER), - CFINIT(FILENAME), - CFINIT(END), - CFINIT(OBSOLETE2), - - CFINIT(STREAM), - CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + CURLFORM_NOTHING, /********* the first one is unused ************/ + CURLFORM_COPYNAME, + CURLFORM_PTRNAME, + CURLFORM_NAMELENGTH, + CURLFORM_COPYCONTENTS, + CURLFORM_PTRCONTENTS, + CURLFORM_CONTENTSLENGTH, + CURLFORM_FILECONTENT, + CURLFORM_ARRAY, + CURLFORM_OBSOLETE, + CURLFORM_FILE, + + CURLFORM_BUFFER, + CURLFORM_BUFFERPTR, + CURLFORM_BUFFERLENGTH, + + CURLFORM_CONTENTTYPE, + CURLFORM_CONTENTHEADER, + CURLFORM_FILENAME, + CURLFORM_END, + CURLFORM_OBSOLETE2, + + CURLFORM_STREAM, + CURLFORM_CONTENTLEN, /* added in 7.46.0, provide a curl_off_t length */ CURLFORM_LASTENTRY /* the last unused */ } CURLformoption; -#undef CFINIT /* done */ - /* structure to be used as parameter for CURLFORM_ARRAY */ struct curl_forms { CURLformoption option; diff --git a/release/src/router/curl/include/curl/curlver.h b/release/src/router/curl/include/curl/curlver.h index 85b93553ca8..5fc49d41888 100644 --- a/release/src/router/curl/include/curl/curlver.h +++ b/release/src/router/curl/include/curl/curlver.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,17 +26,17 @@ a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2019 Daniel Stenberg, ." +#define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.68.0" +#define LIBCURL_VERSION "7.69.1" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 68 -#define LIBCURL_VERSION_PATCH 0 +#define LIBCURL_VERSION_MINOR 69 +#define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -57,7 +57,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x074400 +#define LIBCURL_VERSION_NUM 0x074501 /* * This is the date and time when the full source package was created. The @@ -68,7 +68,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2020-01-08" +#define LIBCURL_TIMESTAMP "2020-03-11" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/release/src/router/curl/include/curl/multi.h b/release/src/router/curl/include/curl/multi.h index 04996ffcaf4..bda9bb7b816 100644 --- a/release/src/router/curl/include/curl/multi.h +++ b/release/src/router/curl/include/curl/multi.h @@ -72,7 +72,8 @@ typedef enum { attempted to get added - again */ CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a callback */ - CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ + CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ + CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ CURLM_LAST } CURLMcode; @@ -343,71 +344,58 @@ CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, long *milliseconds); -#undef CINIT /* re-using the same name as in curl.h */ - -#ifdef CURL_ISOCPP -#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLMOPT_/**/name = type + number -#endif - typedef enum { /* This is the socket callback function pointer */ - CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1), /* This is the argument passed to the socket callback */ - CINIT(SOCKETDATA, OBJECTPOINT, 2), + CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2), /* set to 1 to enable pipelining for this multi handle */ - CINIT(PIPELINING, LONG, 3), + CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3), /* This is the timer callback function pointer */ - CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4), /* This is the argument passed to the timer callback */ - CINIT(TIMERDATA, OBJECTPOINT, 5), + CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5), /* maximum number of entries in the connection cache */ - CINIT(MAXCONNECTS, LONG, 6), + CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6), /* maximum number of (pipelining) connections to one host */ - CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7), /* maximum number of requests in a pipeline */ - CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8), /* a connection with a content-length longer than this will not be considered for pipelining */ - CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9), /* a connection with a chunk length longer than this will not be considered for pipelining */ - CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), /* a list of site names(+port) that are blacklisted from pipelining */ - CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), /* a list of server types that are blacklisted from pipelining */ - CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), /* maximum number of open connections in total */ - CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13), /* This is the server push callback function pointer */ - CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14), /* This is the argument passed to the server push callback */ - CINIT(PUSHDATA, OBJECTPOINT, 15), + CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15), /* maximum number of concurrent streams to support on a connection */ - CINIT(MAX_CONCURRENT_STREAMS, LONG, 16), + CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; diff --git a/release/src/router/curl/lib/CMakeLists.txt b/release/src/router/curl/lib/CMakeLists.txt index a9c90b66507..e73efb90aff 100644 --- a/release/src/router/curl/lib/CMakeLists.txt +++ b/release/src/router/curl/lib/CMakeLists.txt @@ -96,6 +96,12 @@ endif() set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") +if(CURL_HAS_LTO) + set_target_properties(${LIB_NAME} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) +endif() + if(WIN32) if(BUILD_SHARED_LIBS) # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" diff --git a/release/src/router/curl/lib/Makefile.in b/release/src/router/curl/lib/Makefile.in index 92598417440..3fc95847d4c 100644 --- a/release/src/router/curl/lib/Makefile.in +++ b/release/src/router/curl/lib/Makefile.in @@ -21,7 +21,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -229,7 +229,8 @@ am__objects_1 = libcurl_la-file.lo libcurl_la-timeval.lo \ libcurl_la-curl_path.lo libcurl_la-curl_ctype.lo \ libcurl_la-curl_range.lo libcurl_la-psl.lo libcurl_la-doh.lo \ libcurl_la-urlapi.lo libcurl_la-curl_get_line.lo \ - libcurl_la-altsvc.lo libcurl_la-socketpair.lo + libcurl_la-altsvc.lo libcurl_la-socketpair.lo \ + libcurl_la-rename.lo am__dirstamp = $(am__leading_dot)dirstamp am__objects_2 = vauth/libcurl_la-vauth.lo \ vauth/libcurl_la-cleartext.lo vauth/libcurl_la-cram.lo \ @@ -240,15 +241,15 @@ am__objects_2 = vauth/libcurl_la-vauth.lo \ vauth/libcurl_la-spnego_sspi.lo am__objects_3 = vtls/libcurl_la-openssl.lo vtls/libcurl_la-gtls.lo \ vtls/libcurl_la-vtls.lo vtls/libcurl_la-nss.lo \ - vtls/libcurl_la-polarssl.lo \ - vtls/libcurl_la-polarssl_threadlock.lo \ + vtls/libcurl_la-mbedtls_threadlock.lo \ vtls/libcurl_la-wolfssl.lo vtls/libcurl_la-schannel.lo \ vtls/libcurl_la-schannel_verify.lo \ vtls/libcurl_la-sectransp.lo vtls/libcurl_la-gskit.lo \ vtls/libcurl_la-mbedtls.lo vtls/libcurl_la-mesalink.lo \ vtls/libcurl_la-bearssl.lo am__objects_4 = vquic/libcurl_la-ngtcp2.lo vquic/libcurl_la-quiche.lo -am__objects_5 = vssh/libcurl_la-libssh2.lo vssh/libcurl_la-libssh.lo +am__objects_5 = vssh/libcurl_la-libssh2.lo vssh/libcurl_la-libssh.lo \ + vssh/libcurl_la-wolfssh.lo am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ $(am__objects_4) $(am__objects_5) am__objects_7 = @@ -317,7 +318,7 @@ am__objects_9 = libcurlu_la-file.lo libcurlu_la-timeval.lo \ libcurlu_la-curl_ctype.lo libcurlu_la-curl_range.lo \ libcurlu_la-psl.lo libcurlu_la-doh.lo libcurlu_la-urlapi.lo \ libcurlu_la-curl_get_line.lo libcurlu_la-altsvc.lo \ - libcurlu_la-socketpair.lo + libcurlu_la-socketpair.lo libcurlu_la-rename.lo am__objects_10 = vauth/libcurlu_la-vauth.lo \ vauth/libcurlu_la-cleartext.lo vauth/libcurlu_la-cram.lo \ vauth/libcurlu_la-digest.lo vauth/libcurlu_la-digest_sspi.lo \ @@ -328,8 +329,7 @@ am__objects_10 = vauth/libcurlu_la-vauth.lo \ vauth/libcurlu_la-spnego_sspi.lo am__objects_11 = vtls/libcurlu_la-openssl.lo vtls/libcurlu_la-gtls.lo \ vtls/libcurlu_la-vtls.lo vtls/libcurlu_la-nss.lo \ - vtls/libcurlu_la-polarssl.lo \ - vtls/libcurlu_la-polarssl_threadlock.lo \ + vtls/libcurlu_la-mbedtls_threadlock.lo \ vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-schannel.lo \ vtls/libcurlu_la-schannel_verify.lo \ vtls/libcurlu_la-sectransp.lo vtls/libcurlu_la-gskit.lo \ @@ -338,7 +338,7 @@ am__objects_11 = vtls/libcurlu_la-openssl.lo vtls/libcurlu_la-gtls.lo \ am__objects_12 = vquic/libcurlu_la-ngtcp2.lo \ vquic/libcurlu_la-quiche.lo am__objects_13 = vssh/libcurlu_la-libssh2.lo \ - vssh/libcurlu_la-libssh.lo + vssh/libcurlu_la-libssh.lo vssh/libcurlu_la-wolfssh.lo am__objects_14 = $(am__objects_9) $(am__objects_10) $(am__objects_11) \ $(am__objects_12) $(am__objects_13) am_libcurlu_la_OBJECTS = $(am__objects_14) $(am__objects_8) @@ -438,6 +438,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ ./$(DEPDIR)/libcurl_la-pop3.Plo \ ./$(DEPDIR)/libcurl_la-progress.Plo \ ./$(DEPDIR)/libcurl_la-psl.Plo ./$(DEPDIR)/libcurl_la-rand.Plo \ + ./$(DEPDIR)/libcurl_la-rename.Plo \ ./$(DEPDIR)/libcurl_la-rtsp.Plo \ ./$(DEPDIR)/libcurl_la-security.Plo \ ./$(DEPDIR)/libcurl_la-select.Plo \ @@ -548,6 +549,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ ./$(DEPDIR)/libcurlu_la-progress.Plo \ ./$(DEPDIR)/libcurlu_la-psl.Plo \ ./$(DEPDIR)/libcurlu_la-rand.Plo \ + ./$(DEPDIR)/libcurlu_la-rename.Plo \ ./$(DEPDIR)/libcurlu_la-rtsp.Plo \ ./$(DEPDIR)/libcurlu_la-security.Plo \ ./$(DEPDIR)/libcurlu_la-select.Plo \ @@ -610,17 +612,18 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ vquic/$(DEPDIR)/libcurlu_la-quiche.Plo \ vssh/$(DEPDIR)/libcurl_la-libssh.Plo \ vssh/$(DEPDIR)/libcurl_la-libssh2.Plo \ + vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo \ vssh/$(DEPDIR)/libcurlu_la-libssh.Plo \ vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo \ + vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo \ vtls/$(DEPDIR)/libcurl_la-bearssl.Plo \ vtls/$(DEPDIR)/libcurl_la-gskit.Plo \ vtls/$(DEPDIR)/libcurl_la-gtls.Plo \ vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo \ + vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo \ vtls/$(DEPDIR)/libcurl_la-mesalink.Plo \ vtls/$(DEPDIR)/libcurl_la-nss.Plo \ vtls/$(DEPDIR)/libcurl_la-openssl.Plo \ - vtls/$(DEPDIR)/libcurl_la-polarssl.Plo \ - vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Plo \ vtls/$(DEPDIR)/libcurl_la-schannel.Plo \ vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo \ vtls/$(DEPDIR)/libcurl_la-sectransp.Plo \ @@ -630,11 +633,10 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ vtls/$(DEPDIR)/libcurlu_la-gskit.Plo \ vtls/$(DEPDIR)/libcurlu_la-gtls.Plo \ vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo \ + vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo \ vtls/$(DEPDIR)/libcurlu_la-mesalink.Plo \ vtls/$(DEPDIR)/libcurlu_la-nss.Plo \ vtls/$(DEPDIR)/libcurlu_la-openssl.Plo \ - vtls/$(DEPDIR)/libcurlu_la-polarssl.Plo \ - vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Plo \ vtls/$(DEPDIR)/libcurlu_la-schannel.Plo \ vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo \ vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo \ @@ -838,6 +840,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -978,19 +981,18 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c \ - vtls/wolfssl.c vtls/schannel.c vtls/schannel_verify.c \ - vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c \ - vtls/bearssl.c + vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ + vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ + vtls/mesalink.c vtls/bearssl.c -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ - vtls/wolfssl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \ - vtls/mbedtls.h vtls/mesalink.h vtls/bearssl.h +LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ + vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ + vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ + vtls/bearssl.h LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h -LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c +LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ @@ -1010,7 +1012,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_multibyte.c hostcheck.c conncache.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ - doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c + doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -1031,7 +1033,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ - curl_get_line.h altsvc.h quic.h socketpair.h + curl_get_line.h altsvc.h quic.h socketpair.h rename.h LIB_RCFILES = libcurl.rc CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ @@ -1194,9 +1196,7 @@ vtls/libcurl_la-vtls.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurl_la-nss.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurl_la-polarssl.lo: vtls/$(am__dirstamp) \ - vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurl_la-polarssl_threadlock.lo: vtls/$(am__dirstamp) \ +vtls/libcurl_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurl_la-wolfssl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) @@ -1234,6 +1234,8 @@ vssh/libcurl_la-libssh2.lo: vssh/$(am__dirstamp) \ vssh/$(DEPDIR)/$(am__dirstamp) vssh/libcurl_la-libssh.lo: vssh/$(am__dirstamp) \ vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurl_la-wolfssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) libcurl.la: $(libcurl_la_OBJECTS) $(libcurl_la_DEPENDENCIES) $(EXTRA_libcurl_la_DEPENDENCIES) $(AM_V_CCLD)$(libcurl_la_LINK) -rpath $(libdir) $(libcurl_la_OBJECTS) $(libcurl_la_LIBADD) $(LIBS) @@ -1269,9 +1271,7 @@ vtls/libcurlu_la-vtls.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-nss.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurlu_la-polarssl.lo: vtls/$(am__dirstamp) \ - vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurlu_la-polarssl_threadlock.lo: vtls/$(am__dirstamp) \ +vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-wolfssl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) @@ -1297,6 +1297,8 @@ vssh/libcurlu_la-libssh2.lo: vssh/$(am__dirstamp) \ vssh/$(DEPDIR)/$(am__dirstamp) vssh/libcurlu_la-libssh.lo: vssh/$(am__dirstamp) \ vssh/$(DEPDIR)/$(am__dirstamp) +vssh/libcurlu_la-wolfssh.lo: vssh/$(am__dirstamp) \ + vssh/$(DEPDIR)/$(am__dirstamp) libcurlu.la: $(libcurlu_la_OBJECTS) $(libcurlu_la_DEPENDENCIES) $(EXTRA_libcurlu_la_DEPENDENCIES) $(AM_V_CCLD)$(libcurlu_la_LINK) $(am_libcurlu_la_rpath) $(libcurlu_la_OBJECTS) $(libcurlu_la_LIBADD) $(LIBS) @@ -1394,6 +1396,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-progress.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-psl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rename.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rtsp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-security.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-select.Plo@am__quote@ # am--include-marker @@ -1505,6 +1508,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-progress.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-psl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rename.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rtsp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-security.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-select.Plo@am__quote@ # am--include-marker @@ -1567,17 +1571,18 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-quiche.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-bearssl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gskit.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gtls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mesalink.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-nss.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-openssl.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-polarssl.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-sectransp.Plo@am__quote@ # am--include-marker @@ -1587,11 +1592,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gskit.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gtls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mesalink.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-nss.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-openssl.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-polarssl.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo@am__quote@ # am--include-marker @@ -2405,6 +2409,13 @@ libcurl_la-socketpair.lo: socketpair.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c +libcurl_la-rename.lo: rename.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rename.Tpo -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rename.Tpo $(DEPDIR)/libcurl_la-rename.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rename.c' object='libcurl_la-rename.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c + vauth/libcurl_la-vauth.lo: vauth/vauth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-vauth.Tpo -c -o vauth/libcurl_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-vauth.Tpo vauth/$(DEPDIR)/libcurl_la-vauth.Plo @@ -2517,19 +2528,12 @@ vtls/libcurl_la-nss.lo: vtls/nss.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-nss.lo `test -f 'vtls/nss.c' || echo '$(srcdir)/'`vtls/nss.c -vtls/libcurl_la-polarssl.lo: vtls/polarssl.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-polarssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-polarssl.Tpo -c -o vtls/libcurl_la-polarssl.lo `test -f 'vtls/polarssl.c' || echo '$(srcdir)/'`vtls/polarssl.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-polarssl.Tpo vtls/$(DEPDIR)/libcurl_la-polarssl.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/polarssl.c' object='vtls/libcurl_la-polarssl.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-polarssl.lo `test -f 'vtls/polarssl.c' || echo '$(srcdir)/'`vtls/polarssl.c - -vtls/libcurl_la-polarssl_threadlock.lo: vtls/polarssl_threadlock.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-polarssl_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Tpo -c -o vtls/libcurl_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Tpo vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/polarssl_threadlock.c' object='vtls/libcurl_la-polarssl_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ +vtls/libcurl_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurl_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c vtls/libcurl_la-wolfssl.lo: vtls/wolfssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-wolfssl.Tpo -c -o vtls/libcurl_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c @@ -2615,6 +2619,13 @@ vssh/libcurl_la-libssh.lo: vssh/libssh.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c +vssh/libcurl_la-wolfssh.lo: vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurl_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c + libcurlu_la-file.lo: file.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-file.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-file.Tpo -c -o libcurlu_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-file.Tpo $(DEPDIR)/libcurlu_la-file.Plo @@ -3392,6 +3403,13 @@ libcurlu_la-socketpair.lo: socketpair.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c +libcurlu_la-rename.lo: rename.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rename.Tpo -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rename.Tpo $(DEPDIR)/libcurlu_la-rename.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rename.c' object='libcurlu_la-rename.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c + vauth/libcurlu_la-vauth.lo: vauth/vauth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo -c -o vauth/libcurlu_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo vauth/$(DEPDIR)/libcurlu_la-vauth.Plo @@ -3504,19 +3522,12 @@ vtls/libcurlu_la-nss.lo: vtls/nss.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-nss.lo `test -f 'vtls/nss.c' || echo '$(srcdir)/'`vtls/nss.c -vtls/libcurlu_la-polarssl.lo: vtls/polarssl.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-polarssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-polarssl.Tpo -c -o vtls/libcurlu_la-polarssl.lo `test -f 'vtls/polarssl.c' || echo '$(srcdir)/'`vtls/polarssl.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-polarssl.Tpo vtls/$(DEPDIR)/libcurlu_la-polarssl.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/polarssl.c' object='vtls/libcurlu_la-polarssl.lo' libtool=yes @AMDEPBACKSLASH@ +vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurlu_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-polarssl.lo `test -f 'vtls/polarssl.c' || echo '$(srcdir)/'`vtls/polarssl.c - -vtls/libcurlu_la-polarssl_threadlock.lo: vtls/polarssl_threadlock.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-polarssl_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Tpo -c -o vtls/libcurlu_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Tpo vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/polarssl_threadlock.c' object='vtls/libcurlu_la-polarssl_threadlock.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c vtls/libcurlu_la-wolfssl.lo: vtls/wolfssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-wolfssl.Tpo -c -o vtls/libcurlu_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c @@ -3602,6 +3613,13 @@ vssh/libcurlu_la-libssh.lo: vssh/libssh.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c +vssh/libcurlu_la-wolfssh.lo: vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurlu_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c + mostlyclean-libtool: -rm -f *.lo @@ -3828,6 +3846,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libcurl_la-progress.Plo -rm -f ./$(DEPDIR)/libcurl_la-psl.Plo -rm -f ./$(DEPDIR)/libcurl_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rename.Plo -rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo -rm -f ./$(DEPDIR)/libcurl_la-security.Plo -rm -f ./$(DEPDIR)/libcurl_la-select.Plo @@ -3939,6 +3958,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo -rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo -rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo -rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo -rm -f ./$(DEPDIR)/libcurlu_la-security.Plo -rm -f ./$(DEPDIR)/libcurlu_la-select.Plo @@ -4001,17 +4021,18 @@ distclean: distclean-am -rm -f vquic/$(DEPDIR)/libcurlu_la-quiche.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gskit.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-mesalink.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-nss.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-polarssl.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo @@ -4021,11 +4042,10 @@ distclean: distclean-am -rm -f vtls/$(DEPDIR)/libcurlu_la-gskit.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-mesalink.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-nss.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-polarssl.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo @@ -4155,6 +4175,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libcurl_la-progress.Plo -rm -f ./$(DEPDIR)/libcurl_la-psl.Plo -rm -f ./$(DEPDIR)/libcurl_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurl_la-rename.Plo -rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo -rm -f ./$(DEPDIR)/libcurl_la-security.Plo -rm -f ./$(DEPDIR)/libcurl_la-select.Plo @@ -4266,6 +4287,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo -rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo -rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo -rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo -rm -f ./$(DEPDIR)/libcurlu_la-security.Plo -rm -f ./$(DEPDIR)/libcurlu_la-select.Plo @@ -4328,17 +4350,18 @@ maintainer-clean: maintainer-clean-am -rm -f vquic/$(DEPDIR)/libcurlu_la-quiche.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo + -rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gskit.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-mesalink.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-nss.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-polarssl.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-polarssl_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo @@ -4348,11 +4371,10 @@ maintainer-clean: maintainer-clean-am -rm -f vtls/$(DEPDIR)/libcurlu_la-gskit.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo + -rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-mesalink.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-nss.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-polarssl.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-polarssl_threadlock.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo diff --git a/release/src/router/curl/lib/Makefile.inc b/release/src/router/curl/lib/Makefile.inc index 6c90c26752f..46ded90bb62 100644 --- a/release/src/router/curl/lib/Makefile.inc +++ b/release/src/router/curl/lib/Makefile.inc @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -28,21 +28,20 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c \ - vtls/wolfssl.c vtls/schannel.c vtls/schannel_verify.c \ - vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c \ - vtls/bearssl.c + vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ + vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ + vtls/mesalink.c vtls/bearssl.c -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ - vtls/wolfssl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \ - vtls/mbedtls.h vtls/mesalink.h vtls/bearssl.h +LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ + vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ + vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ + vtls/bearssl.h LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h -LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c +LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h @@ -64,7 +63,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_multibyte.c hostcheck.c conncache.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ - doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c + doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -85,7 +84,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ - curl_get_line.h altsvc.h quic.h socketpair.h + curl_get_line.h altsvc.h quic.h socketpair.h rename.h LIB_RCFILES = libcurl.rc diff --git a/release/src/router/curl/lib/Makefile.m32 b/release/src/router/curl/lib/Makefile.m32 index b6ef0a5cbdd..ac6b3de631d 100644 --- a/release/src/router/curl/lib/Makefile.m32 +++ b/release/src/router/curl/lib/Makefile.m32 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1999 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1999 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -270,7 +270,7 @@ ifdef SSL OPENSSL_LIBS += -lgdi32 -lcrypt32 endif INCLUDES += -I"$(OPENSSL_INCLUDE)" - CFLAGS += -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ + CFLAGS += -DUSE_OPENSSL -DHAVE_OPENSSL_PKCS12_H \ -DOPENSSL_NO_KRB5 DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) ifdef SRP diff --git a/release/src/router/curl/lib/Makefile.netware b/release/src/router/curl/lib/Makefile.netware index a40534684d7..752d3d6fba7 100644 --- a/release/src/router/curl/lib/Makefile.netware +++ b/release/src/router/curl/lib/Makefile.netware @@ -6,7 +6,7 @@ # \___|\___/|_| \_\_____| # # Copyright (C) 2004 - 2015, Guenter Knauf -# Copyright (C) 2001 - 2018, Daniel Stenberg, , et al. +# Copyright (C) 2001 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -639,7 +639,6 @@ ifdef WITH_SSL @echo $(DL)#define HAVE_OPENSSL_PEM_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_CRYPTO_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_OPENSSL_ENGINE_H 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ ifdef WITH_SRP @echo $(DL)#define USE_TLS_SRP 1$(DL) >> $@ diff --git a/release/src/router/curl/lib/altsvc.c b/release/src/router/curl/lib/altsvc.c index bf869c37a51..c39d86eaff7 100644 --- a/release/src/router/curl/lib/altsvc.c +++ b/release/src/router/curl/lib/altsvc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019, Daniel Stenberg, , et al. + * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,6 +34,8 @@ #include "parsedate.h" #include "sendf.h" #include "warnless.h" +#include "rand.h" +#include "rename.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -48,19 +50,20 @@ #define MAX_ALTSVC_ALPNLENSTR "10" #define MAX_ALTSVC_ALPNLEN 10 +#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS) +#define H3VERSION "h3-27" +#else +#define H3VERSION "h3" +#endif + static enum alpnid alpn2alpnid(char *name) { if(strcasecompare(name, "h1")) return ALPN_h1; if(strcasecompare(name, "h2")) return ALPN_h2; -#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS) - if(strcasecompare(name, "h3-24")) - return ALPN_h3; -#else - if(strcasecompare(name, "h3")) + if(strcasecompare(name, H3VERSION)) return ALPN_h3; -#endif return ALPN_none; /* unknown, probably rubbish input */ } @@ -73,11 +76,7 @@ const char *Curl_alpnid2str(enum alpnid id) case ALPN_h2: return "h2"; case ALPN_h3: -#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS) - return "h3-24"; -#else - return "h3"; -#endif + return H3VERSION; default: return ""; /* bad */ } @@ -188,7 +187,16 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) { CURLcode result = CURLE_OK; char *line = NULL; - FILE *fp = fopen(file, FOPEN_READTEXT); + FILE *fp; + + /* we need a private copy of the file name so that the altsvc cache file + name survives an easy handle reset */ + free(asi->filename); + asi->filename = strdup(file); + if(!asi->filename) + return CURLE_OUT_OF_MEMORY; + + fp = fopen(file, FOPEN_READTEXT); if(fp) { line = malloc(MAX_ALTSVC_LINE); if(!line) @@ -209,6 +217,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) return result; fail: + Curl_safefree(asi->filename); free(line); fclose(fp); return CURLE_OUT_OF_MEMORY; @@ -302,6 +311,7 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc) n = e->next; altsvc_free(as); } + free(altsvc->filename); free(altsvc); } } @@ -309,34 +319,57 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc) /* * Curl_altsvc_save() writes the altsvc cache to a file. */ -CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file) +CURLcode Curl_altsvc_save(struct Curl_easy *data, + struct altsvcinfo *altsvc, const char *file) { struct curl_llist_element *e; struct curl_llist_element *n; CURLcode result = CURLE_OK; FILE *out; + char *tempstore; + unsigned char randsuffix[9]; if(!altsvc) /* no cache activated */ return CURLE_OK; + /* if not new name is given, use the one we stored from the load */ + if(!file && altsvc->filename) + file = altsvc->filename; + if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0]) /* marked as read-only, no file or zero length file name */ return CURLE_OK; - out = fopen(file, FOPEN_WRITETEXT); + + if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) + return CURLE_FAILED_INIT; + + tempstore = aprintf("%s.%s.tmp", file, randsuffix); + if(!tempstore) + return CURLE_OUT_OF_MEMORY; + + out = fopen(tempstore, FOPEN_WRITETEXT); if(!out) - return CURLE_WRITE_ERROR; - fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n" - "# This file was generated by libcurl! Edit at your own risk.\n", - out); - for(e = altsvc->list.head; e; e = n) { - struct altsvc *as = e->ptr; - n = e->next; - result = altsvc_out(as, out); + result = CURLE_WRITE_ERROR; + else { + fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n", + out); + for(e = altsvc->list.head; e; e = n) { + struct altsvc *as = e->ptr; + n = e->next; + result = altsvc_out(as, out); + if(result) + break; + } + fclose(out); + if(!result && Curl_rename(tempstore, file)) + result = CURLE_WRITE_ERROR; + if(result) - break; + unlink(tempstore); } - fclose(out); + free(tempstore); return result; } @@ -351,12 +384,12 @@ static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen) while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '=')) p++; len = p - protop; + *ptr = p; if(!len || (len >= buflen)) return CURLE_BAD_FUNCTION_ARGUMENT; memcpy(alpnbuf, protop, len); alpnbuf[len] = 0; - *ptr = p; return CURLE_OK; } @@ -402,6 +435,10 @@ static time_t debugtime(void *unused) * * 'value' points to the header *value*. That's contents to the right of the * header name. + * + * Currently this function rejects invalid data without returning an error. + * Invalid host name, port number will result in the specific alternative + * being rejected. Unknown protocols are skipped. */ CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvcinfo *asi, const char *value, @@ -415,12 +452,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, char alpnbuf[MAX_ALTSVC_ALPNLEN] = ""; struct altsvc *as; unsigned short dstport = srcport; /* the same by default */ - const char *semip; - time_t maxage = 24 * 3600; /* default is 24 hours */ - bool persist = FALSE; CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); - if(result) - return result; + if(result) { + infof(data, "Excessive alt-svc header, ignoring...\n"); + return CURLE_OK; + } DEBUGASSERT(asi); @@ -432,57 +468,20 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, return CURLE_OK; } - /* The 'ma' and 'persist' flags are annoyingly meant for all alternatives - but are set after the list on the line. Scan for the semicolons and get - those fields first! */ - semip = p; - do { - semip = strchr(semip, ';'); - if(semip) { - char option[32]; - unsigned long num; - char *end_ptr; - bool quoted = FALSE; - semip++; /* pass the semicolon */ - result = getalnum(&semip, option, sizeof(option)); - if(result) - break; - while(*semip && ISBLANK(*semip)) - semip++; - if(*semip != '=') - continue; - semip++; - while(*semip && ISBLANK(*semip)) - semip++; - if(*semip == '\"') { - /* quoted value */ - semip++; - quoted = TRUE; - } - num = strtoul(semip, &end_ptr, 10); - if((end_ptr != semip) && num && (num < ULONG_MAX)) { - if(strcasecompare("ma", option)) - maxage = num; - else if(strcasecompare("persist", option) && (num == 1)) - persist = TRUE; - if(quoted && (*end_ptr == '\"')) - end_ptr++; - } - semip = end_ptr; - } - } while(semip); - do { if(*p == '=') { /* [protocol]="[host][:port]" */ dstalpnid = alpn2alpnid(alpnbuf); - if(!dstalpnid) { - infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf); - return CURLE_OK; - } p++; if(*p == '\"') { const char *dsthost; + const char *value_ptr; + char option[32]; + unsigned long num; + char *end_ptr; + bool quoted = FALSE; + time_t maxage = 24 * 3600; /* default is 24 hours */ + bool persist = FALSE; p++; if(*p != ':') { /* host name starts here */ @@ -490,11 +489,15 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-'))) p++; len = p - hostp; - if(!len || (len >= MAX_ALTSVC_HOSTLEN)) - return CURLE_BAD_FUNCTION_ARGUMENT; - memcpy(namebuf, hostp, len); - namebuf[len] = 0; - dsthost = namebuf; + if(!len || (len >= MAX_ALTSVC_HOSTLEN)) { + infof(data, "Excessive alt-svc host name, ignoring...\n"); + dstalpnid = ALPN_none; + } + else { + memcpy(namebuf, hostp, len); + namebuf[len] = 0; + dsthost = namebuf; + } } else { /* no destination name, use source host */ @@ -502,31 +505,86 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, } if(*p == ':') { /* a port number */ - char *end_ptr; unsigned long port = strtoul(++p, &end_ptr, 10); if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { infof(data, "Unknown alt-svc port number, ignoring...\n"); - return CURLE_OK; + dstalpnid = ALPN_none; } p = end_ptr; dstport = curlx_ultous(port); } if(*p++ != '\"') - return CURLE_BAD_FUNCTION_ARGUMENT; - as = altsvc_createid(srchost, dsthost, - srcalpnid, dstalpnid, - srcport, dstport); - if(as) { - /* The expires time also needs to take the Age: value (if any) into - account. [See RFC 7838 section 3.1] */ - as->expires = maxage + time(NULL); - as->persist = persist; - Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); - asi->num++; /* one more entry */ - infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, - Curl_alpnid2str(dstalpnid)); + break; + /* Handle the optional 'ma' and 'persist' flags. Unknown flags + are skipped. */ + for(;;) { + while(*p && ISBLANK(*p) && *p != ';' && *p != ',') + p++; + if(!*p || *p == ',') + break; + p++; /* pass the semicolon */ + if(!*p) + break; + result = getalnum(&p, option, sizeof(option)); + if(result) { + /* skip option if name is too long */ + option[0] = '\0'; + } + while(*p && ISBLANK(*p)) + p++; + if(*p != '=') + return CURLE_OK; + p++; + while(*p && ISBLANK(*p)) + p++; + if(!*p) + return CURLE_OK; + if(*p == '\"') { + /* quoted value */ + p++; + quoted = TRUE; + } + value_ptr = p; + if(quoted) { + while(*p && *p != '\"') + p++; + if(!*p++) + return CURLE_OK; + } + else { + while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',') + p++; + } + num = strtoul(value_ptr, &end_ptr, 10); + if((end_ptr != value_ptr) && (num < ULONG_MAX)) { + if(strcasecompare("ma", option)) + maxage = num; + else if(strcasecompare("persist", option) && (num == 1)) + persist = TRUE; + } + } + if(dstalpnid) { + as = altsvc_createid(srchost, dsthost, + srcalpnid, dstalpnid, + srcport, dstport); + if(as) { + /* The expires time also needs to take the Age: value (if any) into + account. [See RFC 7838 section 3.1] */ + as->expires = maxage + time(NULL); + as->persist = persist; + Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); + asi->num++; /* one more entry */ + infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, + Curl_alpnid2str(dstalpnid)); + } + } + else { + infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n", + alpnbuf); } } + else + break; /* after the double quote there can be a comma if there's another string or a semicolon if no more */ if(*p == ',') { @@ -534,11 +592,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, p++; result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); if(result) - /* failed to parse, but since we already did at least one host we - return OK */ - return CURLE_OK; + break; } } + else + break; } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r')); return CURLE_OK; diff --git a/release/src/router/curl/lib/altsvc.h b/release/src/router/curl/lib/altsvc.h index 99d0499af75..248e71eef87 100644 --- a/release/src/router/curl/lib/altsvc.h +++ b/release/src/router/curl/lib/altsvc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019, Daniel Stenberg, , et al. + * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -59,7 +59,8 @@ struct altsvcinfo { const char *Curl_alpnid2str(enum alpnid id); struct altsvcinfo *Curl_altsvc_init(void); CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file); -CURLcode Curl_altsvc_save(struct altsvcinfo *asi, const char *file); +CURLcode Curl_altsvc_save(struct Curl_easy *data, + struct altsvcinfo *asi, const char *file); CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl); void Curl_altsvc_cleanup(struct altsvcinfo *altsvc); CURLcode Curl_altsvc_parse(struct Curl_easy *data, @@ -70,9 +71,9 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi, enum alpnid srcalpnid, const char *srchost, int srcport, struct altsvc **dstentry, - int versions); /* one or more CURLALTSVC_H* bits */ + const int versions); /* CURLALTSVC_H* bits */ #else /* disabled */ -#define Curl_altsvc_save(a,b) +#define Curl_altsvc_save(a,b,c) #endif /* CURL_DISABLE_HTTP || USE_ALTSVC */ #endif /* HEADER_CURL_ALTSVC_H */ diff --git a/release/src/router/curl/lib/asyn-ares.c b/release/src/router/curl/lib/asyn-ares.c index 835cfa48fa2..b76e66548eb 100644 --- a/release/src/router/curl/lib/asyn-ares.c +++ b/release/src/router/curl/lib/asyn-ares.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -626,26 +626,11 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, { char *bufp; struct Curl_easy *data = conn->data; - struct in_addr in; int family = PF_INET; -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - struct in6_addr in6; -#endif /* CURLRES_IPV6 */ *waitp = 0; /* default to synchronous response */ - /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - } - #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - /* Otherwise, check if this is an IPv6 address string */ - if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) - /* This must be an IPv6 address literal. */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - switch(conn->ip_version) { default: #if ARES_VERSION >= 0x010601 @@ -684,7 +669,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, res->last_status = ARES_ENOTFOUND; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ if(family == PF_UNSPEC) { - if(Curl_ipv6works()) { + if(Curl_ipv6works(conn)) { res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ diff --git a/release/src/router/curl/lib/asyn-thread.c b/release/src/router/curl/lib/asyn-thread.c index b08497aaa0a..68dcbb3ecd7 100644 --- a/release/src/router/curl/lib/asyn-thread.c +++ b/release/src/router/curl/lib/asyn-thread.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,7 +71,6 @@ #include "strerror.h" #include "url.h" #include "multiif.h" -#include "inet_pton.h" #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" @@ -692,26 +691,11 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int port, int *waitp) { - struct in_addr in; struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; *waitp = 0; /* default to synchronous response */ -#ifdef ENABLE_IPV6 - { - struct in6_addr in6; - /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) - /* This is an IPv6 address literal */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } -#endif /* ENABLE_IPV6 */ - - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - reslv->start = Curl_now(); /* fire up a new resolver thread! */ @@ -736,32 +720,12 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { struct addrinfo hints; - char sbuf[12]; int pf = PF_INET; struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; *waitp = 0; /* default to synchronous response */ -#ifndef USE_RESOLVE_ON_IPS - { - struct in_addr in; - /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - } -#ifdef ENABLE_IPV6 - { - struct in6_addr in6; - /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) - /* This is an IPv6 address literal */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } -#endif /* ENABLE_IPV6 */ -#endif /* !USE_RESOLVE_ON_IPS */ - #ifdef CURLRES_IPV6 /* * Check if a limited name resolve has been requested. @@ -778,7 +742,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, break; } - if((pf != PF_INET) && !Curl_ipv6works()) + if((pf != PF_INET) && !Curl_ipv6works(conn)) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; #endif /* CURLRES_IPV6 */ @@ -788,8 +752,6 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, hints.ai_socktype = (conn->transport == TRNSPRT_TCP)? SOCK_STREAM : SOCK_DGRAM; - msnprintf(sbuf, sizeof(sbuf), "%d", port); - reslv->start = Curl_now(); /* fire up a new resolver thread! */ if(init_resolve_thread(conn, hostname, port, &hints)) { diff --git a/release/src/router/curl/lib/checksrc.pl b/release/src/router/curl/lib/checksrc.pl index 83436456100..e1bb1a63394 100755 --- a/release/src/router/curl/lib/checksrc.pl +++ b/release/src/router/curl/lib/checksrc.pl @@ -36,7 +36,7 @@ my $dir="."; my $wlist=""; my @alist; -my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin'; +my $windows_os = $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys'; my $verbose; my %whitelist; diff --git a/release/src/router/curl/lib/config-dos.h b/release/src/router/curl/lib/config-dos.h index 25f751eb56b..aa83c4be55c 100644 --- a/release/src/router/curl/lib/config-dos.h +++ b/release/src/router/curl/lib/config-dos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -138,7 +138,6 @@ /* USE_OPENSSL on cmd-line */ #ifdef USE_OPENSSL #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 - #define HAVE_OPENSSL_ENGINE_H 1 #define OPENSSL_NO_KRB5 1 #endif diff --git a/release/src/router/curl/lib/config-plan9.h b/release/src/router/curl/lib/config-plan9.h index 4063d4bbd60..41440a14ecd 100644 --- a/release/src/router/curl/lib/config-plan9.h +++ b/release/src/router/curl/lib/config-plan9.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -138,7 +138,6 @@ #define USE_OPENSSL 1 #define HAVE_OPENSSL_CRYPTO_H 1 -#define HAVE_OPENSSL_ENGINE_H 1 #define HAVE_OPENSSL_ERR_H 1 #define HAVE_OPENSSL_PEM_H 1 #define HAVE_OPENSSL_PKCS12_H 1 diff --git a/release/src/router/curl/lib/config-symbian.h b/release/src/router/curl/lib/config-symbian.h index c01e1bfab8c..82a27bfefac 100644 --- a/release/src/router/curl/lib/config-symbian.h +++ b/release/src/router/curl/lib/config-symbian.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -358,9 +358,6 @@ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_CRYPTO_H 1*/ -/* Define to 1 if you have the header file. */ -/*#define HAVE_OPENSSL_ENGINE_H 1*/ - /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_ERR_H 1*/ diff --git a/release/src/router/curl/lib/config-tpf.h b/release/src/router/curl/lib/config-tpf.h index 85b634f9d43..a79afae6d39 100644 --- a/release/src/router/curl/lib/config-tpf.h +++ b/release/src/router/curl/lib/config-tpf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -316,10 +316,6 @@ /* #undef HAVE_OPENSSL_CRYPTO_H */ #define HAVE_OPENSSL_CRYPTO_H 1 -/* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_ENGINE_H */ -#define HAVE_OPENSSL_ENGINE_H 1 - /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_ERR_H */ #define HAVE_OPENSSL_ERR_H 1 diff --git a/release/src/router/curl/lib/config-vxworks.h b/release/src/router/curl/lib/config-vxworks.h index 004fd4e8009..2769cdfd941 100644 --- a/release/src/router/curl/lib/config-vxworks.h +++ b/release/src/router/curl/lib/config-vxworks.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -418,9 +418,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_CRYPTO_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_ENGINE_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_ERR_H 1 diff --git a/release/src/router/curl/lib/config-win32.h b/release/src/router/curl/lib/config-win32.h index 1dcce0db41a..d19665d71ae 100644 --- a/release/src/router/curl/lib/config-win32.h +++ b/release/src/router/curl/lib/config-win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -183,7 +183,7 @@ /* #define HAVE_DOPRNT 1 */ /* Define if you have the ftruncate function. */ -#define HAVE_FTRUNCATE 1 +/* #define HAVE_FTRUNCATE 1 */ /* Define to 1 if you have the `getpeername' function. */ #define HAVE_GETPEERNAME 1 @@ -714,7 +714,9 @@ Vista #endif /* Define to use the Windows crypto library. */ +#if !defined(CURL_WINDOWS_APP) #define USE_WIN32_CRYPTO +#endif /* Define to use Unix sockets. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) diff --git a/release/src/router/curl/lib/conncache.c b/release/src/router/curl/lib/conncache.c index 28044644bfc..cbd3bb1bb39 100644 --- a/release/src/router/curl/lib/conncache.c +++ b/release/src/router/curl/lib/conncache.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -179,18 +179,6 @@ size_t Curl_conncache_size(struct Curl_easy *data) return num; } -/* Returns number of connections currently held in the connections's bundle - Locks/unlocks the cache itself! -*/ -size_t Curl_conncache_bundle_size(struct connectdata *conn) -{ - size_t num; - CONN_LOCK(conn->data); - num = conn->bundle->num_connections; - CONN_UNLOCK(conn->data); - return num; -} - /* Look up the bundle with all the connections to the same host this connectdata struct is setup to use. diff --git a/release/src/router/curl/lib/conncache.h b/release/src/router/curl/lib/conncache.h index 5fe80b4c8d9..e3e4c9c282b 100644 --- a/release/src/router/curl/lib/conncache.h +++ b/release/src/router/curl/lib/conncache.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2015 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2015 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, * * This software is licensed as described in the file COPYING, which @@ -80,7 +80,6 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, void Curl_conncache_unlock(struct Curl_easy *data); /* returns number of connections currently held in the connection cache */ size_t Curl_conncache_size(struct Curl_easy *data); -size_t Curl_conncache_bundle_size(struct connectdata *conn); bool Curl_conncache_return_conn(struct Curl_easy *data, struct connectdata *conn); diff --git a/release/src/router/curl/lib/connect.c b/release/src/router/curl/lib/connect.c index 611d6d2f026..0a7475cb6a4 100644 --- a/release/src/router/curl/lib/connect.c +++ b/release/src/router/curl/lib/connect.c @@ -745,13 +745,15 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) Curl_persistconninfo(conn); } -/* after a TCP connection to the proxy has been verified, this function does - the next magic step. +/* After a TCP connection to the proxy has been verified, this function does + the next magic steps. If 'done' isn't set TRUE, it is not done yet and + must be called again. Note: this function's sub-functions call failf() */ -static CURLcode connected_proxy(struct connectdata *conn, int sockindex) +static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex, + bool *done) { CURLcode result = CURLE_OK; @@ -760,43 +762,62 @@ static CURLcode connected_proxy(struct connectdata *conn, int sockindex) /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ - const char * const host = conn->bits.httpproxy ? - conn->http_proxy.host.name : - conn->bits.conn_to_host ? - conn->conn_to_host.name : - sockindex == SECONDARYSOCKET ? - conn->secondaryhostname : conn->host.name; - const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : - sockindex == SECONDARYSOCKET ? conn->secondary_port : - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; - conn->bits.socksproxy_connecting = TRUE; + const char * const host = + conn->bits.httpproxy ? + conn->http_proxy.host.name : + conn->bits.conn_to_host ? + conn->conn_to_host.name : + sockindex == SECONDARYSOCKET ? + conn->secondaryhostname : conn->host.name; + const int port = + conn->bits.httpproxy ? (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? conn->secondary_port : + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; switch(conn->socks_proxy.proxytype) { case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd, - host, port, sockindex, conn); + host, port, sockindex, conn, done); break; case CURLPROXY_SOCKS4: case CURLPROXY_SOCKS4A: result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex, - conn); + conn, done); break; default: failf(conn->data, "unknown proxytype option given"); result = CURLE_COULDNT_CONNECT; } /* switch proxytype */ - conn->bits.socksproxy_connecting = FALSE; #else (void)sockindex; #endif /* CURL_DISABLE_PROXY */ } + else + *done = TRUE; /* no SOCKS proxy, so consider us connected */ return result; } +/* + * post_SOCKS() is called after a successful connect to the peer, which + * *could* be a SOCKS proxy + */ +static void post_SOCKS(struct connectdata *conn, + int sockindex, + bool *connected) +{ + conn->bits.tcpconnect[sockindex] = TRUE; + + *connected = TRUE; + if(sockindex == FIRSTSOCKET) + Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */ + Curl_updateconninfo(conn, conn->sock[sockindex]); + Curl_verboseconnect(conn); +} + /* * Curl_is_connected() checks if the socket has connected. */ @@ -834,6 +855,14 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OPERATION_TIMEDOUT; } + if(SOCKS_STATE(conn->cnnct.state)) { + /* still doing SOCKS */ + result = connect_SOCKS(conn, sockindex, connected); + if(!result && *connected) + post_SOCKS(conn, sockindex, connected); + return result; + } + for(i = 0; i<2; i++) { const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) @@ -900,18 +929,13 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->tempsock[other] = CURL_SOCKET_BAD; } - /* see if we need to do any proxy magic first once we connected */ - result = connected_proxy(conn, sockindex); - if(result) + /* see if we need to kick off any SOCKS proxy magic once we + connected */ + result = connect_SOCKS(conn, sockindex, connected); + if(result || !*connected) return result; - conn->bits.tcpconnect[sockindex] = TRUE; - - *connected = TRUE; - if(sockindex == FIRSTSOCKET) - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ - Curl_updateconninfo(conn, conn->sock[sockindex]); - Curl_verboseconnect(conn); + post_SOCKS(conn, sockindex, connected); return CURLE_OK; } @@ -1007,8 +1031,6 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - else - infof(data, "TCP_NODELAY set\n"); #else (void)conn; (void)sockfd; @@ -1216,8 +1238,6 @@ static CURLcode singleipconnect(struct connectdata *conn, if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd); - else - infof(data, "TCP_FASTOPEN_CONNECT set\n"); rc = connect(sockfd, &addr.sa_addr, addr.addrlen); #elif defined(MSG_FASTOPEN) /* old Linux */ @@ -1428,12 +1448,11 @@ int Curl_closesocket(struct connectdata *conn, curl_socket_t sock) { if(conn && conn->fclosesocket) { - if((sock == conn->sock[SECONDARYSOCKET]) && - conn->sock_accepted[SECONDARYSOCKET]) + if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted) /* if this socket matches the second socket, and that was created with accept, then we MUST NOT call the callback but clear the accepted status */ - conn->sock_accepted[SECONDARYSOCKET] = FALSE; + conn->sock_accepted = FALSE; else { int rc; Curl_multi_closed(conn->data, sock); diff --git a/release/src/router/curl/lib/cookie.c b/release/src/router/curl/lib/cookie.c index 0091132aa34..68054e1c4c7 100644 --- a/release/src/router/curl/lib/cookie.c +++ b/release/src/router/curl/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -97,6 +97,8 @@ Example set of cookies: #include "curl_memrchr.h" #include "inet_pton.h" #include "parsedate.h" +#include "rand.h" +#include "rename.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -243,18 +245,17 @@ static bool pathmatch(const char *cookie_path, const char *request_uri) */ static const char *get_top_domain(const char * const domain, size_t *outlen) { - size_t len; + size_t len = 0; const char *first = NULL, *last; - if(!domain) - return NULL; - - len = strlen(domain); - last = memrchr(domain, '.', len); - if(last) { - first = memrchr(domain, '.', (last - domain)); - if(first) - len -= (++first - domain); + if(domain) { + len = strlen(domain); + last = memrchr(domain, '.', len); + if(last) { + first = memrchr(domain, '.', (last - domain)); + if(first) + len -= (++first - domain); + } } if(outlen) @@ -537,9 +538,9 @@ Curl_cookie_add(struct Curl_easy *data, * only test for names where that can possibly be true. */ if(nlen > 3 && name[0] == '_' && name[1] == '_') { - if(strncasecompare("__Secure-", name, 9)) + if(!strncmp("__Secure-", name, 9)) co->prefix |= COOKIE_PREFIX__SECURE; - else if(strncasecompare("__Host-", name, 7)) + else if(!strncmp("__Host-", name, 7)) co->prefix |= COOKIE_PREFIX__HOST; } @@ -1046,7 +1047,7 @@ Curl_cookie_add(struct Curl_easy *data, *clist = *co; /* then store all the new data */ - free(co); /* free the newly alloced memory */ + free(co); /* free the newly allocated memory */ co = clist; /* point to the previous struct instead */ /* We have replaced a cookie, now skip the rest of the list but @@ -1501,11 +1502,14 @@ static char *get_netscape_format(const struct Cookie *co) * * The function returns non-zero on write failure. */ -static int cookie_output(struct CookieInfo *c, const char *dumphere) +static int cookie_output(struct Curl_easy *data, + struct CookieInfo *c, const char *filename) { struct Cookie *co; - FILE *out; + FILE *out = NULL; bool use_stdout = FALSE; + char *tempstore = NULL; + bool error = false; if(!c) /* no cookie engine alive */ @@ -1514,16 +1518,24 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) /* at first, remove expired cookies */ remove_expired(c); - if(!strcmp("-", dumphere)) { + if(!strcmp("-", filename)) { /* use stdout */ out = stdout; use_stdout = TRUE; } else { - out = fopen(dumphere, FOPEN_WRITETEXT); - if(!out) { - return 1; /* failure */ - } + unsigned char randsuffix[9]; + + if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) + return 2; + + tempstore = aprintf("%s.%s.tmp", filename, randsuffix); + if(!tempstore) + return 1; + + out = fopen(tempstore, FOPEN_WRITETEXT); + if(!out) + goto error; } fputs("# Netscape HTTP Cookie File\n" @@ -1538,9 +1550,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) array = calloc(1, sizeof(struct Cookie *) * c->numcookies); if(!array) { - if(!use_stdout) - fclose(out); - return 1; + goto error; } /* only sort the cookies with a domain property */ @@ -1559,9 +1569,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) if(format_ptr == NULL) { fprintf(out, "#\n# Fatal libcurl error\n"); free(array); - if(!use_stdout) - fclose(out); - return 1; + goto error; } fprintf(out, "%s\n", format_ptr); free(format_ptr); @@ -1569,10 +1577,24 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) free(array); } - if(!use_stdout) + + if(!use_stdout) { fclose(out); + out = NULL; + if(Curl_rename(tempstore, filename)) { + unlink(tempstore); + goto error; + } + } - return 0; + goto cleanup; +error: + error = true; +cleanup: + if(out && !use_stdout) + fclose(out); + free(tempstore); + return error ? 1 : 0; } static struct curl_slist *cookie_list(struct Curl_easy *data) @@ -1631,7 +1653,7 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); /* if we have a destination file for all the cookies to get dumped to */ - if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) + if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR])) infof(data, "WARNING: failed to save cookies in %s\n", data->set.str[STRING_COOKIEJAR]); } diff --git a/release/src/router/curl/lib/curl_config.h.cmake b/release/src/router/curl/lib/curl_config.h.cmake index 2c3b6562d43..98cdf514542 100644 --- a/release/src/router/curl/lib/curl_config.h.cmake +++ b/release/src/router/curl/lib/curl_config.h.cmake @@ -73,6 +73,9 @@ #define CURL_EXTERN_SYMBOL #endif +/* Allow SMB to work on Windows */ +#cmakedefine USE_WIN32_CRYPTO + /* Use Windows LDAP implementation */ #cmakedefine USE_WIN32_LDAP 1 @@ -452,9 +455,6 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_CRYPTO_H 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENSSL_ENGINE_H 1 - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_ERR_H 1 @@ -936,9 +936,6 @@ ${SIZEOF_TIME_T_CODE} /* if GnuTLS is enabled */ #cmakedefine USE_GNUTLS 1 -/* if PolarSSL is enabled */ -#cmakedefine USE_POLARSSL 1 - /* if Secure Transport is enabled */ #cmakedefine USE_SECTRANSP 1 diff --git a/release/src/router/curl/lib/curl_config.h.in b/release/src/router/curl/lib/curl_config.h.in index bb7f4e3402a..8f29f51c11b 100644 --- a/release/src/router/curl/lib/curl_config.h.in +++ b/release/src/router/curl/lib/curl_config.h.in @@ -435,6 +435,9 @@ /* Define to 1 if you have the `ssl' library (-lssl). */ #undef HAVE_LIBSSL +/* Define to 1 if you have the `wolfssh' library (-lwolfssh). */ +#undef HAVE_LIBWOLFSSH + /* if zlib is available */ #undef HAVE_LIBZ @@ -787,6 +790,9 @@ /* Define to 1 if you have the winsock.h header file. */ #undef HAVE_WINSOCK_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WOLFSSH_SSH_H + /* Define to 1 if you have the `wolfSSLv3_client_method' function. */ #undef HAVE_WOLFSSLV3_CLIENT_METHOD @@ -1050,6 +1056,9 @@ /* to enable SSPI support */ #undef USE_WINDOWS_SSPI +/* if wolfSSH is in use */ +#undef USE_WOLFSSH + /* if wolfSSL is enabled */ #undef USE_WOLFSSL diff --git a/release/src/router/curl/lib/curl_hmac.h b/release/src/router/curl/lib/curl_hmac.h index 756dc9e4cd2..3ff799bbda3 100644 --- a/release/src/router/curl/lib/curl_hmac.h +++ b/release/src/router/curl/lib/curl_hmac.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,6 +24,8 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#define HMAC_MD5_LENGTH 16 + typedef void (* HMAC_hinit_func)(void *context); typedef void (* HMAC_hupdate_func)(void *context, const unsigned char *data, @@ -62,6 +64,11 @@ int Curl_HMAC_update(HMAC_context *context, unsigned int len); int Curl_HMAC_final(HMAC_context *context, unsigned char *result); +CURLcode Curl_hmacit(const HMAC_params *hashparams, + const unsigned char *key, const size_t keylen, + const unsigned char *data, const size_t datalen, + unsigned char *output); + #endif #endif /* HEADER_CURL_HMAC_H */ diff --git a/release/src/router/curl/lib/curl_md4.h b/release/src/router/curl/lib/curl_md4.h index 82df708cee3..c7bb2098154 100644 --- a/release/src/router/curl/lib/curl_md4.h +++ b/release/src/router/curl/lib/curl_md4.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,8 @@ #define MD4_DIGEST_LENGTH 16 -void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len); +void Curl_md4it(unsigned char *output, const unsigned char *input, + const size_t len); #endif /* !defined(CURL_DISABLE_CRYPTO_AUTH) */ diff --git a/release/src/router/curl/lib/curl_md5.h b/release/src/router/curl/lib/curl_md5.h index aaf25f61bbd..dd464416a2e 100644 --- a/release/src/router/curl/lib/curl_md5.h +++ b/release/src/router/curl/lib/curl_md5.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,8 +49,8 @@ typedef struct { extern const MD5_params Curl_DIGEST_MD5[1]; extern const HMAC_params Curl_HMAC_MD5[1]; -void Curl_md5it(unsigned char *output, - const unsigned char *input); +void Curl_md5it(unsigned char *output, const unsigned char *input, + const size_t len); MD5_context * Curl_MD5_init(const MD5_params *md5params); CURLcode Curl_MD5_update(MD5_context *context, diff --git a/release/src/router/curl/lib/curl_ntlm_core.c b/release/src/router/curl/lib/curl_ntlm_core.c index 19f9b61d870..f9b823b4f6a 100644 --- a/release/src/router/curl/lib/curl_ntlm_core.c +++ b/release/src/router/curl/lib/curl_ntlm_core.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -120,7 +120,6 @@ #include "curl_memory.h" #include "memdebug.h" -#define NTLM_HMAC_MD5_LEN (16) #define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" #define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) @@ -567,25 +566,6 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) -/* This returns the HMAC MD5 digest */ -static CURLcode hmac_md5(const unsigned char *key, unsigned int keylen, - const unsigned char *data, unsigned int datalen, - unsigned char *output) -{ - HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen); - - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - /* Update the digest with the given challenge */ - Curl_HMAC_update(ctxt, data, datalen); - - /* Finalise the digest */ - Curl_HMAC_final(ctxt, output); - - return CURLE_OK; -} - /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode * (uppercase UserName + Domain) as the data */ @@ -615,8 +595,8 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, ascii_uppercase_to_unicode_le(identity, user, userlen); ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); - result = hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len), - ntlmv2hash); + result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len, + ntlmv2hash); free(identity); return result; @@ -662,7 +642,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, unsigned int len = 0; unsigned char *ptr = NULL; - unsigned char hmac_output[NTLM_HMAC_MD5_LEN]; + unsigned char hmac_output[HMAC_MD5_LENGTH]; curl_off_t tw; CURLcode result = CURLE_OK; @@ -681,7 +661,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000; /* Calculate the response len */ - len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN; + len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN; /* Allocate the response */ ptr = calloc(1, len); @@ -689,7 +669,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, return CURLE_OUT_OF_MEMORY; /* Create the BLOB structure */ - msnprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, + msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN, "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ "%c%c%c%c", /* Reserved = 0 */ NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], @@ -702,7 +682,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ memcpy(ptr + 8, &ntlm->nonce[0], 8); - result = hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8, + result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8, NTLMv2_BLOB_LEN + 8, hmac_output); if(result) { free(ptr); @@ -710,7 +690,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, } /* Concatenate the HMAC MD5 output with the BLOB */ - memcpy(ptr, hmac_output, NTLM_HMAC_MD5_LEN); + memcpy(ptr, hmac_output, HMAC_MD5_LENGTH); /* Return the response */ *ntresp = ptr; @@ -745,7 +725,8 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, memcpy(&data[0], challenge_server, 8); memcpy(&data[8], challenge_client, 8); - result = hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output); + result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16, + hmac_output); if(result) return result; diff --git a/release/src/router/curl/lib/curl_ntlm_core.h b/release/src/router/curl/lib/curl_ntlm_core.h index 392a1b81de0..e1643d62773 100644 --- a/release/src/router/curl/lib/curl_ntlm_core.h +++ b/release/src/router/curl/lib/curl_ntlm_core.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -46,11 +46,9 @@ #define USE_NTRESPONSES /* Define USE_NTLM2SESSION in order to make the type-3 message include the - NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a - Crypto engine that we have curl_ssl_md5sum() for. */ -#if defined(USE_NTRESPONSES) && \ - (!defined(USE_WIN32_CRYPTO) || \ - (defined(USE_SSL) && !defined(CURL_DISABLE_CRYPTO_AUTH))) + NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and + MD5 support */ +#if defined(USE_NTRESPONSES) && !defined(CURL_DISABLE_CRYPTO_AUTH) #define USE_NTLM2SESSION #endif diff --git a/release/src/router/curl/lib/curl_ntlm_wb.c b/release/src/router/curl/lib/curl_ntlm_wb.c index 30b54de4444..f820b842e84 100644 --- a/release/src/router/curl/lib/curl_ntlm_wb.c +++ b/release/src/router/curl/lib/curl_ntlm_wb.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -76,22 +76,22 @@ # define sclose_nolog(x) close((x)) #endif -void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) +static void ntlm_wb_cleanup(struct ntlmdata *ntlm) { - if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { - sclose(conn->ntlm_auth_hlpr_socket); - conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { + sclose(ntlm->ntlm_auth_hlpr_socket); + ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; } - if(conn->ntlm_auth_hlpr_pid) { + if(ntlm->ntlm_auth_hlpr_pid) { int i; for(i = 0; i < 4; i++) { - pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG); - if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD) + pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG); + if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD) break; switch(i) { case 0: - kill(conn->ntlm_auth_hlpr_pid, SIGTERM); + kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM); break; case 1: /* Give the process another moment to shut down cleanly before @@ -99,20 +99,21 @@ void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) Curl_wait_ms(1); break; case 2: - kill(conn->ntlm_auth_hlpr_pid, SIGKILL); + kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL); break; case 3: break; } } - conn->ntlm_auth_hlpr_pid = 0; + ntlm->ntlm_auth_hlpr_pid = 0; } - Curl_safefree(conn->challenge_header); - Curl_safefree(conn->response_header); + Curl_safefree(ntlm->challenge); + Curl_safefree(ntlm->response); } -static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) +static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm, + const char *userp) { curl_socket_t sockfds[2]; pid_t child_pid; @@ -126,9 +127,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) #endif char buffer[STRERROR_LEN]; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + /* Return if communication with ntlm_auth already set up */ - if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || - conn->ntlm_auth_hlpr_pid) + if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || + ntlm->ntlm_auth_hlpr_pid) return CURLE_OK; username = userp; @@ -179,13 +184,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) ntlm_auth = NTLM_WB_FILE; if(access(ntlm_auth, X_OK) != 0) { - failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", + failf(data, "Could not access ntlm_auth: %s errno %d: %s", ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } - if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { - failf(conn->data, "Could not open socket pair. errno %d: %s", + if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { + failf(data, "Could not open socket pair. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } @@ -194,7 +199,7 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) if(child_pid == -1) { sclose(sockfds[0]); sclose(sockfds[1]); - failf(conn->data, "Could not fork. errno %d: %s", + failf(data, "Could not fork. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } @@ -206,13 +211,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) /* Don't use sclose in the child since it fools the socket leak detector */ sclose_nolog(sockfds[0]); if(dup2(sockfds[1], STDIN_FILENO) == -1) { - failf(conn->data, "Could not redirect child stdin. errno %d: %s", + failf(data, "Could not redirect child stdin. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } if(dup2(sockfds[1], STDOUT_FILENO) == -1) { - failf(conn->data, "Could not redirect child stdout. errno %d: %s", + failf(data, "Could not redirect child stdout. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } @@ -232,14 +237,14 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) NULL); sclose_nolog(sockfds[1]); - failf(conn->data, "Could not execl(). errno %d: %s", + failf(data, "Could not execl(). errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } sclose(sockfds[1]); - conn->ntlm_auth_hlpr_socket = sockfds[0]; - conn->ntlm_auth_hlpr_pid = child_pid; + ntlm->ntlm_auth_hlpr_socket = sockfds[0]; + ntlm->ntlm_auth_hlpr_pid = child_pid; free(domain); free(ntlm_auth_alloc); return CURLE_OK; @@ -253,17 +258,21 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) /* if larger than this, something is seriously wrong */ #define MAX_NTLM_WB_RESPONSE 100000 -static CURLcode ntlm_wb_response(struct connectdata *conn, +static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, const char *input, curlntlm state) { char *buf = malloc(NTLM_BUFSIZE); size_t len_in = strlen(input), len_out = 0; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + if(!buf) return CURLE_OUT_OF_MEMORY; while(len_in > 0) { - ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in); + ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in); if(written == -1) { /* Interrupted by a signal, retry it */ if(errno == EINTR) @@ -279,7 +288,7 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, ssize_t size; char *newbuf; - size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); + size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); if(size == -1) { if(errno == EINTR) continue; @@ -295,7 +304,7 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, } if(len_out > MAX_NTLM_WB_RESPONSE) { - failf(conn->data, "too large ntlm_wb response!"); + failf(data, "too large ntlm_wb response!"); free(buf); return CURLE_OUT_OF_MEMORY; } @@ -323,9 +332,9 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) goto done; - conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3); + ntlm->response = aprintf("%.*s", len_out - 4, buf + 3); free(buf); - if(!conn->response_header) + if(!ntlm->response) return CURLE_OUT_OF_MEMORY; return CURLE_OK; done: @@ -337,6 +346,7 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy, const char *header) { + struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; if(!checkprefix("NTLM", header)) @@ -347,8 +357,8 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn, header++; if(*header) { - conn->challenge_header = strdup(header); - if(!conn->challenge_header) + ntlm->challenge = strdup(header); + if(!ntlm->challenge) return CURLE_OUT_OF_MEMORY; *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ @@ -387,6 +397,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, char **allocuserpwd; /* point to the name and password for this */ const char *userp; + struct ntlmdata *ntlm; curlntlm *state; struct auth *authp; @@ -398,12 +409,14 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; + ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; + ntlm = &conn->ntlm; state = &conn->http_ntlm_state; authp = &conn->data->state.authhost; } @@ -429,36 +442,36 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, * request handling process. */ /* Create communication with ntlm_auth */ - res = ntlm_wb_init(conn, userp); + res = ntlm_wb_init(conn->data, ntlm, userp); if(res) return res; - res = ntlm_wb_response(conn, "YR\n", *state); + res = ntlm_wb_response(conn->data, ntlm, "YR\n", *state); if(res) return res; free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", - conn->response_header); + ntlm->response); DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - Curl_safefree(conn->response_header); + Curl_safefree(ntlm->response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; break; case NTLMSTATE_TYPE2: { - char *input = aprintf("TT %s\n", conn->challenge_header); + char *input = aprintf("TT %s\n", ntlm->challenge); if(!input) return CURLE_OUT_OF_MEMORY; - res = ntlm_wb_response(conn, input, *state); + res = ntlm_wb_response(conn->data, ntlm, input, *state); free(input); if(res) return res; free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", - conn->response_header); + ntlm->response); DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); *state = NTLMSTATE_TYPE3; /* we sent a type-3 */ authp->done = TRUE; @@ -481,4 +494,10 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, return CURLE_OK; } +void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) +{ + ntlm_wb_cleanup(&conn->ntlm); + ntlm_wb_cleanup(&conn->proxyntlm); +} + #endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ diff --git a/release/src/router/curl/lib/curl_sasl.c b/release/src/router/curl/lib/curl_sasl.c index 0aa1f5bb7a6..8c1c86623de 100644 --- a/release/src/router/curl/lib/curl_sasl.c +++ b/release/src/router/curl/lib/curl_sasl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -272,6 +272,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, data->set.str[STRING_SERVICE_NAME] : sasl->params->service; #endif + const char *oauth_bearer = data->set.str[STRING_BEARER]; sasl->force_ir = force_ir; /* Latch for future use */ sasl->authused = 0; /* No mechanism used yet */ @@ -341,7 +342,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, } else #endif - if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) { + if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { mech = SASL_MECH_STRING_OAUTHBEARER; state1 = SASL_OAUTH2; state2 = SASL_OAUTH2_RESP; @@ -351,17 +352,17 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, result = Curl_auth_create_oauth_bearer_message(data, conn->user, hostname, port, - conn->oauth_bearer, + oauth_bearer, &resp, &len); } - else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { + else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { mech = SASL_MECH_STRING_XOAUTH2; state1 = SASL_OAUTH2; sasl->authused = SASL_MECH_XOAUTH2; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_xoauth_bearer_message(data, conn->user, - conn->oauth_bearer, + oauth_bearer, &resp, &len); } else if(enabledmechs & SASL_MECH_PLAIN) { @@ -431,6 +432,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, char *serverdata; #endif size_t len = 0; + const char *oauth_bearer = data->set.str[STRING_BEARER]; *progress = SASL_INPROGRESS; @@ -558,7 +560,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, result = Curl_auth_create_oauth_bearer_message(data, conn->user, hostname, port, - conn->oauth_bearer, + oauth_bearer, &resp, &len); /* Failures maybe sent by the server as continuations for OAUTHBEARER */ @@ -566,7 +568,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, } else result = Curl_auth_create_xoauth_bearer_message(data, conn->user, - conn->oauth_bearer, + oauth_bearer, &resp, &len); break; diff --git a/release/src/router/curl/lib/curl_sha256.h b/release/src/router/curl/lib/curl_sha256.h index 14b6414ea0a..35d286cebda 100644 --- a/release/src/router/curl/lib/curl_sha256.h +++ b/release/src/router/curl/lib/curl_sha256.h @@ -7,7 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Florin Petriuc, + * Copyright (C) 2017, Florin Petriuc, + * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,8 +25,10 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH -void Curl_sha256it(unsigned char *outbuffer, - const unsigned char *input); +#define SHA256_DIGEST_LENGTH 32 + +void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, + const size_t len); #endif diff --git a/release/src/router/curl/lib/doh.c b/release/src/router/curl/lib/doh.c index 7f4eee5d815..aaa8f15ca6f 100644 --- a/release/src/router/curl/lib/doh.c +++ b/release/src/router/curl/lib/doh.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -548,7 +548,7 @@ static DOHcode store_cname(unsigned char *doh, if((index + 1) >= dohlen) return DOH_DNS_OUT_OF_RANGE; - /* move to the the new index */ + /* move to the new index */ newpos = (length & 0x3f) << 8 | doh[index + 1]; index = newpos; continue; diff --git a/release/src/router/curl/lib/easy.c b/release/src/router/curl/lib/easy.c index 6382cee3d5d..b648e80c142 100644 --- a/release/src/router/curl/lib/easy.c +++ b/release/src/router/curl/lib/easy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -76,14 +76,13 @@ #include "setopt.h" #include "http_digest.h" #include "system_win32.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -void Curl_version_init(void); - /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; @@ -185,21 +184,21 @@ static CURLcode global_init(long flags, bool memoryfuncs) goto fail; } - (void)Curl_ipv6works(); - #if defined(USE_SSH) if(Curl_ssh_init()) { goto fail; } #endif - if(flags & CURL_GLOBAL_ACK_EINTR) - Curl_ack_eintr = 1; +#ifdef USE_WOLFSSH + if(WS_SUCCESS != wolfSSH_Init()) { + DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); + return CURLE_FAILED_INIT; + } +#endif init_flags = flags; - Curl_version_init(); - return CURLE_OK; fail: @@ -272,6 +271,10 @@ void curl_global_cleanup(void) Curl_ssh_cleanup(); +#ifdef USE_WOLFSSH + (void)wolfSSH_Cleanup(); +#endif + init_flags = 0; } @@ -684,10 +687,6 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) sigpipe_ignore(data, &pipe_st); - /* assign this after curl_multi_add_handle() since that function checks for - it and rejects this handle otherwise */ - data->multi = multi; - /* run the transfer */ result = events ? easy_events(multi) : easy_transfer(multi); @@ -884,6 +883,17 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) data->state.resolver)) goto fail; +#ifdef USE_ARES + if(Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS])) + goto fail; + if(Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE])) + goto fail; + if(Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4])) + goto fail; + if(Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6])) + goto fail; +#endif /* USE_ARES */ + Curl_convert_setup(outcurl); Curl_initinfo(outcurl); @@ -970,56 +980,81 @@ void curl_easy_reset(struct Curl_easy *data) */ CURLcode curl_easy_pause(struct Curl_easy *data, int action) { - struct SingleRequest *k = &data->req; + struct SingleRequest *k; CURLcode result = CURLE_OK; + int oldstate; + int newstate; + + if(!GOOD_EASY_HANDLE(data) || !data->conn) + /* crazy input, don't continue */ + return CURLE_BAD_FUNCTION_ARGUMENT; - /* first switch off both pause bits */ - int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); + k = &data->req; + oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); - /* set the new desired pause bits */ - newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | + /* first switch off both pause bits then set the new pause bits */ + newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) | + ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); + if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) { + /* Not changing any pause state, return */ + DEBUGF(infof(data, "pause: no change, early return\n")); + return CURLE_OK; + } + + /* Unpause parts in active mime tree. */ + if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && + (data->mstate == CURLM_STATE_PERFORM || + data->mstate == CURLM_STATE_TOOFAST) && + data->state.fread_func == (curl_read_callback) Curl_mime_read) { + Curl_mime_unpause(data->state.in); + } + /* put it back in the keepon */ k->keepon = newstate; - if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) { - /* there are buffers for sending that can be delivered as the receive - pausing is lifted! */ - unsigned int i; - unsigned int count = data->state.tempcount; - struct tempbuf writebuf[3]; /* there can only be three */ - struct connectdata *conn = data->conn; - struct Curl_easy *saved_data = NULL; - - /* copy the structs to allow for immediate re-pausing */ - for(i = 0; i < data->state.tempcount; i++) { - writebuf[i] = data->state.tempwrite[i]; - data->state.tempwrite[i].buf = NULL; - } - data->state.tempcount = 0; + if(!(newstate & KEEP_RECV_PAUSE)) { + Curl_http2_stream_pause(data, FALSE); + + if(data->state.tempcount) { + /* there are buffers for sending that can be delivered as the receive + pausing is lifted! */ + unsigned int i; + unsigned int count = data->state.tempcount; + struct tempbuf writebuf[3]; /* there can only be three */ + struct connectdata *conn = data->conn; + struct Curl_easy *saved_data = NULL; + + /* copy the structs to allow for immediate re-pausing */ + for(i = 0; i < data->state.tempcount; i++) { + writebuf[i] = data->state.tempwrite[i]; + data->state.tempwrite[i].buf = NULL; + } + data->state.tempcount = 0; - /* set the connection's current owner */ - if(conn->data != data) { - saved_data = conn->data; - conn->data = data; - } + /* set the connection's current owner */ + if(conn->data != data) { + saved_data = conn->data; + conn->data = data; + } - for(i = 0; i < count; i++) { - /* even if one function returns error, this loops through and frees all - buffers */ - if(!result) - result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf, - writebuf[i].len); - free(writebuf[i].buf); - } + for(i = 0; i < count; i++) { + /* even if one function returns error, this loops through and frees + all buffers */ + if(!result) + result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf, + writebuf[i].len); + free(writebuf[i].buf); + } - /* recover previous owner of the connection */ - if(saved_data) - conn->data = saved_data; + /* recover previous owner of the connection */ + if(saved_data) + conn->data = saved_data; - if(result) - return result; + if(result) + return result; + } } /* if there's no error and we're not pausing both directions, we want @@ -1027,6 +1062,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ + + /* force a recv/send check of this connection, as the data might've been + read off the socket already */ + data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; if(data->multi) Curl_update_timer(data->multi); } diff --git a/release/src/router/curl/lib/formdata.c b/release/src/router/curl/lib/formdata.c index 429d479da5d..57ec6ad2549 100644 --- a/release/src/router/curl/lib/formdata.c +++ b/release/src/router/curl/lib/formdata.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -728,14 +728,10 @@ int curl_formget(struct curl_httppost *form, void *arg, if(!nread) break; - switch(nread) { - default: - if(append(arg, buffer, nread) != nread) - result = CURLE_READ_ERROR; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - break; + if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) { + result = CURLE_READ_ERROR; + if(nread == CURL_READFUNC_ABORT) + result = CURLE_ABORTED_BY_CALLBACK; } } diff --git a/release/src/router/curl/lib/ftp.c b/release/src/router/curl/lib/ftp.c index 469096f0f69..57b22ade976 100644 --- a/release/src/router/curl/lib/ftp.c +++ b/release/src/router/curl/lib/ftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,7 +55,6 @@ #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ -#include "socks.h" #include "ftp.h" #include "fileinfo.h" #include "ftplistparser.h" @@ -78,6 +77,7 @@ #include "warnless.h" #include "http_proxy.h" #include "non-ascii.h" +#include "socks.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -253,18 +253,6 @@ static void freedirs(struct ftp_conn *ftpc) Curl_safefree(ftpc->newhost); } -/* Returns non-zero if the given string contains CR (\r) or LF (\n), - which are not allowed within RFC 959 . - Note: The input string is in the client's encoding which might - not be ASCII, so escape sequences \r & \n must be used instead - of hex values 0x0d & 0x0a. -*/ -static bool isBadFtpString(const char *string) -{ - return ((NULL != strchr(string, '\r')) || - (NULL != strchr(string, '\n'))) ? TRUE : FALSE; -} - /*********************************************************************** * * AcceptServerConnect() @@ -303,7 +291,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) conn->sock[SECONDARYSOCKET] = s; (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ - conn->sock_accepted[SECONDARYSOCKET] = TRUE; + conn->sock_accepted = TRUE; if(data->set.fsockopt) { int error = 0; @@ -785,9 +773,8 @@ static void _state(struct connectdata *conn, static CURLcode ftp_state_user(struct connectdata *conn) { CURLcode result; - struct FTP *ftp = conn->data->req.protop; /* send USER */ - PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:""); + PPSENDF(&conn->proto.ftpc.pp, "USER %s", conn->user?conn->user:""); state(conn, FTP_USER); conn->data->state.ftp_trying_alternative = FALSE; @@ -823,6 +810,9 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks) * handle ordinary commands. */ + if(SOCKS_STATE(conn->cnnct.state)) + return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET); + if(FTP_STOP == ftpc->state) { int bits = GETSOCK_READSOCK(0); @@ -920,7 +910,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, struct ftp_conn *ftpc = &conn->proto.ftpc; struct Curl_easy *data = conn->data; curl_socket_t portsock = CURL_SOCKET_BAD; - char myhost[256] = ""; + char myhost[MAX_IPADR_LEN + 1] = ""; struct Curl_sockaddr_storage ss; Curl_addrinfo *res, *ai; @@ -931,9 +921,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, #ifdef ENABLE_IPV6 struct sockaddr_in6 * const sa6 = (void *)sa; #endif - char tmp[1024]; static const char mode[][5] = { "EPRT", "PORT" }; - int rc; + enum resolve_t rc; int error; char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; @@ -1246,8 +1235,10 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, break; } if(PORT == fcmd) { + /* large enough for [IP address],[num],[num] */ + char target[sizeof(myhost) + 20]; char *source = myhost; - char *dest = tmp; + char *dest = target; /* translate x.x.x.x to x,x,x,x */ while(source && *source) { @@ -1261,7 +1252,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, *dest = 0; msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); - result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); + result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], target); if(result) { failf(data, "Failure sending PORT command: %s", curl_easy_strerror(result)); @@ -1806,7 +1797,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, CURLcode result; struct Curl_easy *data = conn->data; struct Curl_dns_entry *addr = NULL; - int rc; + enum resolve_t rc; unsigned short connectport; /* the local port connect() should use! */ char *str = &data->state.buffer[4]; /* start on the first letter */ @@ -2528,7 +2519,6 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; (void)instate; /* no use for this yet */ @@ -2536,7 +2526,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, if((ftpcode == 331) && (ftpc->state == FTP_USER)) { /* 331 Password required for ... (the server requires to send the user's password too) */ - PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:""); + PPSENDF(&ftpc->pp, "PASS %s", conn->passwd?conn->passwd:""); state(conn, FTP_PASS); } else if(ftpcode/100 == 2) { @@ -4369,18 +4359,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn) /* get some initial data into the ftp struct */ ftp->transfer = FTPTRANSFER_BODY; ftp->downloadsize = 0; - - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - ftp->user = conn->user; - ftp->passwd = conn->passwd; - if(isBadFtpString(ftp->user)) - return CURLE_URL_MALFORMAT; - if(isBadFtpString(ftp->passwd)) - return CURLE_URL_MALFORMAT; - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ return CURLE_OK; diff --git a/release/src/router/curl/lib/ftp.h b/release/src/router/curl/lib/ftp.h index 2c88d568c1f..984347f2a37 100644 --- a/release/src/router/curl/lib/ftp.h +++ b/release/src/router/curl/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -102,8 +102,6 @@ typedef enum { perhaps the Curl_easy is changed between the times the connection is used. */ struct FTP { - char *user; /* user name string */ - char *passwd; /* password string */ char *path; /* points to the urlpieces struct field */ char *pathalloc; /* if non-NULL a pointer to an allocated path */ diff --git a/release/src/router/curl/lib/getenv.c b/release/src/router/curl/lib/getenv.c index e444a6a3adc..9385b8f677f 100644 --- a/release/src/router/curl/lib/getenv.c +++ b/release/src/router/curl/lib/getenv.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,25 +27,48 @@ #include "memdebug.h" -static -char *GetEnv(const char *variable) +static char *GetEnv(const char *variable) { #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) (void)variable; return NULL; -#else -#ifdef WIN32 - char env[4096]; - char *temp = getenv(variable); - env[0] = '\0'; - if(temp != NULL) - ExpandEnvironmentStringsA(temp, env, sizeof(env)); - return (env[0] != '\0')?strdup(env):NULL; +#elif defined(WIN32) + /* This uses Windows API instead of C runtime getenv() to get the environment + variable since some changes aren't always visible to the latter. #4774 */ + char *buf = NULL; + char *tmp; + DWORD bufsize; + DWORD rc = 1; + const DWORD max = 32768; /* max env var size from MSCRT source */ + + for(;;) { + tmp = realloc(buf, rc); + if(!tmp) { + free(buf); + return NULL; + } + + buf = tmp; + bufsize = rc; + + /* It's possible for rc to be 0 if the variable was found but empty. + Since getenv doesn't make that distinction we ignore it as well. */ + rc = GetEnvironmentVariableA(variable, buf, bufsize); + if(!rc || rc == bufsize || rc > max) { + free(buf); + return NULL; + } + + /* if rc < bufsize then rc is bytes written not including null */ + if(rc < bufsize) + return buf; + + /* else rc is bytes needed, try again */ + } #else char *env = getenv(variable); return (env && env[0])?strdup(env):NULL; #endif -#endif } char *curl_getenv(const char *v) diff --git a/release/src/router/curl/lib/hmac.c b/release/src/router/curl/lib/hmac.c index bf49ebec54d..ae68827bea0 100644 --- a/release/src/router/curl/lib/hmac.c +++ b/release/src/router/curl/lib/hmac.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,7 @@ #include "curl_hmac.h" #include "curl_memory.h" +#include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" @@ -129,4 +130,40 @@ int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) return 0; } +/* + * Curl_hmacit() + * + * This is used to generate a HMAC hash, for the specified input data, given + * the specified hash function and key. + * + * Parameters: + * + * hashparams [in] - The hash function (Curl_HMAC_MD5). + * key [in] - The key to use. + * keylen [in] - The length of the key. + * data [in] - The data to encrypt. + * datalen [in] - The length of the data. + * output [in/out] - The output buffer. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_hmacit(const HMAC_params *hashparams, + const unsigned char *key, const size_t keylen, + const unsigned char *data, const size_t datalen, + unsigned char *output) +{ + HMAC_context *ctxt = Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen)); + + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen)); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, output); + + return CURLE_OK; +} + #endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/release/src/router/curl/lib/hostip.c b/release/src/router/curl/lib/hostip.c index b434b390a29..c0feb79fb36 100644 --- a/release/src/router/curl/lib/hostip.c +++ b/release/src/router/curl/lib/hostip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -59,6 +59,7 @@ #include "strerror.h" #include "url.h" #include "inet_ntop.h" +#include "inet_pton.h" #include "multiif.h" #include "doh.h" #include "warnless.h" @@ -482,16 +483,16 @@ Curl_cache_addr(struct Curl_easy *data, * CURLRESOLV_PENDING (1) = waiting for response, no pointer */ -int Curl_resolv(struct connectdata *conn, - const char *hostname, - int port, - bool allowDOH, - struct Curl_dns_entry **entry) +enum resolve_t Curl_resolv(struct connectdata *conn, + const char *hostname, + int port, + bool allowDOH, + struct Curl_dns_entry **entry) { struct Curl_dns_entry *dns = NULL; struct Curl_easy *data = conn->data; CURLcode result; - int rc = CURLRESOLV_ERROR; /* default to failure */ + enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; @@ -512,13 +513,11 @@ int Curl_resolv(struct connectdata *conn, if(!dns) { /* The entry was not in the cache. Resolve it to IP address */ - Curl_addrinfo *addr; + Curl_addrinfo *addr = NULL; int respwait = 0; - - /* Check what IP specifics the app has requested and if we can provide it. - * If not, bail out. */ - if(!Curl_ipvalid(conn)) - return CURLRESOLV_ERROR; +#ifndef USE_RESOLVE_ON_IPS + struct in_addr in; +#endif /* notify the resolver start callback */ if(data->set.resolver_start) { @@ -531,20 +530,43 @@ int Curl_resolv(struct connectdata *conn, return CURLRESOLV_ERROR; } - if(allowDOH && data->set.doh) { - addr = Curl_doh(conn, hostname, port, &respwait); +#ifndef USE_RESOLVE_ON_IPS + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + addr = Curl_ip2addr(AF_INET, &in, hostname, port); +#ifdef ENABLE_IPV6 + if(!addr) { + struct in6_addr in6; + /* check if this is an IPv6 address string */ + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + addr = Curl_ip2addr(AF_INET6, &in6, hostname, port); } - else { - /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a - non-zero value indicating that we need to wait for the response to the - resolve call */ - addr = Curl_getaddrinfo(conn, +#endif /* ENABLE_IPV6 */ +#endif /* !USE_RESOLVE_ON_IPS */ + + if(!addr) { + /* Check what IP specifics the app has requested and if we can provide + * it. If not, bail out. */ + if(!Curl_ipvalid(conn)) + return CURLRESOLV_ERROR; + + if(allowDOH && data->set.doh) { + addr = Curl_doh(conn, hostname, port, &respwait); + } + else { + /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a + non-zero value indicating that we need to wait for the response to + the resolve call */ + addr = Curl_getaddrinfo(conn, #ifdef DEBUGBUILD - (data->set.str[STRING_DEVICE] - && !strcmp(data->set.str[STRING_DEVICE], - "LocalHost"))?"localhost": + (data->set.str[STRING_DEVICE] + && !strcmp(data->set.str[STRING_DEVICE], + "LocalHost"))?"localhost": #endif - hostname, port, &respwait); + hostname, port, &respwait); + } } if(!addr) { if(respwait) { @@ -620,11 +642,11 @@ RETSIGTYPE alarmfunc(int sig) * CURLRESOLV_PENDING (1) = waiting for response, no pointer */ -int Curl_resolv_timeout(struct connectdata *conn, - const char *hostname, - int port, - struct Curl_dns_entry **entry, - timediff_t timeoutms) +enum resolve_t Curl_resolv_timeout(struct connectdata *conn, + const char *hostname, + int port, + struct Curl_dns_entry **entry, + timediff_t timeoutms) { #ifdef USE_ALARM_TIMEOUT #ifdef HAVE_SIGACTION @@ -640,7 +662,7 @@ int Curl_resolv_timeout(struct connectdata *conn, volatile unsigned int prev_alarm = 0; struct Curl_easy *data = conn->data; #endif /* USE_ALARM_TIMEOUT */ - int rc; + enum resolve_t rc; *entry = NULL; diff --git a/release/src/router/curl/lib/hostip.h b/release/src/router/curl/lib/hostip.h index e0597ea96a0..baf1e5860af 100644 --- a/release/src/router/curl/lib/hostip.h +++ b/release/src/router/curl/lib/hostip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -79,26 +79,29 @@ struct Curl_dns_entry { * use, or we'll leak memory! */ /* return codes */ -#define CURLRESOLV_TIMEDOUT -2 -#define CURLRESOLV_ERROR -1 -#define CURLRESOLV_RESOLVED 0 -#define CURLRESOLV_PENDING 1 -int Curl_resolv(struct connectdata *conn, - const char *hostname, - int port, - bool allowDOH, - struct Curl_dns_entry **dnsentry); -int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, - int port, struct Curl_dns_entry **dnsentry, - timediff_t timeoutms); +enum resolve_t { + CURLRESOLV_TIMEDOUT = -2, + CURLRESOLV_ERROR = -1, + CURLRESOLV_RESOLVED = 0, + CURLRESOLV_PENDING = 1 +}; +enum resolve_t Curl_resolv(struct connectdata *conn, + const char *hostname, + int port, + bool allowDOH, + struct Curl_dns_entry **dnsentry); +enum resolve_t Curl_resolv_timeout(struct connectdata *conn, + const char *hostname, int port, + struct Curl_dns_entry **dnsentry, + timediff_t timeoutms); #ifdef CURLRES_IPV6 /* * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ -bool Curl_ipv6works(void); +bool Curl_ipv6works(struct connectdata *conn); #else -#define Curl_ipv6works() FALSE +#define Curl_ipv6works(x) FALSE #endif /* diff --git a/release/src/router/curl/lib/hostip4.c b/release/src/router/curl/lib/hostip4.c index 2636851e681..d5009a3efb9 100644 --- a/release/src/router/curl/lib/hostip4.c +++ b/release/src/router/curl/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,7 +52,6 @@ #include "share.h" #include "strerror.h" #include "url.h" -#include "inet_pton.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -128,38 +127,22 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, #endif Curl_addrinfo *ai = NULL; struct hostent *h = NULL; - struct in_addr in; struct hostent *buf = NULL; -#ifdef ENABLE_IPV6 - { - struct in6_addr in6; - /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) - /* This is an IPv6 address literal */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } -#endif /* ENABLE_IPV6 */ - - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - #if defined(HAVE_GETADDRINFO_THREADSAFE) - else { - struct addrinfo hints; - char sbuf[12]; - char *sbufptr = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - if(port) { - msnprintf(sbuf, sizeof(sbuf), "%d", port); - sbufptr = sbuf; - } + struct addrinfo hints; + char sbuf[12]; + char *sbufptr = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + if(port) { + msnprintf(sbuf, sizeof(sbuf), "%d", port); + sbufptr = sbuf; + } - (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai); + (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai); #elif defined(HAVE_GETHOSTBYNAME_R) /* @@ -167,144 +150,141 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, * Since there are three different versions of it, the following code is * somewhat #ifdef-ridden. */ - else { - int h_errnop; - - buf = calloc(1, CURL_HOSTENT_SIZE); - if(!buf) - return NULL; /* major failure */ - /* - * The clearing of the buffer is a workaround for a gethostbyname_r bug in - * qnx nto and it is also _required_ for some of these functions on some - * platforms. - */ + int h_errnop; + + buf = calloc(1, CURL_HOSTENT_SIZE); + if(!buf) + return NULL; /* major failure */ + /* + * The clearing of the buffer is a workaround for a gethostbyname_r bug in + * qnx nto and it is also _required_ for some of these functions on some + * platforms. + */ #if defined(HAVE_GETHOSTBYNAME_R_5) - /* Solaris, IRIX and more */ - h = gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h_errnop); - - /* If the buffer is too small, it returns NULL and sets errno to - * ERANGE. The errno is thread safe if this is compiled with - * -D_REENTRANT as then the 'errno' variable is a macro defined to get - * used properly for threads. - */ + /* Solaris, IRIX and more */ + h = gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h_errnop); + + /* If the buffer is too small, it returns NULL and sets errno to + * ERANGE. The errno is thread safe if this is compiled with + * -D_REENTRANT as then the 'errno' variable is a macro defined to get + * used properly for threads. + */ - if(h) { - ; - } - else + if(h) { + ; + } + else #elif defined(HAVE_GETHOSTBYNAME_R_6) - /* Linux */ - - (void)gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h, /* DIFFERENCE */ - &h_errnop); - /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a - * sudden this function returns EAGAIN if the given buffer size is too - * small. Previous versions are known to return ERANGE for the same - * problem. - * - * This wouldn't be such a big problem if older versions wouldn't - * sometimes return EAGAIN on a common failure case. Alas, we can't - * assume that EAGAIN *or* ERANGE means ERANGE for any given version of - * glibc. - * - * For now, we do that and thus we may call the function repeatedly and - * fail for older glibc versions that return EAGAIN, until we run out of - * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). - * - * If anyone has a better fix, please tell us! - * - * ------------------------------------------------------------------- - * - * On October 23rd 2003, Dan C dug up more details on the mysteries of - * gethostbyname_r() in glibc: - * - * In glibc 2.2.5 the interface is different (this has also been - * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't - * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 - * (shipped/upgraded by Redhat 7.2) don't show this behavior! - * - * In this "buggy" version, the return code is -1 on error and 'errno' - * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a - * thread-safe variable. - */ + /* Linux */ + + (void)gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h, /* DIFFERENCE */ + &h_errnop); + /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a + * sudden this function returns EAGAIN if the given buffer size is too + * small. Previous versions are known to return ERANGE for the same + * problem. + * + * This wouldn't be such a big problem if older versions wouldn't + * sometimes return EAGAIN on a common failure case. Alas, we can't + * assume that EAGAIN *or* ERANGE means ERANGE for any given version of + * glibc. + * + * For now, we do that and thus we may call the function repeatedly and + * fail for older glibc versions that return EAGAIN, until we run out of + * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). + * + * If anyone has a better fix, please tell us! + * + * ------------------------------------------------------------------- + * + * On October 23rd 2003, Dan C dug up more details on the mysteries of + * gethostbyname_r() in glibc: + * + * In glibc 2.2.5 the interface is different (this has also been + * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't + * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 + * (shipped/upgraded by Redhat 7.2) don't show this behavior! + * + * In this "buggy" version, the return code is -1 on error and 'errno' + * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a + * thread-safe variable. + */ - if(!h) /* failure */ + if(!h) /* failure */ #elif defined(HAVE_GETHOSTBYNAME_R_3) - /* AIX, Digital Unix/Tru64, HPUX 10, more? */ - - /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of - * the plain fact that it does not return unique full buffers on each - * call, but instead several of the pointers in the hostent structs will - * point to the same actual data! This have the unfortunate down-side that - * our caching system breaks down horribly. Luckily for us though, AIX 4.3 - * and more recent versions have a "completely thread-safe"[*] libc where - * all the data is stored in thread-specific memory areas making calls to - * the plain old gethostbyname() work fine even for multi-threaded - * programs. - * - * This AIX 4.3 or later detection is all made in the configure script. - * - * Troels Walsted Hansen helped us work this out on March 3rd, 2003. - * - * [*] = much later we've found out that it isn't at all "completely - * thread-safe", but at least the gethostbyname() function is. + /* AIX, Digital Unix/Tru64, HPUX 10, more? */ + + /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of + * the plain fact that it does not return unique full buffers on each + * call, but instead several of the pointers in the hostent structs will + * point to the same actual data! This have the unfortunate down-side that + * our caching system breaks down horribly. Luckily for us though, AIX 4.3 + * and more recent versions have a "completely thread-safe"[*] libc where + * all the data is stored in thread-specific memory areas making calls to + * the plain old gethostbyname() work fine even for multi-threaded + * programs. + * + * This AIX 4.3 or later detection is all made in the configure script. + * + * Troels Walsted Hansen helped us work this out on March 3rd, 2003. + * + * [*] = much later we've found out that it isn't at all "completely + * thread-safe", but at least the gethostbyname() function is. + */ + + if(CURL_HOSTENT_SIZE >= + (sizeof(struct hostent) + sizeof(struct hostent_data))) { + + /* August 22nd, 2000: Albert Chin-A-Young brought an updated version + * that should work! September 20: Richard Prescott worked on the buffer + * size dilemma. */ - if(CURL_HOSTENT_SIZE >= - (sizeof(struct hostent) + sizeof(struct hostent_data))) { - - /* August 22nd, 2000: Albert Chin-A-Young brought an updated version - * that should work! September 20: Richard Prescott worked on the buffer - * size dilemma. - */ - - res = gethostbyname_r(hostname, - (struct hostent *)buf, - (struct hostent_data *)((char *)buf + - sizeof(struct hostent))); - h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */ - } - else - res = -1; /* failure, too smallish buffer size */ - - if(!res) { /* success */ - - h = buf; /* result expected in h */ - - /* This is the worst kind of the different gethostbyname_r() interfaces. - * Since we don't know how big buffer this particular lookup required, - * we can't realloc down the huge alloc without doing closer analysis of - * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every - * name lookup. Fixing this would require an extra malloc() and then - * calling Curl_addrinfo_copy() that subsequent realloc()s down the new - * memory area to the actually used amount. - */ - } - else + res = gethostbyname_r(hostname, + (struct hostent *)buf, + (struct hostent_data *)((char *)buf + + sizeof(struct hostent))); + h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */ + } + else + res = -1; /* failure, too smallish buffer size */ + + if(!res) { /* success */ + + h = buf; /* result expected in h */ + + /* This is the worst kind of the different gethostbyname_r() interfaces. + * Since we don't know how big buffer this particular lookup required, + * we can't realloc down the huge alloc without doing closer analysis of + * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every + * name lookup. Fixing this would require an extra malloc() and then + * calling Curl_addrinfo_copy() that subsequent realloc()s down the new + * memory area to the actually used amount. + */ + } + else #endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */ - { - h = NULL; /* set return code to NULL */ - free(buf); - } + { + h = NULL; /* set return code to NULL */ + free(buf); + } #else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ - /* - * Here is code for platforms that don't have a thread safe - * getaddrinfo() nor gethostbyname_r() function or for which - * gethostbyname() is the preferred one. - */ - else { - h = gethostbyname((void *)hostname); + /* + * Here is code for platforms that don't have a thread safe + * getaddrinfo() nor gethostbyname_r() function or for which + * gethostbyname() is the preferred one. + */ + h = gethostbyname((void *)hostname); #endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ - } if(h) { ai = Curl_he2ai(h, port); diff --git a/release/src/router/curl/lib/hostip6.c b/release/src/router/curl/lib/hostip6.c index e0e0c58dfaa..41ff9869643 100644 --- a/release/src/router/curl/lib/hostip6.c +++ b/release/src/router/curl/lib/hostip6.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -62,13 +62,19 @@ /* * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ -bool Curl_ipv6works(void) +bool Curl_ipv6works(struct connectdata *conn) { - /* the nature of most system is that IPv6 status doesn't come and go - during a program's lifetime so we only probe the first time and then we - have the info kept for fast re-use */ - static int ipv6_works = -1; - if(-1 == ipv6_works) { + if(conn) { + /* the nature of most system is that IPv6 status doesn't come and go + during a program's lifetime so we only probe the first time and then we + have the info kept for fast re-use */ + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + DEBUGASSERT(conn->data->multi); + return conn->data->multi->ipv6_works; + } + else { + int ipv6_works = -1; /* probe to see if we have a working IPv6 stack */ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); if(s == CURL_SOCKET_BAD) @@ -78,8 +84,8 @@ bool Curl_ipv6works(void) ipv6_works = 1; Curl_closesocket(NULL, s); } + return (ipv6_works>0)?TRUE:FALSE; } - return (ipv6_works>0)?TRUE:FALSE; } /* @@ -89,7 +95,7 @@ bool Curl_ipv6works(void) bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) - return Curl_ipv6works(); + return Curl_ipv6works(conn); return TRUE; } @@ -159,7 +165,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, break; } - if((pf != PF_INET) && !Curl_ipv6works()) + if((pf != PF_INET) && !Curl_ipv6works(conn)) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; diff --git a/release/src/router/curl/lib/http.c b/release/src/router/curl/lib/http.c index 837f53c415a..bff3adc1701 100644 --- a/release/src/router/curl/lib/http.c +++ b/release/src/router/curl/lib/http.c @@ -344,7 +344,7 @@ static CURLcode http_output_bearer(struct connectdata *conn) userp = &conn->allocptr.userpwd; free(*userp); *userp = aprintf("Authorization: Bearer %s\r\n", - conn->oauth_bearer); + conn->data->set.str[STRING_BEARER]); if(!*userp) { result = CURLE_OUT_OF_MEMORY; @@ -555,7 +555,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) CURLcode result = CURLE_OK; unsigned long authmask = ~0ul; - if(!conn->oauth_bearer) + if(!data->set.str[STRING_BEARER]) authmask &= (unsigned long)~CURLAUTH_BEARER; if(100 <= data->req.httpcode && 199 >= data->req.httpcode) @@ -565,7 +565,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if(data->state.authproblem) return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; - if((conn->bits.user_passwd || conn->oauth_bearer) && + if((conn->bits.user_passwd || data->set.str[STRING_BEARER]) && ((data->req.httpcode == 401) || (conn->bits.authneg && data->req.httpcode < 300))) { pickhost = pickoneauth(&data->state.authhost, authmask); @@ -641,9 +641,7 @@ output_auth_headers(struct connectdata *conn, { const char *auth = NULL; CURLcode result = CURLE_OK; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) struct Curl_easy *data = conn->data; -#endif #ifdef CURL_DISABLE_CRYPTO_AUTH (void)request; @@ -707,7 +705,7 @@ output_auth_headers(struct connectdata *conn, } if(authstatus->picked == CURLAUTH_BEARER) { /* Bearer */ - if((!proxy && conn->oauth_bearer && + if((!proxy && data->set.str[STRING_BEARER] && !Curl_checkheaders(conn, "Authorization:"))) { auth = "Bearer"; result = http_output_bearer(conn); @@ -765,7 +763,7 @@ Curl_http_output_auth(struct connectdata *conn, authproxy = &data->state.authproxy; if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || - conn->bits.user_passwd || conn->oauth_bearer) + conn->bits.user_passwd || data->set.str[STRING_BEARER]) /* continue please */; else { authhost->done = TRUE; @@ -1691,7 +1689,7 @@ static CURLcode expect100(struct Curl_easy *data, CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ - if(use_http_1_1plus(data, conn) && + if(!data->state.disableexpect && use_http_1_1plus(data, conn) && (conn->httpversion < 20)) { /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an Expect: 100-continue to the headers which actually speeds up post @@ -2390,7 +2388,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return CURLE_OUT_OF_MEMORY; } } - /* Extract the the URL to use in the request. Store in STRING_TEMP_URL for + /* Extract the URL to use in the request. Store in STRING_TEMP_URL for clean-up reasons if the function returns before the free() further down. */ uc = curl_url_get(h, CURLUPART_URL, &data->set.str[STRING_TEMP_URL], 0); @@ -3046,6 +3044,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(result) return result; + if(!postsize) + data->req.upload_done = TRUE; if(data->req.writebytecount) { /* if a request-body has been sent off, we make sure this progress is noted @@ -3545,7 +3545,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, */ Curl_expire_done(data, EXPIRE_100_TIMEOUT); if(!k->upload_done) { - if(data->set.http_keep_sending_on_error) { + if((k->httpcode == 417) && data->state.expect100header) { + /* 417 Expectation Failed - try again without the Expect + header */ + infof(data, "Got 417 while waiting for a 100\n"); + data->state.disableexpect = TRUE; + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(conn->data->change.url); + Curl_done_sending(conn, k); + } + else if(data->set.http_keep_sending_on_error) { infof(data, "HTTP error before end of send, keep sending\n"); if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; diff --git a/release/src/router/curl/lib/http.h b/release/src/router/curl/lib/http.h index 70d5dccec6b..4c1825f60ff 100644 --- a/release/src/router/curl/lib/http.h +++ b/release/src/router/curl/lib/http.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -116,7 +116,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn); * */ #ifndef EXPECT_100_THRESHOLD -#define EXPECT_100_THRESHOLD 1024 +#define EXPECT_100_THRESHOLD (1024*1024) #endif #endif /* CURL_DISABLE_HTTP */ diff --git a/release/src/router/curl/lib/http2.c b/release/src/router/curl/lib/http2.c index 65f3513ee51..41d8db6856c 100644 --- a/release/src/router/curl/lib/http2.c +++ b/release/src/router/curl/lib/http2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,19 +43,11 @@ #define H2_BUFSIZE 32768 -#if (NGHTTP2_VERSION_NUM < 0x010000) +#if (NGHTTP2_VERSION_NUM < 0x010c00) #error too old nghttp2 version, upgrade! #endif -#if (NGHTTP2_VERSION_NUM > 0x010800) -#define NGHTTP2_HAS_HTTP2_STRERROR 1 -#endif - -#if (NGHTTP2_VERSION_NUM >= 0x010900) -/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or - later */ -#define NGHTTP2_HAS_ERROR_CALLBACK 1 -#else +#ifdef CURL_DISABLE_VERBOSE_STRINGS #define nghttp2_session_callbacks_set_error_callback(x,y) #endif @@ -63,7 +55,7 @@ #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 #endif -#define HTTP2_HUGE_WINDOW_SIZE (1 << 30) +#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */ #ifdef DEBUG_HTTP2 #define H2BUGF(x) x @@ -341,36 +333,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = { int Curl_http2_ver(char *p, size_t len) { nghttp2_info *h2 = nghttp2_version(0); - return msnprintf(p, len, " nghttp2/%s", h2->version_str); -} - -/* HTTP/2 error code to name based on the Error Code Registry. -https://tools.ietf.org/html/rfc7540#page-77 -nghttp2_error_code enums are identical. -*/ -static const char *http2_strerror(uint32_t err) -{ -#ifndef NGHTTP2_HAS_HTTP2_STRERROR - const char *str[] = { - "NO_ERROR", /* 0x0 */ - "PROTOCOL_ERROR", /* 0x1 */ - "INTERNAL_ERROR", /* 0x2 */ - "FLOW_CONTROL_ERROR", /* 0x3 */ - "SETTINGS_TIMEOUT", /* 0x4 */ - "STREAM_CLOSED", /* 0x5 */ - "FRAME_SIZE_ERROR", /* 0x6 */ - "REFUSED_STREAM", /* 0x7 */ - "CANCEL", /* 0x8 */ - "COMPRESSION_ERROR", /* 0x9 */ - "CONNECT_ERROR", /* 0xA */ - "ENHANCE_YOUR_CALM", /* 0xB */ - "INADEQUATE_SECURITY", /* 0xC */ - "HTTP_1_1_REQUIRED" /* 0xD */ - }; - return (err < sizeof(str) / sizeof(str[0])) ? str[err] : "unknown"; -#else - return nghttp2_http2_strerror(err); -#endif + return msnprintf(p, len, "nghttp2/%s", h2->version_str); } /* @@ -838,7 +801,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, return 0; } H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", - http2_strerror(error_code), error_code, stream_id)); + nghttp2_strerror(error_code), error_code, stream_id)); stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1138,8 +1101,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session, return nread; } -#if defined(NGHTTP2_HAS_ERROR_CALLBACK) && \ - !defined(CURL_DISABLE_VERBOSE_STRINGS) +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) static int error_callback(nghttp2_session *session, const char *msg, size_t len, @@ -1156,9 +1118,10 @@ static void populate_settings(struct connectdata *conn, struct http_conn *httpc) { nghttp2_settings_entry *iv = httpc->local_settings; + DEBUGASSERT(conn->data); iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; - iv[0].value = (uint32_t)Curl_multi_max_concurrent_streams(conn->data->multi); + iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi); iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = HTTP2_HUGE_WINDOW_SIZE; @@ -1257,9 +1220,7 @@ static CURLcode http2_init(struct connectdata *conn) /* nghttp2_on_header_callback */ nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); -#ifndef CURL_DISABLE_VERBOSE_STRINGS nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); -#endif /* The nghttp2 session is not yet setup, do it */ rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); @@ -1457,7 +1418,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, } else if(httpc->error_code != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)", - stream->stream_id, http2_strerror(httpc->error_code), + stream->stream_id, nghttp2_strerror(httpc->error_code), httpc->error_code); *err = CURLE_HTTP2_STREAM; return -1; @@ -1594,8 +1555,12 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, return ncopy; } - H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n", - data, stream->stream_id)); + H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n", + data, stream->stream_id, + nghttp2_session_get_local_window_size(httpc->h2), + nghttp2_session_get_stream_local_window_size(httpc->h2, + stream->stream_id) + )); if((data->state.drain) && stream->memlen) { H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", @@ -1626,7 +1591,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->pausedata += nread; stream->pauselen -= nread; - infof(data, "%zd data bytes written\n", nread); if(stream->pauselen == 0) { H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); @@ -2264,7 +2228,6 @@ CURLcode Curl_http2_switched(struct connectdata *conn, } } -#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0, HTTP2_HUGE_WINDOW_SIZE); if(rv != 0) { @@ -2272,7 +2235,6 @@ CURLcode Curl_http2_switched(struct connectdata *conn, nghttp2_strerror(rv), rv); return CURLE_HTTP2; } -#endif /* we are going to copy mem to httpc->inbuf. This is required since mem is part of buffer pointed by stream->mem, and callbacks @@ -2330,6 +2292,51 @@ CURLcode Curl_http2_switched(struct connectdata *conn, return CURLE_OK; } +CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause) +{ + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + /* if it isn't HTTP/2, we're done */ + if(!data->conn->proto.httpc.h2) + return CURLE_OK; +#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE + else { + struct HTTP *stream = data->req.protop; + struct http_conn *httpc = &data->conn->proto.httpc; + uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE; + int rv = nghttp2_session_set_local_window_size(httpc->h2, + NGHTTP2_FLAG_NONE, + stream->stream_id, + window); + if(rv) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + + /* make sure the window update gets sent */ + rv = h2_session_send(data, httpc->h2); + if(rv) + return CURLE_SEND_ERROR; + + DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n", + window, stream->stream_id)); + +#ifdef DEBUGBUILD + { + /* read out the stream local window again */ + uint32_t window2 = + nghttp2_session_get_stream_local_window_size(httpc->h2, + stream->stream_id); + DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n", + window2, stream->stream_id)); + } +#endif + } +#endif + return CURLE_OK; +} + CURLcode Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, bool exclusive) diff --git a/release/src/router/curl/lib/http2.h b/release/src/router/curl/lib/http2.h index 12d36eef9b8..1989aff8267 100644 --- a/release/src/router/curl/lib/http2.h +++ b/release/src/router/curl/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -58,6 +58,7 @@ CURLcode Curl_http2_add_child(struct Curl_easy *parent, void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child); void Curl_http2_cleanup_dependencies(struct Curl_easy *data); +CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause); /* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */ bool Curl_h2_http_1_1_error(struct connectdata *conn); @@ -74,6 +75,7 @@ bool Curl_h2_http_1_1_error(struct connectdata *conn); #define Curl_http2_add_child(x, y, z) #define Curl_http2_remove_child(x, y) #define Curl_http2_cleanup_dependencies(x) +#define Curl_http2_stream_pause(x, y) #define Curl_h2_http_1_1_error(x) 0 #endif diff --git a/release/src/router/curl/lib/libcurl.plist b/release/src/router/curl/lib/libcurl.plist index 236ec4279bb..0b521b0f866 100644 --- a/release/src/router/curl/lib/libcurl.plist +++ b/release/src/router/curl/lib/libcurl.plist @@ -15,7 +15,7 @@ se.haxx.curl.libcurl CFBundleVersion - 7.68.0 + 7.69.1 CFBundleName libcurl @@ -27,9 +27,9 @@ ???? CFBundleShortVersionString - libcurl 7.68.0 + libcurl 7.69.1 CFBundleGetInfoString - libcurl.plist 7.68.0 + libcurl.plist 7.69.1 diff --git a/release/src/router/curl/lib/llist.c b/release/src/router/curl/lib/llist.c index f8769c2af84..e7c6f51dc73 100644 --- a/release/src/router/curl/lib/llist.c +++ b/release/src/router/curl/lib/llist.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -144,54 +144,3 @@ Curl_llist_count(struct curl_llist *list) { return list->size; } - -/* - * @unittest: 1300 - */ -void Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, - struct curl_llist *to_list, - struct curl_llist_element *to_e) -{ - /* Remove element from list */ - if(e == NULL || list->size == 0) - return; - - if(e == list->head) { - list->head = e->next; - - if(list->head == NULL) - list->tail = NULL; - else - e->next->prev = NULL; - } - else { - e->prev->next = e->next; - if(!e->next) - list->tail = e->prev; - else - e->next->prev = e->prev; - } - - --list->size; - - /* Add element to to_list after to_e */ - if(to_list->size == 0) { - to_list->head = e; - to_list->head->prev = NULL; - to_list->head->next = NULL; - to_list->tail = e; - } - else { - e->next = to_e->next; - e->prev = to_e; - if(to_e->next) { - to_e->next->prev = e; - } - else { - to_list->tail = e; - } - to_e->next = e; - } - - ++to_list->size; -} diff --git a/release/src/router/curl/lib/llist.h b/release/src/router/curl/lib/llist.h index a5e2ecbfb41..0178c425980 100644 --- a/release/src/router/curl/lib/llist.h +++ b/release/src/router/curl/lib/llist.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,7 +47,4 @@ void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, void *); size_t Curl_llist_count(struct curl_llist *); void Curl_llist_destroy(struct curl_llist *, void *); -void Curl_llist_move(struct curl_llist *, struct curl_llist_element *, - struct curl_llist *, struct curl_llist_element *); - #endif /* HEADER_CURL_LLIST_H */ diff --git a/release/src/router/curl/lib/md4.c b/release/src/router/curl/lib/md4.c index bbf89750811..38f1b2bc96d 100644 --- a/release/src/router/curl/lib/md4.c +++ b/release/src/router/curl/lib/md4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,10 +29,16 @@ #ifdef USE_OPENSSL #include -#endif +#endif /* USE_OPENSSL */ + #ifdef USE_MBEDTLS #include +#include + +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS #endif +#endif /* USE_MBEDTLS */ #if defined(USE_GNUTLS_NETTLE) @@ -65,10 +71,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) #include #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" -typedef struct gcry_md_hd_t MD4_CTX; +typedef gcry_md_hd_t MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { @@ -82,52 +89,41 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { - memcpy(result, gcry_md_read(ctx, 0), MD4_DIGEST_LENGTH); - gcry_md_close(ctx); + memcpy(result, gcry_md_read(*ctx, 0), MD4_DIGEST_LENGTH); + gcry_md_close(*ctx); } #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) /* When OpenSSL is available we use the MD4-functions from OpenSSL */ #include -#elif defined(USE_SECTRANSP) +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) #include #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" -typedef struct { - void *data; - unsigned long size; -} MD4_CTX; +typedef CC_MD4_CTX MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { - ctx->data = NULL; - ctx->size = 0; + (void)CC_MD4_Init(ctx); } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { - if(ctx->data == NULL) { - ctx->data = malloc(size); - if(ctx->data != NULL) { - memcpy(ctx->data, data, size); - ctx->size = size; - } - } + (void)CC_MD4_Update(ctx, data, (CC_LONG)size); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { - if(ctx->data != NULL) { - (void)CC_MD4(ctx->data, (CC_LONG) ctx->size, result); - - Curl_safefree(ctx->data); - ctx->size = 0; - } + (void)CC_MD4_Final(result, ctx); } #elif defined(USE_WIN32_CRYPTO) @@ -135,7 +131,8 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) #include #include "curl_memory.h" - /* The last #include file should be: */ + +/* The last #include file should be: */ #include "memdebug.h" typedef struct { @@ -156,7 +153,7 @@ static void MD4_Init(MD4_CTX *ctx) static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { - CryptHashData(ctx->hHash, data, (unsigned int) size, 0); + CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) @@ -179,6 +176,7 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) #include #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -207,7 +205,11 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { if(ctx->data != NULL) { +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md4(ctx->data, ctx->size, result); +#else + (void) mbedtls_md4_ret(ctx->data, ctx->size, result); +#endif Curl_safefree(ctx->data); ctx->size = 0; @@ -505,9 +507,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) #endif /* CRYPTO LIBS */ -void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len) +void Curl_md4it(unsigned char *output, const unsigned char *input, + const size_t len) { MD4_CTX ctx; + MD4_Init(&ctx); MD4_Update(&ctx, input, curlx_uztoui(len)); MD4_Final(output, &ctx); diff --git a/release/src/router/curl/lib/md5.c b/release/src/router/curl/lib/md5.c index 2b81ca455a9..3f601b3a422 100644 --- a/release/src/router/curl/lib/md5.c +++ b/release/src/router/curl/lib/md5.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,14 @@ #include "curl_hmac.h" #include "warnless.h" +#ifdef USE_MBEDTLS +#include + +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#endif +#endif /* USE_MBEDTLS */ + #if defined(USE_GNUTLS_NETTLE) #include @@ -51,7 +59,7 @@ static void MD5_Update(MD5_CTX *ctx, md5_update(ctx, inputLen, input); } -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { md5_digest(ctx, 16, digest); } @@ -77,7 +85,7 @@ static void MD5_Update(MD5_CTX *ctx, gcry_md_write(*ctx, input, inputLen); } -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), 16); gcry_md_close(*ctx); @@ -90,6 +98,46 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" +#elif defined(USE_MBEDTLS) + +#include + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef mbedtls_md5_context MD5_CTX; + +static void MD5_Init(MD5_CTX *ctx) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_md5_starts(ctx); +#else + (void) mbedtls_md5_starts_ret(ctx); +#endif +} + +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_md5_update(ctx, data, length); +#else + (void) mbedtls_md5_update_ret(ctx, data, length); +#endif +} + +static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) +{ +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_md5_finish(ctx, digest); +#else + (void) mbedtls_md5_finish_ret(ctx, digest); +#endif +} + #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ @@ -119,12 +167,12 @@ static void MD5_Update(MD5_CTX *ctx, CC_MD5_Update(ctx, input, inputLen); } -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { CC_MD5_Final(digest, ctx); } -#elif defined(WIN32) && !defined(CURL_WINDOWS_APP) +#elif defined(USE_WIN32_CRYPTO) #include #include "curl_memory.h" @@ -151,7 +199,7 @@ static void MD5_Update(MD5_CTX *ctx, CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { unsigned long length = 0; CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); @@ -164,7 +212,9 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) } #else + /* When no other crypto library is available we use this code segment */ + /* * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. * MD5 Message-Digest Algorithm (RFC 1321). @@ -513,12 +563,13 @@ const MD5_params Curl_DIGEST_MD5[] = { /* * @unittest: 1601 */ -void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ - const unsigned char *input) +void Curl_md5it(unsigned char *outbuffer, const unsigned char *input, + const size_t len) { MD5_CTX ctx; + MD5_Init(&ctx); - MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input))); + MD5_Update(&ctx, input, curlx_uztoui(len)); MD5_Final(outbuffer, &ctx); } diff --git a/release/src/router/curl/lib/mime.c b/release/src/router/curl/lib/mime.c index 081e51e5089..b72732310df 100644 --- a/release/src/router/curl/lib/mime.c +++ b/release/src/router/curl/lib/mime.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #include "mime.h" #include "non-ascii.h" +#include "warnless.h" #include "urldata.h" #include "sendf.h" @@ -52,6 +53,10 @@ #define READ_ERROR ((size_t) -1) +#define STOP_FILLING ((size_t) -2) + +static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, + void *instream, bool *hasread); /* Encoders. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, @@ -354,10 +359,15 @@ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, (void) ateof; + if(!size) + return STOP_FILLING; + if(size > insize) size = insize; + if(size) - memcpy(buffer, st->buf, size); + memcpy(buffer, st->buf + st->bufbeg, size); + st->bufbeg += size; return size; } @@ -377,6 +387,9 @@ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, (void) ateof; + if(!size) + return STOP_FILLING; + if(size > cursize) size = cursize; @@ -404,8 +417,11 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, /* Line full ? */ if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) { /* Yes, we need 2 characters for CRLF. */ - if(size < 2) + if(size < 2) { + if(!cursize) + return STOP_FILLING; break; + } *ptr++ = '\r'; *ptr++ = '\n'; st->pos = 0; @@ -414,7 +430,12 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, } /* Be sure there is enough space and input data for a base64 group. */ - if(size < 4 || st->bufend - st->bufbeg < 3) + if(size < 4) { + if(!cursize) + return STOP_FILLING; + break; + } + if(st->bufend - st->bufbeg < 3) break; /* Encode three bytes as four characters. */ @@ -431,25 +452,31 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, } /* If at eof, we have to flush the buffered data. */ - if(ateof && size >= 4) { - /* Buffered data size can only be 0, 1 or 2. */ - ptr[2] = ptr[3] = '='; - i = 0; - switch(st->bufend - st->bufbeg) { - case 2: - i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; - /* FALLTHROUGH */ - case 1: - i |= (st->buf[st->bufbeg] & 0xFF) << 16; - ptr[0] = base64[(i >> 18) & 0x3F]; - ptr[1] = base64[(i >> 12) & 0x3F]; - if(++st->bufbeg != st->bufend) { - ptr[2] = base64[(i >> 6) & 0x3F]; - st->bufbeg++; + if(ateof) { + if(size < 4) { + if(!cursize) + return STOP_FILLING; + } + else { + /* Buffered data size can only be 0, 1 or 2. */ + ptr[2] = ptr[3] = '='; + i = 0; + switch(st->bufend - st->bufbeg) { + case 2: + i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; + /* FALLTHROUGH */ + case 1: + i |= (st->buf[st->bufbeg] & 0xFF) << 16; + ptr[0] = base64[(i >> 18) & 0x3F]; + ptr[1] = base64[(i >> 12) & 0x3F]; + if(++st->bufbeg != st->bufend) { + ptr[2] = base64[(i >> 6) & 0x3F]; + st->bufbeg++; + } + cursize += 4; + st->pos += 4; + break; } - cursize += 4; - st->pos += 4; - break; } } @@ -581,8 +608,11 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, } /* If the output buffer would overflow, do not store. */ - if(len > size) + if(len > size) { + if(!cursize) + return STOP_FILLING; break; + } /* Append to output buffer. */ memcpy(ptr, buf, len); @@ -612,16 +642,18 @@ static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; - size_t sz = (size_t) part->datasize - part->state.offset; + size_t sz = curlx_sotouz(part->datasize - part->state.offset); (void) size; /* Always 1.*/ + if(!nitems) + return STOP_FILLING; + if(sz > nitems) sz = nitems; if(sz) - memcpy(buffer, (char *) &part->data[part->state.offset], sz); + memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz); - part->state.offset += sz; return sz; } @@ -641,7 +673,7 @@ static int mime_mem_seek(void *instream, curl_off_t offset, int whence) if(offset < 0 || offset > part->datasize) return CURL_SEEKFUNC_FAIL; - part->state.offset = (size_t) offset; + part->state.offset = offset; return CURL_SEEKFUNC_OK; } @@ -668,6 +700,9 @@ static size_t mime_file_read(char *buffer, size_t size, size_t nitems, { curl_mimepart *part = (curl_mimepart *) instream; + if(!nitems) + return STOP_FILLING; + if(mime_open_file(part)) return READ_ERROR; @@ -711,15 +746,16 @@ static size_t readback_bytes(mime_state *state, const char *trail) { size_t sz; + size_t offset = curlx_sotouz(state->offset); - if(numbytes > state->offset) { - sz = numbytes - state->offset; - bytes += state->offset; + if(numbytes > offset) { + sz = numbytes - offset; + bytes += offset; } else { size_t tsz = strlen(trail); - sz = state->offset - numbytes; + sz = offset - numbytes; if(sz >= tsz) return 0; bytes = trail + sz; @@ -736,25 +772,79 @@ static size_t readback_bytes(mime_state *state, /* Read a non-encoded part content. */ static size_t read_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) + char *buffer, size_t bufsize, bool *hasread) { size_t sz = 0; - if(part->readfunc) - sz = part->readfunc(buffer, 1, bufsize, part->arg); + switch(part->lastreadstatus) { + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return part->lastreadstatus; + default: + break; + } + + /* If we can determine we are at end of part data, spare a read. */ + if(part->datasize != (curl_off_t) -1 && + part->state.offset >= part->datasize) { + /* sz is already zero. */ + } + else { + switch(part->kind) { + case MIMEKIND_MULTIPART: + /* + * Cannot be processed as other kinds since read function requires + * an additional parameter and is highly recursive. + */ + sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread); + break; + case MIMEKIND_FILE: + if(part->fp && feof(part->fp)) + break; /* At EOF. */ + /* FALLTHROUGH */ + default: + if(part->readfunc) { + if(!(part->flags & MIME_FAST_READ)) { + if(*hasread) + return STOP_FILLING; + *hasread = TRUE; + } + sz = part->readfunc(buffer, 1, bufsize, part->arg); + } + break; + } + } + + switch(sz) { + case STOP_FILLING: + break; + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + part->lastreadstatus = sz; + break; + default: + part->state.offset += sz; + part->lastreadstatus = sz; + break; + } + return sz; } /* Read and encode part content. */ -static size_t read_encoded_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) +static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, + size_t bufsize, bool *hasread) { mime_encoder_state *st = &part->encstate; size_t cursize = 0; size_t sz; bool ateof = FALSE; - while(bufsize) { + for(;;) { if(st->bufbeg < st->bufend || ateof) { /* Encode buffered data. */ sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); @@ -763,9 +853,8 @@ static size_t read_encoded_part_content(curl_mimepart *part, if(ateof) return cursize; break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; default: cursize += sz; @@ -787,7 +876,7 @@ static size_t read_encoded_part_content(curl_mimepart *part, if(st->bufend >= sizeof(st->buf)) return cursize? cursize: READ_ERROR; /* Buffer full. */ sz = read_part_content(part, st->buf + st->bufend, - sizeof(st->buf) - st->bufend); + sizeof(st->buf) - st->bufend, hasread); switch(sz) { case 0: ateof = TRUE; @@ -795,6 +884,7 @@ static size_t read_encoded_part_content(curl_mimepart *part, case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; default: st->bufend += sz; @@ -802,12 +892,12 @@ static size_t read_encoded_part_content(curl_mimepart *part, } } - return cursize; + /* NOTREACHED */ } /* Readback a mime part. */ static size_t readback_part(curl_mimepart *part, - char *buffer, size_t bufsize) + char *buffer, size_t bufsize, bool *hasread) { size_t cursize = 0; #ifdef CURL_DOES_CONVERSIONS @@ -866,9 +956,9 @@ static size_t readback_part(curl_mimepart *part, break; case MIMESTATE_CONTENT: if(part->encoder) - sz = read_encoded_part_content(part, buffer, bufsize); + sz = read_encoded_part_content(part, buffer, bufsize, hasread); else - sz = read_part_content(part, buffer, bufsize); + sz = read_part_content(part, buffer, bufsize, hasread); switch(sz) { case 0: mimesetstate(&part->state, MIMESTATE_END, NULL); @@ -881,6 +971,7 @@ static size_t readback_part(curl_mimepart *part, case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; } break; @@ -909,9 +1000,9 @@ static size_t readback_part(curl_mimepart *part, return cursize; } -/* Readback from mime. */ +/* Readback from mime. Warning: not a read callback function. */ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, - void *instream) + void *instream, bool *hasread) { curl_mime *mime = (curl_mime *) instream; size_t cursize = 0; @@ -932,7 +1023,7 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, #endif mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart); /* The first boundary always follows the header termination empty line, - so is always preceded by a CRLK. We can then spare 2 characters + so is always preceded by a CRLF. We can then spare 2 characters by skipping the leading CRLF in boundary. */ mime->state.offset += 2; break; @@ -962,11 +1053,12 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, mimesetstate(&mime->state, MIMESTATE_END, NULL); break; } - sz = readback_part(part, buffer, nitems); + sz = readback_part(part, buffer, nitems, hasread); switch(sz) { case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; case 0: #ifdef CURL_DOES_CONVERSIONS @@ -1031,6 +1123,7 @@ static int mime_part_rewind(curl_mimepart *part) if(res == CURL_SEEKFUNC_OK) mimesetstate(&part->state, targetstate, NULL); + part->lastreadstatus = 1; /* Successful read status. */ return res; } @@ -1073,6 +1166,8 @@ static void cleanup_part_content(curl_mimepart *part) part->datasize = (curl_off_t) 0; /* No size yet. */ cleanup_encoder_state(&part->encstate); part->kind = MIMEKIND_NONE; + part->flags &= ~MIME_FAST_READ; + part->lastreadstatus = 1; /* Successful read status. */ } static void mime_subparts_free(void *ptr) @@ -1238,6 +1333,7 @@ void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) { memset((char *) part, 0, sizeof(*part)); part->easy = easy; + part->lastreadstatus = 1; /* Successful read status. */ mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); } @@ -1328,6 +1424,7 @@ CURLcode curl_mime_data(curl_mimepart *part, part->readfunc = mime_mem_read; part->seekfunc = mime_mem_seek; part->freefunc = mime_mem_free; + part->flags |= MIME_FAST_READ; part->kind = MIMEKIND_DATA; } @@ -1502,7 +1599,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part, } subparts->parent = part; - part->readfunc = mime_subparts_read; + /* Subparts are processed internally: no read callback. */ part->seekfunc = mime_subparts_seek; part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind; part->arg = subparts; @@ -1524,9 +1621,23 @@ CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; + size_t ret; + bool hasread; (void) size; /* Always 1. */ - return readback_part(part, buffer, nitems); + + do { + hasread = FALSE; + ret = readback_part(part, buffer, nitems, &hasread); + /* + * If this is not possible to get some data without calling more than + * one read callback (probably because a content encoder is not able to + * deliver a new bunch for the few data accumulated so far), force another + * read until we get enough data or a special exit code. + */ + } while(ret == STOP_FILLING); + + return ret; } /* Rewind mime stream. */ @@ -1805,6 +1916,26 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, return ret; } +/* Recursively reset paused status in the given part. */ +void Curl_mime_unpause(curl_mimepart *part) +{ + if(part) { + if(part->lastreadstatus == CURL_READFUNC_PAUSE) + part->lastreadstatus = 1; /* Successful read status. */ + if(part->kind == MIMEKIND_MULTIPART) { + curl_mime *mime = (curl_mime *) part->arg; + + if(mime) { + curl_mimepart *subpart; + + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) + Curl_mime_unpause(subpart); + } + } + } +} + + #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ /* Mime not compiled in: define stubs for externally-referenced functions. */ diff --git a/release/src/router/curl/lib/mime.h b/release/src/router/curl/lib/mime.h index 3241fdc1f72..d7f25132e39 100644 --- a/release/src/router/curl/lib/mime.h +++ b/release/src/router/curl/lib/mime.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,6 +31,7 @@ /* Part flags. */ #define MIME_USERHEADERS_OWNER (1 << 0) #define MIME_BODY_ONLY (1 << 1) +#define MIME_FAST_READ (1 << 2) #define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" #define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" @@ -87,7 +88,7 @@ typedef struct { typedef struct { enum mimestate state; /* Current state token. */ void *ptr; /* State-dependent pointer. */ - size_t offset; /* State-dependent offset. */ + curl_off_t offset; /* State-dependent offset. */ } mime_state; /* minimum buffer size for the boundary string */ @@ -125,6 +126,7 @@ struct curl_mimepart_s { mime_state state; /* Current readback state. */ const mime_encoder *encoder; /* Content data encoder. */ mime_encoder_state encstate; /* Data encoder state. */ + size_t lastreadstatus; /* Last read callback returned status. */ }; CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); @@ -147,6 +149,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream); CURLcode Curl_mime_rewind(curl_mimepart *part); const char *Curl_mime_contenttype(const char *filename); +void Curl_mime_unpause(curl_mimepart *part); #else /* if disabled */ @@ -158,6 +161,7 @@ const char *Curl_mime_contenttype(const char *filename); #define Curl_mime_size(x) (curl_off_t) -1 #define Curl_mime_read NULL #define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_mime_unpause(x) #endif diff --git a/release/src/router/curl/lib/mk-ca-bundle.pl b/release/src/router/curl/lib/mk-ca-bundle.pl index 33977f32269..09e8e5b9bbd 100755 --- a/release/src/router/curl/lib/mk-ca-bundle.pl +++ b/release/src/router/curl/lib/mk-ca-bundle.pl @@ -6,7 +6,7 @@ # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * -# * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +# * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms @@ -38,6 +38,7 @@ use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); use List::Util; use Text::Wrap; +use Time::Local; my $MOD_SHA = "Digest::SHA"; eval "require $MOD_SHA"; if ($@) { @@ -421,6 +422,8 @@ (%) my $skipnum = 0; my $start_of_cert = 0; my @precert; +my $cka_value; +my $valid = 1; open(TXT,"$txt") or die "Couldn't open $txt: $!\n"; while () { @@ -435,6 +438,7 @@ (%) } elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { push @precert, $_; + $valid = 1; next; } elsif(/^#|^\s*$/) { @@ -443,6 +447,49 @@ (%) } chomp; + # Example: + # CKA_NSS_SERVER_DISTRUST_AFTER MULTILINE_OCTAL + # \062\060\060\066\061\067\060\060\060\060\060\060\132 + # END + + if (/^CKA_NSS_SERVER_DISTRUST_AFTER (CK_BBOOL CK_FALSE|MULTILINE_OCTAL)/) { + if($1 eq "MULTILINE_OCTAL") { + my @timestamp; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + push @timestamp, chr(oct); + } + } + # A trailing Z in the timestamp signifies UTC + if($timestamp[12] ne "Z") { + report "distrust date stamp is not using UTC"; + } + # Example date: 200617000000Z + # Means 2020-06-17 00:00:00 UTC + my $distrustat = + timegm($timestamp[10] . $timestamp[11], # second + $timestamp[8] . $timestamp[9], # minute + $timestamp[6] . $timestamp[7], # hour + $timestamp[4] . $timestamp[5], # day + ($timestamp[2] . $timestamp[3]) - 1, # month + "20" . $timestamp[0] . $timestamp[1]); # year + if(time >= $distrustat) { + # not trusted anymore + $skipnum++; + report "Skipping: $caname is not trusted anymore" if ($opt_v); + $valid = 0; + } + else { + # still trusted + } + } + next; + } + # this is a match for the start of a certificate if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { $start_of_cert = 1 @@ -452,21 +499,18 @@ (%) } my %trust_purposes_by_level; if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { - my $data; + $cka_value=""; while () { last if (/^END/); chomp; my @octets = split(/\\/); shift @octets; for (@octets) { - $data .= chr(oct); + $cka_value .= chr(oct); } } - # scan forwards until the trust part - while () { - last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); - chomp; - } + } + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/ && $valid) { # now scan the trust part to determine how we should trust this cert while () { last if (/^#/); @@ -485,6 +529,8 @@ (%) $skipnum ++; report "Skipping: $caname" if ($opt_v); } else { + my $data = $cka_value; + $cka_value = ""; my $encoded = MIME::Base64::encode_base64($data, ''); $encoded =~ s/(.{1,${opt_w}})/$1\n/g; my $pem = "-----BEGIN CERTIFICATE-----\n" diff --git a/release/src/router/curl/lib/multi.c b/release/src/router/curl/lib/multi.c index 6d819b4aaa7..e10e7529319 100644 --- a/release/src/router/curl/lib/multi.c +++ b/release/src/router/curl/lib/multi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,6 +47,7 @@ #include "http_proxy.h" #include "http2.h" #include "socketpair.h" +#include "socks.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -369,6 +370,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; + multi->max_concurrent_streams = 100; + multi->ipv6_works = Curl_ipv6works(NULL); #ifdef ENABLE_WAKEUP if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) { @@ -590,6 +593,9 @@ static CURLcode multi_done(struct Curl_easy *data, detach_connnection(data); if(CONN_INUSE(conn)) { /* Stop if still used. */ + /* conn->data must not remain pointing to this transfer since it is going + away! Find another to own it! */ + conn->data = conn->easyq.head->ptr; CONN_UNLOCK(data); DEBUGF(infof(data, "Connection still in use %zu, " "no more multi_done now!\n", @@ -725,8 +731,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, we don't leave a half-baked one around */ if(easy_owns_conn) { - /* multi_done() clears the conn->data field to lose the association - between the easy handle and the connection + /* multi_done() clears the association between the easy handle and the + connection. Note that this ignores the return code simply because there's nothing really useful to do with it anyway! */ @@ -851,6 +857,9 @@ static int waitconnect_getsock(struct connectdata *conn, return Curl_ssl_getsock(conn, sock); #endif + if(SOCKS_STATE(conn->cnnct.state)) + return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET); + for(i = 0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { sock[s] = conn->tempsock[i]; @@ -1048,6 +1057,9 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(timeout_ms < 0) + return CURLM_BAD_FUNCTION_ARGUMENT; + /* Count up how many fds we have from the multi handle */ data = multi->easyp; while(data) { @@ -1182,14 +1194,16 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { if(ufds[curlfds + extra_nfds].revents & POLLIN) { char buf[64]; + ssize_t nread; while(1) { /* the reading socket is non-blocking, try to read data from it until it receives an error (except EINTR). In normal cases it will get EAGAIN or EWOULDBLOCK when there is no more data, breaking the loop. */ - if(sread(multi->wakeup_pair[0], buf, sizeof(buf)) < 0) { + nread = sread(multi->wakeup_pair[0], buf, sizeof(buf)); + if(nread <= 0) { #ifndef USE_WINSOCK - if(EINTR == SOCKERRNO) + if(nread < 0 && EINTR == SOCKERRNO) continue; #endif break; @@ -2183,8 +2197,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } } - else if(comeback) - rc = CURLM_CALL_MULTI_PERFORM; + else if(comeback) { + /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer + won't get stuck on this transfer at the expense of other concurrent + transfers */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + rc = CURLM_OK; + } break; } @@ -2897,8 +2916,8 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi, if(streams < 1) streams = 100; multi->max_concurrent_streams = - (streams > (long)INITIAL_MAX_CONCURRENT_STREAMS)? - (long)INITIAL_MAX_CONCURRENT_STREAMS : streams; + (streams > (long)INITIAL_MAX_CONCURRENT_STREAMS)? + INITIAL_MAX_CONCURRENT_STREAMS : (unsigned int)streams; } break; default: @@ -3340,8 +3359,8 @@ void Curl_multi_dump(struct Curl_multi *multi) } #endif -size_t Curl_multi_max_concurrent_streams(struct Curl_multi *multi) +unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) { - return multi ? ((size_t)multi->max_concurrent_streams ? - (size_t)multi->max_concurrent_streams : 100) : 0; + DEBUGASSERT(multi); + return multi->max_concurrent_streams; } diff --git a/release/src/router/curl/lib/multihandle.h b/release/src/router/curl/lib/multihandle.h index 0bf09e6bb55..91eca16c4a8 100644 --- a/release/src/router/curl/lib/multihandle.h +++ b/release/src/router/curl/lib/multihandle.h @@ -119,11 +119,6 @@ struct Curl_multi { same actual socket) */ struct curl_hash sockhash; - /* multiplexing wanted */ - bool multiplexing; - - bool recheckstate; /* see Curl_multi_connchanged */ - /* Shared connection cache (bundles)*/ struct conncache conn_cache; @@ -141,13 +136,17 @@ struct Curl_multi { void *timer_userp; struct curltime timer_lastcall; /* the fixed time for the timeout for the previous callback */ - bool in_callback; /* true while executing a callback */ - long max_concurrent_streams; /* max concurrent streams client to support */ + unsigned int max_concurrent_streams; #ifdef ENABLE_WAKEUP curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup 0 is used for read, 1 is used for write */ #endif + /* multiplexing wanted */ + bool multiplexing; + bool recheckstate; /* see Curl_multi_connchanged */ + bool in_callback; /* true while executing a callback */ + bool ipv6_works; }; #endif /* HEADER_CURL_MULTIHANDLE_H */ diff --git a/release/src/router/curl/lib/multiif.h b/release/src/router/curl/lib/multiif.h index 75025232c42..bde755ee0f7 100644 --- a/release/src/router/curl/lib/multiif.h +++ b/release/src/router/curl/lib/multiif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -90,9 +90,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, struct connectdata *conn); -/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option - * If not specified or 0, default would be 100 - */ -size_t Curl_multi_max_concurrent_streams(struct Curl_multi *multi); +/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */ +unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi); #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/release/src/router/curl/lib/rename.c b/release/src/router/curl/lib/rename.c new file mode 100644 index 00000000000..bb170d3cc7b --- /dev/null +++ b/release/src/router/curl/lib/rename.c @@ -0,0 +1,62 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "rename.h" + +#include "curl_setup.h" + +#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \ + defined(USE_ALTSVC) + +#include "timeval.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* return 0 on success, 1 on error */ +int Curl_rename(const char *oldpath, const char *newpath) +{ +#ifdef WIN32 + /* rename() on Windows doesn't overwrite, so we can't use it here. + MoveFileExA() will overwrite and is usually atomic, however it fails + when there are open handles to the file. */ + const int max_wait_ms = 1000; + struct curltime start = Curl_now(); + for(;;) { + timediff_t diff; + if(MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) + break; + diff = Curl_timediff(Curl_now(), start); + if(diff < 0 || diff > max_wait_ms) + return 1; + Sleep(1); + } +#else + if(rename(oldpath, newpath)) + return 1; +#endif + return 0; +} + +#endif diff --git a/release/src/router/curl/lib/vtls/polarssl.h b/release/src/router/curl/lib/rename.h similarity index 73% rename from release/src/router/curl/lib/vtls/polarssl.h rename to release/src/router/curl/lib/rename.h index f36f24f8dfb..d7442c8447c 100644 --- a/release/src/router/curl/lib/vtls/polarssl.h +++ b/release/src/router/curl/lib/rename.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_POLARSSL_H -#define HEADER_CURL_POLARSSL_H +#ifndef HEADER_CURL_RENAME_H +#define HEADER_CURL_RENAME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,8 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. - * Copyright (C) 2010, Hoi-Ho Chan, + * Copyright (C) 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,11 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "curl_setup.h" -#ifdef USE_POLARSSL +int Curl_rename(const char *oldpath, const char *newpath); -extern const struct Curl_ssl Curl_ssl_polarssl; - -#endif /* USE_POLARSSL */ -#endif /* HEADER_CURL_POLARSSL_H */ +#endif /* HEADER_CURL_RENAME_H */ diff --git a/release/src/router/curl/lib/select.c b/release/src/router/curl/lib/select.c index 2de503d3706..b372efff100 100644 --- a/release/src/router/curl/lib/select.c +++ b/release/src/router/curl/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,9 +53,6 @@ /* Convenience local macros */ #define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv) -int Curl_ack_eintr = 0; -#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) - /* * Internal function used for waiting a specific amount of ms * in Curl_socket_check() and Curl_poll() when no file descriptor @@ -74,13 +71,6 @@ int Curl_ack_eintr = 0; */ int Curl_wait_ms(int timeout_ms) { -#if !defined(MSDOS) && !defined(USE_WINSOCK) -#ifndef HAVE_POLL_FINE - struct timeval pending_tv; -#endif - struct curltime initial_tv; - int pending_ms; -#endif int r = 0; if(!timeout_ms) @@ -94,28 +84,16 @@ int Curl_wait_ms(int timeout_ms) #elif defined(USE_WINSOCK) Sleep(timeout_ms); #else - pending_ms = timeout_ms; - initial_tv = Curl_now(); - do { - int error; #if defined(HAVE_POLL_FINE) - r = poll(NULL, 0, pending_ms); + r = poll(NULL, 0, timeout_ms); #else - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; + { + struct timeval pending_tv; + pending_tv.tv_sec = timeout_ms / 1000; + pending_tv.tv_usec = (timeout_ms % 1000) * 1000; r = select(0, NULL, NULL, NULL, &pending_tv); + } #endif /* HAVE_POLL_FINE */ - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - pending_ms = timeout_ms - ELAPSED_MS(); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } while(r == -1); #endif /* USE_WINSOCK */ if(r) r = -1; @@ -158,7 +136,6 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ fd_set fds_err; curl_socket_t maxfd; #endif - struct curltime initial_tv = {0, 0}; int pending_ms = 0; int r; int ret; @@ -183,7 +160,6 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(timeout_ms > 0) { pending_ms = (int)timeout_ms; - initial_tv = Curl_now(); } #ifdef HAVE_POLL_FINE @@ -208,26 +184,11 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ num++; } - do { - int error; - if(timeout_ms < 0) - pending_ms = -1; - else if(!timeout_ms) - pending_ms = 0; - r = poll(pfd, num, pending_ms); - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); + if(timeout_ms < 0) + pending_ms = -1; + else if(!timeout_ms) + pending_ms = 0; + r = poll(pfd, num, pending_ms); if(r < 0) return -1; @@ -290,61 +251,45 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - do { - int error; - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } + if(timeout_ms > 0) { + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + } + else if(!timeout_ms) { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } - /* WinSock select() must not be called with an fd_set that contains zero - fd flags, or it will return WSAEINVAL. But, it also can't be called - with no fd_sets at all! From the documentation: + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: - Any two of the parameters, readfds, writefds, or exceptfds, can be - given as null. At least one must be non-null, and any non-null - descriptor set must contain at least one handle to a socket. + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. - We know that we have at least one bit set in at least two fd_sets in - this case, but we may have no bits set in either fds_read or fd_write, - so check for that and handle it. Luckily, with WinSock, we can _also_ - ask how many bits are set on an fd_set. + We know that we have at least one bit set in at least two fd_sets in + this case, but we may have no bits set in either fds_read or fd_write, + so check for that and handle it. Luckily, with WinSock, we can _also_ + ask how many bits are set on an fd_set. - It is unclear why WinSock doesn't just handle this for us instead of - calling this an error. + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. - Note also that WinSock ignores the first argument, so we don't worry - about the fact that maxfd is computed incorrectly with WinSock (since - curl_socket_t is unsigned in such cases and thus -1 is the largest - value). - */ + Note also that WinSock ignores the first argument, so we don't worry + about the fact that maxfd is computed incorrectly with WinSock (since + curl_socket_t is unsigned in such cases and thus -1 is the largest + value). + */ #ifdef USE_WINSOCK - r = select((int)maxfd + 1, - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - &fds_err, ptimeout); + r = select((int)maxfd + 1, + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + &fds_err, ptimeout); #else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); #endif - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); - if(r < 0) return -1; if(r == 0) @@ -399,7 +344,6 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) fd_set fds_err; curl_socket_t maxfd; #endif - struct curltime initial_tv = {0, 0}; bool fds_none = TRUE; unsigned int i; int pending_ms = 0; @@ -425,31 +369,15 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(timeout_ms > 0) { pending_ms = timeout_ms; - initial_tv = Curl_now(); } #ifdef HAVE_POLL_FINE - do { - int error; - if(timeout_ms < 0) - pending_ms = -1; - else if(!timeout_ms) - pending_ms = 0; - r = poll(ufds, nfds, pending_ms); - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - ELAPSED_MS()); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); + if(timeout_ms < 0) + pending_ms = -1; + else if(!timeout_ms) + pending_ms = 0; + r = poll(ufds, nfds, pending_ms); if(r < 0) return -1; @@ -502,42 +430,27 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - do { - int error; - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } + if(timeout_ms > 0) { + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + } + else if(!timeout_ms) { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } #ifdef USE_WINSOCK - r = select((int)maxfd + 1, - /* WinSock select() can't handle fd_sets with zero bits set, so - don't give it such arguments. See the comment about this in - Curl_check_socket(). - */ - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, ptimeout); + r = select((int)maxfd + 1, + /* WinSock select() can't handle fd_sets with zero bits set, so + don't give it such arguments. See the comment about this in + Curl_check_socket(). + */ + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + fds_err.fd_count ? &fds_err : NULL, ptimeout); #else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); #endif - if(r != -1) - break; - error = SOCKERRNO; - if(error && ERROR_NOT_EINTR(error)) - break; - if(timeout_ms > 0) { - pending_ms = timeout_ms - ELAPSED_MS(); - if(pending_ms <= 0) { - r = 0; /* Simulate a "call timed out" case */ - break; - } - } - } while(r == -1); if(r < 0) return -1; diff --git a/release/src/router/curl/lib/select.h b/release/src/router/curl/lib/select.h index 687ab164c42..ec3021aac25 100644 --- a/release/src/router/curl/lib/select.h +++ b/release/src/router/curl/lib/select.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -75,20 +75,12 @@ struct pollfd int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, time_t timeout_ms); - #define SOCKET_READABLE(x,z) \ Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, (time_t)z) #define SOCKET_WRITABLE(x,z) \ Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, (time_t)z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); - -/* On non-DOS and non-Winsock platforms, when Curl_ack_eintr is set, - * EINTR condition is honored and function might exit early without - * awaiting full timeout. Otherwise EINTR will be ignored and full - * timeout will elapse. */ -extern int Curl_ack_eintr; - int Curl_wait_ms(int timeout_ms); #ifdef TPF diff --git a/release/src/router/curl/lib/sendf.c b/release/src/router/curl/lib/sendf.c index 6c38b04b237..6ef47aa801d 100644 --- a/release/src/router/curl/lib/sendf.c +++ b/release/src/router/curl/lib/sendf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,6 +43,7 @@ #include "strerror.h" #include "select.h" #include "strdup.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -501,6 +502,9 @@ static CURLcode pausewrite(struct Curl_easy *data, unsigned int i; bool newtype = TRUE; + /* If this transfers over HTTP/2, pause the stream! */ + Curl_http2_stream_pause(data, TRUE); + if(s->tempcount) { for(i = 0; i< s->tempcount; i++) { if(s->tempwrite[i].type == type) { @@ -529,6 +533,8 @@ static CURLcode pausewrite(struct Curl_easy *data, /* update the pointer and the size */ s->tempwrite[i].buf = newptr; s->tempwrite[i].len = newlen; + + len = newlen; /* for the debug output below */ } else { dupl = Curl_memdup(ptr, len); @@ -692,19 +698,20 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, ssize_t nread = sread(sockfd, buf, bytesfromsocket); if(-1 == nread) { - int err = SOCKERRNO; - int return_error; + const int err = SOCKERRNO; + const bool return_error = #ifdef USE_WINSOCK - return_error = WSAEWOULDBLOCK == err; + WSAEWOULDBLOCK == err #else - return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err; + EWOULDBLOCK == err || EAGAIN == err || EINTR == err #endif + ; + *n = 0; /* no data returned */ if(return_error) return CURLE_AGAIN; return CURLE_RECV_ERROR; } - /* we only return number of bytes read when we return OK */ *n = nread; return CURLE_OK; } diff --git a/release/src/router/curl/lib/setopt.c b/release/src/router/curl/lib/setopt.c index 5f88ad3afdb..4648c872b4f 100644 --- a/release/src/router/curl/lib/setopt.c +++ b/release/src/router/curl/lib/setopt.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -2288,7 +2288,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_SSH_KEYFUNCTION: /* setting to NULL is fine since the ssh.c functions themselves will - then rever to use the internal default */ + then revert to use the internal default */ data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); break; @@ -2391,6 +2391,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* Set the list of mail recipients */ data->set.mail_rcpt = va_arg(param, struct curl_slist *); break; + case CURLOPT_MAIL_RCPT_ALLLOWFAILS: + /* allow RCPT TO command to fail for some recipients */ + data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE; + break; #endif case CURLOPT_SASL_AUTHZID: @@ -2579,16 +2583,32 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #endif #ifdef USE_ARES case CURLOPT_DNS_SERVERS: - result = Curl_set_dns_servers(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); break; case CURLOPT_DNS_INTERFACE: - result = Curl_set_dns_interface(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]); break; case CURLOPT_DNS_LOCAL_IP4: - result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]); break; case CURLOPT_DNS_LOCAL_IP6: - result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]); break; #endif case CURLOPT_TCP_KEEPALIVE: diff --git a/release/src/router/curl/lib/sha256.c b/release/src/router/curl/lib/sha256.c index bcaaeae3086..352d577e8df 100644 --- a/release/src/router/curl/lib/sha256.c +++ b/release/src/router/curl/lib/sha256.c @@ -5,7 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Florin Petriuc, + * Copyright (C) 2017, Florin Petriuc, + * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,16 +36,209 @@ #define USE_OPENSSL_SHA256 #endif +#endif /* USE_OPENSSL */ + +#ifdef USE_MBEDTLS +#include + +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) + #define HAS_RESULT_CODE_BASED_FUNCTIONS #endif +#endif /* USE_MBEDTLS */ + +/* Please keep the SSL backend-specific #if branches in this order: + * + * 1. USE_OPENSSL + * 2. USE_GNUTLS_NETTLE + * 3. USE_GNUTLS + * 4. USE_MBEDTLS + * 5. USE_COMMON_CRYPTO + * 6. USE_WIN32_CRYPTO + * + * This ensures that the same SSL branch gets activated throughout this source + * file even if multiple backends are enabled at the same time. + */ + +#if defined(USE_OPENSSL_SHA256) -#ifdef USE_OPENSSL_SHA256 /* When OpenSSL is available we use the SHA256-function from OpenSSL */ #include + +#elif defined(USE_GNUTLS_NETTLE) + +#include + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef struct sha256_ctx SHA256_CTX; + +static void SHA256_Init(SHA256_CTX *ctx) +{ + sha256_init(ctx); +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + sha256_update(ctx, length, data); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + sha256_digest(ctx, SHA256_DIGEST_SIZE, digest); +} + +#elif defined(USE_GNUTLS) + +#include + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef gcry_md_hd_t SHA256_CTX; + +static void SHA256_Init(SHA256_CTX *ctx) +{ + gcry_md_open(ctx, GCRY_MD_SHA256, 0); +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + gcry_md_write(*ctx, data, length); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + memcpy(digest, gcry_md_read(*ctx, 0), SHA256_DIGEST_LENGTH); + gcry_md_close(*ctx); +} + +#elif defined(USE_MBEDTLS) + +#include + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef mbedtls_sha256_context SHA256_CTX; + +static void SHA256_Init(SHA256_CTX *ctx) +{ +#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_sha256_starts(ctx, 0); +#else + (void) mbedtls_sha256_starts_ret(ctx, 0); +#endif +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ +#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_sha256_update(ctx, data, length); +#else + (void) mbedtls_sha256_update_ret(ctx, data, length); +#endif +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ +#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) + mbedtls_sha256_finish(ctx, digest); +#else + (void) mbedtls_sha256_finish_ret(ctx, digest); +#endif +} + +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) + +#include + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef CC_SHA256_CTX SHA256_CTX; + +static void SHA256_Init(SHA256_CTX *ctx) +{ + (void) CC_SHA256_Init(ctx); +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + (void) CC_SHA256_Update(ctx, data, length); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + (void) CC_SHA256_Final(digest, ctx); +} + +#elif defined(USE_WIN32_CRYPTO) + +#include + +typedef struct { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +} SHA256_CTX; + +#if !defined(CALG_SHA_256) +#define CALG_SHA_256 0x0000800c +#endif + +static void SHA256_Init(SHA256_CTX *ctx) +{ + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, + PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); + } +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + CryptHashData(ctx->hHash, (unsigned char *) data, length, 0); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + unsigned long length; + + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == SHA256_DIGEST_LENGTH) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + #else /* When no other crypto library is available we use this code segment */ -/* ===== start - public domain SHA256 implementation ===== */ /* This is based on SHA256 implementation in LibTomCrypt that was released into * public domain by Tom St Denis. */ @@ -95,7 +289,8 @@ typedef struct sha256_state { unsigned long state[8], curlen; unsigned char buf[64]; } SHA256_CTX; -/* the K array */ + +/* The K array */ static const unsigned long K[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, @@ -111,6 +306,7 @@ static const unsigned long K[64] = { 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; + /* Various logical functions */ #define RORc(x, y) \ (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ @@ -123,13 +319,15 @@ static const unsigned long K[64] = { #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -/* compress 512-bits */ + +/* Compress 512-bits */ static int sha256_compress(struct sha256_state *md, unsigned char *buf) { unsigned long S[8], W[64]; int i; - /* copy state into S */ + + /* Copy state into S */ for(i = 0; i < 8; i++) { S[i] = md->state[i]; } @@ -141,6 +339,7 @@ static int sha256_compress(struct sha256_state *md, W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } + /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ @@ -153,12 +352,15 @@ static int sha256_compress(struct sha256_state *md, t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; } - /* feedback */ + + /* Feedback */ for(i = 0; i < 8; i++) { md->state[i] = md->state[i] + S[i]; } + return 0; } + /* Initialize the hash state */ static void SHA256_Init(struct sha256_state *md) { @@ -173,7 +375,8 @@ static void SHA256_Init(struct sha256_state *md) md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; } -/** + +/* Process a block of memory though the hash @param md The hash state @param in The data to hash @@ -185,6 +388,7 @@ static int SHA256_Update(struct sha256_state *md, unsigned long inlen) { unsigned long n; + #define block_size 64 if(md->curlen > sizeof(md->buf)) return -1; @@ -210,9 +414,11 @@ static int SHA256_Update(struct sha256_state *md, } } } + return 0; } -/** + +/* Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) @@ -222,13 +428,17 @@ static int SHA256_Final(unsigned char *out, struct sha256_state *md) { int i; + if(md->curlen >= sizeof(md->buf)) return -1; - /* increase the length of the message */ + + /* Increase the length of the message */ md->length += md->curlen * 8; - /* append the '1' bit */ + + /* Append the '1' bit */ md->buf[md->curlen++] = (unsigned char)0x80; - /* if the length is currently above 56 bytes we append zeros + + /* If the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ @@ -239,29 +449,44 @@ static int SHA256_Final(unsigned char *out, sha256_compress(md, md->buf); md->curlen = 0; } - /* pad up to 56 bytes of zeroes */ + + /* Pad up to 56 bytes of zeroes */ while(md->curlen < 56) { md->buf[md->curlen++] = (unsigned char)0; } - /* store length */ + + /* Store length */ WPA_PUT_BE64(md->buf + 56, md->length); sha256_compress(md, md->buf); - /* copy output */ + + /* Copy output */ for(i = 0; i < 8; i++) WPA_PUT_BE32(out + (4 * i), md->state[i]); + return 0; } -/* ===== end - public domain SHA256 implementation ===== */ -#endif +#endif /* CRYPTO LIBS */ -void Curl_sha256it(unsigned char *outbuffer, /* 32 unsigned chars */ - const unsigned char *input) +/* + * Curl_sha256it() + * + * Generates a SHA256 hash for the given input data. + * + * Parameters: + * + * output [in/out] - The output buffer. + * input [in] - The input data. + * length [in] - The input length. + */ +void Curl_sha256it(unsigned char *output, const unsigned char *input, + const size_t length) { SHA256_CTX ctx; + SHA256_Init(&ctx); - SHA256_Update(&ctx, input, curlx_uztoui(strlen((char *)input))); - SHA256_Final(outbuffer, &ctx); + SHA256_Update(&ctx, input, curlx_uztoui(length)); + SHA256_Final(output, &ctx); } #endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/release/src/router/curl/lib/smtp.c b/release/src/router/curl/lib/smtp.c index 65220b0f683..e1872871dcf 100644 --- a/release/src/router/curl/lib/smtp.c +++ b/release/src/router/curl/lib/smtp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,6 +27,9 @@ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * RFC4954 SMTP Authentication * RFC5321 SMTP protocol + * RFC5890 Internationalized Domain Names for Applications (IDNA) + * RFC6531 SMTP Extension for Internationalized Email + * RFC6532 Internationalized Email Headers * RFC6749 OAuth 2.0 Authorization Framework * RFC8314 Use of TLS for Email Submission and Access * Draft SMTP URL Interface @@ -101,6 +104,8 @@ static CURLcode smtp_setup_connection(struct connectdata *conn); static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn); static CURLcode smtp_parse_custom_request(struct connectdata *conn); +static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, + char **address, struct hostname *host); static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); @@ -481,13 +486,55 @@ static CURLcode smtp_perform_command(struct connectdata *conn) struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; - /* Send the command */ - if(smtp->rcpt) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s", - smtp->custom && smtp->custom[0] != '\0' ? - smtp->custom : "VRFY", - smtp->rcpt->data); + if(smtp->rcpt) { + /* We notify the server we are sending UTF-8 data if a) it supports the + SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in + either the local address or host name parts. This is regardless of + whether the host name is encoded using IDN ACE */ + bool utf8 = FALSE; + + if((!smtp->custom) || (!smtp->custom[0])) { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the mailbox to verify into the local address and host name + parts, converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(conn, smtp->rcpt->data, + &address, &host); + if(result) + return result; + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 6 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name))); + + /* Send the VRFY command (Note: The host name part may be absent when the + host is a local system) */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "VRFY %s%s%s%s", + address, + host.name ? "@" : "", + host.name ? host.name : "", + utf8 ? " SMTPUTF8" : ""); + + Curl_free_idnconverted_hostname(&host); + free(address); + } + else { + /* Establish whether we should report that we support SMTPUTF8 for EXPN + commands to the server as per RFC-6531 sect. 3.1 point 6 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + (!strcmp(smtp->custom, "EXPN")); + + /* Send the custom recipient based command such as the EXPN command */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s%s", smtp->custom, + smtp->rcpt->data, + utf8 ? " SMTPUTF8" : ""); + } + } else + /* Send the non-recipient based command such as HELP */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", smtp->custom && smtp->custom[0] != '\0' ? smtp->custom : "HELP"); @@ -512,22 +559,86 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; + /* We notify the server we are sending UTF-8 data if a) it supports the + SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in + either the local address or host name parts. This is regardless of + whether the host name is encoded using IDN ACE */ + bool utf8 = FALSE; + /* Calculate the FROM parameter */ - if(!data->set.str[STRING_MAIL_FROM]) + if(data->set.str[STRING_MAIL_FROM]) { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the FROM mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM], + &address, &host); + if(result) + return result; + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ + utf8 = (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name))); + + if(host.name) { + from = aprintf("<%s@%s>", address, host.name); + + Curl_free_idnconverted_hostname(&host); + } + else + /* An invalid mailbox was provided but we'll simply let the server worry + about that and reply with a 501 error */ + from = aprintf("<%s>", address); + + free(address); + } + else /* Null reverse-path, RFC-5321, sect. 3.6.3 */ from = strdup("<>"); - else if(data->set.str[STRING_MAIL_FROM][0] == '<') - from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); - else - from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); if(!from) return CURLE_OUT_OF_MEMORY; /* Calculate the optional AUTH parameter */ if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { - if(data->set.str[STRING_MAIL_AUTH][0] != '\0') - auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]); + if(data->set.str[STRING_MAIL_AUTH][0] != '\0') { + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the AUTH mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH], + &address, &host); + if(result) { + free(from); + return result; + } + + /* Establish whether we should report SMTPUTF8 to the server for this + mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ + if((!utf8) && (conn->proto.smtpc.utf8_supported) && + ((host.encalloc) || (!Curl_is_ASCII_name(address)) || + (!Curl_is_ASCII_name(host.name)))) + utf8 = TRUE; + + if(host.name) { + free(from); + from = aprintf("<%s@%s>", address, host.name); + + Curl_free_idnconverted_hostname(&host); + } + else + /* An invalid mailbox was provided but we'll simply let the server + worry about it */ + auth = aprintf("<%s>", address); + + free(address); + if(!from) + return CURLE_OUT_OF_MEMORY; + } else /* Empty AUTH, RFC-2554, sect. 5 */ auth = strdup("<>"); @@ -561,6 +672,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) if(result) { free(from); free(auth); + return result; } @@ -583,19 +695,33 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) } } + /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8 + based address then quickly scan through the recipient list and check if + any there do, as we need to correctly identify our support for SMTPUTF8 + in the envelope, as per RFC-6531 sect. 3.4 */ + if(conn->proto.smtpc.utf8_supported && !utf8) { + struct SMTP *smtp = data->req.protop; + struct curl_slist *rcpt = smtp->rcpt; + + while(rcpt && !utf8) { + /* Does the host name contain non-ASCII characters? */ + if(!Curl_is_ASCII_name(rcpt->data)) + utf8 = TRUE; + + rcpt = rcpt->next; + } + } + /* Send the MAIL command */ - if(!auth && !size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s", from); - else if(auth && !size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s AUTH=%s", from, auth); - else if(auth && size) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size); - else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, - "MAIL FROM:%s SIZE=%s", from, size); + result = Curl_pp_sendf(&conn->proto.smtpc.pp, + "MAIL FROM:%s%s%s%s%s%s", + from, /* Mandatory */ + auth ? " AUTH=" : "", /* Optional on AUTH support */ + auth ? auth : "", /* */ + size ? " SIZE=" : "", /* Optional on SIZE support */ + size ? size : "", /* */ + utf8 ? " SMTPUTF8" /* Internationalised mailbox */ + : ""); /* included in our envelope */ free(from); free(auth); @@ -619,14 +745,28 @@ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; + char *address = NULL; + struct hostname host = { NULL, NULL, NULL, NULL }; + + /* Parse the recipient mailbox into the local address and host name parts, + converting the host name to an IDN A-label if necessary */ + result = smtp_parse_address(conn, smtp->rcpt->data, + &address, &host); + if(result) + return result; /* Send the RCPT TO command */ - if(smtp->rcpt->data[0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", - smtp->rcpt->data); + if(host.name) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", address, + host.name); else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", - smtp->rcpt->data); + /* An invalid mailbox was provided but we'll simply let the server worry + about that and reply with a 501 error */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", address); + + Curl_free_idnconverted_hostname(&host); + free(address); + if(!result) state(conn, SMTP_RCPT); @@ -726,6 +866,10 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, else if(len >= 4 && !memcmp(line, "SIZE", 4)) smtpc->size_supported = TRUE; + /* Does the server support the UTF-8 capability? */ + else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8)) + smtpc->utf8_supported = TRUE; + /* Does the server support authentication? */ else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { smtpc->auth_supported = TRUE; @@ -915,25 +1059,53 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; + bool is_smtp_err = FALSE; + bool is_smtp_blocking_err = FALSE; (void)instate; /* no use for this yet */ - if(smtpcode/100 != 2) { - failf(data, "RCPT failed: %d", smtpcode); - result = CURLE_SEND_ERROR; + is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE; + + /* If there's multiple RCPT TO to be issued, it's possible to ignore errors + and proceed with only the valid addresses. */ + is_smtp_blocking_err = + (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE; + + if(is_smtp_err) { + /* Remembering the last failure which we can report if all "RCPT TO" have + failed and we cannot proceed. */ + smtp->rcpt_last_error = smtpcode; + + if(is_smtp_blocking_err) { + failf(data, "RCPT failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } } else { + /* Some RCPT TO commands have succeeded. */ + smtp->rcpt_had_ok = TRUE; + } + + if(!is_smtp_blocking_err) { smtp->rcpt = smtp->rcpt->next; if(smtp->rcpt) /* Send the next RCPT TO command */ result = smtp_perform_rcpt_to(conn); else { - /* Send the DATA command */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); + /* We weren't able to issue a successful RCPT TO command while going + over recipients (potentially multiple). Sending back last error. */ + if(!smtp->rcpt_had_ok) { + failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error); + result = CURLE_SEND_ERROR; + } + else { + /* Send the DATA command */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); - if(!result) - state(conn, SMTP_DATA); + if(!result) + state(conn, SMTP_DATA); + } } } @@ -1287,6 +1459,12 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, /* Store the first recipient (or NULL if not specified) */ smtp->rcpt = data->set.mail_rcpt; + /* Track of whether we've successfully sent at least one RCPT TO command */ + smtp->rcpt_had_ok = FALSE; + + /* Track of the last error we've received by sending RCPT TO command */ + smtp->rcpt_last_error = 0; + /* Initial data character is the first character in line: it is implicitly preceded by a virtual CRLF. */ smtp->trailing_crlf = TRUE; @@ -1537,6 +1715,76 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) return result; } +/*********************************************************************** + * + * smtp_parse_address() + * + * Parse the fully qualified mailbox address into a local address part and the + * host name, converting the host name to an IDN A-label, as per RFC-5890, if + * necessary. + * + * Parameters: + * + * conn [in] - The connection handle. + * fqma [in] - The fully qualified mailbox address (which may or + * may not contain UTF-8 characters). + * address [in/out] - A new allocated buffer which holds the local + * address part of the mailbox. This buffer must be + * free'ed by the caller. + * host [in/out] - The host name structure that holds the original, + * and optionally encoded, host name. + * Curl_free_idnconverted_hostname() must be called + * once the caller has finished with the structure. + * + * Returns CURLE_OK on success. + * + * Notes: + * + * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor + * that convertion then we shall return success. This allow the caller to send + * the data to the server as a U-label (as per RFC-6531 sect. 3.2). + * + * If an mailbox '@' seperator cannot be located then the mailbox is considered + * to be either a local mailbox or an invalid mailbox (depending on what the + * calling function deems it to be) then the input will simply be returned in + * the address part with the host name being NULL. + */ +static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, + char **address, struct hostname *host) +{ + CURLcode result = CURLE_OK; + size_t length; + + /* Duplicate the fully qualified email address so we can manipulate it, + ensuring it doesn't contain the delimiters if specified */ + char *dup = strdup(fqma[0] == '<' ? fqma + 1 : fqma); + if(!dup) + return CURLE_OUT_OF_MEMORY; + + length = strlen(dup); + if(dup[length - 1] == '>') + dup[length - 1] = '\0'; + + /* Extract the host name from the addresss (if we can) */ + host->name = strpbrk(dup, "@"); + if(host->name) { + *host->name = '\0'; + host->name = host->name + 1; + + /* Attempt to convert the host name to IDN ACE */ + (void) Curl_idnconvert_hostname(conn, host); + + /* If Curl_idnconvert_hostname() fails then we shall attempt to continue + and send the host name using UTF-8 rather than as 7-bit ACE (which is + our preference) */ + } + + /* Extract the local address from the mailbox */ + *address = dup; + + return result; +} + CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) { /* When sending a SMTP payload we must detect CRLF. sequences making sure diff --git a/release/src/router/curl/lib/smtp.h b/release/src/router/curl/lib/smtp.h index 20fc081190e..164a175d759 100644 --- a/release/src/router/curl/lib/smtp.h +++ b/release/src/router/curl/lib/smtp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2009 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,6 +55,9 @@ struct SMTP { curl_pp_transfer transfer; char *custom; /* Custom Request */ struct curl_slist *rcpt; /* Recipient list */ + bool rcpt_had_ok; /* Whether any of RCPT TO commands (depends on + total number of recipients) succeeded so far */ + int rcpt_last_error; /* The last error received for RCPT TO command */ size_t eob; /* Number of bytes of the EOB (End Of Body) that have been received so far */ bool trailing_crlf; /* Specifies if the tailing CRLF is present */ @@ -71,6 +74,8 @@ struct smtp_conn { bool tls_supported; /* StartTLS capability supported by server */ bool size_supported; /* If server supports SIZE extension according to RFC 1870 */ + bool utf8_supported; /* If server supports SMTPUTF8 extension according + to RFC 6531 */ bool auth_supported; /* AUTH capability supported by server */ }; diff --git a/release/src/router/curl/lib/socks.c b/release/src/router/curl/lib/socks.c index 6ae98184d16..37099130e5d 100644 --- a/release/src/router/curl/lib/socks.c +++ b/release/src/router/curl/lib/socks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,18 +37,19 @@ #include "connect.h" #include "timeval.h" #include "socks.h" +#include "multiif.h" /* for getsock macros */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* * Helper read-from-socket functions. Does the same as Curl_read() but it * blocks until all bytes amount of buffersize will be read. No more, no less. * - * This is STUPID BLOCKING behaviour which we frown upon, but right now this - * is what we have... + * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions. */ int Curl_blockread_all(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ @@ -94,6 +95,81 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ } return result; } +#endif + +#ifndef DEBUGBUILD +#define sxstate(x,y) socksstate(x,y) +#else +#define sxstate(x,y) socksstate(x,y, __LINE__) +#endif + + +/* always use this function to change state, to make debugging easier */ +static void socksstate(struct connectdata *conn, + enum connect_t state +#ifdef DEBUGBUILD + , int lineno +#endif +) +{ + enum connect_t oldstate = conn->cnnct.state; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* synced with the state list in urldata.h */ + static const char * const statename[] = { + "INIT", + "SOCKS_INIT", + "SOCKS_SEND", + "SOCKS_READ_INIT", + "SOCKS_READ", + "GSSAPI_INIT", + "AUTH_INIT", + "AUTH_SEND", + "AUTH_READ", + "REQ_INIT", + "RESOLVING", + "RESOLVED", + "RESOLVE_REMOTE", + "REQ_SEND", + "REQ_SENDING", + "REQ_READ", + "REQ_READ_MORE", + "DONE" + }; +#endif + + if(oldstate == state) + /* don't bother when the new state is the same as the old state */ + return; + + conn->cnnct.state = state; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(conn->data, + "SXSTATE: %s => %s conn %p; line %d\n", + statename[oldstate], statename[conn->cnnct.state], conn, + lineno); +#endif +} + +int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock, + int sockindex) +{ + int rc = 0; + sock[0] = conn->sock[sockindex]; + switch(conn->cnnct.state) { + case CONNECT_RESOLVING: + case CONNECT_SOCKS_READ: + case CONNECT_AUTH_READ: + case CONNECT_REQ_READ: + case CONNECT_REQ_READ_MORE: + rc = GETSOCK_READSOCK(0); + break; + default: + rc = GETSOCK_WRITESOCK(0); + break; + } + return rc; +} /* * This function logs in to a SOCKS4 proxy and sends the specifics to the final @@ -110,62 +186,91 @@ CURLcode Curl_SOCKS4(const char *proxy_user, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn) + struct connectdata *conn, + bool *done) { const bool protocol4a = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; -#define SOCKS4REQLEN 262 - unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user - id */ - CURLcode code; - curl_socket_t sock = conn->sock[sockindex]; + unsigned char *socksreq = &conn->cnnct.socksreq[0]; + CURLcode result; + curl_socket_t sockfd = conn->sock[sockindex]; struct Curl_easy *data = conn->data; + struct connstate *sx = &conn->cnnct; + struct Curl_dns_entry *dns = NULL; + ssize_t actualread; + ssize_t written; - if(Curl_timeleft(data, NULL, TRUE) < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(conn->bits.httpproxy) - infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", - protocol4a ? "a" : "", hostname, remote_port); - - (void)curlx_nonblock(sock, FALSE); + if(!SOCKS_STATE(sx->state) && !*done) + sxstate(conn, CONNECT_SOCKS_INIT); - infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + /* SOCKS4 can only do IPv4, insist! */ + conn->ip_version = CURL_IPRESOLVE_V4; + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", + protocol4a ? "a" : "", hostname, remote_port); - /* - * Compose socks4 request - * - * Request format - * - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * | VN | CD | DSTPORT | DSTIP | USERID |NULL| - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * # of bytes: 1 1 2 4 variable 1 - */ + infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); - socksreq[0] = 4; /* version (SOCKS4) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ - socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ - - /* DNS resolve only for SOCKS4, not SOCKS4a */ - if(!protocol4a) { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp = NULL; - int rc; + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ - rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns); + socksreq[0] = 4; /* version (SOCKS4) */ + socksreq[1] = 1; /* connect */ + socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ + socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ + + /* DNS resolve only for SOCKS4, not SOCKS4a */ + if(!protocol4a) { + enum resolve_t rc = + Curl_resolv(conn, hostname, remote_port, FALSE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLE_COULDNT_RESOLVE_PROXY; + else if(rc == CURLRESOLV_PENDING) { + sxstate(conn, CONNECT_RESOLVING); + infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname); + return CURLE_OK; + } + sxstate(conn, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_PROXY; + /* socks4a doesn't resolve anything locally */ + sxstate(conn, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; - if(rc == CURLRESOLV_PENDING) - /* ignores the return code, but 'dns' remains NULL on failure */ - (void)Curl_resolver_wait_resolv(conn, &dns); + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(conn, hostname, (int)conn->port); + if(dns) { +#ifdef CURLRES_ASYNCH + conn->async.dns = dns; + conn->async.done = TRUE; +#endif + infof(data, "Hostname '%s' was found\n", hostname); + sxstate(conn, CONNECT_RESOLVED); + } + else { + result = Curl_resolv_check(data->conn, &dns); + if(!dns) + return result; + } + /* FALLTHROUGH */ + CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + Curl_addrinfo *hp = NULL; + char buf[64]; /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It * returns a Curl_addrinfo pointer that may not always look the same. @@ -173,7 +278,6 @@ CURLcode Curl_SOCKS4(const char *proxy_user, if(dns) hp = dns->addr; if(hp) { - char buf[64]; Curl_printable_address(hp, buf, sizeof(buf)); if(hp->ai_family == AF_INET) { @@ -189,7 +293,6 @@ CURLcode Curl_SOCKS4(const char *proxy_user, } else { hp = NULL; /* fail! */ - failf(data, "SOCKS4 connection to %s not supported\n", buf); } @@ -201,149 +304,166 @@ CURLcode Curl_SOCKS4(const char *proxy_user, return CURLE_COULDNT_RESOLVE_HOST; } } - - /* - * This is currently not supporting "Identification Protocol (RFC1413)". - */ - socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ - if(proxy_user) { - size_t plen = strlen(proxy_user); - if(plen >= sizeof(socksreq) - 8) { - failf(data, "Too long SOCKS proxy name, can't use!\n"); - return CURLE_COULDNT_CONNECT; + /* FALLTHROUGH */ + CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + /* + * This is currently not supporting "Identification Protocol (RFC1413)". + */ + socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ + if(proxy_user) { + size_t plen = strlen(proxy_user); + if(plen >= sizeof(sx->socksreq) - 8) { + failf(data, "Too long SOCKS proxy name, can't use!\n"); + return CURLE_COULDNT_CONNECT; + } + /* copy the proxy name WITH trailing zero */ + memcpy(socksreq + 8, proxy_user, plen + 1); } - /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, proxy_user, plen + 1); - } - /* - * Make connection - */ - { - int result; - ssize_t actualread; - ssize_t written; - ssize_t hostnamelen = 0; - ssize_t packetsize = 9 + - strlen((char *)socksreq + 8); /* size including NUL */ - - /* If SOCKS4a, set special invalid IP address 0.0.0.x */ - if(protocol4a) { - socksreq[4] = 0; - socksreq[5] = 0; - socksreq[6] = 0; - socksreq[7] = 1; - /* If still enough room in buffer, also append hostname */ - hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ - if(packetsize + hostnamelen <= SOCKS4REQLEN) - strcpy((char *)socksreq + packetsize, hostname); - else - hostnamelen = 0; /* Flag: hostname did not fit in buffer */ + /* + * Make connection + */ + { + ssize_t packetsize = 9 + + strlen((char *)socksreq + 8); /* size including NUL */ + + /* If SOCKS4a, set special invalid IP address 0.0.0.x */ + if(protocol4a) { + ssize_t hostnamelen = 0; + socksreq[4] = 0; + socksreq[5] = 0; + socksreq[6] = 0; + socksreq[7] = 1; + /* append hostname */ + hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ + if(hostnamelen <= 255) + strcpy((char *)socksreq + packetsize, hostname); + else { + failf(data, "SOCKS4: too long host name"); + return CURLE_COULDNT_CONNECT; + } + packetsize += hostnamelen; + } + sx->outp = socksreq; + sx->outstanding = packetsize; + sxstate(conn, CONNECT_REQ_SENDING); } - + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: /* Send request */ - code = Curl_write_plain(conn, sock, (char *)socksreq, - packetsize + hostnamelen, - &written); - if(code || (written != packetsize + hostnamelen)) { + result = Curl_write_plain(conn, sockfd, (char *)sx->outp, + sx->outstanding, &written); + if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } - if(protocol4a && hostnamelen == 0) { - /* SOCKS4a with very long hostname - send that name separately */ - hostnamelen = (ssize_t)strlen(hostname) + 1; - code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen, - &written); - if(code || (written != hostnamelen)) { - failf(data, "Failed to send SOCKS4 connect request."); - return CURLE_COULDNT_CONNECT; - } + if(written != sx->outstanding) { + /* not done, remain in state */ + sx->outstanding -= written; + sx->outp += written; + return CURLE_OK; } - packetsize = 8; /* receive data size */ + /* done sending! */ + sx->outstanding = 8; /* receive data size */ + sx->outp = socksreq; + sxstate(conn, CONNECT_SOCKS_READ); + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: /* Receive response */ - result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread); - if(result || (actualread != packetsize)) { - failf(data, "Failed to receive SOCKS4 connect request ack."); + result = Curl_read_plain(sockfd, (char *)sx->outp, + sx->outstanding, &actualread); + if(result && (CURLE_AGAIN != result)) { + failf(data, "SOCKS4: Failed receiving connect request ack: %s", + curl_easy_strerror(result)); return CURLE_COULDNT_CONNECT; } - - /* - * Response format - * - * +----+----+----+----+----+----+----+----+ - * | VN | CD | DSTPORT | DSTIP | - * +----+----+----+----+----+----+----+----+ - * # of bytes: 1 1 2 4 - * - * VN is the version of the reply code and should be 0. CD is the result - * code with one of the following values: - * - * 90: request granted - * 91: request rejected or failed - * 92: request rejected because SOCKS server cannot connect to - * identd on the client - * 93: request rejected because the client program and identd - * report different user-ids - */ - - /* wrong version ? */ - if(socksreq[0] != 0) { - failf(data, - "SOCKS4 reply has wrong version, version should be 0."); - return CURLE_COULDNT_CONNECT; + else if(actualread != sx->outstanding) { + /* remain in reading state */ + sx->outstanding -= actualread; + sx->outp += actualread; + return CURLE_OK; } + sxstate(conn, CONNECT_DONE); + break; + default: /* lots of unused states in SOCKS4 */ + break; + } - /* Result */ - switch(socksreq[1]) { - case 90: - infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); - break; - case 91: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected or failed.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 92: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because SOCKS server cannot connect to " - "identd on the client.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 93: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because the client program and identd " - "report different user-ids.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - default: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", Unknown.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; - } + /* + * Response format + * + * +----+----+----+----+----+----+----+----+ + * | VN | CD | DSTPORT | DSTIP | + * +----+----+----+----+----+----+----+----+ + * # of bytes: 1 1 2 4 + * + * VN is the version of the reply code and should be 0. CD is the result + * code with one of the following values: + * + * 90: request granted + * 91: request rejected or failed + * 92: request rejected because SOCKS server cannot connect to + * identd on the client + * 93: request rejected because the client program and identd + * report different user-ids + */ + + /* wrong version ? */ + if(socksreq[0] != 0) { + failf(data, + "SOCKS4 reply has wrong version, version should be 0."); + return CURLE_COULDNT_CONNECT; } - (void)curlx_nonblock(sock, TRUE); + /* Result */ + switch(socksreq[1]) { + case 90: + infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); + break; + case 91: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected or failed.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLE_COULDNT_CONNECT; + case 92: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because SOCKS server cannot connect to " + "identd on the client.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLE_COULDNT_CONNECT; + case 93: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because the client program and identd " + "report different user-ids.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLE_COULDNT_CONNECT; + default: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", Unknown.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), + (unsigned char)socksreq[1]); + return CURLE_COULDNT_CONNECT; + } + *done = TRUE; return CURLE_OK; /* Proxy was successful! */ } @@ -356,7 +476,8 @@ CURLcode Curl_SOCKS5(const char *proxy_user, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn) + struct connectdata *conn, + bool *done) { /* According to the RFC1928, section "6. Replies". This is what a SOCK5 @@ -374,141 +495,158 @@ CURLcode Curl_SOCKS5(const char *proxy_user, o REP Reply field: o X'00' succeeded */ -#define REQUEST_BUFSIZE 600 /* room for large user/pw (255 max each) */ - unsigned char socksreq[REQUEST_BUFSIZE]; - char dest[REQUEST_BUFSIZE] = "unknown"; /* printable hostname:port */ + unsigned char *socksreq = &conn->cnnct.socksreq[0]; + char dest[256] = "unknown"; /* printable hostname:port */ int idx; ssize_t actualread; ssize_t written; - int result; - CURLcode code; - curl_socket_t sock = conn->sock[sockindex]; + CURLcode result; + curl_socket_t sockfd = conn->sock[sockindex]; struct Curl_easy *data = conn->data; - timediff_t timeout; bool socks5_resolve_local = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(hostname); ssize_t len = 0; const unsigned long auth = data->set.socks5auth; bool allow_gssapi = FALSE; + struct connstate *sx = &conn->cnnct; + struct Curl_dns_entry *dns = NULL; + + if(!SOCKS_STATE(sx->state) && !*done) + sxstate(conn, CONNECT_SOCKS_INIT); + + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", + hostname, remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " + "length > 255 [actual len=%zu]\n", hostname_len); + socks5_resolve_local = TRUE; + } - if(conn->bits.httpproxy) - infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", - hostname, remote_port); - - /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) { - infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " - "length > 255 [actual len=%zu]\n", hostname_len); - socks5_resolve_local = TRUE; - } - - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - - if(timeout < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - (void)curlx_nonblock(sock, TRUE); - - /* wait until socket gets connected */ - result = SOCKET_WRITABLE(sock, timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5: no connection here"); - return CURLE_COULDNT_CONNECT; - } - if(0 == result) { - failf(conn->data, "SOCKS5: connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5: error occurred during connection"); - return CURLE_COULDNT_CONNECT; - } - - if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - infof(conn->data, - "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n", - auth); - if(!(auth & CURLAUTH_BASIC)) - /* disable username/password auth */ - proxy_user = NULL; + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(conn->data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + proxy_user = NULL; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(auth & CURLAUTH_GSSAPI) - allow_gssapi = TRUE; + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; #endif - idx = 0; - socksreq[idx++] = 5; /* version */ - idx++; /* reserve for the number of authentication methods */ - socksreq[idx++] = 0; /* no authentication */ - if(allow_gssapi) - socksreq[idx++] = 1; /* GSS-API */ - if(proxy_user) - socksreq[idx++] = 2; /* username/password */ - /* write the number of authentication methods */ - socksreq[1] = (unsigned char) (idx - 2); - - (void)curlx_nonblock(sock, FALSE); - - infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); - - code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), - &written); - if(code || (written != (2 + (int)socksreq[1]))) { - failf(data, "Unable to send initial SOCKS5 request."); - return CURLE_COULDNT_CONNECT; - } - - (void)curlx_nonblock(sock, TRUE); - - result = SOCKET_READABLE(sock, timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5 nothing to read"); - return CURLE_COULDNT_CONNECT; - } - if(0 == result) { - failf(conn->data, "SOCKS5 read timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5 read error occurred"); - return CURLE_RECV_ERROR; - } - - (void)curlx_nonblock(sock, FALSE); - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if(result || (actualread != 2)) { - failf(data, "Unable to receive initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[0] != 5) { - failf(data, "Received invalid version in initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - if(socksreq[1] == 0) { - /* Nothing to do, no authentication needed */ - ; - } + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Unable to send initial SOCKS5 request."); + return CURLE_COULDNT_CONNECT; + } + if(written != idx) { + sxstate(conn, CONNECT_SOCKS_SEND); + sx->outstanding = idx - written; + sx->outp = &socksreq[written]; + return CURLE_OK; + } + sxstate(conn, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + result = Curl_write_plain(conn, sockfd, (char *)sx->outp, + sx->outstanding, &written); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Unable to send initial SOCKS5 request."); + return CURLE_COULDNT_CONNECT; + } + if(written != sx->outstanding) { + /* not done, remain in state */ + sx->outstanding -= written; + sx->outp += written; + return CURLE_OK; + } + /* FALLTHROUGH */ + CONNECT_SOCKS_READ_INIT: + case CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: + result = Curl_read_plain(sockfd, (char *)sx->outp, + sx->outstanding, &actualread); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Unable to receive initial SOCKS5 response."); + return CURLE_COULDNT_CONNECT; + } + else if(actualread != sx->outstanding) { + /* remain in reading state */ + sx->outstanding -= actualread; + sx->outp += actualread; + return CURLE_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLE_COULDNT_CONNECT; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(conn, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(conn, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else if(allow_gssapi && (socksreq[1] == 1)) { - code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); - if(code) { - failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(conn, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLE_COULDNT_CONNECT; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLE_COULDNT_CONNECT; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLE_COULDNT_CONNECT; + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); return CURLE_COULDNT_CONNECT; } - } + break; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; #endif - else if(socksreq[1] == 2) { + + default: /* do nothing! */ + break; + + CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { /* Needs user name and password */ size_t proxy_user_len, proxy_password_len; if(proxy_user && proxy_password) { @@ -549,18 +687,41 @@ CURLcode Curl_SOCKS5(const char *proxy_user, memcpy(socksreq + len, proxy_password, proxy_password_len); } len += proxy_password_len; - - code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - if(code || (len != written)) { + sxstate(conn, CONNECT_AUTH_SEND); + sx->outstanding = len; + sx->outp = socksreq; + } + /* FALLTHROUGH */ + case CONNECT_AUTH_SEND: + result = Curl_write_plain(conn, sockfd, (char *)sx->outp, + sx->outstanding, &written); + if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to send SOCKS5 sub-negotiation request."); return CURLE_COULDNT_CONNECT; } - - result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if(result || (actualread != 2)) { + if(sx->outstanding != written) { + /* remain in state */ + sx->outstanding -= written; + sx->outp += written; + return CURLE_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(conn, CONNECT_AUTH_READ); + /* FALLTHROUGH */ + case CONNECT_AUTH_READ: + result = Curl_read_plain(sockfd, (char *)sx->outp, + sx->outstanding, &actualread); + if(result && (CURLE_AGAIN != result)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; } + if(actualread != sx->outstanding) { + /* remain in state */ + sx->outstanding -= actualread; + sx->outp += actualread; + return CURLE_OK; + } /* ignore the first (VER) byte */ if(socksreq[1] != 0) { /* status */ @@ -570,209 +731,248 @@ CURLcode Curl_SOCKS5(const char *proxy_user, } /* Everything is good so far, user was authenticated! */ - } - else { - /* error */ - if(!allow_gssapi && (socksreq[1] == 1)) { - failf(data, - "SOCKS5 GSSAPI per-message authentication is not supported."); - return CURLE_COULDNT_CONNECT; - } - if(socksreq[1] == 255) { - if(!proxy_user || !*proxy_user) { - failf(data, - "No authentication method was acceptable. (It is quite likely" - " that the SOCKS5 server wanted a username/password, since none" - " was supplied to the server on this connection.)"); + sxstate(conn, CONNECT_REQ_INIT); + /* FALLTHROUGH */ + CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(conn, hostname, remote_port, + FALSE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLE_COULDNT_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(conn, CONNECT_RESOLVING); + return CURLE_OK; } - else { - failf(data, "No authentication method was acceptable."); - } - return CURLE_COULDNT_CONNECT; + sxstate(conn, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; } - else { - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLE_COULDNT_CONNECT; - } - } + goto CONNECT_RESOLVE_REMOTE; - /* Authentication is complete, now specify destination to the proxy */ - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - - if(!socks5_resolve_local) { - socksreq[len++] = 3; /* ATYP: domain name = 3 */ - socksreq[len++] = (char) hostname_len; /* address length */ - memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */ - len += hostname_len; - msnprintf(dest, sizeof(dest), "%s:%d", hostname, remote_port); - infof(data, "SOCKS5 connect to %s (remotely resolved)\n", dest); - } - else { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp = NULL; - int rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns); - - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_HOST; + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(conn, hostname, (int)conn->port); - if(rc == CURLRESOLV_PENDING) { - /* this requires that we're in "wait for resolve" state */ - code = Curl_resolver_wait_resolv(conn, &dns); - if(code) - return code; + if(dns) { +#ifdef CURLRES_ASYNCH + conn->async.dns = dns; + conn->async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found\n", hostname); } - /* - * We cannot use 'hostent' as a struct that Curl_resolv() returns. It - * returns a Curl_addrinfo pointer that may not always look the same. - */ + if(!dns) { + result = Curl_resolv_check(data->conn, &dns); + if(!dns) + return result; + } + /* FALLTHROUGH */ + CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + Curl_addrinfo *hp = NULL; if(dns) hp = dns->addr; - if(hp) { - if(Curl_printable_address(hp, dest, sizeof(dest))) { - size_t destlen = strlen(dest); - msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port); - } - else { - strcpy(dest, "unknown"); - } - - if(hp->ai_family == AF_INET) { - int i; - struct sockaddr_in *saddr_in; - socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ - - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - for(i = 0; i < 4; i++) { - socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; - } + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + hostname); + return CURLE_COULDNT_RESOLVE_HOST; + } - infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest); - } -#ifdef ENABLE_IPV6 - else if(hp->ai_family == AF_INET6) { - int i; - struct sockaddr_in6 *saddr_in6; - socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - - saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; - for(i = 0; i < 16; i++) { - socksreq[len++] = - ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; - } + if(Curl_printable_address(hp, dest, sizeof(dest))) { + size_t destlen = strlen(dest); + msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port); + } + else { + strcpy(dest, "unknown"); + } - infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest); + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; } -#endif - else { - hp = NULL; /* fail! */ - failf(data, "SOCKS5 connection to %s not supported\n", dest); + infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; } - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest); } - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", - hostname); - return CURLE_COULDNT_RESOLVE_HOST; +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported\n", dest); } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; } + CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + socksreq[len++] = 3; /* ATYP: domain name = 3 */ + socksreq[len++] = (char) hostname_len; /* one byte address length */ + memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */ + len += hostname_len; + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)\n", + hostname, remote_port); + } + /* FALLTHROUGH */ - socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ - socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ + CONNECT_REQ_SEND: + case CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(remote_port & 0xff); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - } - else + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLE_COULDNT_CONNECT; + } #endif - code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - - if(code || (len != written)) { - failf(data, "Failed to send SOCKS5 connect request."); - return CURLE_COULDNT_CONNECT; - } - - len = 10; /* minimum packet size is 10 */ - + sx->outp = socksreq; + sx->outstanding = len; + sxstate(conn, CONNECT_REQ_SENDING); + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: + result = Curl_write_plain(conn, sockfd, (char *)sx->outp, + sx->outstanding, &written); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Failed to send SOCKS5 connect request."); + return CURLE_COULDNT_CONNECT; + } + if(sx->outstanding != written) { + /* remain in state */ + sx->outstanding -= written; + sx->outp += written; + return CURLE_OK; + } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - } - else + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLE_COULDNT_CONNECT; + } #endif - result = Curl_blockread_all(conn, sock, (char *)socksreq, - len, &actualread); - - if(result || (len != actualread)) { - failf(data, "Failed to receive SOCKS5 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - - if(socksreq[0] != 5) { /* version */ - failf(data, - "SOCKS5 reply has wrong version, version should be 5."); - return CURLE_COULDNT_CONNECT; - } - - /* Fix: in general, returned BND.ADDR is variable length parameter by RFC - 1928, so the reply packet should be read until the end to avoid errors at - subsequent protocol level. - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(conn, CONNECT_REQ_READ); + /* FALLTHROUGH */ + case CONNECT_REQ_READ: + result = Curl_read_plain(sockfd, (char *)sx->outp, + sx->outstanding, &actualread); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Failed to receive SOCKS5 connect request ack."); + return CURLE_COULDNT_CONNECT; + } + else if(actualread != sx->outstanding) { + /* remain in state */ + sx->outstanding -= actualread; + sx->outp += actualread; + return CURLE_OK; + } - ATYP: - o IP v4 address: X'01', BND.ADDR = 4 byte - o domain name: X'03', BND.ADDR = [ 1 byte length, string ] - o IP v6 address: X'04', BND.ADDR = 16 byte - */ + if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLE_COULDNT_CONNECT; + } + else if(socksreq[1] != 0) { /* Anything besides 0 is an error */ + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + hostname, (unsigned char)socksreq[1]); + return CURLE_COULDNT_CONNECT; + } - /* Calculate real packet size */ - if(socksreq[3] == 3) { - /* domain name */ - int addrlen = (int) socksreq[4]; - len = 5 + addrlen + 2; - } - else if(socksreq[3] == 4) { - /* IPv6 */ - len = 4 + 16 + 2; - } + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } - /* At this point we already read first 10 bytes */ + /* At this point we already read first 10 bytes */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(!conn->socks5_gssapi_enctype) { - /* decrypt_gssapi_blockread already read the whole packet */ + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ #endif - if(len > 10) { - result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - len - 10, &actualread); - if(result || ((len - 10) != actualread)) { - failf(data, "Failed to receive SOCKS5 connect request ack."); - return CURLE_COULDNT_CONNECT; + if(len > 10) { + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(conn, CONNECT_REQ_READ_MORE); + } + else { + sxstate(conn, CONNECT_DONE); + break; } - } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - } + } #endif - - if(socksreq[1] != 0) { /* Anything besides 0 is an error */ - failf(data, "Can't complete SOCKS5 connection to %s. (%d)", - dest, (unsigned char)socksreq[1]); - return CURLE_COULDNT_CONNECT; + /* FALLTHROUGH */ + case CONNECT_REQ_READ_MORE: + result = Curl_read_plain(sockfd, (char *)sx->outp, + sx->outstanding, &actualread); + if(result && (CURLE_AGAIN != result)) { + failf(data, "Failed to receive SOCKS5 connect request ack."); + return CURLE_COULDNT_CONNECT; + } + if(actualread != sx->outstanding) { + /* remain in state */ + sx->outstanding -= actualread; + sx->outp += actualread; + return CURLE_OK; + } + sxstate(conn, CONNECT_DONE); } infof(data, "SOCKS5 request granted.\n"); - (void)curlx_nonblock(sock, TRUE); + *done = TRUE; return CURLE_OK; /* Proxy was successful! */ } diff --git a/release/src/router/curl/lib/socks.h b/release/src/router/curl/lib/socks.h index 3b319a6ef11..64a7563373c 100644 --- a/release/src/router/curl/lib/socks.h +++ b/release/src/router/curl/lib/socks.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,13 +27,13 @@ #ifdef CURL_DISABLE_PROXY #define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN #define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#define Curl_SOCKS_getsock(x,y,z) 0 #else /* * Helper read-from-socket functions. Does the same as Curl_read() but it * blocks until all bytes amount of buffersize will be read. No more, no less. * - * This is STUPID BLOCKING behaviour which we frown upon, but right now this - * is what we have... + * This is STUPID BLOCKING behavior */ int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, @@ -41,6 +41,9 @@ int Curl_blockread_all(struct connectdata *conn, ssize_t buffersize, ssize_t *n); +int Curl_SOCKS_getsock(struct connectdata *conn, + curl_socket_t *sock, + int sockindex); /* * This function logs in to a SOCKS4(a) proxy and sends the specifics to the * final destination server. @@ -49,7 +52,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn); + struct connectdata *conn, + bool *done); /* * This function logs in to a SOCKS5 proxy and sends the specifics to the @@ -60,7 +64,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn); + struct connectdata *conn, + bool *done); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* diff --git a/release/src/router/curl/lib/socks_gssapi.c b/release/src/router/curl/lib/socks_gssapi.c index 65294bbebd1..97ee7183e09 100644 --- a/release/src/router/curl/lib/socks_gssapi.c +++ b/release/src/router/curl/lib/socks_gssapi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2009, Markus Moeller, - * Copyright (C) 2012 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -167,6 +167,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } + (void)curlx_nonblock(sock, FALSE); + /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { @@ -513,6 +515,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_recv_token); } + (void)curlx_nonblock(sock, TRUE); + infof(data, "SOCKS5 access with%s protection granted.\n", (socksreq[0] == 0)?"out GSS-API data": ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); diff --git a/release/src/router/curl/lib/socks_sspi.c b/release/src/router/curl/lib/socks_sspi.c index 57027ef686e..d5be64a3c0b 100644 --- a/release/src/router/curl/lib/socks_sspi.c +++ b/release/src/router/curl/lib/socks_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which @@ -153,6 +153,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } + (void)curlx_nonblock(sock, FALSE); + /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { @@ -587,6 +589,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); } + (void)curlx_nonblock(sock, TRUE); infof(data, "SOCKS5 access with%s protection granted.\n", (socksreq[0] == 0)?"out GSS-API data": diff --git a/release/src/router/curl/lib/strcase.c b/release/src/router/curl/lib/strcase.c index a8947122547..a309e352910 100644 --- a/release/src/router/curl/lib/strcase.c +++ b/release/src/router/curl/lib/strcase.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,8 @@ #include "strcase.h" +static char raw_tolower(char in); + /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ char Curl_raw_toupper(char in) @@ -96,7 +98,7 @@ char Curl_raw_toupper(char in) /* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because its behavior is altered by the current locale. */ -char Curl_raw_tolower(char in) +static char raw_tolower(char in) { #if !defined(CURL_DOES_CONVERSIONS) if(in >= 'A' && in <= 'Z') @@ -245,7 +247,7 @@ void Curl_strntolower(char *dest, const char *src, size_t n) return; do { - *dest++ = Curl_raw_tolower(*src); + *dest++ = raw_tolower(*src); } while(*src++ && --n); } diff --git a/release/src/router/curl/lib/strcase.h b/release/src/router/curl/lib/strcase.h index baa768b2b24..cd4c4191a9a 100644 --- a/release/src/router/curl/lib/strcase.h +++ b/release/src/router/curl/lib/strcase.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,7 +40,6 @@ int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); -char Curl_raw_tolower(char in); /* checkprefix() is a shorter version of the above, used when the first argument is zero-byte terminated */ diff --git a/release/src/router/curl/lib/strerror.c b/release/src/router/curl/lib/strerror.c index 29df5aa55a9..1a166bf019b 100644 --- a/release/src/router/curl/lib/strerror.c +++ b/release/src/router/curl/lib/strerror.c @@ -317,6 +317,9 @@ curl_easy_strerror(CURLcode error) case CURLE_HTTP3: return "HTTP/3 error"; + case CURLE_QUIC_CONNECT_ERROR: + return "QUIC connection error"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -392,6 +395,9 @@ curl_multi_strerror(CURLMcode error) case CURLM_WAKEUP_FAILURE: return "Wakeup is unavailable or failed"; + case CURLM_BAD_FUNCTION_ARGUMENT: + return "A libcurl function was given a bad argument"; + case CURLM_LAST: break; } diff --git a/release/src/router/curl/lib/strerror.h b/release/src/router/curl/lib/strerror.h index 278c1082f0a..bae8f897454 100644 --- a/release/src/router/curl/lib/strerror.h +++ b/release/src/router/curl/lib/strerror.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,7 +24,7 @@ #include "urldata.h" -#define STRERROR_LEN 128 /* a suitable length */ +#define STRERROR_LEN 256 /* a suitable length */ const char *Curl_strerror(int err, char *buf, size_t buflen); #if defined(WIN32) || defined(_WIN32_WCE) diff --git a/release/src/router/curl/lib/system_win32.c b/release/src/router/curl/lib/system_win32.c index 52a5fd95197..b9587b5f3af 100644 --- a/release/src/router/curl/lib/system_win32.c +++ b/release/src/router/curl/lib/system_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2019, Steve Holme, . + * Copyright (C) 2016 - 2020, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -109,11 +109,11 @@ CURLcode Curl_win32_init(long flags) if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { Curl_isVistaOrGreater = TRUE; - QueryPerformanceFrequency(&Curl_freq); } else Curl_isVistaOrGreater = FALSE; + QueryPerformanceFrequency(&Curl_freq); return CURLE_OK; } diff --git a/release/src/router/curl/lib/timeval.c b/release/src/router/curl/lib/timeval.c index 9b05cf05124..e761966a1b0 100644 --- a/release/src/router/curl/lib/timeval.c +++ b/release/src/router/curl/lib/timeval.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,6 +28,7 @@ extern LARGE_INTEGER Curl_freq; extern bool Curl_isVistaOrGreater; +/* In case of bug fix this function has a counterpart in tool_util.c */ struct curltime Curl_now(void) { struct curltime now; diff --git a/release/src/router/curl/lib/transfer.c b/release/src/router/curl/lib/transfer.c index ead8b36db9b..e76834eb343 100644 --- a/release/src/router/curl/lib/transfer.c +++ b/release/src/router/curl/lib/transfer.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -890,7 +890,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, } /* if(!header and data to read) */ - if(conn->handler->readwrite && excess && !conn->bits.stream_was_rewound) { + if(conn->handler->readwrite && excess) { /* Parse the excess data */ k->str += nread; @@ -1234,9 +1234,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, /* We go ahead and do a read if we have a readable socket or if the stream was rewound (in which case we have data in a buffer) */ - if((k->keepon & KEEP_RECV) && - ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - + if((k->keepon & KEEP_RECV) && (select_res & CURL_CSELECT_IN)) { result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; diff --git a/release/src/router/curl/lib/url.c b/release/src/router/curl/lib/url.c index 56fb736368b..47fc66aedda 100644 --- a/release/src/router/curl/lib/url.c +++ b/release/src/router/curl/lib/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -128,7 +128,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "memdebug.h" static void conn_free(struct connectdata *conn); -static void free_idnconverted_hostname(struct hostname *host); static unsigned int get_protocol_family(unsigned int protocol); /* Some parts of the code (e.g. chunked encoding) assume this buffer has at @@ -187,7 +186,7 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_tftp, #endif -#if defined(USE_SSH) +#if defined(USE_SSH) && !defined(USE_WOLFSSH) &Curl_handler_scp, #endif @@ -380,7 +379,7 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); #ifdef USE_ALTSVC - Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]); + Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_cleanup(data->asi); data->asi = NULL; #endif @@ -714,14 +713,13 @@ static void conn_free(struct connectdata *conn) if(!conn) return; - free_idnconverted_hostname(&conn->host); - free_idnconverted_hostname(&conn->conn_to_host); - free_idnconverted_hostname(&conn->http_proxy.host); - free_idnconverted_hostname(&conn->socks_proxy.host); + Curl_free_idnconverted_hostname(&conn->host); + Curl_free_idnconverted_hostname(&conn->conn_to_host); + Curl_free_idnconverted_hostname(&conn->http_proxy.host); + Curl_free_idnconverted_hostname(&conn->socks_proxy.host); Curl_safefree(conn->user); Curl_safefree(conn->passwd); - Curl_safefree(conn->oauth_bearer); Curl_safefree(conn->sasl_authzid); Curl_safefree(conn->options); Curl_safefree(conn->http_proxy.user); @@ -883,9 +881,37 @@ proxy_info_matches(const struct proxy_info* data, return FALSE; } + +static bool +socks_proxy_info_matches(const struct proxy_info* data, + const struct proxy_info* needle) +{ + if(!proxy_info_matches(data, needle)) + return FALSE; + + /* the user information is case-sensitive + or at least it is not defined as case-insensitive + see https://tools.ietf.org/html/rfc3986#section-3.2.1 */ + if((data->user == NULL) != (needle->user == NULL)) + return FALSE; + /* curl_strequal does a case insentive comparison, so do not use it here! */ + if(data->user && + needle->user && + strcmp(data->user, needle->user) != 0) + return FALSE; + if((data->passwd == NULL) != (needle->passwd == NULL)) + return FALSE; + /* curl_strequal does a case insentive comparison, so do not use it here! */ + if(data->passwd && + needle->passwd && + strcmp(data->passwd, needle->passwd) != 0) + return FALSE; + return TRUE; +} #else /* disabled, won't get called */ #define proxy_info_matches(x,y) FALSE +#define socks_proxy_info_matches(x,y) FALSE #endif /* A connection has to have been idle for a shorter time than 'maxage_conn' to @@ -1073,7 +1099,7 @@ ConnectionExists(struct Curl_easy *data, curr = bundle->conn_list.head; while(curr) { bool match = FALSE; - size_t multiplexed; + size_t multiplexed = 0; /* * Note that if we use a HTTP proxy in normal mode (no tunneling), we @@ -1086,8 +1112,8 @@ ConnectionExists(struct Curl_easy *data, /* connect-only or to-be-closed connections will not be reused */ continue; - multiplexed = CONN_INUSE(check) && - (bundle->multiuse == BUNDLE_MULTIPLEX); + if(bundle->multiuse == BUNDLE_MULTIPLEX) + multiplexed = CONN_INUSE(check); if(canmultiplex) { ; @@ -1144,8 +1170,9 @@ ConnectionExists(struct Curl_easy *data, needle->bits.socksproxy != check->bits.socksproxy) continue; - if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy, - &check->socks_proxy)) + if(needle->bits.socksproxy && + !socks_proxy_info_matches(&needle->socks_proxy, + &check->socks_proxy)) continue; if(needle->bits.conn_to_host != check->bits.conn_to_host) @@ -1185,6 +1212,8 @@ ConnectionExists(struct Curl_easy *data, } } + DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data)); + if(!canmultiplex && check->data) /* this request can't be multiplexed but the checked connection is already in use so we skip it */ @@ -1239,7 +1268,7 @@ ConnectionExists(struct Curl_easy *data, needle->conn_to_port == check->conn_to_port) && strcasecompare(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { - /* The schemes match or the the protocol family is the same and the + /* The schemes match or the protocol family is the same and the previous connection was TLS upgraded, and the hostname and host port match */ if(needle->handler->flags & PROTOPT_SSL) { @@ -1347,6 +1376,13 @@ ConnectionExists(struct Curl_easy *data, multiplexed); continue; } + else if(multiplexed >= + Curl_multi_max_concurrent_streams(needle->data->multi)) { + infof(data, "client side MAX_CONCURRENT_STREAMS reached" + ", skip (%zu)\n", + multiplexed); + continue; + } } #endif /* When not multiplexed, we have a match here! */ @@ -1400,10 +1436,14 @@ void Curl_verboseconnect(struct connectdata *conn) /* * Helpers for IDNA conversions. */ -static bool is_ASCII_name(const char *hostname) +bool Curl_is_ASCII_name(const char *hostname) { + /* get an UNSIGNED local version of the pointer */ const unsigned char *ch = (const unsigned char *)hostname; + if(!hostname) /* bad input, consider it ASCII! */ + return TRUE; + while(*ch) { if(*ch++ & 0x80) return FALSE; @@ -1428,8 +1468,8 @@ static void strip_trailing_dot(struct hostname *host) /* * Perform any necessary IDN conversion of hostname */ -static CURLcode idnconvert_hostname(struct connectdata *conn, - struct hostname *host) +CURLcode Curl_idnconvert_hostname(struct connectdata *conn, + struct hostname *host) { struct Curl_easy *data = conn->data; @@ -1444,7 +1484,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn, host->dispname = host->name; /* Check name for non-ASCII and convert hostname to ACE form if we can */ - if(!is_ASCII_name(host->name)) { + if(!Curl_is_ASCII_name(host->name)) { #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; @@ -1477,7 +1517,9 @@ static CURLcode idnconvert_hostname(struct connectdata *conn, host->name = host->encalloc; } else { - failf(data, "Failed to convert %s to ACE;\n", host->name); + char buffer[STRERROR_LEN]; + failf(data, "Failed to convert %s to ACE; %s\n", host->name, + Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); return CURLE_URL_MALFORMAT; } #else @@ -1490,7 +1532,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn, /* * Frees data allocated by idnconvert_hostname() */ -static void free_idnconverted_hostname(struct hostname *host) +void Curl_free_idnconverted_hostname(struct hostname *host) { #if defined(USE_LIBIDN2) if(host->encalloc) { @@ -1615,7 +1657,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) - conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; #endif /* Initialize the easy handle list */ @@ -3194,8 +3237,8 @@ static CURLcode resolve_server(struct Curl_easy *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { - free_idnconverted_hostname(&old_conn->http_proxy.host); - free_idnconverted_hostname(&old_conn->socks_proxy.host); + Curl_free_idnconverted_hostname(&old_conn->http_proxy.host); + Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); @@ -3239,8 +3282,8 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ - free_idnconverted_hostname(&conn->host); - free_idnconverted_hostname(&conn->conn_to_host); + Curl_free_idnconverted_hostname(&conn->host); + Curl_free_idnconverted_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); Curl_safefree(conn->conn_to_host.rawalloc); conn->host = old_conn->host; @@ -3336,14 +3379,6 @@ static CURLcode create_conn(struct Curl_easy *data, if(result) goto out; - if(data->set.str[STRING_BEARER]) { - conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); - if(!conn->oauth_bearer) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - if(data->set.str[STRING_SASL_AUTHZID]) { conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); if(!conn->sasl_authzid) { @@ -3407,21 +3442,21 @@ static CURLcode create_conn(struct Curl_easy *data, /************************************************************* * IDN-convert the hostnames *************************************************************/ - result = idnconvert_hostname(conn, &conn->host); + result = Curl_idnconvert_hostname(conn, &conn->host); if(result) goto out; if(conn->bits.conn_to_host) { - result = idnconvert_hostname(conn, &conn->conn_to_host); + result = Curl_idnconvert_hostname(conn, &conn->conn_to_host); if(result) goto out; } if(conn->bits.httpproxy) { - result = idnconvert_hostname(conn, &conn->http_proxy.host); + result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host); if(result) goto out; } if(conn->bits.socksproxy) { - result = idnconvert_hostname(conn, &conn->socks_proxy.host); + result = Curl_idnconvert_hostname(conn, &conn->socks_proxy.host); if(result) goto out; } diff --git a/release/src/router/curl/lib/url.h b/release/src/router/curl/lib/url.h index 053fbdffc21..5000c512a88 100644 --- a/release/src/router/curl/lib/url.h +++ b/release/src/router/curl/lib/url.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -62,6 +62,11 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, const struct Curl_handler *Curl_builtin_scheme(const char *scheme); +bool Curl_is_ASCII_name(const char *hostname); +CURLcode Curl_idnconvert_hostname(struct connectdata *conn, + struct hostname *host); +void Curl_free_idnconverted_hostname(struct hostname *host); + #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */ diff --git a/release/src/router/curl/lib/urlapi.c b/release/src/router/curl/lib/urlapi.c index fa514bce532..506e244dc4f 100644 --- a/release/src/router/curl/lib/urlapi.c +++ b/release/src/router/curl/lib/urlapi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -428,7 +428,6 @@ static char *concat_url(const char *base, const char *relurl) * */ static CURLUcode parse_hostname_login(struct Curl_URL *u, - const struct Curl_handler *h, char **hostname, unsigned int flags) { @@ -437,6 +436,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, char *userp = NULL; char *passwdp = NULL; char *optionsp = NULL; + const struct Curl_handler *h = NULL; /* At this point, we're hoping all the other special cases have * been taken care of, so conn->host.name is at most @@ -456,6 +456,10 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, * ftp://user:password@ftp.my.site:8021/README */ *hostname = ++ptr; + /* if this is a known scheme, get some details */ + if(u->scheme) + h = Curl_builtin_scheme(u->scheme); + /* We could use the login information in the URL so extract it. Only parse options if the handler says we should. Note that 'h' might be NULL! */ ccode = Curl_parse_login_details(login, ptr - login - 1, @@ -571,7 +575,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname) } /* scan for byte values < 31 or 127 */ -static CURLUcode junkscan(char *part) +static CURLUcode junkscan(const char *part) { if(part) { static const char badbytes[]={ @@ -668,10 +672,9 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) CURLUcode result; bool url_has_scheme = FALSE; char schemebuf[MAX_SCHEME_LEN + 1]; - char *schemep = NULL; + const char *schemep = NULL; size_t schemelen = 0; size_t urllen; - const struct Curl_handler *h = NULL; if(!url) return CURLUE_MALFORMED_INPUT; @@ -798,7 +801,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) return CURLUE_MALFORMED_INPUT; if(flags & CURLU_DEFAULT_SCHEME) - schemep = (char *) DEFAULT_SCHEME; + schemep = DEFAULT_SCHEME; /* * The URL was badly formatted, let's try without scheme specified. @@ -820,36 +823,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) return CURLUE_MALFORMED_INPUT; } - if((flags & CURLU_GUESS_SCHEME) && !schemep) { - /* legacy curl-style guess based on host name */ - if(checkprefix("ftp.", hostname)) - schemep = (char *)"ftp"; - else if(checkprefix("dict.", hostname)) - schemep = (char *)"dict"; - else if(checkprefix("ldap.", hostname)) - schemep = (char *)"ldap"; - else if(checkprefix("imap.", hostname)) - schemep = (char *)"imap"; - else if(checkprefix("smtp.", hostname)) - schemep = (char *)"smtp"; - else if(checkprefix("pop3.", hostname)) - schemep = (char *)"pop3"; - else - schemep = (char *)"http"; - } - len = strlen(p); memcpy(path, p, len); path[len] = 0; - u->scheme = strdup(schemep); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + if(schemep) { + u->scheme = strdup(schemep); + if(!u->scheme) + return CURLUE_OUT_OF_MEMORY; + } } - /* if this is a known scheme, get some details */ - h = Curl_builtin_scheme(u->scheme); - if(junkscan(path)) return CURLUE_MALFORMED_INPUT; @@ -916,7 +900,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(junkscan(hostname)) return CURLUE_MALFORMED_INPUT; - result = parse_hostname_login(u, h, &hostname, flags); + result = parse_hostname_login(u, &hostname, flags); if(result) return result; @@ -936,6 +920,28 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) u->host = strdup(hostname); if(!u->host) return CURLUE_OUT_OF_MEMORY; + + if((flags & CURLU_GUESS_SCHEME) && !schemep) { + /* legacy curl-style guess based on host name */ + if(checkprefix("ftp.", hostname)) + schemep = "ftp"; + else if(checkprefix("dict.", hostname)) + schemep = "dict"; + else if(checkprefix("ldap.", hostname)) + schemep = "ldap"; + else if(checkprefix("imap.", hostname)) + schemep = "imap"; + else if(checkprefix("smtp.", hostname)) + schemep = "smtp"; + else if(checkprefix("pop3.", hostname)) + schemep = "pop3"; + else + schemep = "http"; + + u->scheme = strdup(schemep); + if(!u->scheme) + return CURLUE_OUT_OF_MEMORY; + } } Curl_safefree(u->scratch); diff --git a/release/src/router/curl/lib/urldata.h b/release/src/router/curl/lib/urldata.h index 3effb1626f0..fbb8b645ec2 100644 --- a/release/src/router/curl/lib/urldata.h +++ b/release/src/router/curl/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -367,6 +367,14 @@ struct ntlmdata { unsigned char nonce[8]; void *target_info; /* TargetInfo received in the ntlm type-2 message */ unsigned int target_info_len; + +#if defined(NTLM_WB_ENABLED) + /* used for communication with Samba's winbind daemon helper ntlm_auth */ + curl_socket_t ntlm_auth_hlpr_socket; + pid_t ntlm_auth_hlpr_pid; + char *challenge; /* The received base64 encoded ntlm type-2 message */ + char *response; /* The generated base64 ntlm type-1/type-3 message */ +#endif #endif }; #endif @@ -456,8 +464,6 @@ struct ConnectBits { #endif BIT(netrc); /* name+password provided by netrc */ BIT(userpwd_in_url); /* name+password found in url */ - BIT(stream_was_rewound); /* The stream was rewound after a request read - past the end of its response byte boundary */ BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection in a CONNECT request with auth, so that libcurl should reconnect and continue. */ @@ -468,7 +474,6 @@ struct ConnectBits { BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ - BIT(socksproxy_connecting); /* connecting through a socks proxy */ BIT(connect_only); }; @@ -809,6 +814,41 @@ struct http_connect_state { struct ldapconninfo; +/* for the (SOCKS) connect state machine */ +enum connect_t { + CONNECT_INIT, + CONNECT_SOCKS_INIT, /* 1 */ + CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */ + CONNECT_SOCKS_READ_INIT, /* 3 set up read */ + CONNECT_SOCKS_READ, /* 4 read server response */ + CONNECT_GSSAPI_INIT, /* 5 */ + CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */ + CONNECT_AUTH_SEND, /* 7 send auth */ + CONNECT_AUTH_READ, /* 8 read auth response */ + CONNECT_REQ_INIT, /* 9 init SOCKS "request" */ + CONNECT_RESOLVING, /* 10 */ + CONNECT_RESOLVED, /* 11 */ + CONNECT_RESOLVE_REMOTE, /* 12 */ + CONNECT_REQ_SEND, /* 13 */ + CONNECT_REQ_SENDING, /* 14 */ + CONNECT_REQ_READ, /* 15 */ + CONNECT_REQ_READ_MORE, /* 16 */ + CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ +}; + +#define SOCKS_STATE(x) (((x) >= CONNECT_SOCKS_INIT) && \ + ((x) < CONNECT_DONE)) +#define SOCKS_REQUEST_BUFSIZE 600 /* room for large user/pw (255 max each) */ + +struct connstate { + enum connect_t state; + unsigned char socksreq[SOCKS_REQUEST_BUFSIZE]; + + /* CONNECT_SOCKS_SEND */ + ssize_t outstanding; /* send this many bytes more */ + unsigned char *outp; /* send from this pointer */ +}; + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -818,7 +858,7 @@ struct connectdata { caution that this might very well vary between different times this connection is used! */ struct Curl_easy *data; - + struct connstate cnnct; struct curl_llist_element bundle_node; /* conncache */ /* chunk is for HTTP chunked encoding, but is in the general connectdata @@ -906,7 +946,6 @@ struct connectdata { char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ - char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ char *sasl_authzid; /* authorisation identity string, allocated */ int httpversion; /* the HTTP version*10 reported by the server */ @@ -918,8 +957,6 @@ struct connectdata { curl_socket_t sock[2]; /* two sockets, the second is used for the data transfer when doing FTP */ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ - bool sock_accepted[2]; /* TRUE if the socket on this index was created with - accept() */ Curl_recv *recv[2]; Curl_send *send[2]; @@ -1011,14 +1048,6 @@ struct connectdata { because it authenticates connections, not single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ - -#if defined(NTLM_WB_ENABLED) - /* used for communication with Samba's winbind daemon helper ntlm_auth */ - curl_socket_t ntlm_auth_hlpr_socket; - pid_t ntlm_auth_hlpr_pid; - char *challenge_header; - char *response_header; -#endif #endif #ifdef USE_SPNEGO @@ -1082,6 +1111,8 @@ struct connectdata { handle */ BIT(writechannel_inuse); /* whether the write channel is in use by an easy handle */ + BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with + accept() */ }; /* The end of connectdata. */ @@ -1409,6 +1440,8 @@ struct UrlState { BIT(ftp_trying_alternative); BIT(wildcardmatch); /* enable wildcard matching */ BIT(expect100header); /* TRUE if we added Expect: 100-continue */ + BIT(disableexpect); /* TRUE if Expect: is disabled due to a previous + 417 response */ BIT(use_range); BIT(rangestringalloc); /* the range string is malloc()'ed */ BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE @@ -1451,6 +1484,14 @@ struct DynamicStatic { struct Curl_multi; /* declared and used only in multi.c */ +/* + * This enumeration MUST not use conditional directives (#ifdefs), new + * null terminated strings MUST be added to the enumeration immediately + * before STRING_LASTZEROTERMINATED, binary fields immediately before + * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c + * test is updated and applicable changes for EBCDIC to ASCII conversion + * are catered for in curl_easy_setopt_ccsid() + */ enum dupstring { STRING_CERT_ORIG, /* client certificate file name */ STRING_CERT_PROXY, /* client certificate file name */ @@ -1507,36 +1548,40 @@ enum dupstring { STRING_RTSP_SESSION_ID, /* Session ID to use */ STRING_RTSP_STREAM_URI, /* Stream URI for this request */ STRING_RTSP_TRANSPORT, /* Transport for this session */ -#ifdef USE_SSH + STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ -#endif + STRING_PROXY_SERVICE_NAME, /* Proxy service name */ STRING_SERVICE_NAME, /* Service name */ STRING_MAIL_FROM, STRING_MAIL_AUTH, -#ifdef USE_TLS_SRP STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth */ STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth */ STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ -#endif + STRING_BEARER, /* , if used */ -#ifdef USE_UNIX_SOCKETS + STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ -#endif + STRING_TARGET, /* CURLOPT_REQUEST_TARGET */ STRING_DOH, /* CURLOPT_DOH_URL */ -#ifdef USE_ALTSVC + STRING_ALTSVC, /* CURLOPT_ALTSVC */ -#endif + STRING_SASL_AUTHZID, /* CURLOPT_SASL_AUTHZID */ -#ifndef CURL_DISABLE_PROXY + STRING_TEMP_URL, /* temp URL storage for proxy use */ -#endif + + STRING_DNS_SERVERS, + STRING_DNS_INTERFACE, + STRING_DNS_LOCAL_IP4, + STRING_DNS_LOCAL_IP6, + /* -- end of zero-terminated strings -- */ STRING_LASTZEROTERMINATED, @@ -1545,6 +1590,7 @@ enum dupstring { STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ + STRING_LAST /* not used, just an end-of-list marker */ }; @@ -1792,6 +1838,8 @@ struct UserDefined { BIT(doh); /* DNS-over-HTTPS enabled */ BIT(doh_get); /* use GET for DoH requests, instead of POST */ BIT(http09_allowed); /* allow HTTP/0.9 responses */ + BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some + recipients */ }; struct Names { diff --git a/release/src/router/curl/lib/vauth/digest.c b/release/src/router/curl/lib/vauth/digest.c index 8cd4d83ed3d..a8835705f3e 100644 --- a/release/src/router/curl/lib/vauth/digest.c +++ b/release/src/router/curl/lib/vauth/digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -62,7 +62,7 @@ what ultimately goes over the network. */ #define CURL_OUTPUT_DIGEST_CONV(a, b) \ - result = Curl_convert_to_network(a, (char *)b, strlen((const char *)b)); \ + result = Curl_convert_to_network(a, b, strlen(b)); \ if(result) { \ free(b); \ return result; \ @@ -660,7 +660,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, } /* - * _Curl_auth_create_digest_http_message() + * auth_create_digest_http_message() * * This is used to generate a HTTP DIGEST response message ready for sending * to the recipient. @@ -679,7 +679,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, * * Returns CURLE_OK on success. */ -static CURLcode _Curl_auth_create_digest_http_message( +static CURLcode auth_create_digest_http_message( struct Curl_easy *data, const char *userp, const char *passwdp, @@ -688,12 +688,12 @@ static CURLcode _Curl_auth_create_digest_http_message( struct digestdata *digest, char **outptr, size_t *outlen, void (*convert_to_ascii)(unsigned char *, unsigned char *), - void (*hash)(unsigned char *, const unsigned char *)) + void (*hash)(unsigned char *, const unsigned char *, + const size_t)) { CURLcode result; unsigned char hashbuf[32]; /* 32 bytes/256 bits */ unsigned char request_digest[65]; - unsigned char *hashthis; unsigned char ha1[65]; /* 64 digits and 1 zero byte */ unsigned char ha2[65]; /* 64 digits and 1 zero byte */ char userh[65]; @@ -701,6 +701,7 @@ static CURLcode _Curl_auth_create_digest_http_message( size_t cnonce_sz = 0; char *userp_quoted; char *response = NULL; + char *hashthis = NULL; char *tmp = NULL; if(!digest->nc) @@ -722,12 +723,12 @@ static CURLcode _Curl_auth_create_digest_http_message( } if(digest->userhash) { - hashthis = (unsigned char *) aprintf("%s:%s", userp, digest->realm); + hashthis = aprintf("%s:%s", userp, digest->realm); if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); - hash(hashbuf, hashthis); + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, (unsigned char *)userh); } @@ -743,14 +744,13 @@ static CURLcode _Curl_auth_create_digest_http_message( unq(nonce-value) ":" unq(cnonce-value) */ - hashthis = (unsigned char *) - aprintf("%s:%s:%s", digest->userhash ? userh : userp, - digest->realm, passwdp); + hashthis = aprintf("%s:%s:%s", digest->userhash ? userh : userp, + digest->realm, passwdp); if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ - hash(hashbuf, hashthis); + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, ha1); @@ -763,7 +763,7 @@ static CURLcode _Curl_auth_create_digest_http_message( return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */ - hash(hashbuf, (unsigned char *) tmp); + hash(hashbuf, (unsigned char *) tmp, strlen(tmp)); free(tmp); convert_to_ascii(hashbuf, ha1); } @@ -781,19 +781,19 @@ static CURLcode _Curl_auth_create_digest_http_message( 5.1.1 of RFC 2616) */ - hashthis = (unsigned char *) aprintf("%s:%s", request, uripath); + hashthis = aprintf("%s:%s", request, uripath); if(!hashthis) return CURLE_OUT_OF_MEMORY; if(digest->qop && strcasecompare(digest->qop, "auth-int")) { /* We don't support auth-int for PUT or POST */ char hashed[65]; - unsigned char *hashthis2; + char *hashthis2; - hash(hashbuf, (const unsigned char *)""); + hash(hashbuf, (const unsigned char *)"", 0); convert_to_ascii(hashbuf, (unsigned char *)hashed); - hashthis2 = (unsigned char *)aprintf("%s:%s", hashthis, hashed); + hashthis2 = aprintf("%s:%s", hashthis, hashed); free(hashthis); hashthis = hashthis2; } @@ -802,31 +802,23 @@ static CURLcode _Curl_auth_create_digest_http_message( return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ - hash(hashbuf, hashthis); + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, ha2); if(digest->qop) { - hashthis = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - digest->nonce, - digest->nc, - digest->cnonce, - digest->qop, - ha2); + hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc, + digest->cnonce, digest->qop, ha2); } else { - hashthis = (unsigned char *) aprintf("%s:%s:%s", - ha1, - digest->nonce, - ha2); + hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2); } if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ - hash(hashbuf, hashthis); + hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, request_digest); @@ -899,7 +891,7 @@ static CURLcode _Curl_auth_create_digest_http_message( if(digest->algorithm) { /* Append the algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); + tmp = aprintf("%s, algorithm=%s", response, digest->algorithm); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; @@ -955,21 +947,21 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, switch(digest->algo) { case CURLDIGESTALGO_MD5: case CURLDIGESTALGO_MD5SESS: - return _Curl_auth_create_digest_http_message(data, userp, passwdp, - request, uripath, digest, - outptr, outlen, - auth_digest_md5_to_ascii, - Curl_md5it); + return auth_create_digest_http_message(data, userp, passwdp, + request, uripath, digest, + outptr, outlen, + auth_digest_md5_to_ascii, + Curl_md5it); case CURLDIGESTALGO_SHA256: case CURLDIGESTALGO_SHA256SESS: case CURLDIGESTALGO_SHA512_256: case CURLDIGESTALGO_SHA512_256SESS: - return _Curl_auth_create_digest_http_message(data, userp, passwdp, - request, uripath, digest, - outptr, outlen, - auth_digest_sha256_to_ascii, - Curl_sha256it); + return auth_create_digest_http_message(data, userp, passwdp, + request, uripath, digest, + outptr, outlen, + auth_digest_sha256_to_ascii, + Curl_sha256it); default: return CURLE_UNSUPPORTED_PROTOCOL; diff --git a/release/src/router/curl/lib/vauth/ntlm.c b/release/src/router/curl/lib/vauth/ntlm.c index 047c2b5a3fa..8f91038064b 100644 --- a/release/src/router/curl/lib/vauth/ntlm.c +++ b/release/src/router/curl/lib/vauth/ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,6 +40,7 @@ #include "curl_ntlm_core.h" #include "curl_gethostname.h" #include "curl_multibyte.h" +#include "curl_md5.h" #include "warnless.h" #include "rand.h" #include "vtls/vtls.h" @@ -621,11 +622,11 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, memcpy(tmp, &ntlm->nonce[0], 8); memcpy(tmp + 8, entropy, 8); - result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); - if(!result) - /* We shall only use the first 8 bytes of md5sum, but the des code in - Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ - result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + Curl_md5it(md5sum, tmp, 16); + + /* We shall only use the first 8 bytes of md5sum, but the des code in + Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; diff --git a/release/src/router/curl/lib/version.c b/release/src/router/curl/lib/version.c index 6405d369d7c..8170106eead 100644 --- a/release/src/router/curl/lib/version.c +++ b/release/src/router/curl/lib/version.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -66,16 +66,6 @@ #include #endif -void Curl_version_init(void); - -/* For thread safety purposes this function is called by global_init so that - the static data in both version functions is initialized. */ -void Curl_version_init(void) -{ - curl_version(); - curl_version_info(CURLVERSION_NOW); -} - #ifdef HAVE_BROTLI static size_t brotli_version(char *buf, size_t bufsz) { @@ -88,95 +78,108 @@ static size_t brotli_version(char *buf, size_t bufsz) } #endif +/* + * curl_version() returns a pointer to a static buffer. + * + * It is implemented to work multi-threaded by making sure repeated invokes + * generate the exact same string and never write any temporary data like + * zeros in the data. + */ char *curl_version(void) { - static bool initialized; - static char version[250]; - char *ptr = version; - size_t len; - size_t left = sizeof(version); - - if(initialized) - return version; - - strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); - len = strlen(ptr); - left -= len; - ptr += len; - - len = Curl_ssl_version(ptr + 1, left - 1); - - if(len > 0) { - *ptr = ' '; - left -= ++len; - ptr += len; - } + static char out[250]; + char *outp; + size_t outlen; + const char *src[14]; +#ifdef USE_SSL + char ssl_version[40]; +#endif +#ifdef HAVE_LIBZ + char z_version[40]; +#endif +#ifdef HAVE_BROTLI + char br_version[40] = "brotli/"; +#endif +#ifdef USE_ARES + char cares_version[40]; +#endif +#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) + char idn_version[40]; +#endif +#ifdef USE_LIBPSL + char psl_version[40]; +#endif +#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) + char iconv_version[40]="iconv"; +#endif +#ifdef USE_SSH + char ssh_version[40]; +#endif +#ifdef USE_NGHTTP2 + char h2_version[40]; +#endif +#ifdef ENABLE_QUIC + char h3_version[40]; +#endif +#ifdef USE_LIBRTMP + char rtmp_version[40]; +#endif + int i = 0; + int j; + src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; +#ifdef USE_SSL + Curl_ssl_version(ssl_version, sizeof(ssl_version)); + src[i++] = ssl_version; +#endif #ifdef HAVE_LIBZ - len = msnprintf(ptr, left, " zlib/%s", zlibVersion()); - left -= len; - ptr += len; + msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion()); + src[i++] = z_version; #endif #ifdef HAVE_BROTLI - len = msnprintf(ptr, left, "%s", " brotli/"); - left -= len; - ptr += len; - len = brotli_version(ptr, left); - left -= len; - ptr += len; + brotli_version(&br_version[7], sizeof(br_version) - 7); + src[i++] = br_version; #endif #ifdef USE_ARES - /* this function is only present in c-ares, not in the original ares */ - len = msnprintf(ptr, left, " c-ares/%s", ares_version(NULL)); - left -= len; - ptr += len; + msnprintf(cares_version, sizeof(cares_version), + "c-ares/%s", ares_version(NULL)); + src[i++] = cares_version; #endif #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { - len = msnprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); - left -= len; - ptr += len; + msnprintf(idn_version, sizeof(idn_version), + "libidn2/%s", idn2_check_version(NULL)); + src[i++] = idn_version; } +#elif defined(USE_WIN32_IDN) + msnprintf(idn_version, sizeof(idn_version), "WinIDN"); + src[i++] = idn_version; #endif + #ifdef USE_LIBPSL - len = msnprintf(ptr, left, " libpsl/%s", psl_get_version()); - left -= len; - ptr += len; -#endif -#ifdef USE_WIN32_IDN - len = msnprintf(ptr, left, " WinIDN"); - left -= len; - ptr += len; + msnprintf(psl_version, sizeof(psl_version), "libpsl/%s", psl_get_version()); + src[i++] = psl_version; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION - len = msnprintf(ptr, left, " iconv/%d.%d", - _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); + msnprintf(iconv_version, sizeof(iconv_version), "iconv/%d.%d", + _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); #else - /* version unknown */ - len = msnprintf(ptr, left, " iconv"); + /* version unknown, let the default stand */ #endif /* _LIBICONV_VERSION */ - left -= len; - ptr += len; + src[i++] = iconv_version; #endif #ifdef USE_SSH - if(left) { - *ptr++=' '; - left--; - } - len = Curl_ssh_version(ptr, left); - left -= len; - ptr += len; + Curl_ssh_version(ssh_version, sizeof(ssh_version)); + src[i++] = ssh_version; #endif #ifdef USE_NGHTTP2 - len = Curl_http2_ver(ptr, left); - left -= len; - ptr += len; + Curl_http2_ver(h2_version, sizeof(h2_version)); + src[i++] = h2_version; #endif #ifdef ENABLE_QUIC - len = Curl_quic_ver(ptr, left); - left -= len; - ptr += len; + Curl_quic_ver(h3_version, sizeof(h3_version)); + src[i++] = h3_version; #endif #ifdef USE_LIBRTMP { @@ -188,27 +191,32 @@ char *curl_version(void) else suff[0] = '\0'; - msnprintf(ptr, left, " librtmp/%d.%d%s", + msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s", RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, suff); -/* - If another lib version is added below this one, this code would - also have to do: - - len = what msnprintf() returned - - left -= len; - ptr += len; -*/ + src[i++] = rtmp_version; } #endif - /* Silent scan-build even if librtmp is not enabled. */ - (void) left; - (void) ptr; + outp = &out[0]; + outlen = sizeof(out); + for(j = 0; j < i; j++) { + size_t n = strlen(src[j]); + /* we need room for a space, the string and the final zero */ + if(outlen <= (n + 2)) + break; + if(j) { + /* prepend a space if not the first */ + *outp++ = ' '; + outlen--; + } + memcpy(outp, src[j], n); + outp += n; + outlen -= n; + } + *outp = 0; - initialized = true; - return version; + return out; } /* data for curl_version_info @@ -265,8 +273,10 @@ static const char * const protocols[] = { #ifndef CURL_DISABLE_RTSP "rtsp", #endif -#if defined(USE_SSH) +#if defined(USE_SSH) && !defined(USE_WOLFSSH) "scp", +#endif +#ifdef USE_SSH "sftp", #endif #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ @@ -389,7 +399,6 @@ static curl_version_info_data version_info = { curl_version_info_data *curl_version_info(CURLversion stamp) { - static bool initialized; #if defined(USE_SSH) static char ssh_buffer[80]; #endif @@ -404,9 +413,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp) static char brotli_buffer[80]; #endif - if(initialized) - return &version_info; - #ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; @@ -474,7 +480,5 @@ curl_version_info_data *curl_version_info(CURLversion stamp) #endif (void)stamp; /* avoid compiler warnings, we don't use this */ - - initialized = true; return &version_info; } diff --git a/release/src/router/curl/lib/vquic/ngtcp2.c b/release/src/router/curl/lib/vquic/ngtcp2.c index e97e9e871b4..2f6ee8bdf9f 100644 --- a/release/src/router/curl/lib/vquic/ngtcp2.c +++ b/release/src/router/curl/lib/vquic/ngtcp2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -146,7 +146,7 @@ static void quic_settings(ngtcp2_settings *s, s->transport_params.initial_max_data = QUIC_MAX_DATA; s->transport_params.initial_max_streams_bidi = 1; s->transport_params.initial_max_streams_uni = 3; - s->transport_params.idle_timeout = QUIC_IDLE_TIMEOUT; + s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT; } static FILE *keylog_file; /* not thread-safe */ @@ -535,6 +535,8 @@ static ngtcp2_conn_callbacks ng_callbacks = { NULL, /* extend_max_remote_streams_bidi */ NULL, /* extend_max_remote_streams_uni */ cb_extend_max_stream_data, + NULL, /* dcid_status */ + NULL /* handshake_confirmed */ }; /* @@ -574,10 +576,10 @@ CURLcode Curl_quic_connect(struct connectdata *conn, qs->version = NGTCP2_PROTO_VER; qs->sslctx = quic_ssl_ctx(data); if(!qs->sslctx) - return CURLE_FAILED_INIT; /* TODO: better return code */ + return CURLE_QUIC_CONNECT_ERROR; if(quic_init_ssl(qs)) - return CURLE_FAILED_INIT; /* TODO: better return code */ + return CURLE_QUIC_CONNECT_ERROR; qs->dcid.datalen = NGTCP2_MAX_CIDLEN; result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN); @@ -595,7 +597,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr, &qs->local_addrlen); if(rv == -1) - return CURLE_FAILED_INIT; + return CURLE_QUIC_CONNECT_ERROR; ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen, NULL); @@ -609,7 +611,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, QUICVER, &ng_callbacks, &qs->settings, NULL, qs); if(rc) - return CURLE_FAILED_INIT; /* TODO: create a QUIC error code */ + return CURLE_QUIC_CONNECT_ERROR; ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); nwrite = ngtcp2_encode_transport_params( @@ -618,15 +620,15 @@ CURLcode Curl_quic_connect(struct connectdata *conn, if(nwrite < 0) { failf(data, "ngtcp2_encode_transport_params: %s\n", ngtcp2_strerror((int)nwrite)); - return CURLE_FAILED_INIT; + return CURLE_QUIC_CONNECT_ERROR; } if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite)) - return CURLE_FAILED_INIT; + return CURLE_QUIC_CONNECT_ERROR; rc = setup_initial_crypto_context(qs); if(rc) - return CURLE_FAILED_INIT; /* TODO: better return code */ + return CURLE_QUIC_CONNECT_ERROR; return CURLE_OK; } @@ -639,7 +641,7 @@ int Curl_quic_ver(char *p, size_t len) { ngtcp2_info *ng2 = ngtcp2_version(0); nghttp3_info *ht3 = nghttp3_version(0); - return msnprintf(p, len, " ngtcp2/%s nghttp3/%s", + return msnprintf(p, len, "ngtcp2/%s nghttp3/%s", ng2->version_str, ht3->version_str); } @@ -998,7 +1000,7 @@ static int init_ngh3_conn(struct quicsocket *qs) if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) { failf(qs->conn->data, "too few available QUIC streams"); - return CURLE_FAILED_INIT; + return CURLE_QUIC_CONNECT_ERROR; } nghttp3_conn_settings_default(&qs->h3settings); @@ -1015,32 +1017,32 @@ static int init_ngh3_conn(struct quicsocket *qs) rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL); if(rc) { - result = CURLE_FAILED_INIT; + result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id); if(rc) { - result = CURLE_FAILED_INIT; + result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL); if(rc) { - result = CURLE_FAILED_INIT; + result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL); if(rc) { - result = CURLE_FAILED_INIT; + result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id, qpack_dec_stream_id); if(rc) { - result = CURLE_FAILED_INIT; + result = CURLE_QUIC_CONNECT_ERROR; goto fail; } @@ -1599,9 +1601,11 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, case AF_INET: pktlen = NGTCP2_MAX_PKTLEN_IPV4; break; +#ifdef ENABLE_IPV6 case AF_INET6: pktlen = NGTCP2_MAX_PKTLEN_IPV6; break; +#endif default: assert(0); } diff --git a/release/src/router/curl/lib/vquic/quiche.c b/release/src/router/curl/lib/vquic/quiche.c index e2f43237fa8..c40e5e937ca 100644 --- a/release/src/router/curl/lib/vquic/quiche.c +++ b/release/src/router/curl/lib/vquic/quiche.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -171,7 +171,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, return CURLE_FAILED_INIT; } - quiche_config_set_idle_timeout(qs->cfg, QUIC_IDLE_TIMEOUT); + quiche_config_set_max_idle_timeout(qs->cfg, QUIC_IDLE_TIMEOUT); quiche_config_set_initial_max_data(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_stream_data_bidi_local(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_stream_data_bidi_remote(qs->cfg, @@ -532,7 +532,7 @@ static ssize_t h3_stream_send(struct connectdata *conn, */ int Curl_quic_ver(char *p, size_t len) { - return msnprintf(p, len, " quiche/%s", quiche_version()); + return msnprintf(p, len, "quiche/%s", quiche_version()); } /* Index where :authority header field will appear in request header diff --git a/release/src/router/curl/lib/vssh/libssh.c b/release/src/router/curl/lib/vssh/libssh.c index 62a7f1960c6..08d9f9e0fb2 100644 --- a/release/src/router/curl/lib/vssh/libssh.c +++ b/release/src/router/curl/lib/vssh/libssh.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2017 - 2019 Red Hat, Inc. + * Copyright (C) 2017 - 2020 Red Hat, Inc. * * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek, * Robert Kolcun, Andreas Schneider @@ -322,25 +322,50 @@ static int myssh_is_known(struct connectdata *conn) ssh_key pubkey; size_t hlen; unsigned char *hash = NULL; - char *base64 = NULL; + char *found_base64 = NULL; + char *known_base64 = NULL; int vstate; enum curl_khmatch keymatch; struct curl_khkey foundkey; + struct curl_khkey *knownkeyp = NULL; curl_sshkeycallback func = data->set.ssh_keyfunc; +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + struct ssh_knownhosts_entry *knownhostsentry = NULL; + struct curl_khkey knownkey; +#endif + +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) + rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey); +#else rc = ssh_get_publickey(sshc->ssh_session, &pubkey); +#endif if(rc != SSH_OK) return rc; if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { + int i; + char md5buffer[33]; + const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hlen); - if(rc != SSH_OK) + if(rc != SSH_OK || hlen != 16) { + failf(data, + "Denied establishing ssh session: md5 fingerprint not available"); goto cleanup; + } + + for(i = 0; i < 16; i++) + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]); + + infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); - if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) || - memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) { + if(!strcasecompare(md5buffer, pubkey_md5)) { + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); rc = SSH_ERROR; goto cleanup; } @@ -354,6 +379,65 @@ static int myssh_is_known(struct connectdata *conn) goto cleanup; } +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + /* Get the known_key from the known hosts file */ + vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session, + &knownhostsentry); + + /* Case an entry was found in a known hosts file */ + if(knownhostsentry) { + if(knownhostsentry->publickey) { + rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey, + &known_base64); + if(rc != SSH_OK) { + goto cleanup; + } + knownkey.key = known_base64; + knownkey.len = strlen(known_base64); + + switch(ssh_key_type(knownhostsentry->publickey)) { + case SSH_KEYTYPE_RSA: + knownkey.keytype = CURLKHTYPE_RSA; + break; + case SSH_KEYTYPE_RSA1: + knownkey.keytype = CURLKHTYPE_RSA1; + break; + case SSH_KEYTYPE_ECDSA: + knownkey.keytype = CURLKHTYPE_ECDSA; + break; + case SSH_KEYTYPE_ED25519: + knownkey.keytype = CURLKHTYPE_ED25519; + break; + case SSH_KEYTYPE_DSS: + knownkey.keytype = CURLKHTYPE_DSS; + break; + default: + rc = SSH_ERROR; + goto cleanup; + } + knownkeyp = &knownkey; + } + } + + switch(vstate) { + case SSH_KNOWN_HOSTS_OK: + keymatch = CURLKHMATCH_OK; + break; + case SSH_KNOWN_HOSTS_OTHER: + /* fallthrough */ + case SSH_KNOWN_HOSTS_NOT_FOUND: + /* fallthrough */ + case SSH_KNOWN_HOSTS_UNKNOWN: + /* fallthrough */ + case SSH_KNOWN_HOSTS_ERROR: + keymatch = CURLKHMATCH_MISSING; + break; + default: + keymatch = CURLKHMATCH_MISMATCH; + break; + } + +#else vstate = ssh_is_server_known(sshc->ssh_session); switch(vstate) { case SSH_SERVER_KNOWN_OK: @@ -368,14 +452,15 @@ static int myssh_is_known(struct connectdata *conn) keymatch = CURLKHMATCH_MISMATCH; break; } +#endif if(func) { /* use callback to determine action */ - rc = ssh_pki_export_pubkey_base64(pubkey, &base64); + rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64); if(rc != SSH_OK) goto cleanup; - foundkey.key = base64; - foundkey.len = strlen(base64); + foundkey.key = found_base64; + foundkey.len = strlen(found_base64); switch(ssh_key_type(pubkey)) { case SSH_KEYTYPE_RSA: @@ -400,15 +485,19 @@ static int myssh_is_known(struct connectdata *conn) goto cleanup; } - /* we don't have anything equivalent to knownkey. Always NULL */ Curl_set_in_callback(data, true); - rc = func(data, NULL, &foundkey, /* from the remote host */ + rc = func(data, knownkeyp, /* from the knownhosts file */ + &foundkey, /* from the remote host */ keymatch, data->set.ssh_keyfunc_userp); Curl_set_in_callback(data, false); switch(rc) { case CURLKHSTAT_FINE_ADD_TO_FILE: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) + rc = ssh_session_update_known_hosts(sshc->ssh_session); +#else rc = ssh_write_knownhost(sshc->ssh_session); +#endif if(rc != SSH_OK) { goto cleanup; } @@ -429,9 +518,20 @@ static int myssh_is_known(struct connectdata *conn) rc = SSH_OK; cleanup: + if(found_base64) { + free(found_base64); + } + if(known_base64) { + free(known_base64); + } if(hash) ssh_clean_pubkey_hash(&hash); ssh_key_free(pubkey); +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + if(knownhostsentry) { + ssh_knownhosts_entry_free(knownhostsentry); + } +#endif return rc; } @@ -1586,7 +1686,6 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) return CURLE_BAD_DOWNLOAD_RESUME; } } - /* Does a completed file need to be seeked and started or closed ? */ /* Now store the number of bytes we are expected to download */ data->req.size = size - data->state.resume_from; data->req.maxdownload = size - data->state.resume_from; diff --git a/release/src/router/curl/lib/vssh/libssh2.c b/release/src/router/curl/lib/vssh/libssh2.c index 063f3d2ae69..c487ccabb5d 100644 --- a/release/src/router/curl/lib/vssh/libssh2.c +++ b/release/src/router/curl/lib/vssh/libssh2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -106,6 +106,7 @@ static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); +static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn); static CURLcode ssh_connect(struct connectdata *conn, bool *done); static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done); static CURLcode ssh_do(struct connectdata *conn, bool *done); @@ -648,6 +649,138 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) return ssh_knownhost(conn); } +/* + * ssh_force_knownhost_key_type() will check the known hosts file and try to + * force a specific public key type from the server if an entry is found. + */ +static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + static const char * const hostkey_method_ssh_ed25519 + = "ssh-ed25519"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 + static const char * const hostkey_method_ssh_ecdsa_521 + = "ecdsa-sha2-nistp521"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 + static const char * const hostkey_method_ssh_ecdsa_384 + = "ecdsa-sha2-nistp384"; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + static const char * const hostkey_method_ssh_ecdsa_256 + = "ecdsa-sha2-nistp256"; +#endif + static const char * const hostkey_method_ssh_rsa + = "ssh-rsa"; + static const char * const hostkey_method_ssh_dss + = "ssh-dss"; + + const char *hostkey_method = NULL; + struct ssh_conn *sshc = &conn->proto.sshc; + struct Curl_easy *data = conn->data; + struct libssh2_knownhost* store = NULL; + const char *kh_name_end = NULL; + size_t kh_name_size = 0; + int port = 0; + bool found = false; + + if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { + /* lets try to find our host in the known hosts file */ + while(!libssh2_knownhost_get(sshc->kh, &store, store)) { + /* For non-standard ports, the name will be enclosed in */ + /* square brackets, followed by a colon and the port */ + if(store) { + if(store->name) { + if(store->name[0] == '[') { + kh_name_end = strstr(store->name, "]:"); + if(!kh_name_end) { + infof(data, "Invalid host pattern %s in %s\n", + store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); + continue; + } + port = atoi(kh_name_end + 2); + if(kh_name_end && (port == conn->remote_port)) { + kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end); + if(strncmp(store->name + 1, + conn->host.name, kh_name_size) == 0) { + found = true; + break; + } + } + } + else if(strcmp(store->name, conn->host.name) == 0) { + found = true; + break; + } + } + else { + found = true; + break; + } + } + } + + if(found) { + infof(data, "Found host %s in %s\n", + conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); + + switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 + case LIBSSH2_KNOWNHOST_KEY_ED25519: + hostkey_method = hostkey_method_ssh_ed25519; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: + hostkey_method = hostkey_method_ssh_ecdsa_521; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: + hostkey_method = hostkey_method_ssh_ecdsa_384; + break; +#endif +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 + case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: + hostkey_method = hostkey_method_ssh_ecdsa_256; + break; +#endif + case LIBSSH2_KNOWNHOST_KEY_SSHRSA: + hostkey_method = hostkey_method_ssh_rsa; + break; + case LIBSSH2_KNOWNHOST_KEY_SSHDSS: + hostkey_method = hostkey_method_ssh_dss; + break; + case LIBSSH2_KNOWNHOST_KEY_RSA1: + failf(data, "Found host key type RSA1 which is not supported\n"); + return CURLE_SSH; + default: + failf(data, "Unknown host key type: %i\n", + (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK)); + return CURLE_SSH; + } + + infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method); + result = libssh2_session_error_to_CURLE( + libssh2_session_method_pref( + sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method)); + } + else { + infof(data, "Did not find host %s in %s\n", + conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); + } + } + +#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ + + return result; +} + /* * ssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points @@ -680,6 +813,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) non-blocking */ libssh2_session_set_blocking(sshc->ssh_session, 0); + result = ssh_force_knownhost_key_type(conn); + if(result) { + state(conn, SSH_SESSION_FREE); + break; + } + state(conn, SSH_S_STARTUP); /* FALLTHROUGH */ @@ -2251,7 +2390,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) return CURLE_BAD_DOWNLOAD_RESUME; } } - /* Does a completed file need to be seeked and started or closed ? */ /* Now store the number of bytes we are expected to download */ data->req.size = attrs.filesize - data->state.resume_from; data->req.maxdownload = attrs.filesize - data->state.resume_from; diff --git a/release/src/router/curl/lib/vssh/ssh.h b/release/src/router/curl/lib/vssh/ssh.h index 3213c5a52e6..0d4ee521d16 100644 --- a/release/src/router/curl/lib/vssh/ssh.h +++ b/release/src/router/curl/lib/vssh/ssh.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,7 +30,10 @@ #elif defined(HAVE_LIBSSH_LIBSSH_H) #include #include -#endif /* HAVE_LIBSSH2_H */ +#elif defined(USE_WOLFSSH) +#include +#include +#endif /**************************************************************************** * SSH unique setup @@ -188,6 +191,12 @@ struct ssh_conn { #ifdef HAVE_LIBSSH2_KNOWNHOST_API LIBSSH2_KNOWNHOSTS *kh; #endif +#elif defined(USE_WOLFSSH) + WOLFSSH *ssh_session; + WOLFSSH_CTX *ctx; + word32 handleSz; + byte handle[WOLFSSH_MAX_HANDLE]; + curl_off_t offset; #endif /* USE_LIBSSH */ }; @@ -195,9 +204,6 @@ struct ssh_conn { #define CURL_LIBSSH_VERSION ssh_version(0) -extern const struct Curl_handler Curl_handler_scp; -extern const struct Curl_handler Curl_handler_sftp; - #elif defined(USE_LIBSSH2) /* Feature detection based on version numbers to better work with @@ -237,11 +243,13 @@ extern const struct Curl_handler Curl_handler_sftp; #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION #endif -extern const struct Curl_handler Curl_handler_scp; -extern const struct Curl_handler Curl_handler_sftp; #endif /* USE_LIBSSH2 */ #ifdef USE_SSH + +extern const struct Curl_handler Curl_handler_scp; +extern const struct Curl_handler Curl_handler_sftp; + /* generic SSH backend functions */ CURLcode Curl_ssh_init(void); void Curl_ssh_cleanup(void); diff --git a/release/src/router/curl/lib/vssh/wolfssh.c b/release/src/router/curl/lib/vssh/wolfssh.c new file mode 100644 index 00000000000..363a52c772a --- /dev/null +++ b/release/src/router/curl/lib/vssh/wolfssh.c @@ -0,0 +1,1156 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WOLFSSH + +#include + +#include +#include +#include "urldata.h" +#include "connect.h" +#include "sendf.h" +#include "progress.h" +#include "curl_path.h" +#include "strtoofft.h" +#include "transfer.h" +#include "speedcheck.h" +#include "select.h" +#include "multiif.h" +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static CURLcode wssh_connect(struct connectdata *conn, bool *done); +static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done); +static CURLcode wssh_do(struct connectdata *conn, bool *done); +#if 0 +static CURLcode wscp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode wscp_doing(struct connectdata *conn, + bool *dophase_done); +static CURLcode wscp_disconnect(struct connectdata *conn, + bool dead_connection); +#endif +static CURLcode wsftp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode wsftp_doing(struct connectdata *conn, + bool *dophase_done); +static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead); +static int wssh_getsock(struct connectdata *conn, + curl_socket_t *sock); +static int wssh_perform_getsock(const struct connectdata *conn, + curl_socket_t *sock); +static CURLcode wssh_setup_connection(struct connectdata *conn); + +#if 0 +/* + * SCP protocol handler. + */ + +const struct Curl_handler Curl_handler_scp = { + "SCP", /* scheme */ + wssh_setup_connection, /* setup_connection */ + wssh_do, /* do_it */ + wscp_done, /* done */ + ZERO_NULL, /* do_more */ + wssh_connect, /* connect_it */ + wssh_multi_statemach, /* connecting */ + wscp_doing, /* doing */ + wssh_getsock, /* proto_getsock */ + wssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + wssh_perform_getsock, /* perform_getsock */ + wscp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + PORT_SSH, /* defport */ + CURLPROTO_SCP, /* protocol */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +#endif + +/* + * SFTP protocol handler. + */ + +const struct Curl_handler Curl_handler_sftp = { + "SFTP", /* scheme */ + wssh_setup_connection, /* setup_connection */ + wssh_do, /* do_it */ + wsftp_done, /* done */ + ZERO_NULL, /* do_more */ + wssh_connect, /* connect_it */ + wssh_multi_statemach, /* connecting */ + wsftp_doing, /* doing */ + wssh_getsock, /* proto_getsock */ + wssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + wssh_perform_getsock, /* perform_getsock */ + wsftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + PORT_SSH, /* defport */ + CURLPROTO_SFTP, /* protocol */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ +}; + +/* + * SSH State machine related code + */ +/* This is the ONLY way to change SSH state! */ +static void state(struct connectdata *conn, sshstate nowstate) +{ + struct ssh_conn *sshc = &conn->proto.sshc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "SSH_STOP", + "SSH_INIT", + "SSH_S_STARTUP", + "SSH_HOSTKEY", + "SSH_AUTHLIST", + "SSH_AUTH_PKEY_INIT", + "SSH_AUTH_PKEY", + "SSH_AUTH_PASS_INIT", + "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", + "SSH_AUTH_HOST_INIT", + "SSH_AUTH_HOST", + "SSH_AUTH_KEY_INIT", + "SSH_AUTH_KEY", + "SSH_AUTH_GSSAPI", + "SSH_AUTH_DONE", + "SSH_SFTP_INIT", + "SSH_SFTP_REALPATH", + "SSH_SFTP_QUOTE_INIT", + "SSH_SFTP_POSTQUOTE_INIT", + "SSH_SFTP_QUOTE", + "SSH_SFTP_NEXT_QUOTE", + "SSH_SFTP_QUOTE_STAT", + "SSH_SFTP_QUOTE_SETSTAT", + "SSH_SFTP_QUOTE_SYMLINK", + "SSH_SFTP_QUOTE_MKDIR", + "SSH_SFTP_QUOTE_RENAME", + "SSH_SFTP_QUOTE_RMDIR", + "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", + "SSH_SFTP_TRANS_INIT", + "SSH_SFTP_UPLOAD_INIT", + "SSH_SFTP_CREATE_DIRS_INIT", + "SSH_SFTP_CREATE_DIRS", + "SSH_SFTP_CREATE_DIRS_MKDIR", + "SSH_SFTP_READDIR_INIT", + "SSH_SFTP_READDIR", + "SSH_SFTP_READDIR_LINK", + "SSH_SFTP_READDIR_BOTTOM", + "SSH_SFTP_READDIR_DONE", + "SSH_SFTP_DOWNLOAD_INIT", + "SSH_SFTP_DOWNLOAD_STAT", + "SSH_SFTP_CLOSE", + "SSH_SFTP_SHUTDOWN", + "SSH_SCP_TRANS_INIT", + "SSH_SCP_UPLOAD_INIT", + "SSH_SCP_DOWNLOAD_INIT", + "SSH_SCP_DOWNLOAD", + "SSH_SCP_DONE", + "SSH_SCP_SEND_EOF", + "SSH_SCP_WAIT_EOF", + "SSH_SCP_WAIT_CLOSE", + "SSH_SCP_CHANNEL_FREE", + "SSH_SESSION_DISCONNECT", + "SSH_SESSION_FREE", + "QUIT" + }; + + /* a precaution to make sure the lists are in sync */ + DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); + + if(sshc->state != nowstate) { + infof(conn->data, "wolfssh %p state change from %s to %s\n", + (void *)sshc, names[sshc->state], names[nowstate]); + } +#endif + + sshc->state = nowstate; +} + +static ssize_t wscp_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + ssize_t nwrite = 0; + (void)conn; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + (void)mem; + (void)len; + (void)err; + + return nwrite; +} + +static ssize_t wscp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + ssize_t nread = 0; + (void)conn; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + (void)mem; + (void)len; + (void)err; + + return nread; +} + +/* return number of sent bytes */ +static ssize_t wsftp_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + word32 offset[2]; + int rc; + (void)sockindex; + + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + + rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, + sshc->handleSz, + &offset[0], + (byte *)mem, (word32)len); + + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + conn->waitfor = KEEP_RECV; + *err = CURLE_AGAIN; + return -1; + } + else if(rc == WS_WANT_WRITE) { + conn->waitfor = KEEP_SEND; + *err = CURLE_AGAIN; + return -1; + } + if(rc < 0) { + failf(conn->data, "wolfSSH_SFTP_SendWritePacket returned %d\n", rc); + return -1; + } + DEBUGASSERT(rc == (int)len); + infof(conn->data, "sent %zd bytes SFTP from offset %zd\n", + len, sshc->offset); + sshc->offset += len; + return (ssize_t)rc; +} + +/* + * Return number of received (decrypted) bytes + * or <0 on error + */ +static ssize_t wsftp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + int rc; + struct ssh_conn *sshc = &conn->proto.sshc; + word32 offset[2]; + (void)sockindex; + + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + + rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, + sshc->handleSz, + &offset[0], + (byte *)mem, (word32)len); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + conn->waitfor = KEEP_RECV; + *err = CURLE_AGAIN; + return -1; + } + else if(rc == WS_WANT_WRITE) { + conn->waitfor = KEEP_SEND; + *err = CURLE_AGAIN; + return -1; + } + + DEBUGASSERT(rc <= (int)len); + + if(rc < 0) { + failf(conn->data, "wolfSSH_SFTP_SendReadPacket returned %d\n", rc); + return -1; + } + sshc->offset += len; + + return (ssize_t)rc; +} + +/* + * SSH setup and connection + */ +static CURLcode wssh_setup_connection(struct connectdata *conn) +{ + struct SSHPROTO *ssh; + + conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); + if(!ssh) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +static Curl_recv wscp_recv, wsftp_recv; +static Curl_send wscp_send, wsftp_send; + +static int userauth(byte authtype, + WS_UserAuthData* authdata, + void *ctx) +{ + struct connectdata *conn = ctx; + DEBUGF(infof(conn->data, "wolfssh callback: type %s\n", + authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : + "PUBLICCKEY")); + if(authtype == WOLFSSH_USERAUTH_PASSWORD) { + authdata->sf.password.password = (byte *)conn->passwd; + authdata->sf.password.passwordSz = (word32) strlen(conn->passwd); + } + + return 0; +} + +static CURLcode wssh_connect(struct connectdata *conn, bool *done) +{ + struct Curl_easy *data = conn->data; + struct ssh_conn *sshc; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + + /* initialize per-handle data if not already */ + if(!data->req.protop) + wssh_setup_connection(conn); + + /* We default to persistent connections. We set this already in this connect + function to make the re-use checks properly be able to check this bit. */ + connkeep(conn, "SSH default"); + + if(conn->handler->protocol & CURLPROTO_SCP) { + conn->recv[FIRSTSOCKET] = wscp_recv; + conn->send[FIRSTSOCKET] = wscp_send; + } + else { + conn->recv[FIRSTSOCKET] = wsftp_recv; + conn->send[FIRSTSOCKET] = wsftp_send; + } + sshc = &conn->proto.sshc; + sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + if(!sshc->ctx) { + failf(data, "No wolfSSH context"); + goto error; + } + + sshc->ssh_session = wolfSSH_new(sshc->ctx); + if(sshc->ssh_session == NULL) { + failf(data, "No wolfSSH session"); + goto error; + } + + rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); + if(rc != WS_SUCCESS) { + failf(data, "wolfSSH failed to set user name"); + goto error; + } + + /* set callback for authentication */ + wolfSSH_SetUserAuth(sshc->ctx, userauth); + wolfSSH_SetUserAuthCtx(sshc->ssh_session, conn); + + rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); + if(rc) { + failf(data, "wolfSSH failed to set socket"); + goto error; + } + +#if 0 + wolfSSH_Debugging_ON(); +#endif + + *done = TRUE; + if(conn->handler->protocol & CURLPROTO_SCP) + state(conn, SSH_INIT); + else + state(conn, SSH_SFTP_INIT); + + return wssh_multi_statemach(conn, done); + error: + wolfSSH_free(sshc->ssh_session); + wolfSSH_CTX_free(sshc->ctx); + return CURLE_FAILED_INIT; +} + +/* + * wssh_statemach_act() runs the SSH state machine as far as it can without + * blocking and without reaching the end. The data the pointer 'block' points + * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it + * wants to be called again when the socket is ready + */ + +static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block) +{ + CURLcode result = CURLE_OK; + struct ssh_conn *sshc = &conn->proto.sshc; + struct Curl_easy *data = conn->data; + struct SSHPROTO *sftp_scp = data->req.protop; + WS_SFTPNAME *name; + int rc = 0; + *block = FALSE; /* we're not blocking by default */ + + do { + switch(sshc->state) { + case SSH_INIT: + state(conn, SSH_S_STARTUP); + /* FALLTHROUGH */ + case SSH_S_STARTUP: + rc = wolfSSH_connect(sshc->ssh_session); + if(rc != WS_SUCCESS) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc != WS_SUCCESS) { + state(conn, SSH_STOP); + return CURLE_SSH; + } + infof(data, "wolfssh connected!\n"); + state(conn, SSH_STOP); + break; + case SSH_STOP: + break; + + case SSH_SFTP_INIT: + rc = wolfSSH_SFTP_connect(sshc->ssh_session); + if(rc != WS_SUCCESS) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP connected!\n"); + state(conn, SSH_SFTP_REALPATH); + } + else { + failf(data, "wolfssh SFTP connect error %d", rc); + return CURLE_SSH; + } + break; + case SSH_SFTP_REALPATH: + name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)"."); + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(name && (rc == WS_SUCCESS)) { + sshc->homedir = malloc(name->fSz + 1); + if(!sshc->homedir) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + } + else { + memcpy(sshc->homedir, name->fName, name->fSz); + sshc->homedir[name->fSz] = 0; + infof(data, "wolfssh SFTP realpath succeeded!\n"); + } + wolfSSH_SFTPNAME_list_free(name); + state(conn, SSH_STOP); + return CURLE_OK; + } + failf(data, "wolfssh SFTP realpath %d", rc); + return CURLE_SSH; + + case SSH_SFTP_QUOTE_INIT: + result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path); + if(result) { + sshc->actualcode = result; + state(conn, SSH_STOP); + break; + } + + if(data->set.quote) { + infof(data, "Sending quote commands\n"); + sshc->quote_item = data->set.quote; + state(conn, SSH_SFTP_QUOTE); + } + else { + state(conn, SSH_SFTP_GETINFO); + } + break; + case SSH_SFTP_GETINFO: + if(data->set.get_filetime) { + state(conn, SSH_SFTP_FILETIME); + } + else { + state(conn, SSH_SFTP_TRANS_INIT); + } + break; + case SSH_SFTP_TRANS_INIT: + if(data->set.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') + state(conn, SSH_SFTP_READDIR_INIT); + else + state(conn, SSH_SFTP_DOWNLOAD_INIT); + } + break; + case SSH_SFTP_UPLOAD_INIT: { + word32 flags; + WS_SFTP_FILEATRB createattrs; + if(data->state.resume_from) { + WS_SFTP_FILEATRB attrs; + if(data->state.resume_from < 0) { + rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, + &attrs); + if(rc != WS_SUCCESS) + break; + + if(rc) { + data->state.resume_from = 0; + } + else { + curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; + if(size < 0) { + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + data->state.resume_from = size; + } + } + } + + if(data->set.ftp_append) + /* Try to open for append, but create if nonexisting */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; + else if(data->state.resume_from > 0) + /* If we have restart position then open for append */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; + else + /* Clear file before writing (normal behaviour) */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; + + memset(&createattrs, 0, sizeof(createattrs)); + createattrs.per = (word32)data->set.new_file_perms; + sshc->handleSz = sizeof(sshc->handle); + rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, + flags, &createattrs, + sshc->handle, &sshc->handleSz); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP open succeeded!\n"); + } + else { + failf(data, "wolfssh SFTP upload open failed: %d", rc); + return CURLE_SSH; + } + state(conn, SSH_SFTP_DOWNLOAD_STAT); + + /* If we have a restart point then we need to seek to the correct + position. */ + if(data->state.resume_from > 0) { + /* Let's read off the proper amount of bytes from the input. */ + int seekerr = CURL_SEEKFUNC_OK; + if(conn->seek_func) { + Curl_set_in_callback(data, true); + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + Curl_set_in_callback(data, false); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + do { + size_t readthisamountnow = + (data->state.resume_from - passed > data->set.buffer_size) ? + (size_t)data->set.buffer_size : + curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread; + Curl_set_in_callback(data, true); + actuallyread = data->state.fread_func(data->state.buffer, 1, + readthisamountnow, + data->state.in); + Curl_set_in_callback(data, false); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + + /* now, decrease the size of the read */ + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + + sshc->offset += data->state.resume_from; + } + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + /* upload data */ + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->sockfd = conn->writesockfd; + + if(result) { + state(conn, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 sftp send function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_OUT; + + /* since we don't really wait for anything at this point, we want the + state machine to move on as soon as possible so we set a very short + timeout here */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + state(conn, SSH_STOP); + } + break; + } + case SSH_SFTP_DOWNLOAD_INIT: + sshc->handleSz = sizeof(sshc->handle); + rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, + WOLFSSH_FXF_READ, NULL, + sshc->handle, &sshc->handleSz); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP open succeeded!\n"); + state(conn, SSH_SFTP_DOWNLOAD_STAT); + return CURLE_OK; + } + + failf(data, "wolfssh SFTP open failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_DOWNLOAD_STAT: { + WS_SFTP_FILEATRB attrs; + curl_off_t size; + + rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh STAT succeeded!\n"); + } + else { + failf(data, "wolfssh SFTP open failed: %d", rc); + data->req.size = -1; + data->req.maxdownload = -1; + Curl_pgrsSetDownloadSize(data, -1); + return CURLE_SSH; + } + + size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0]; + + data->req.size = size; + data->req.maxdownload = size; + Curl_pgrsSetDownloadSize(data, size); + + infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes\n", size); + + /* We cannot seek with wolfSSH so resuming and range requests are not + possible */ + if(conn->data->state.use_range || data->state.resume_from) { + infof(data, "wolfSSH cannot do range/seek on SFTP\n"); + return CURLE_BAD_DOWNLOAD_RESUME; + } + + /* Setup the actual download */ + if(data->req.size == 0) { + /* no data to transfer */ + Curl_setup_transfer(data, -1, -1, FALSE, -1); + infof(data, "File already completely downloaded\n"); + state(conn, SSH_STOP); + break; + } + Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); + + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_IN; + + if(result) { + /* this should never occur; the close state should be entered + at the time the error occurs */ + state(conn, SSH_SFTP_CLOSE); + sshc->actualcode = result; + } + else { + state(conn, SSH_STOP); + } + break; + } + case SSH_SFTP_CLOSE: + if(sshc->handleSz) + rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, + sshc->handleSz); + else + rc = WS_SUCCESS; /* directory listing */ + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + state(conn, SSH_STOP); + return CURLE_OK; + } + + failf(data, "wolfssh SFTP CLOSE failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_READDIR_INIT: + Curl_pgrsSetDownloadSize(data, -1); + if(data->set.opt_no_body) { + state(conn, SSH_STOP); + break; + } + state(conn, SSH_SFTP_READDIR); + /* FALLTHROUGH */ + case SSH_SFTP_READDIR: + name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); + if(!name) + rc = wolfSSH_get_error(sshc->ssh_session); + else + rc = WS_SUCCESS; + + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(name && (rc == WS_SUCCESS)) { + WS_SFTPNAME *origname = name; + result = CURLE_OK; + while(name) { + char *line = aprintf("%s\n", + data->set.ftp_list_only ? + name->fName : name->lName); + if(line == NULL) { + state(conn, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + break; + } + result = Curl_client_write(conn, CLIENTWRITE_BODY, + line, strlen(line)); + free(line); + if(result) { + sshc->actualcode = result; + break; + } + name = name->next; + } + wolfSSH_SFTPNAME_list_free(origname); + state(conn, SSH_STOP); + return result; + } + failf(data, "wolfssh SFTP ls failed: %d", rc); + return CURLE_SSH; + + case SSH_SFTP_SHUTDOWN: + Curl_safefree(sshc->homedir); + wolfSSH_free(sshc->ssh_session); + wolfSSH_CTX_free(sshc->ctx); + state(conn, SSH_STOP); + return CURLE_OK; + default: + break; + } + } while(!rc && (sshc->state != SSH_STOP)); + return result; +} + +/* called repeatedly until done from multi.c */ +static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + bool block; /* we store the status and use that to provide a ssh_getsock() + implementation */ + do { + result = wssh_statemach_act(conn, &block); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; + /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then + try again */ + if(*done) { + DEBUGF(infof(conn->data, "wssh_statemach_act says DONE\n")); + } + } while(!result && !*done && !block); + + return result; +} + +static +CURLcode wscp_perform(struct connectdata *conn, + bool *connected, + bool *dophase_done) +{ + (void)conn; + (void)connected; + (void)dophase_done; + return CURLE_OK; +} + +static +CURLcode wsftp_perform(struct connectdata *conn, + bool *connected, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + + DEBUGF(infof(conn->data, "DO phase starts\n")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + state(conn, SSH_SFTP_QUOTE_INIT); + + /* run the state-machine */ + result = wssh_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; + + if(*dophase_done) { + DEBUGF(infof(conn->data, "DO phase is complete\n")); + } + + return result; +} + +/* + * The DO function is generic for both protocols. + */ +static CURLcode wssh_do(struct connectdata *conn, bool *done) +{ + CURLcode result; + bool connected = 0; + struct Curl_easy *data = conn->data; + struct ssh_conn *sshc = &conn->proto.sshc; + + *done = FALSE; /* default to false */ + data->req.size = -1; /* make sure this is unknown at this point */ + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs = 0; /* reset the create dir attempt state + variable */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + if(conn->handler->protocol & CURLPROTO_SCP) + result = wscp_perform(conn, &connected, done); + else + result = wsftp_perform(conn, &connected, done); + + return result; +} + +static CURLcode wssh_block_statemach(struct connectdata *conn, + bool disconnect) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + + while((sshc->state != SSH_STOP) && !result) { + bool block; + timediff_t left = 1000; + struct curltime now = Curl_now(); + + result = wssh_statemach_act(conn, &block); + if(result) + break; + + if(!disconnect) { + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + + result = Curl_speedcheck(data, now); + if(result) + break; + + left = Curl_timeleft(data, NULL, FALSE); + if(left < 0) { + failf(data, "Operation timed out"); + return CURLE_OPERATION_TIMEDOUT; + } + } + + if(!result) { + int dir = conn->waitfor; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + curl_socket_t fd_read = CURL_SOCKET_BAD; + curl_socket_t fd_write = CURL_SOCKET_BAD; + if(dir == KEEP_RECV) + fd_read = sock; + else if(dir == KEEP_SEND) + fd_write = sock; + + /* wait for the socket to become ready */ + (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, + left>1000?1000:left); /* ignore result */ + } + } + + return result; +} + +/* generic done function for both SCP and SFTP called from their specific + done functions */ +static CURLcode wssh_done(struct connectdata *conn, CURLcode status) +{ + CURLcode result = CURLE_OK; + struct SSHPROTO *sftp_scp = conn->data->req.protop; + + if(!status) { + /* run the state-machine */ + result = wssh_block_statemach(conn, FALSE); + } + else + result = status; + + if(sftp_scp) + Curl_safefree(sftp_scp->path); + if(Curl_pgrsDone(conn)) + return CURLE_ABORTED_BY_CALLBACK; + + conn->data->req.keepon = 0; /* clear all bits */ + return result; +} + +#if 0 +static CURLcode wscp_done(struct connectdata *conn, + CURLcode code, bool premature) +{ + CURLcode result = CURLE_OK; + (void)conn; + (void)code; + (void)premature; + + return result; +} + +static CURLcode wscp_doing(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result = CURLE_OK; + (void)conn; + (void)dophase_done; + + return result; +} + +static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection) +{ + CURLcode result = CURLE_OK; + (void)conn; + (void)dead_connection; + + return result; +} +#endif + +static CURLcode wsftp_done(struct connectdata *conn, + CURLcode code, bool premature) +{ + (void)premature; + state(conn, SSH_SFTP_CLOSE); + + return wssh_done(conn, code); +} + +static CURLcode wsftp_doing(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result = wssh_multi_statemach(conn, dophase_done); + + if(*dophase_done) { + DEBUGF(infof(conn->data, "DO phase is complete\n")); + } + return result; +} + +static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead) +{ + CURLcode result = CURLE_OK; + (void)dead; + + DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); + + if(conn->proto.sshc.ssh_session) { + /* only if there's a session still around to use! */ + state(conn, SSH_SFTP_SHUTDOWN); + result = wssh_block_statemach(conn, TRUE); + } + + DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); + return result; +} + +static int wssh_getsock(struct connectdata *conn, + curl_socket_t *sock) +{ + return wssh_perform_getsock(conn, sock); +} + +static int wssh_perform_getsock(const struct connectdata *conn, + curl_socket_t *sock) +{ + int bitmap = GETSOCK_BLANK; + int dir = conn->waitfor; + sock[0] = conn->sock[FIRSTSOCKET]; + + if(dir == KEEP_RECV) + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + else if(dir == KEEP_SEND) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + return bitmap; +} + +size_t Curl_ssh_version(char *buffer, size_t buflen) +{ + return msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); +} + +CURLcode Curl_ssh_init(void) +{ + if(WS_SUCCESS != wolfSSH_Init()) { + DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); + return CURLE_FAILED_INIT; + } + + return CURLE_OK; +} +void Curl_ssh_cleanup(void) +{ +} + +#endif /* USE_WOLFSSH */ diff --git a/release/src/router/curl/lib/vtls/gtls.c b/release/src/router/curl/lib/vtls/gtls.c index 3737d7c685a..5f740eeba11 100644 --- a/release/src/router/curl/lib/vtls/gtls.c +++ b/release/src/router/curl/lib/vtls/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -666,6 +666,10 @@ gtls_connect_step1(struct connectdata *conn, /* Initialize TLS session as a client */ init_flags = GNUTLS_CLIENT; +#if defined(GNUTLS_FORCE_CLIENT_CERT) + init_flags |= GNUTLS_FORCE_CLIENT_CERT; +#endif + #if defined(GNUTLS_NO_TICKETS) /* Disable TLS session tickets */ init_flags |= GNUTLS_NO_TICKETS; diff --git a/release/src/router/curl/lib/vtls/mbedtls.c b/release/src/router/curl/lib/vtls/mbedtls.c index e34ec9d13f4..f057315f30c 100644 --- a/release/src/router/curl/lib/vtls/mbedtls.c +++ b/release/src/router/curl/lib/vtls/mbedtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,7 +55,7 @@ #include "connect.h" /* for the connect timeout */ #include "select.h" #include "multiif.h" -#include "polarssl_threadlock.h" +#include "mbedtls_threadlock.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -91,12 +91,12 @@ static int entropy_init_initialized = 0; static void entropy_init_mutex(mbedtls_entropy_context *ctx) { /* lock 0 = entropy_init_mutex() */ - Curl_polarsslthreadlock_lock_function(0); + Curl_mbedtlsthreadlock_lock_function(0); if(entropy_init_initialized == 0) { mbedtls_entropy_init(ctx); entropy_init_initialized = 1; } - Curl_polarsslthreadlock_unlock_function(0); + Curl_mbedtlsthreadlock_unlock_function(0); } /* end of entropy_init_mutex() */ @@ -105,9 +105,9 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { int ret; /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); + Curl_mbedtlsthreadlock_lock_function(1); ret = mbedtls_entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); + Curl_mbedtlsthreadlock_unlock_function(1); return ret; } @@ -1017,12 +1017,12 @@ static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex) */ static int Curl_mbedtls_init(void) { - return Curl_polarsslthreadlock_thread_setup(); + return Curl_mbedtlsthreadlock_thread_setup(); } static void Curl_mbedtls_cleanup(void) { - (void)Curl_polarsslthreadlock_thread_cleanup(); + (void)Curl_mbedtlsthreadlock_thread_cleanup(); } static bool Curl_mbedtls_data_pending(const struct connectdata *conn, diff --git a/release/src/router/curl/lib/vtls/polarssl_threadlock.c b/release/src/router/curl/lib/vtls/mbedtls_threadlock.c similarity index 76% rename from release/src/router/curl/lib/vtls/polarssl_threadlock.c rename to release/src/router/curl/lib/vtls/mbedtls_threadlock.c index 4e269c8e6a7..4d672f106e0 100644 --- a/release/src/router/curl/lib/vtls/polarssl_threadlock.c +++ b/release/src/router/curl/lib/vtls/mbedtls_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2013 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -22,19 +22,19 @@ ***************************************************************************/ #include "curl_setup.h" -#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \ - ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ - (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))) +#if defined(USE_MBEDTLS) && \ + ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ + (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))) #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) # include -# define POLARSSL_MUTEX_T pthread_mutex_t +# define MBEDTLS_MUTEX_T pthread_mutex_t #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) # include -# define POLARSSL_MUTEX_T HANDLE +# define MBEDTLS_MUTEX_T HANDLE #endif -#include "polarssl_threadlock.h" +#include "mbedtls_threadlock.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -43,14 +43,14 @@ /* number of thread locks */ #define NUMT 2 -/* This array will store all of the mutexes available to PolarSSL. */ -static POLARSSL_MUTEX_T *mutex_buf = NULL; +/* This array will store all of the mutexes available to Mbedtls. */ +static MBEDTLS_MUTEX_T *mutex_buf = NULL; -int Curl_polarsslthreadlock_thread_setup(void) +int Curl_mbedtlsthreadlock_thread_setup(void) { int i; - mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1); + mutex_buf = calloc(NUMT * sizeof(MBEDTLS_MUTEX_T), 1); if(!mutex_buf) return 0; /* error, no number of threads defined */ @@ -70,7 +70,7 @@ int Curl_polarsslthreadlock_thread_setup(void) return 1; /* OK */ } -int Curl_polarsslthreadlock_thread_cleanup(void) +int Curl_mbedtlsthreadlock_thread_cleanup(void) { int i; @@ -95,7 +95,7 @@ int Curl_polarsslthreadlock_thread_cleanup(void) return 1; /* OK */ } -int Curl_polarsslthreadlock_lock_function(int n) +int Curl_mbedtlsthreadlock_lock_function(int n) { if(n < NUMT) { int ret; @@ -103,14 +103,14 @@ int Curl_polarsslthreadlock_lock_function(int n) ret = pthread_mutex_lock(&mutex_buf[n]); if(ret) { DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_lock_function failed\n")); + "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); if(ret) { DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_lock_function failed\n")); + "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ @@ -118,7 +118,7 @@ int Curl_polarsslthreadlock_lock_function(int n) return 1; /* OK */ } -int Curl_polarsslthreadlock_unlock_function(int n) +int Curl_mbedtlsthreadlock_unlock_function(int n) { if(n < NUMT) { int ret; @@ -126,14 +126,14 @@ int Curl_polarsslthreadlock_unlock_function(int n) ret = pthread_mutex_unlock(&mutex_buf[n]); if(ret) { DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_unlock_function failed\n")); + "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_unlock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) ret = ReleaseMutex(mutex_buf[n]); if(!ret) { DEBUGF(fprintf(stderr, - "Error: polarsslthreadlock_unlock_function failed\n")); + "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ @@ -141,4 +141,4 @@ int Curl_polarsslthreadlock_unlock_function(int n) return 1; /* OK */ } -#endif /* USE_POLARSSL || USE_MBEDTLS */ +#endif /* USE_MBEDTLS */ diff --git a/release/src/router/curl/lib/vtls/polarssl_threadlock.h b/release/src/router/curl/lib/vtls/mbedtls_threadlock.h similarity index 64% rename from release/src/router/curl/lib/vtls/polarssl_threadlock.h rename to release/src/router/curl/lib/vtls/mbedtls_threadlock.h index c1900bfe81c..96a787d1a24 100644 --- a/release/src/router/curl/lib/vtls/polarssl_threadlock.h +++ b/release/src/router/curl/lib/vtls/mbedtls_threadlock.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H -#define HEADER_CURL_POLARSSL_THREADLOCK_H +#ifndef HEADER_CURL_MBEDTLS_THREADLOCK_H +#define HEADER_CURL_MBEDTLS_THREADLOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2013 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -24,25 +24,25 @@ ***************************************************************************/ #include "curl_setup.h" -#if (defined USE_POLARSSL) || (defined USE_MBEDTLS) +#ifdef USE_MBEDTLS #if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)) -int Curl_polarsslthreadlock_thread_setup(void); -int Curl_polarsslthreadlock_thread_cleanup(void); -int Curl_polarsslthreadlock_lock_function(int n); -int Curl_polarsslthreadlock_unlock_function(int n); +int Curl_mbedtlsthreadlock_thread_setup(void); +int Curl_mbedtlsthreadlock_thread_cleanup(void); +int Curl_mbedtlsthreadlock_lock_function(int n); +int Curl_mbedtlsthreadlock_unlock_function(int n); #else -#define Curl_polarsslthreadlock_thread_setup() 1 -#define Curl_polarsslthreadlock_thread_cleanup() 1 -#define Curl_polarsslthreadlock_lock_function(x) 1 -#define Curl_polarsslthreadlock_unlock_function(x) 1 +#define Curl_mbedtlsthreadlock_thread_setup() 1 +#define Curl_mbedtlsthreadlock_thread_cleanup() 1 +#define Curl_mbedtlsthreadlock_lock_function(x) 1 +#define Curl_mbedtlsthreadlock_unlock_function(x) 1 #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ -#endif /* USE_POLARSSL */ +#endif /* USE_MBEDTLS */ -#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */ +#endif /* HEADER_CURL_MBEDTLS_THREADLOCK_H */ diff --git a/release/src/router/curl/lib/vtls/openssl.c b/release/src/router/curl/lib/vtls/openssl.c index 726ff6e7ca8..1d09cadca8d 100644 --- a/release/src/router/curl/lib/vtls/openssl.c +++ b/release/src/router/curl/lib/vtls/openssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -2212,7 +2212,6 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) curl_ssl_version_max = SSL_CONN_CONFIG(version_max); /* convert cURL max SSL version option to OpenSSL constant */ - ossl_ssl_version_max = 0; switch(curl_ssl_version_max) { case CURL_SSLVERSION_MAX_TLSv1_0: ossl_ssl_version_max = TLS1_VERSION; @@ -3122,28 +3121,25 @@ do { \ } while(0) #endif -static int X509V3_ext(struct Curl_easy *data, +static void X509V3_ext(struct Curl_easy *data, int certnum, CONST_EXTS STACK_OF(X509_EXTENSION) *exts) { int i; - size_t j; if((int)sk_X509_EXTENSION_num(exts) <= 0) /* no extensions, bail out */ - return 1; + return; for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { ASN1_OBJECT *obj; X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); BUF_MEM *biomem; - char buf[512]; - char *ptr = buf; char namebuf[128]; BIO *bio_out = BIO_new(BIO_s_mem()); if(!bio_out) - return 1; + return; obj = X509_EXTENSION_get_object(ext); @@ -3153,26 +3149,10 @@ static int X509V3_ext(struct Curl_easy *data, ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); BIO_get_mem_ptr(bio_out, &biomem); - - for(j = 0; j < (size_t)biomem->length; j++) { - const char *sep = ""; - if(biomem->data[j] == '\n') { - sep = ", "; - j++; /* skip the newline */ - }; - while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) - j++; - if(j<(size_t)biomem->length) - ptr += msnprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, - biomem->data[j]); - } - - Curl_ssl_push_certinfo(data, certnum, namebuf, buf); - + Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, + biomem->length); BIO_free(bio_out); - } - return 0; /* all is fine */ } #ifdef OPENSSL_IS_BORINGSSL diff --git a/release/src/router/curl/lib/vtls/polarssl.c b/release/src/router/curl/lib/vtls/polarssl.c deleted file mode 100644 index 9e7dd904370..00000000000 --- a/release/src/router/curl/lib/vtls/polarssl.c +++ /dev/null @@ -1,931 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. - * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - * - */ - -#include "curl_setup.h" - -#ifdef USE_POLARSSL -#include -#include -#include -#include -#include -#include - -#if POLARSSL_VERSION_NUMBER < 0x01030000 -#error too old PolarSSL -#endif - -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "polarssl.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "strcase.h" -#include "polarssl_threadlock.h" -#include "multiif.h" -#include "curl_printf.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* See https://tls.mbed.org/discussions/generic/ - howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der -*/ -#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE) -#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES) - -#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ - RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) - -struct ssl_backend_data { - ctr_drbg_context ctr_drbg; - entropy_context entropy; - ssl_context ssl; - int server_fd; - x509_crt cacert; - x509_crt clicert; - x509_crl crl; - rsa_context rsa; -}; - -#define BACKEND connssl->backend - -/* apply threading? */ -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -#define THREADING_SUPPORT -#endif - -#ifndef POLARSSL_ERROR_C -#define error_strerror(x,y,z) -#endif /* POLARSSL_ERROR_C */ - - -#if defined(THREADING_SUPPORT) -static entropy_context entropy; - -static int entropy_init_initialized = 0; - -/* start of entropy_init_mutex() */ -static void entropy_init_mutex(entropy_context *ctx) -{ - /* lock 0 = entropy_init_mutex() */ - Curl_polarsslthreadlock_lock_function(0); - if(entropy_init_initialized == 0) { - entropy_init(ctx); - entropy_init_initialized = 1; - } - Curl_polarsslthreadlock_unlock_function(0); -} -/* end of entropy_init_mutex() */ - -/* start of entropy_func_mutex() */ -static int entropy_func_mutex(void *data, unsigned char *output, size_t len) -{ - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); - - return ret; -} -/* end of entropy_func_mutex() */ - -#endif /* THREADING_SUPPORT */ - -/* Define this to enable lots of debugging for PolarSSL */ -#undef POLARSSL_DEBUG - -#ifdef POLARSSL_DEBUG -static void polarssl_debug(void *context, int level, const char *line) -{ - struct Curl_easy *data = NULL; - - if(!context) - return; - - data = (struct Curl_easy *)context; - - infof(data, "%s", line); - (void) level; -} -#else -#endif - -/* ALPN for http2? */ -#ifdef POLARSSL_SSL_ALPN -# define HAS_ALPN -#endif - -static Curl_recv polarssl_recv; -static Curl_send polarssl_send; - -static CURLcode polarssl_version_from_curl(int *polarver, long ssl_version) -{ - switch(ssl_version) { - case CURL_SSLVERSION_TLSv1_0: - *polarver = SSL_MINOR_VERSION_1; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1: - *polarver = SSL_MINOR_VERSION_2; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2: - *polarver = SSL_MINOR_VERSION_3; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3: - break; - } - return CURLE_SSL_CONNECT_ERROR; -} - -static CURLcode -set_ssl_version_min_max(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - int ssl_min_ver = SSL_MINOR_VERSION_1; - int ssl_max_ver = SSL_MINOR_VERSION_1; - CURLcode result = CURLE_OK; - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_version = CURL_SSLVERSION_TLSv1_0; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - result = polarssl_version_from_curl(&ssl_min_ver, ssl_version); - if(result) { - failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); - return result; - } - result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16); - if(result) { - failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); - return result; - } - - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver); - ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver); - - return result; -} - -static CURLcode -polarssl_connect_step1(struct connectdata *conn, - int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - const char *capath = SSL_CONN_CONFIG(CApath); - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - int ret = -1; - char errorbuf[128]; - errorbuf[0] = 0; - - /* PolarSSL only supports SSLv3 and TLSv1 */ - if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { - failf(data, "PolarSSL does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef THREADING_SUPPORT - entropy_init_mutex(&entropy); - - if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func_mutex, &entropy, - NULL, 0)) != 0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#else - entropy_init(&BACKEND->entropy); - - if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func, &BACKEND->entropy, - NULL, 0)) != 0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); - } -#endif /* THREADING_SUPPORT */ - - /* Load the trusted CA */ - memset(&BACKEND->cacert, 0, sizeof(x509_crt)); - - if(SSL_CONN_CONFIG(CAfile)) { - ret = x509_crt_parse_file(&BACKEND->cacert, - SSL_CONN_CONFIG(CAfile)); - - if(ret<0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", - SSL_CONN_CONFIG(CAfile), -ret, errorbuf); - - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - } - - if(capath) { - ret = x509_crt_parse_path(&BACKEND->cacert, capath); - - if(ret<0) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", - capath, -ret, errorbuf); - - if(SSL_CONN_CONFIG(verifypeer)) - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Load the client certificate */ - memset(&BACKEND->clicert, 0, sizeof(x509_crt)); - - if(SSL_SET_OPTION(cert)) { - ret = x509_crt_parse_file(&BACKEND->clicert, - SSL_SET_OPTION(cert)); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(cert), -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the client private key */ - if(SSL_SET_OPTION(key)) { - pk_context pk; - pk_init(&pk); - ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key), - SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - if(ret == 0) - rsa_copy(&BACKEND->rsa, pk_rsa(pk)); - else - rsa_free(&BACKEND->rsa); - pk_free(&pk); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(key), -ret, errorbuf); - - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the CRL */ - memset(&BACKEND->crl, 0, sizeof(x509_crl)); - - if(SSL_SET_OPTION(CRLfile)) { - ret = x509_crl_parse_file(&BACKEND->crl, - SSL_SET_OPTION(CRLfile)); - - if(ret) { - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", - SSL_SET_OPTION(CRLfile), -ret, errorbuf); - - return CURLE_SSL_CRL_BADFILE; - } - } - - infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port); - - if(ssl_init(&BACKEND->ssl)) { - failf(data, "PolarSSL: ssl_init failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_1); - break; - case CURL_SSLVERSION_SSLv3: - ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_0); - ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_0); - infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(conn, sockindex); - if(result != CURLE_OK) - return result; - break; - } - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - ssl_set_endpoint(&BACKEND->ssl, SSL_IS_CLIENT); - ssl_set_authmode(&BACKEND->ssl, SSL_VERIFY_OPTIONAL); - - ssl_set_rng(&BACKEND->ssl, ctr_drbg_random, - &BACKEND->ctr_drbg); - ssl_set_bio(&BACKEND->ssl, - net_recv, &conn->sock[sockindex], - net_send, &conn->sock[sockindex]); - - ssl_set_ciphersuites(&BACKEND->ssl, ssl_list_ciphersuites()); - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *old_session = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = ssl_set_session(&BACKEND->ssl, old_session); - if(ret) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "ssl_set_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "PolarSSL re-using session\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - ssl_set_ca_chain(&BACKEND->ssl, - &BACKEND->cacert, - &BACKEND->crl, - hostname); - - ssl_set_own_cert_rsa(&BACKEND->ssl, - &BACKEND->clicert, &BACKEND->rsa); - - if(ssl_set_hostname(&BACKEND->ssl, hostname)) { - /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name - to set in the SNI extension. So even if curl connects to a host - specified as an IP address, this function must be used. */ - failf(data, "couldn't set hostname in PolarSSL"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - static const char *protocols[3]; - int cur = 0; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { - protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - protocols[cur++] = ALPN_HTTP_1_1; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - protocols[cur] = NULL; - - ssl_set_alpn_protocols(&BACKEND->ssl, protocols); - } -#endif - -#ifdef POLARSSL_DEBUG - ssl_set_dbg(&BACKEND->ssl, polarssl_debug, data); -#endif - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode -polarssl_connect_step2(struct connectdata *conn, - int sockindex) -{ - int ret; - struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - char buffer[1024]; - const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - - - char errorbuf[128]; - errorbuf[0] = 0; - - conn->recv[sockindex] = polarssl_recv; - conn->send[sockindex] = polarssl_send; - - ret = ssl_handshake(&BACKEND->ssl); - - switch(ret) { - case 0: - break; - - case POLARSSL_ERR_NET_WANT_READ: - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - - case POLARSSL_ERR_NET_WANT_WRITE: - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - - default: - error_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", - -ret, errorbuf); - return CURLE_SSL_CONNECT_ERROR; - } - - infof(data, "PolarSSL: Handshake complete, cipher is %s\n", - ssl_get_ciphersuite(&BACKEND->ssl) ); - - ret = ssl_get_verify_result(&BACKEND->ssl); - - if(ret && SSL_CONN_CONFIG(verifypeer)) { - if(ret & BADCERT_EXPIRED) - failf(data, "Cert verify failed: BADCERT_EXPIRED"); - - if(ret & BADCERT_REVOKED) { - failf(data, "Cert verify failed: BADCERT_REVOKED"); - return CURLE_PEER_FAILED_VERIFICATION; - } - - if(ret & BADCERT_CN_MISMATCH) - failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); - - if(ret & BADCERT_NOT_TRUSTED) - failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); - - return CURLE_PEER_FAILED_VERIFICATION; - } - - if(ssl_get_peer_cert(&(BACKEND->ssl))) { - /* If the session was resumed, there will be no peer certs */ - memset(buffer, 0, sizeof(buffer)); - - if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ", - ssl_get_peer_cert(&(BACKEND->ssl))) != -1) - infof(data, "Dumping cert info:\n%s\n", buffer); - } - - /* adapted from mbedtls.c */ - if(pinnedpubkey) { - int size; - CURLcode result; - x509_crt *p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; - const x509_crt *peercert; - - peercert = ssl_get_peer_cert(&BACKEND->ssl); - - if(!peercert || !peercert->raw.p || !peercert->raw.len) { - failf(data, "Failed due to missing peer certificate"); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - p = calloc(1, sizeof(*p)); - - if(!p) - return CURLE_OUT_OF_MEMORY; - - x509_crt_init(p); - - /* Make a copy of our const peercert because pk_write_pubkey_der - needs a non-const key, for now. - https://github.com/ARMmbed/mbedtls/issues/396 */ - if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { - failf(data, "Failed copying peer certificate"); - x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); - - if(size <= 0) { - failf(data, "Failed copying public key from peer certificate"); - x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - } - - /* pk_write_pubkey_der writes data at the end of the buffer. */ - result = Curl_pin_peer_pubkey(data, - pinnedpubkey, - &pubkey[PUB_DER_MAX_BYTES - size], size); - if(result) { - x509_crt_free(p); - free(p); - return result; - } - - x509_crt_free(p); - free(p); - } - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl); - - if(next_protocol != NULL) { - infof(data, "ALPN, server accepted to use %s\n", next_protocol); - -#ifdef USE_NGHTTP2 - if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); - } -#endif - - connssl->connecting_state = ssl_connect_3; - infof(data, "SSL connected\n"); - - return CURLE_OK; -} - -static CURLcode -polarssl_connect_step3(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - int ret; - ssl_session *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = calloc(1, sizeof(ssl_session)); - if(!our_ssl_sessionid) - return CURLE_OUT_OF_MEMORY; - - ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); - if(ret) { - failf(data, "ssl_get_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } - - /* If there's already a matching session in the cache, delete it */ - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); - Curl_ssl_sessionid_unlock(conn); - if(retcode) { - free(our_ssl_sessionid); - failf(data, "failed to store ssl session"); - return retcode; - } - } - - connssl->connecting_state = ssl_connect_done; - - return CURLE_OK; -} - -static ssize_t polarssl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int ret = -1; - - ret = ssl_write(&BACKEND->ssl, - (unsigned char *)mem, len); - - if(ret < 0) { - *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ? - CURLE_AGAIN : CURLE_SEND_ERROR; - ret = -1; - } - - return ret; -} - -static void Curl_polarssl_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - rsa_free(&BACKEND->rsa); - x509_crt_free(&BACKEND->clicert); - x509_crt_free(&BACKEND->cacert); - x509_crl_free(&BACKEND->crl); - ssl_free(&BACKEND->ssl); -} - -static ssize_t polarssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - int ret = -1; - ssize_t len = -1; - - memset(buf, 0, buffersize); - ret = ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize); - - if(ret <= 0) { - if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) - return 0; - - *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ? - CURLE_AGAIN : CURLE_RECV_ERROR; - return -1; - } - - len = ret; - - return len; -} - -static void Curl_polarssl_session_free(void *ptr) -{ - ssl_session_free(ptr); - free(ptr); -} - -/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and - higher) will be mbed TLS branded.. */ - -static size_t Curl_polarssl_version(char *buffer, size_t size) -{ - unsigned int version = version_get_number(); - return msnprintf(buffer, size, "%s/%d.%d.%d", - version >= 0x01030A00?"mbedTLS":"PolarSSL", - version>>24, (version>>16)&0xff, (version>>8)&0xff); -} - -static CURLcode -polarssl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - timediff_t timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = polarssl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:(time_t)timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - result = polarssl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = polarssl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = polarssl_recv; - conn->send[sockindex] = polarssl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - return polarssl_connect_common(conn, sockindex, TRUE, done); -} - - -static CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = polarssl_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -/* - * return 0 error initializing SSL - * return 1 SSL initialized successfully - */ -static int Curl_polarssl_init(void) -{ - return Curl_polarsslthreadlock_thread_setup(); -} - -static void Curl_polarssl_cleanup(void) -{ - (void)Curl_polarsslthreadlock_thread_cleanup(); -} - -static bool Curl_polarssl_data_pending(const struct connectdata *conn, - int sockindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - return ssl_get_bytes_avail(&BACKEND->ssl) != 0; -} - -static CURLcode Curl_polarssl_sha256sum(const unsigned char *input, - size_t inputlen, - unsigned char *sha256sum, - size_t sha256len UNUSED_PARAM) -{ - (void)sha256len; - sha256(input, inputlen, sha256sum, 0); - return CURLE_OK; -} - -static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return &BACKEND->ssl; -} - -const struct Curl_ssl Curl_ssl_polarssl = { - { CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */ - - SSLSUPP_CA_PATH | - SSLSUPP_PINNEDPUBKEY, - - sizeof(struct ssl_backend_data), - - Curl_polarssl_init, /* init */ - Curl_polarssl_cleanup, /* cleanup */ - Curl_polarssl_version, /* version */ - Curl_none_check_cxn, /* check_cxn */ - Curl_none_shutdown, /* shutdown */ - Curl_polarssl_data_pending, /* data_pending */ - /* This might cause libcurl to use a weeker random! */ - Curl_none_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_polarssl_connect, /* connect */ - Curl_polarssl_connect_nonblocking, /* connect_nonblocking */ - Curl_polarssl_get_internals, /* get_internals */ - Curl_polarssl_close, /* close_one */ - Curl_none_close_all, /* close_all */ - Curl_polarssl_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - Curl_polarssl_sha256sum /* sha256sum */ -}; - -#endif /* USE_POLARSSL */ diff --git a/release/src/router/curl/lib/vtls/schannel.c b/release/src/router/curl/lib/vtls/schannel.c index dc58ed0d3b0..f665ee34041 100644 --- a/release/src/router/curl/lib/vtls/schannel.c +++ b/release/src/router/curl/lib/vtls/schannel.c @@ -27,16 +27,6 @@ * but vtls.c should ever call or use these functions. */ -/* - * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: - * Copyright (C) 2010, 2011, Hoi-Ho Chan, - * - * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. - * - * Thanks for code and inspiration! - */ - #include "curl_setup.h" #ifdef USE_SCHANNEL @@ -718,7 +708,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) unsigned short* list_len = NULL; /* The first four bytes will be an unsigned int indicating number - of bytes of data in the rest of the the buffer. */ + of bytes of data in the rest of the buffer. */ extension_len = (unsigned int *)(&alpn_buffer[cur]); cur += sizeof(unsigned int); diff --git a/release/src/router/curl/lib/vtls/schannel_verify.c b/release/src/router/curl/lib/vtls/schannel_verify.c index 3a668adc768..e75132caddd 100644 --- a/release/src/router/curl/lib/vtls/schannel_verify.c +++ b/release/src/router/curl/lib/vtls/schannel_verify.c @@ -7,7 +7,7 @@ * * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -293,6 +293,133 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store, return result; } +/* + * Returns the number of characters necessary to populate all the host_names. + * If host_names is not NULL, populate it with all the host names. Each string + * in the host_names is null-terminated and the last string is double + * null-terminated. If no DNS names are found, a single null-terminated empty + * string is returned. + */ +static DWORD cert_get_name_string(struct Curl_easy *data, + CERT_CONTEXT *cert_context, + LPTSTR host_names, + DWORD length) +{ + DWORD actual_length = 0; + BOOL compute_content = FALSE; + CERT_INFO *cert_info = NULL; + CERT_EXTENSION *extension = NULL; + CRYPT_DECODE_PARA decode_para = {0, 0, 0}; + CERT_ALT_NAME_INFO *alt_name_info = NULL; + DWORD alt_name_info_size = 0; + BOOL ret_val = FALSE; + LPTSTR current_pos = NULL; + DWORD i; + + /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ + if(Curl_verify_windows_version(6, 2, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { +#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG + /* CertGetNameString will provide the 8-bit character string without + * any decoding */ + DWORD name_flags = + CERT_NAME_DISABLE_IE4_UTF8_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG; + actual_length = CertGetNameString(cert_context, + CERT_NAME_DNS_TYPE, + name_flags, + NULL, + host_names, + length); + return actual_length; +#endif + } + + compute_content = host_names != NULL && length != 0; + + /* Initialize default return values. */ + actual_length = 1; + if(compute_content) { + *host_names = '\0'; + } + + if(!cert_context) { + failf(data, "schannel: Null certificate context."); + return actual_length; + } + + cert_info = cert_context->pCertInfo; + if(!cert_info) { + failf(data, "schannel: Null certificate info."); + return actual_length; + } + + extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2, + cert_info->cExtension, + cert_info->rgExtension); + if(!extension) { + failf(data, "schannel: CertFindExtension() returned no extension."); + return actual_length; + } + + decode_para.cbSize = sizeof(CRYPT_DECODE_PARA); + + ret_val = + CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + szOID_SUBJECT_ALT_NAME2, + extension->Value.pbData, + extension->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, + &decode_para, + &alt_name_info, + &alt_name_info_size); + if(!ret_val) { + failf(data, + "schannel: CryptDecodeObjectEx() returned no alternate name " + "information."); + return actual_length; + } + + current_pos = host_names; + + /* Iterate over the alternate names and populate host_names. */ + for(i = 0; i < alt_name_info->cAltEntry; i++) { + const CERT_ALT_NAME_ENTRY *entry = &alt_name_info->rgAltEntry[i]; + wchar_t *dns_w = NULL; + size_t current_length = 0; + + if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) { + continue; + } + if(entry->pwszDNSName == NULL) { + infof(data, "schannel: Empty DNS name."); + continue; + } + current_length = wcslen(entry->pwszDNSName) + 1; + if(!compute_content) { + actual_length += (DWORD)current_length; + continue; + } + /* Sanity check to prevent buffer overrun. */ + if((actual_length + current_length) > length) { + failf(data, "schannel: Not enough memory to list all host names."); + break; + } + dns_w = entry->pwszDNSName; + /* pwszDNSName is in ia5 string format and hence doesn't contain any + * non-ascii characters. */ + while(*dns_w != '\0') { + *current_pos++ = (char)(*dns_w++); + } + *current_pos++ = '\0'; + actual_length += (DWORD)current_length; + } + if(compute_content) { + /* Last string has double null-terminator. */ + *current_pos = '\0'; + } + return actual_length; +} + static CURLcode verify_host(struct Curl_easy *data, CERT_CONTEXT *pCertContextServer, const char * const conn_hostname) @@ -303,21 +430,8 @@ static CURLcode verify_host(struct Curl_easy *data, DWORD len = 0; DWORD actual_len = 0; - /* CertGetNameString will provide the 8-bit character string without - * any decoding */ - DWORD name_flags = CERT_NAME_DISABLE_IE4_UTF8_FLAG; - -#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG - name_flags |= CERT_NAME_SEARCH_ALL_NAMES_FLAG; -#endif - /* Determine the size of the string needed for the cert hostname */ - len = CertGetNameString(pCertContextServer, - CERT_NAME_DNS_TYPE, - name_flags, - NULL, - NULL, - 0); + len = cert_get_name_string(data, pCertContextServer, NULL, 0); if(len == 0) { failf(data, "schannel: CertGetNameString() returned no " @@ -334,12 +448,8 @@ static CURLcode verify_host(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; goto cleanup; } - actual_len = CertGetNameString(pCertContextServer, - CERT_NAME_DNS_TYPE, - name_flags, - NULL, - (LPTSTR) cert_hostname_buff, - len); + actual_len = cert_get_name_string( + data, pCertContextServer, (LPTSTR)cert_hostname_buff, len); /* Sanity check */ if(actual_len != len) { diff --git a/release/src/router/curl/lib/vtls/sectransp.c b/release/src/router/curl/lib/vtls/sectransp.c index 4eece89d55f..7dd028fb7ff 100644 --- a/release/src/router/curl/lib/vtls/sectransp.c +++ b/release/src/router/curl/lib/vtls/sectransp.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2017, Nick Zitzmann, . - * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -1164,7 +1164,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, * the Keychain. * * As this doesn't match iOS, and apps may not want to see their client - * certificate saved in the the user's keychain, we use SecItemImport + * certificate saved in the user's keychain, we use SecItemImport * with a NULL keychain to avoid importing it. * * This returns a SecCertificateRef from which we can construct a diff --git a/release/src/router/curl/lib/vtls/vtls.c b/release/src/router/curl/lib/vtls/vtls.c index c493b151698..dfefa1bd5e1 100644 --- a/release/src/router/curl/lib/vtls/vtls.c +++ b/release/src/router/curl/lib/vtls/vtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -516,7 +516,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) } #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_SECTRANSP) || defined(USE_POLARSSL) || defined(USE_NSS) || \ + defined(USE_SECTRANSP) || defined(USE_NSS) || \ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL) int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks) { @@ -1183,8 +1183,6 @@ const struct Curl_ssl *Curl_ssl = &Curl_ssl_nss; #elif defined(USE_OPENSSL) &Curl_ssl_openssl; -#elif defined(USE_POLARSSL) - &Curl_ssl_polarssl; #elif defined(USE_SCHANNEL) &Curl_ssl_schannel; #elif defined(USE_MESALINK) @@ -1217,9 +1215,6 @@ static const struct Curl_ssl *available_backends[] = { #if defined(USE_OPENSSL) &Curl_ssl_openssl, #endif -#if defined(USE_POLARSSL) - &Curl_ssl_polarssl, -#endif #if defined(USE_SCHANNEL) &Curl_ssl_schannel, #endif @@ -1236,7 +1231,7 @@ static size_t Curl_multissl_version(char *buffer, size_t size) { static const struct Curl_ssl *selected; static char backends[200]; - static size_t total; + static size_t backends_len; const struct Curl_ssl *current; current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; @@ -1248,27 +1243,32 @@ static size_t Curl_multissl_version(char *buffer, size_t size) selected = current; - for(i = 0; available_backends[i] && p < (end - 4); i++) { - if(i) - *(p++) = ' '; - if(selected != available_backends[i]) - *(p++) = '('; - p += available_backends[i]->version(p, end - p - 2); - if(selected != available_backends[i]) - *(p++) = ')'; + backends[0] = '\0'; + + for(i = 0; available_backends[i]; ++i) { + char vb[200]; + bool paren = (selected != available_backends[i]); + + if(available_backends[i]->version(vb, sizeof(vb))) { + p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), + (paren ? "(" : ""), vb, (paren ? ")" : "")); + } } - *p = '\0'; - total = p - backends; + + backends_len = p - backends; } - if(size > total) - memcpy(buffer, backends, total + 1); - else { - memcpy(buffer, backends, size - 1); + if(!size) + return 0; + + if(size <= backends_len) { + strncpy(buffer, backends, size - 1); buffer[size - 1] = '\0'; + return size - 1; } - return CURLMIN(size - 1, total); + strcpy(buffer, backends); + return backends_len; } static int multissl_init(const struct Curl_ssl *backend) diff --git a/release/src/router/curl/lib/vtls/vtls.h b/release/src/router/curl/lib/vtls/vtls.h index 976cc436019..a81b2f22d1a 100644 --- a/release/src/router/curl/lib/vtls/vtls.h +++ b/release/src/router/curl/lib/vtls/vtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -102,7 +102,6 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, #include "gtls.h" /* GnuTLS versions */ #include "nssg.h" /* NSS versions */ #include "gskit.h" /* Global Secure ToolKit versions */ -#include "polarssl.h" /* PolarSSL versions */ #include "wolfssl.h" /* wolfSSL versions */ #include "schannel.h" /* Schannel SSPI version */ #include "sectransp.h" /* SecureTransport (Darwin) version */ @@ -263,7 +262,6 @@ bool Curl_ssl_false_start(void); #define Curl_ssl_send(a,b,c,d,e) -1 #define Curl_ssl_recv(a,b,c,d,e) -1 #define Curl_ssl_initsessions(x,y) CURLE_OK -#define Curl_ssl_version(x,y) 0 #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt diff --git a/release/src/router/curl/lib/vtls/wolfssl.c b/release/src/router/curl/lib/vtls/wolfssl.c index 890bcbf7978..8c2d3f4a283 100644 --- a/release/src/router/curl/lib/vtls/wolfssl.c +++ b/release/src/router/curl/lib/vtls/wolfssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -923,7 +923,7 @@ static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex) static CURLcode Curl_wolfssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { - RNG rng; + WC_RNG rng; (void)data; if(wc_InitRng(&rng)) return CURLE_FAILED_INIT; @@ -937,11 +937,11 @@ static CURLcode Curl_wolfssl_random(struct Curl_easy *data, } static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) { - Sha256 SHA256pw; + wc_Sha256 SHA256pw; (void)unused; wc_InitSha256(&SHA256pw); wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen); diff --git a/release/src/router/curl/ltmain.sh b/release/src/router/curl/ltmain.sh index d11f1e022c6..e39eeace320 100644 --- a/release/src/router/curl/ltmain.sh +++ b/release/src/router/curl/ltmain.sh @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.4.6 Debian-2.4.6-11" +VERSION="2.4.6 Debian-2.4.6-13" package_revision=2.4.6 @@ -387,7 +387,7 @@ EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # -# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +# debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: @@ -2141,7 +2141,7 @@ include the following information: compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion Debian-2.4.6-11 + version: $progname $scriptversion Debian-2.4.6-13 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` @@ -7368,10 +7368,12 @@ func_mode_link () # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC + # -static-* direct GCC to link specific libraries statically + # -fcilkplus Cilk Plus language extension features for C/C++ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ - -specs=*|-fsanitize=*|-fuse-ld=*) + -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" diff --git a/release/src/router/curl/m4/curl-confopts.m4 b/release/src/router/curl/m4/curl-confopts.m4 index af15a85d977..eaae5b9c61c 100644 --- a/release/src/router/curl/m4/curl-confopts.m4 +++ b/release/src/router/curl/m4/curl-confopts.m4 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -107,7 +107,7 @@ AC_HELP_STRING([--disable-curldebug],[Disable curl debug memory tracking]), ;; default) dnl configure's curldebug option not specified. Initially we will - dnl handle this as a a request to use the same setting as option + dnl handle this as a request to use the same setting as option dnl --enable-debug. IOW, initially, for debug-enabled builds dnl this will be handled as a request to enable curldebug if dnl possible, and for debug-disabled builds this will be handled @@ -198,7 +198,7 @@ AC_HELP_STRING([--disable-optimize],[Disable compiler optimizations]), ;; default) dnl configure's optimize option not specified. Initially we will - dnl handle this as a a request contrary to configure's setting + dnl handle this as a request contrary to configure's setting dnl for --enable-debug. IOW, initially, for debug-enabled builds dnl this will be handled as a request to disable optimizations if dnl possible, and for debug-disabled builds this will be handled diff --git a/release/src/router/curl/m4/curl-functions.m4 b/release/src/router/curl/m4/curl-functions.m4 index 9020f394288..e773f670090 100644 --- a/release/src/router/curl/m4/curl-functions.m4 +++ b/release/src/router/curl/m4/curl-functions.m4 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -6350,7 +6350,7 @@ dnl glibc-style strerror_r: dnl dnl char *strerror_r(int errnum, char *workbuf, size_t bufsize); dnl -dnl glibc-style strerror_r returns a pointer to the the error string, +dnl glibc-style strerror_r returns a pointer to the error string, dnl and might use the provided workbuf as a scratch area if needed. A dnl quick test on a few systems shows that it's usually not used at all. dnl diff --git a/release/src/router/curl/m4/libtool.m4 b/release/src/router/curl/m4/libtool.m4 index 90924a62d89..3a03d8456ce 100644 --- a/release/src/router/curl/m4/libtool.m4 +++ b/release/src/router/curl/m4/libtool.m4 @@ -1041,8 +1041,8 @@ int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD - echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD - $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF @@ -1492,7 +1492,7 @@ need_locks=$enable_libtool_lock m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} -: ${AR_FLAGS=cru} +: ${AR_FLAGS=cr} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) diff --git a/release/src/router/curl/packages/Makefile.in b/release/src/router/curl/packages/Makefile.in index 6d1b80c9d07..742f0a29859 100644 --- a/release/src/router/curl/packages/Makefile.in +++ b/release/src/router/curl/packages/Makefile.in @@ -340,6 +340,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/packages/OS400/ccsidcurl.c b/release/src/router/curl/packages/OS400/ccsidcurl.c index 11e4c777eec..64fb7393d0c 100644 --- a/release/src/router/curl/packages/OS400/ccsidcurl.c +++ b/release/src/router/curl/packages/OS400/ccsidcurl.c @@ -1130,22 +1130,6 @@ curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...) char *cp; unsigned int ccsid; curl_off_t pfsize; - static char testwarn = 1; - - /* Warns if this procedure has not been updated when the dupstring enum - changes. - We (try to) do it only once: there is no need to issue several times - the same message; but since threadsafeness is not handled here, - this may occur (and we don't care!). */ - - if(testwarn) { - testwarn = 0; - - if((int) STRING_LASTZEROTERMINATED != (int) STRING_SASL_AUTHZID + 1 || - (int) STRING_LAST != (int) STRING_COPYPOSTFIELDS + 1) - curl_mfprintf(stderr, - "*** WARNING: curl_easy_setopt_ccsid() should be reworked ***\n"); - } data = (struct Curl_easy *) curl; va_start(arg, tag); diff --git a/release/src/router/curl/packages/OS400/curl.inc.in b/release/src/router/curl/packages/OS400/curl.inc.in index 4e34de16236..a160f108501 100644 --- a/release/src/router/curl/packages/OS400/curl.inc.in +++ b/release/src/router/curl/packages/OS400/curl.inc.in @@ -602,6 +602,8 @@ d c 94 d CURLE_HTTP3... d c 95 + d CURLE_QUIC_CONNECT_ERROR... + d c 96 * /if not defined(CURL_NO_OLDIES) d CURLE_URL_MALFORMAT_USER... @@ -1816,7 +1818,9 @@ d c 8 d CURLM_WAKEUP_FAILURE... d c 9 - d CURLM_LAST c 10 + d CURLM_BAD_FUNCTION_ARGUMENT... + d c 10 + d CURLM_LAST c 11 * d CURLMSG s 10i 0 based(######ptr######) Enum d CURLMSG_NONE c 0 diff --git a/release/src/router/curl/packages/OS400/make-lib.sh b/release/src/router/curl/packages/OS400/make-lib.sh index 410bef05b6b..fadb4c5f6b1 100644 --- a/release/src/router/curl/packages/OS400/make-lib.sh +++ b/release/src/router/curl/packages/OS400/make-lib.sh @@ -46,6 +46,26 @@ sed -e ':begin' \ INCLUDES="'`pwd`'" +# Create a small C program to check ccsidcurl.c is up to date +if action_needed "${LIBIFSNAME}/CHKSTRINGS.PGM" +then + CMD="CRTBNDC PGM(${TARGETLIB}/CHKSTRINGS) SRCSTMF('${SCRIPTDIR}/chkstrings.c')" + CMD="${CMD} INCDIR('${TOPDIR}/include/curl' '${TOPDIR}/include' '${SRCDIR}' ${INCLUDES})" + system -i "${CMD}" + if [ $? -ne 0 ] + then + echo "ERROR: Failed to build CHKSTRINGS *PGM object!" + exit 2 + else + ${LIBIFSNAME}/CHKSTRINGS.PGM + if [ $? -ne 0 ] + then + echo "ERROR: CHKSTRINGS failed!" + exit 2 + fi + fi +fi + make_module OS400SYS "${SCRIPTDIR}/os400sys.c" make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" diff --git a/release/src/router/curl/packages/Symbian/group/libcurl.mmp b/release/src/router/curl/packages/Symbian/group/libcurl.mmp index 6e94d8489d2..3cbea609385 100644 --- a/release/src/router/curl/packages/Symbian/group/libcurl.mmp +++ b/release/src/router/curl/packages/Symbian/group/libcurl.mmp @@ -34,7 +34,7 @@ SOURCE \ ssh.c vtls/nss.c strcase.c curl_addrinfo.c socks_gssapi.c \ socks_sspi.c curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c \ pop3.c smtp.c pingpong.c rtsp.c curl_threads.c warnless.c hmac.c \ - vtls/polarssl.c curl_rtmp.c openldap.c curl_gethostname.c gopher.c \ + curl_rtmp.c openldap.c curl_gethostname.c gopher.c \ idn_win32.c vtls/cyassl.c http_proxy.c non-ascii.c \ asyn-ares.c asyn-thread.c curl_gssapi.c http_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_sasl.c vtls/schannel.c curl_multibyte.c \ diff --git a/release/src/router/curl/packages/vms/Makefile.in b/release/src/router/curl/packages/vms/Makefile.in index cbce0f30685..c9374b9894d 100644 --- a/release/src/router/curl/packages/vms/Makefile.in +++ b/release/src/router/curl/packages/vms/Makefile.in @@ -280,6 +280,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/packages/vms/compare_curl_source.com b/release/src/router/curl/packages/vms/compare_curl_source.com index eeaec31dc38..66f6a4598d3 100644 --- a/release/src/router/curl/packages/vms/compare_curl_source.com +++ b/release/src/router/curl/packages/vms/compare_curl_source.com @@ -17,7 +17,7 @@ $! me because VMS Backup can create a saveset of files from a $! NFS mounted volume. $! $! First the files in the original source directory which is assumed to be -$! under source codde control are compared with the copy directory. +$! under source code control are compared with the copy directory. $! $! Then the files are are only in the copy directory are listed. $! diff --git a/release/src/router/curl/packages/vms/curl_crtl_init.c b/release/src/router/curl/packages/vms/curl_crtl_init.c index 7a8d8474335..9f7cf66c7ac 100644 --- a/release/src/router/curl/packages/vms/curl_crtl_init.c +++ b/release/src/router/curl/packages/vms/curl_crtl_init.c @@ -1,7 +1,7 @@ /* File: curl_crtl_init.c * * This file makes sure that the DECC Unix settings are correct for - * the mode the the program is run in. + * the mode the program is run in. * * The CRTL has not been initialized at the time that these routines * are called, so many routines can not be called. diff --git a/release/src/router/curl/packages/vms/generate_config_vms_h_curl.com b/release/src/router/curl/packages/vms/generate_config_vms_h_curl.com index 809aaaf98d4..6c65b24cb84 100644 --- a/release/src/router/curl/packages/vms/generate_config_vms_h_curl.com +++ b/release/src/router/curl/packages/vms/generate_config_vms_h_curl.com @@ -17,7 +17,7 @@ $! and the [.lib]config-vms.h file do two different tasks and that the $! filenames are slightly different. $! $! -$! Copyright 2013, John Malmberg +$! Copyright 2013 - 2020, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above @@ -349,9 +349,6 @@ $write cvh "#endif" $write cvh "#ifdef USE_OPENLDAP" $write cvh "#undef USE_OPENLDAP" $write cvh "#endif" -$write cvh "#ifdef USE_POLARSSL" -$write cvh "#undef USE_POLARSSL" -$write cvh "#endif" $write cvh "#ifdef USE_THREADS_POSIX" $write cvh "#undef USE_THREADS_POSIX" $write cvh "#endif" diff --git a/release/src/router/curl/packages/vms/readme b/release/src/router/curl/packages/vms/readme index ddfac747a6b..be1278fcac6 100644 --- a/release/src/router/curl/packages/vms/readme +++ b/release/src/router/curl/packages/vms/readme @@ -194,7 +194,7 @@ LDAP and Kerberos installed, you can use the GNV_LINK_CURL.COM file. The GNV_LINK_CURL.COM contains information on how to link and run with a newer version of HP SSL than what may be install on an Alpha or IA64 based system. -To build the PCSI kit, follow the the instructions in the file +To build the PCSI kit, follow the instructions in the file curl_gnv_build_steps.txt. Other Notes: @@ -206,7 +206,7 @@ The libcurl formdata.c module and Curl tools post form now have some understanding of VMS file types. Files will be posted in STREAM_LF format. The Curl tool now has some understanding of VMS file types and will upload the -files in STREAM_LF fomat. +files in STREAM_LF format. When CURL is uploading a VARIABLE format VMS file, it is less efficient as in order to get the file size, it will first read the entire file once, and then diff --git a/release/src/router/curl/projects/Windows/VC10/lib/libcurl.vcxproj b/release/src/router/curl/projects/Windows/VC10/lib/libcurl.vcxproj index 81d9891617c..b3603dc5ad9 100644 --- a/release/src/router/curl/projects/Windows/VC10/lib/libcurl.vcxproj +++ b/release/src/router/curl/projects/Windows/VC10/lib/libcurl.vcxproj @@ -2402,6 +2402,7 @@ + @@ -2450,15 +2451,15 @@ + + - - @@ -2546,6 +2547,7 @@ + @@ -2587,11 +2589,10 @@ + - - diff --git a/release/src/router/curl/projects/Windows/VC11/lib/libcurl.vcxproj b/release/src/router/curl/projects/Windows/VC11/lib/libcurl.vcxproj index 5960b345e33..5374c5be042 100644 --- a/release/src/router/curl/projects/Windows/VC11/lib/libcurl.vcxproj +++ b/release/src/router/curl/projects/Windows/VC11/lib/libcurl.vcxproj @@ -2458,6 +2458,7 @@ + @@ -2506,15 +2507,15 @@ + + - - @@ -2602,6 +2603,7 @@ + @@ -2643,11 +2645,10 @@ + - - diff --git a/release/src/router/curl/projects/Windows/VC12/lib/libcurl.vcxproj b/release/src/router/curl/projects/Windows/VC12/lib/libcurl.vcxproj index 4a766a93150..d4403abb0b0 100644 --- a/release/src/router/curl/projects/Windows/VC12/lib/libcurl.vcxproj +++ b/release/src/router/curl/projects/Windows/VC12/lib/libcurl.vcxproj @@ -2458,6 +2458,7 @@ + @@ -2506,15 +2507,15 @@ + + - - @@ -2602,6 +2603,7 @@ + @@ -2643,11 +2645,10 @@ + - - diff --git a/release/src/router/curl/projects/Windows/VC14/lib/libcurl.vcxproj b/release/src/router/curl/projects/Windows/VC14/lib/libcurl.vcxproj index 4c1e4bd3c75..78e1e47ab49 100644 --- a/release/src/router/curl/projects/Windows/VC14/lib/libcurl.vcxproj +++ b/release/src/router/curl/projects/Windows/VC14/lib/libcurl.vcxproj @@ -2458,6 +2458,7 @@ + @@ -2506,15 +2507,15 @@ + + - - @@ -2602,6 +2603,7 @@ + @@ -2643,11 +2645,10 @@ + - - diff --git a/release/src/router/curl/projects/Windows/VC15/lib/libcurl.vcxproj b/release/src/router/curl/projects/Windows/VC15/lib/libcurl.vcxproj index 227896bb8d9..b5114722654 100644 --- a/release/src/router/curl/projects/Windows/VC15/lib/libcurl.vcxproj +++ b/release/src/router/curl/projects/Windows/VC15/lib/libcurl.vcxproj @@ -2430,6 +2430,7 @@ + @@ -2478,15 +2479,15 @@ + + - - @@ -2574,6 +2575,7 @@ + @@ -2615,11 +2617,10 @@ + - - diff --git a/release/src/router/curl/projects/Windows/VC6/lib/libcurl.dsp b/release/src/router/curl/projects/Windows/VC6/lib/libcurl.dsp index 561a2e91ecd..9c153446ed8 100644 --- a/release/src/router/curl/projects/Windows/VC6/lib/libcurl.dsp +++ b/release/src/router/curl/projects/Windows/VC6/lib/libcurl.dsp @@ -1046,6 +1046,10 @@ SOURCE=..\..\..\..\lib\rand.c # End Source File # Begin Source File +SOURCE=..\..\..\..\lib\rename.c +# End Source File +# Begin Source File + SOURCE=..\..\..\..\lib\rtsp.c # End Source File # Begin Source File @@ -1238,6 +1242,10 @@ SOURCE=..\..\..\..\lib\vssh\libssh.c # End Source File # Begin Source File +SOURCE=..\..\..\..\lib\vssh\wolfssh.c +# End Source File +# Begin Source File + SOURCE=..\..\..\..\lib\vtls\bearssl.c # End Source File # Begin Source File @@ -1254,23 +1262,19 @@ SOURCE=..\..\..\..\lib\vtls\mbedtls.c # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\mesalink.c -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\lib\vtls\nss.c +SOURCE=..\..\..\..\lib\vtls\mbedtls_threadlock.c # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\openssl.c +SOURCE=..\..\..\..\lib\vtls\mesalink.c # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\polarssl.c +SOURCE=..\..\..\..\lib\vtls\nss.c # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\polarssl_threadlock.c +SOURCE=..\..\..\..\lib\vtls\openssl.c # End Source File # Begin Source File @@ -1618,6 +1622,10 @@ SOURCE=..\..\..\..\lib\rand.h # End Source File # Begin Source File +SOURCE=..\..\..\..\lib\rename.h +# End Source File +# Begin Source File + SOURCE=..\..\..\..\lib\rtsp.h # End Source File # Begin Source File @@ -1782,23 +1790,19 @@ SOURCE=..\..\..\..\lib\vtls\mbedtls.h # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\mesalink.h +SOURCE=..\..\..\..\lib\vtls\mbedtls_threadlock.h # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\nssg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\lib\vtls\openssl.h +SOURCE=..\..\..\..\lib\vtls\mesalink.h # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\polarssl.h +SOURCE=..\..\..\..\lib\vtls\nssg.h # End Source File # Begin Source File -SOURCE=..\..\..\..\lib\vtls\polarssl_threadlock.h +SOURCE=..\..\..\..\lib\vtls\openssl.h # End Source File # Begin Source File diff --git a/release/src/router/curl/projects/Windows/VC7.1/lib/libcurl.vcproj b/release/src/router/curl/projects/Windows/VC7.1/lib/libcurl.vcproj index bde256b7649..5471cd1a9b2 100644 --- a/release/src/router/curl/projects/Windows/VC7.1/lib/libcurl.vcproj +++ b/release/src/router/curl/projects/Windows/VC7.1/lib/libcurl.vcproj @@ -1492,6 +1492,9 @@ + + @@ -1832,6 +1835,9 @@ + + @@ -2026,6 +2032,9 @@ + + + + @@ -2062,12 +2074,6 @@ - - - - @@ -2099,6 +2105,9 @@ + + @@ -2108,12 +2117,6 @@ - - - - diff --git a/release/src/router/curl/projects/Windows/VC7/lib/libcurl.vcproj b/release/src/router/curl/projects/Windows/VC7/lib/libcurl.vcproj index b6b349f4882..690038585fb 100644 --- a/release/src/router/curl/projects/Windows/VC7/lib/libcurl.vcproj +++ b/release/src/router/curl/projects/Windows/VC7/lib/libcurl.vcproj @@ -1346,6 +1346,9 @@ + + @@ -1686,6 +1689,9 @@ + + @@ -1880,6 +1886,9 @@ + + + + @@ -1916,12 +1928,6 @@ - - - - @@ -1953,6 +1959,9 @@ + + @@ -1962,12 +1971,6 @@ - - - - diff --git a/release/src/router/curl/projects/Windows/VC8/lib/libcurl.vcproj b/release/src/router/curl/projects/Windows/VC8/lib/libcurl.vcproj index b785c4e77dc..4d35c0005fb 100644 --- a/release/src/router/curl/projects/Windows/VC8/lib/libcurl.vcproj +++ b/release/src/router/curl/projects/Windows/VC8/lib/libcurl.vcproj @@ -3932,6 +3932,10 @@ RelativePath="..\..\..\..\lib\rand.c" > + + @@ -4384,6 +4388,10 @@ RelativePath="..\..\..\..\lib\rand.h" > + + @@ -4631,6 +4639,10 @@ RelativePath="..\..\..\..\lib\vssh\libssh.c" > + + - - - - + + @@ -4325,6 +4329,10 @@ RelativePath="..\..\..\..\lib\rand.h" > + + @@ -4572,6 +4580,10 @@ RelativePath="..\..\..\..\lib\vssh\libssh.c" > + + - - - - . +rem * Copyright (C) 2014 - 2020, Steve Holme, . rem * rem * This software is licensed as described in the file COPYING, which rem * you should have received as part of this distribution. The terms @@ -31,6 +31,9 @@ rem *************************************************************************** set CHECK_SRC=TRUE set CHECK_TESTS=TRUE set CHECK_EXAMPLES=TRUE + set SRC_DIR= + set CUR_DIR=%cd% + set ARG0_DIR=%~dp0 :parseArgs if "%~1" == "" goto prerequisites @@ -88,7 +91,22 @@ rem *************************************************************************** ) :configure - if "%SRC_DIR%" == "" set SRC_DIR=.. + if "%SRC_DIR%" == "" ( + rem Are we being executed from the "projects" or main directory? + if "%CUR_DIR%\" == "%ARG0_DIR%" ( + set SRC_DIR=.. + ) else if exist projects ( + if exist docs ( + if exist lib ( + if exist src ( + if exist tests ( + set SRC_DIR=. + ) + ) + ) + ) + ) + ) if not exist "%SRC_DIR%" goto nosrc :start diff --git a/release/src/router/curl/scripts/Makefile.in b/release/src/router/curl/scripts/Makefile.in index ec5cce74e78..4b88b9623f0 100644 --- a/release/src/router/curl/scripts/Makefile.in +++ b/release/src/router/curl/scripts/Makefile.in @@ -280,6 +280,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/src/CMakeLists.txt b/release/src/router/curl/src/CMakeLists.txt index 63e2b943d44..054541e40bd 100644 --- a/release/src/router/curl/src/CMakeLists.txt +++ b/release/src/router/curl/src/CMakeLists.txt @@ -46,6 +46,12 @@ add_executable( ${CURL_FILES} ) +if(CURL_HAS_LTO) + set_target_properties(${EXE_NAME} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) +endif() + source_group("curlX source files" FILES ${CURLX_CFILES}) source_group("curl source files" FILES ${CURL_CFILES}) source_group("curl header files" FILES ${CURL_HFILES}) diff --git a/release/src/router/curl/src/Makefile.in b/release/src/router/curl/src/Makefile.in index 19d5db6ca50..203dab6a271 100644 --- a/release/src/router/curl/src/Makefile.in +++ b/release/src/router/curl/src/Makefile.in @@ -563,6 +563,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/src/tool_cb_hdr.c b/release/src/router/curl/src/tool_cb_hdr.c index 77224adba48..3b102388866 100644 --- a/release/src/router/curl/src/tool_cb_hdr.c +++ b/release/src/router/curl/src/tool_cb_hdr.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -73,12 +73,12 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) */ size_t failure = (size && nmemb) ? 0 : 1; - if(!heads->config) + if(!per->config) return failure; #ifdef DEBUGBUILD if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { - warnf(heads->config->global, "Header data exceeds single call write " + warnf(per->config->global, "Header data exceeds single call write " "limit!\n"); return failure; } @@ -88,7 +88,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) * Write header data when curl option --dump-header (-D) is given. */ - if(heads->config->headerfile && heads->stream) { + if(per->config->headerfile && heads->stream) { size_t rc = fwrite(ptr, size, nmemb, heads->stream); if(rc != cb) return rc; @@ -100,7 +100,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) * Write etag to file when --etag-save option is given. * etag string that we want is enveloped in double quotes */ - if(etag_save->config->etag_save_file && etag_save->stream) { + if(per->config->etag_save_file && etag_save->stream) { /* match only header that start with etag (case insensitive) */ if(curl_strnequal(str, "etag:", 5)) { char *etag_h = NULL; @@ -109,7 +109,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) size_t etag_length = 0; etag_h = ptr; - /* point to first occurence of double quote */ + /* point to first occurrence of double quote */ first = memchr(etag_h, '\"', cb); /* @@ -118,9 +118,8 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) */ if(!first) { - warnf( - etag_save->config->global, - "\nReceived header etag is missing double quote/s\n"); + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); return 1; } else { @@ -128,13 +127,12 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) first++; } - /* point to last occurence of double quote */ + /* point to last occurrence of double quote */ last = memchr(first, '\"', cb); if(!last) { - warnf( - etag_save->config->global, - "\nReceived header etag is missing double quote/s\n"); + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); return 1; } @@ -197,7 +195,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) /* rename the initial file name to the new file name */ rc = rename(outs->filename, filename); if(rc != 0) { - warnf(outs->config->global, "Failed to rename %s -> %s: %s\n", + warnf(per->config->global, "Failed to rename %s -> %s: %s\n", outs->filename, filename, strerror(errno)); } if(outs->alloc_filename) @@ -213,12 +211,12 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) outs->filename = filename; outs->alloc_filename = TRUE; hdrcbdata->honor_cd_filename = FALSE; /* done now! */ - if(!tool_create_output_file(outs)) + if(!tool_create_output_file(outs, per->config)) return failure; } break; } - if(!outs->stream && !tool_create_output_file(outs)) + if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; } @@ -228,7 +226,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) /* bold headers only for selected protocols */ char *value = NULL; - if(!outs->stream && !tool_create_output_file(outs)) + if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) diff --git a/release/src/router/curl/src/tool_cb_prg.c b/release/src/router/curl/src/tool_cb_prg.c index 505ae751f61..aad451b8797 100644 --- a/release/src/router/curl/src/tool_cb_prg.c +++ b/release/src/router/curl/src/tool_cb_prg.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -46,25 +46,32 @@ my $pi = 3.1415; foreach my $i (1 .. 200) { - printf "%d, ", sin($i/200 * 2 * $pi) * 5000 + 5000; + printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000; } */ static const unsigned int sinus[] = { - 5157, 5313, 5470, 5626, 5782, 5936, 6090, 6243, 6394, 6545, 6693, 6840, 6985, - 7128, 7269, 7408, 7545, 7679, 7810, 7938, 8064, 8187, 8306, 8422, 8535, 8644, - 8750, 8852, 8950, 9045, 9135, 9221, 9303, 9381, 9454, 9524, 9588, 9648, 9704, - 9755, 9801, 9842, 9879, 9911, 9938, 9960, 9977, 9990, 9997, 9999, 9997, 9990, - 9977, 9960, 9938, 9911, 9879, 9842, 9801, 9755, 9704, 9648, 9588, 9524, 9455, - 9381, 9303, 9221, 9135, 9045, 8950, 8852, 8750, 8645, 8535, 8422, 8306, 8187, - 8064, 7939, 7810, 7679, 7545, 7409, 7270, 7129, 6986, 6841, 6694, 6545, 6395, - 6243, 6091, 5937, 5782, 5627, 5470, 5314, 5157, 5000, 4843, 4686, 4529, 4373, - 4218, 4063, 3909, 3757, 3605, 3455, 3306, 3159, 3014, 2871, 2730, 2591, 2455, - 2321, 2190, 2061, 1935, 1813, 1693, 1577, 1464, 1355, 1249, 1147, 1049, 955, - 864, 778, 696, 618, 545, 476, 411, 351, 295, 244, 198, 157, 120, 88, 61, 39, - 22, 9, 2, 0, 2, 9, 22, 39, 61, 88, 120, 156, 198, 244, 295, 350, 410, 475, - 544, 618, 695, 777, 864, 954, 1048, 1146, 1248, 1354, 1463, 1576, 1692, 1812, - 1934, 2060, 2188, 2320, 2454, 2590, 2729, 2870, 3013, 3158, 3305, 3454, 3604, - 3755, 3908, 4062, 4216, 4372, 4528, 4685, 4842, 4999 + 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491, + 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906, + 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047, + 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406, + 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840, + 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060, + 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888, + 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277, + 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072, + 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548, + 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751, + 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703, + 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525, + 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555, + 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613, + 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225, + 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448, + 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445, + 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480, + 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856, + 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854, + 468513, 484202, 499907 }; static void fly(struct ProgressData *bar, bool moved) @@ -76,13 +83,13 @@ static void fly(struct ProgressData *bar, bool moved) msnprintf(buf, sizeof(buf), "%*s\r", bar->width-1, " "); memcpy(&buf[bar->bar], "-=O=-", 5); - pos = sinus[bar->tick%200] / (10000 / check); + pos = sinus[bar->tick%200] / (1000000 / check); buf[pos] = '#'; - pos = sinus[(bar->tick + 5)%200] / (10000 / check); + pos = sinus[(bar->tick + 5)%200] / (1000000 / check); buf[pos] = '#'; - pos = sinus[(bar->tick + 10)%200] / (10000 / check); + pos = sinus[(bar->tick + 10)%200] / (1000000 / check); buf[pos] = '#'; - pos = sinus[(bar->tick + 15)%200] / (10000 / check); + pos = sinus[(bar->tick + 15)%200] / (1000000 / check); buf[pos] = '#'; fputs(buf, bar->out); @@ -123,8 +130,7 @@ int tool_progress_cb(void *clientp, struct timeval now = tvnow(); struct per_transfer *per = clientp; - struct OutStruct *outs = &per->outs; - struct OperationConfig *config = outs->config; + struct OperationConfig *config = per->config; struct ProgressData *bar = &per->progressbar; curl_off_t total; curl_off_t point; @@ -252,7 +258,8 @@ void progressbarinit(struct ProgressData *bar, } } #endif /* TIOCGSIZE */ - bar->width = cols; + if(cols > 20) + bar->width = cols; } if(!bar->width) diff --git a/release/src/router/curl/src/tool_cb_rea.c b/release/src/router/curl/src/tool_cb_rea.c index 03ed4a4671a..78a169fb06e 100644 --- a/release/src/router/curl/src/tool_cb_rea.c +++ b/release/src/router/curl/src/tool_cb_rea.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -63,8 +63,7 @@ int tool_readbusy_cb(void *clientp, curl_off_t ultotal, curl_off_t ulnow) { struct per_transfer *per = clientp; - struct OutStruct *outs = &per->outs; - struct OperationConfig *config = outs->config; + struct OperationConfig *config = per->config; (void)dltotal; /* unused */ (void)dlnow; /* unused */ diff --git a/release/src/router/curl/src/tool_cb_see.c b/release/src/router/curl/src/tool_cb_see.c index 99be273d178..9d660313e38 100644 --- a/release/src/router/curl/src/tool_cb_see.c +++ b/release/src/router/curl/src/tool_cb_see.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -88,7 +88,7 @@ int tool_seek_cb(void *userdata, curl_off_t offset, int whence) return CURL_SEEKFUNC_OK; } -#if defined(WIN32) && !defined(__MINGW64__) +#ifdef USE_TOOL_FTRUNCATE #ifdef __BORLANDC__ /* 64-bit lseek-like function unavailable */ @@ -129,4 +129,4 @@ int tool_ftruncate64(int fd, curl_off_t where) return 0; } -#endif /* WIN32 && ! __MINGW64__ */ +#endif /* USE_TOOL_FTRUNCATE */ diff --git a/release/src/router/curl/src/tool_cb_see.h b/release/src/router/curl/src/tool_cb_see.h index fed8bbf8d32..b5b787ed04c 100644 --- a/release/src/router/curl/src/tool_cb_see.h +++ b/release/src/router/curl/src/tool_cb_see.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,18 +23,17 @@ ***************************************************************************/ #include "tool_setup.h" -#if defined(WIN32) && !defined(__MINGW64__) +#if defined(WIN32) && !defined(HAVE_FTRUNCATE) int tool_ftruncate64(int fd, curl_off_t where); #undef ftruncate #define ftruncate(fd,where) tool_ftruncate64(fd,where) -#ifndef HAVE_FTRUNCATE -# define HAVE_FTRUNCATE 1 -#endif +#define HAVE_FTRUNCATE 1 +#define USE_TOOL_FTRUNCATE 1 -#endif /* WIN32 && ! __MINGW64__ */ +#endif /* WIN32 && ! HAVE_FTRUNCATE */ /* ** callback for CURLOPT_SEEKFUNCTION diff --git a/release/src/router/curl/src/tool_cb_wrt.c b/release/src/router/curl/src/tool_cb_wrt.c index 0f47b4d0f74..ed108911ef5 100644 --- a/release/src/router/curl/src/tool_cb_wrt.c +++ b/release/src/router/curl/src/tool_cb_wrt.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,11 +33,14 @@ #include "memdebug.h" /* keep this as LAST include */ /* create a local file for writing, return TRUE on success */ -bool tool_create_output_file(struct OutStruct *outs) +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config) { - struct GlobalConfig *global = outs->config->global; + struct GlobalConfig *global; FILE *file; - + DEBUGASSERT(outs); + DEBUGASSERT(config); + global = config->global; if(!outs->filename || !*outs->filename) { warnf(global, "Remote filename has no length!\n"); return FALSE; @@ -78,7 +81,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) size_t rc; struct per_transfer *per = userdata; struct OutStruct *outs = &per->outs; - struct OperationConfig *config = outs->config; + struct OperationConfig *config = per->config; size_t bytes = sz * nmemb; bool is_tty = config->global->isatty; #ifdef WIN32 @@ -147,7 +150,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) } #endif - if(!outs->stream && !tool_create_output_file(outs)) + if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { diff --git a/release/src/router/curl/src/tool_cb_wrt.h b/release/src/router/curl/src/tool_cb_wrt.h index 188d3ea7da0..e49d8f35d5e 100644 --- a/release/src/router/curl/src/tool_cb_wrt.h +++ b/release/src/router/curl/src/tool_cb_wrt.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); /* create a local file for writing, return TRUE on success */ -bool tool_create_output_file(struct OutStruct *outs); +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config); #endif /* HEADER_CURL_TOOL_CB_WRT_H */ diff --git a/release/src/router/curl/src/tool_cfgable.h b/release/src/router/curl/src/tool_cfgable.h index 32e811eaa07..e093b2c842e 100644 --- a/release/src/router/curl/src/tool_cfgable.h +++ b/release/src/router/curl/src/tool_cfgable.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -108,6 +108,7 @@ struct OperationConfig { char *mail_from; struct curl_slist *mail_rcpt; char *mail_auth; + bool mail_rcpt_allowfails; /* --mail-rcpt-allowfails */ char *sasl_authzid; /* Authorisation identity (identity to use) */ bool sasl_ir; /* Enable/disable SASL initial response */ bool proxytunnel; diff --git a/release/src/router/curl/src/tool_dirhie.c b/release/src/router/curl/src/tool_dirhie.c index 06b3c03e88f..320fb368842 100644 --- a/release/src/router/curl/src/tool_dirhie.c +++ b/release/src/router/curl/src/tool_dirhie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -125,6 +125,7 @@ CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) tempdir = strtok(outdup, PATH_DELIMITERS); while(tempdir != NULL) { + bool skip = false; tempdir2 = strtok(NULL, PATH_DELIMITERS); /* since strtok returns a token for the last word even if not ending with DIR_CHAR, we need to prune it */ @@ -133,13 +134,27 @@ CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) if(dlen) msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir); else { - if(outdup == tempdir) + if(outdup == tempdir) { +#if defined(MSDOS) || defined(WIN32) + /* Skip creating a drive's current directory. + It may seem as though that would harmlessly fail but it could be + a corner case if X: did not exist, since we would be creating it + erroneously. + eg if outfile is X:\foo\bar\filename then don't mkdir X: + This logic takes into account unsupported drives !:, 1:, etc. */ + char *p = strchr(tempdir, ':'); + if(p && !p[1]) + skip = true; +#endif /* the output string doesn't start with a separator */ strcpy(dirbuildup, tempdir); + } else msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir); } - if((-1 == mkdir(dirbuildup, (mode_t)0000750)) && (errno != EEXIST)) { + /* Create directory. Ignore access denied error to allow traversal. */ + if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) && + (errno != EACCES) && (errno != EEXIST)) { show_dir_errno(errors, dirbuildup); result = CURLE_WRITE_ERROR; break; /* get out of loop */ diff --git a/release/src/router/curl/src/tool_doswin.c b/release/src/router/curl/src/tool_doswin.c index a64a81633fe..221e3864bf4 100644 --- a/release/src/router/curl/src/tool_doswin.c +++ b/release/src/router/curl/src/tool_doswin.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -697,6 +697,32 @@ struct curl_slist *GetLoadedModulePaths(void) return slist; } +LARGE_INTEGER Curl_freq; +bool Curl_isVistaOrGreater; + +CURLcode win32_init(void) +{ + OSVERSIONINFOEXA osvi; + unsigned __int64 mask = 0; + unsigned char op = VER_GREATER_EQUAL; + + memset(&osvi, 0, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = 6; + VER_SET_CONDITION(mask, VER_MAJORVERSION, op); + VER_SET_CONDITION(mask, VER_MINORVERSION, op); + + if(VerifyVersionInfoA(&osvi, (VER_MAJORVERSION | VER_MINORVERSION), mask)) + Curl_isVistaOrGreater = true; + else if(GetLastError() == ERROR_OLD_WIN_VERSION) + Curl_isVistaOrGreater = false; + else + return CURLE_FAILED_INIT; + + QueryPerformanceFrequency(&Curl_freq); + return CURLE_OK; +} + #endif /* WIN32 */ #endif /* MSDOS || WIN32 */ diff --git a/release/src/router/curl/src/tool_doswin.h b/release/src/router/curl/src/tool_doswin.h index 457637665d6..d1649d1f3fc 100644 --- a/release/src/router/curl/src/tool_doswin.h +++ b/release/src/router/curl/src/tool_doswin.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -61,6 +61,7 @@ CURLcode FindWin32CACert(struct OperationConfig *config, curl_sslbackend backend, const char *bundle_file); struct curl_slist *GetLoadedModulePaths(void); +CURLcode win32_init(void); #endif /* WIN32 */ diff --git a/release/src/router/curl/src/tool_getparam.c b/release/src/router/curl/src/tool_getparam.c index 8df6e5e24b6..764caa203ac 100644 --- a/release/src/router/curl/src/tool_getparam.c +++ b/release/src/router/curl/src/tool_getparam.c @@ -273,6 +273,7 @@ static const struct LongShort aliases[]= { {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, + {"fc", "mail-rcpt-allowfails", ARG_BOOL}, {"F", "form", ARG_STRING}, {"Fs", "form-string", ARG_STRING}, {"g", "globoff", ARG_BOOL}, @@ -421,7 +422,7 @@ void parse_cert_parameter(const char *cert_parameter, /* escaped colons and Windows drive letter colons were handled * above; if we're still here, this is a separating colon */ param_place++; - if(strlen(param_place) > 0) { + if(*param_place) { *passphrase = strdup(param_place); } goto done; @@ -1277,7 +1278,10 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ case 'b': switch(subletter) { case 'a': /* --alt-svc */ - GetStr(&config->altsvc, nextarg); + if(curlinfo->features & CURL_VERSION_ALTSVC) + GetStr(&config->altsvc, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; break; default: /* --cookie string coming up: */ if(nextarg[0] == '@') { @@ -1722,6 +1726,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ case 'b': /* --styled-output */ global->styled_output = toggle; break; + case 'c': /* --mail-rcpt-allowfails */ + config->mail_rcpt_allowfails = toggle; + break; default: /* --fail (hard on errors) */ config->failonerror = toggle; } diff --git a/release/src/router/curl/src/tool_help.c b/release/src/router/curl/src/tool_help.c index 8d3f3454766..9ee99d17493 100644 --- a/release/src/router/curl/src/tool_help.c +++ b/release/src/router/curl/src/tool_help.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -239,6 +239,8 @@ static const struct helptxt helptext[] = { "Mail from this address"}, {" --mail-rcpt
", "Mail to this address"}, + {" --mail-rcpt-allowfails", + "Allow RCPT TO command to fail for some recipients"}, {"-M, --manual", "Display the full manual"}, {" --max-filesize ", diff --git a/release/src/router/curl/src/tool_homedir.c b/release/src/router/curl/src/tool_homedir.c index 6bc69551e5e..719ff6a55f4 100644 --- a/release/src/router/curl/src/tool_homedir.c +++ b/release/src/router/curl/src/tool_homedir.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,38 +25,23 @@ # include #endif +#include + #include "tool_homedir.h" #include "memdebug.h" /* keep this as LAST include */ -static char *GetEnv(const char *variable, char do_expand) +static char *GetEnv(const char *variable) { - char *env = NULL; -#ifdef WIN32 - char buf1[1024], buf2[1024]; - DWORD rc; + char *dupe, *env; - /* Don't use getenv(); it doesn't find variable added after program was - * started. Don't accept truncated results (i.e. rc >= sizeof(buf1)). */ + env = curl_getenv(variable); + if(!env) + return NULL; - rc = GetEnvironmentVariableA(variable, buf1, sizeof(buf1)); - if(rc > 0 && rc < sizeof(buf1)) { - env = buf1; - variable = buf1; - } - if(do_expand && strchr(variable, '%')) { - /* buf2 == variable if not expanded */ - rc = ExpandEnvironmentStringsA(variable, buf2, sizeof(buf2)); - if(rc > 0 && rc < sizeof(buf2) && - !strchr(buf2, '%')) /* no vars still unexpanded */ - env = buf2; - } -#else - (void)do_expand; - /* no length control */ - env = getenv(variable); -#endif - return (env && env[0]) ? strdup(env) : NULL; + dupe = strdup(env); + curl_free(env); + return dupe; } /* return the home directory of the current user as an allocated string */ @@ -64,11 +49,11 @@ char *homedir(void) { char *home; - home = GetEnv("CURL_HOME", FALSE); + home = GetEnv("CURL_HOME"); if(home) return home; - home = GetEnv("HOME", FALSE); + home = GetEnv("HOME"); if(home) return home; @@ -86,10 +71,18 @@ char *homedir(void) } #endif /* PWD-stuff */ #ifdef WIN32 - home = GetEnv("APPDATA", TRUE); - if(!home) - home = GetEnv("%USERPROFILE%\\Application Data", TRUE); /* Normally only - on Win-2K/XP */ + home = GetEnv("APPDATA"); + if(!home) { + char *env = GetEnv("USERPROFILE"); + if(env) { + char *path = curl_maprintf("%s\\Application Data", env); + if(path) { + home = strdup(path); + curl_free(path); + } + free(env); + } + } #endif /* WIN32 */ return home; } diff --git a/release/src/router/curl/src/tool_main.c b/release/src/router/curl/src/tool_main.c index 06923c332dc..25042895f88 100644 --- a/release/src/router/curl/src/tool_main.c +++ b/release/src/router/curl/src/tool_main.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -279,6 +279,24 @@ int main(int argc, char *argv[]) struct GlobalConfig global; memset(&global, 0, sizeof(global)); +#ifdef WIN32 + /* Undocumented diagnostic option to list the full paths of all loaded + modules. This is purposely pre-init. */ + if(argc == 2 && !strcmp(argv[1], "--dump-module-paths")) { + struct curl_slist *item, *head = GetLoadedModulePaths(); + for(item = head; item; item = item->next) + printf("%s\n", item->data); + curl_slist_free_all(head); + return head ? 0 : 1; + } + /* win32_init must be called before other init routines. */ + result = win32_init(); + if(result) { + fprintf(stderr, "curl: (%d) Windows-specific init failed.\n", result); + return result; + } +#endif + /* Perform any platform-specific terminal configuration */ configure_terminal(); @@ -294,21 +312,6 @@ int main(int argc, char *argv[]) /* Initialize the curl library - do not call any libcurl functions before this point */ result = main_init(&global); - -#ifdef WIN32 - /* Undocumented diagnostic option to list the full paths of all loaded - modules, regardless of whether or not initialization succeeded. */ - if(argc == 2 && !strcmp(argv[1], "--dump-module-paths")) { - struct curl_slist *item, *head = GetLoadedModulePaths(); - for(item = head; item; item = item->next) { - printf("%s\n", item->data); - } - curl_slist_free_all(head); - if(!result) - main_free(&global); - } - else -#endif /* WIN32 */ if(!result) { /* Start our curl operation */ result = operate(&global, argc, argv); diff --git a/release/src/router/curl/src/tool_metalink.c b/release/src/router/curl/src/tool_metalink.c index 6d62f2d9380..f87f686f122 100644 --- a/release/src/router/curl/src/tool_metalink.c +++ b/release/src/router/curl/src/tool_metalink.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -54,13 +54,6 @@ # define SHA256_CTX void * # define HAVE_NSS_CONTEXT static NSSInitContext *nss_context; -#elif defined(USE_POLARSSL) -# include -# include -# include -# define MD5_CTX md5_context -# define SHA_CTX sha1_context -# define SHA256_CTX sha256_context #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ @@ -73,7 +66,7 @@ and later. If you're building for an older cat, well, sorry. */ # define COMMON_DIGEST_FOR_OPENSSL # include -#elif defined(WIN32) +#elif defined(USE_WIN32_CRYPTO) /* For Windows: If no other crypto library is provided, we fallback to the hash functions provided within the Microsoft Windows CryptoAPI */ # include @@ -325,63 +318,7 @@ static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx) nss_hash_final(pctx, digest, 32); } -#elif defined(USE_POLARSSL) - -static int MD5_Init(MD5_CTX *ctx) -{ - md5_starts(ctx); - return 1; -} - -static void MD5_Update(MD5_CTX *ctx, - const unsigned char *input, - unsigned int inputLen) -{ - md5_update(ctx, input, inputLen); -} - -static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) -{ - md5_finish(ctx, digest); -} - -static int SHA1_Init(SHA_CTX *ctx) -{ - sha1_starts(ctx); - return 1; -} - -static void SHA1_Update(SHA_CTX *ctx, - const unsigned char *input, - unsigned int inputLen) -{ - sha1_update(ctx, input, inputLen); -} - -static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) -{ - sha1_finish(ctx, digest); -} - -static int SHA256_Init(SHA256_CTX *ctx) -{ - sha256_starts(ctx, 0); /* 0 = sha256 */ - return 1; -} - -static void SHA256_Update(SHA256_CTX *ctx, - const unsigned char *input, - unsigned int inputLen) -{ - sha256_update(ctx, input, inputLen); -} - -static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) -{ - sha256_finish(ctx, digest); -} - -#elif defined(WIN32) +#elif defined(USE_WIN32_CRYPTO) static void win32_crypto_final(struct win32_crypto_hash *ctx, unsigned char *digest, @@ -895,7 +832,7 @@ size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, { struct per_transfer *per = userdata; struct OutStruct *outs = &per->outs; - struct OperationConfig *config = outs->config; + struct OperationConfig *config = per->config; int rv; /* diff --git a/release/src/router/curl/src/tool_operate.c b/release/src/router/curl/src/tool_operate.c index 2bee9349a62..4b3caa80c99 100644 --- a/release/src/router/curl/src/tool_operate.c +++ b/release/src/router/curl/src/tool_operate.c @@ -380,7 +380,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, /* do not create (or even overwrite) the file in case we get no data because of unmet condition */ curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); - if(!cond_unmet && !tool_create_output_file(outs)) + if(!cond_unmet && !tool_create_output_file(outs, config)) result = CURLE_WRITE_ERROR; } @@ -866,13 +866,13 @@ static CURLcode single_transfer(struct GlobalConfig *global, /* default headers output stream is stdout */ heads = &per->heads; heads->stream = stdout; - heads->config = config; /* Single header file for all URLs */ if(config->headerfile) { /* open file for output: */ if(strcmp(config->headerfile, "-")) { - FILE *newfile = fopen(config->headerfile, "wb"); + FILE *newfile; + newfile = fopen(config->headerfile, per->prev == NULL?"wb":"ab"); if(!newfile) { warnf(config->global, "Failed to open %s\n", config->headerfile); result = CURLE_WRITE_ERROR; @@ -891,10 +891,22 @@ static CURLcode single_transfer(struct GlobalConfig *global, } } + hdrcbdata = &per->hdrcbdata; + + outs = &per->outs; + input = &per->input; + + per->outfile = NULL; + per->infdopen = FALSE; + per->infd = STDIN_FILENO; + + /* default output stream is stdout */ + outs->stream = stdout; + /* --etag-save */ etag_save = &per->etag_save; etag_save->stream = stdout; - etag_save->config = config; + if(config->etag_save_file) { /* open file for output: */ if(strcmp(config->etag_save_file, "-")) { @@ -961,19 +973,6 @@ static CURLcode single_transfer(struct GlobalConfig *global, } } - hdrcbdata = &per->hdrcbdata; - - outs = &per->outs; - input = &per->input; - - per->outfile = NULL; - per->infdopen = FALSE; - per->infd = STDIN_FILENO; - - /* default output stream is stdout */ - outs->stream = stdout; - outs->config = config; - if(metalink) { /* For Metalink download, use name in Metalink file as filename. */ @@ -1836,6 +1835,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->mail_rcpt) my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); + /* curl 7.69.x */ + my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS, + config->mail_rcpt_allowfails ? 1L : 0L); + /* curl 7.20.x */ if(config->ftp_pret) my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L); @@ -1963,11 +1966,8 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->disallow_username_in_url) my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); -#ifdef USE_ALTSVC - /* only if explicitly enabled in configure */ if(config->altsvc) my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc); -#endif #ifdef USE_METALINK if(!metalink && config->use_metalink) { diff --git a/release/src/router/curl/src/tool_operhlp.c b/release/src/router/curl/src/tool_operhlp.c index 8a9b7c9e8fd..05c9d864a49 100644 --- a/release/src/router/curl/src/tool_operhlp.c +++ b/release/src/router/curl/src/tool_operhlp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -85,7 +85,7 @@ char *add_file_name_to_url(char *url, const char *filename) else ptr = url; ptr = strrchr(ptr, '/'); - if(!ptr || !strlen(++ptr)) { + if(!ptr || !*++ptr) { /* The URL has no file name part, add the local file name. In order to be able to do so, we have to create a new URL in another buffer.*/ diff --git a/release/src/router/curl/src/tool_progress.c b/release/src/router/curl/src/tool_progress.c index ac4f58f4154..31cd56ae495 100644 --- a/release/src/router/curl/src/tool_progress.c +++ b/release/src/router/curl/src/tool_progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -95,8 +95,7 @@ int xferinfo_cb(void *clientp, curl_off_t ulnow) { struct per_transfer *per = clientp; - struct OutStruct *outs = &per->outs; - struct OperationConfig *config = outs->config; + struct OperationConfig *config = per->config; per->dltotal = dltotal; per->dlnow = dlnow; per->ultotal = ultotal; diff --git a/release/src/router/curl/src/tool_sdecls.h b/release/src/router/curl/src/tool_sdecls.h index 562fef852f1..ccc9f5aba5b 100644 --- a/release/src/router/curl/src/tool_sdecls.h +++ b/release/src/router/curl/src/tool_sdecls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,7 +69,6 @@ struct OutStruct { bool s_isreg; bool fopened; FILE *stream; - struct OperationConfig *config; curl_off_t bytes; curl_off_t init; #ifdef USE_METALINK diff --git a/release/src/router/curl/src/tool_urlglob.c b/release/src/router/curl/src/tool_urlglob.c index 450cdcf3297..6c87161048f 100644 --- a/release/src/router/curl/src/tool_urlglob.c +++ b/release/src/router/curl/src/tool_urlglob.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -627,7 +627,7 @@ CURLcode glob_match_url(char **result, char *filename, URLGlob *glob) unsigned long num = strtoul(&filename[1], &filename, 10); URLPattern *pat = NULL; - if(num < glob->size) { + if(num && (num < glob->size)) { unsigned long i; num--; /* make it zero based */ /* find the correct glob entry */ diff --git a/release/src/router/curl/src/tool_util.c b/release/src/router/curl/src/tool_util.c index 04d73e4e38f..8bbfae03e58 100644 --- a/release/src/router/curl/src/tool_util.c +++ b/release/src/router/curl/src/tool_util.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,27 +27,35 @@ #if defined(WIN32) && !defined(MSDOS) +/* set in win32_init() */ +extern LARGE_INTEGER Curl_freq; +extern bool Curl_isVistaOrGreater; + +/* In case of bug fix this function has a counterpart in timeval.c */ struct timeval tvnow(void) { - /* - ** GetTickCount() is available on _all_ Windows versions from W95 up - ** to nowadays. Returns milliseconds elapsed since last system boot, - ** increases monotonically and wraps once 49.7 days have elapsed. - ** - ** GetTickCount64() is available on Windows version from Windows Vista - ** and Windows Server 2008 up to nowadays. The resolution of the - ** function is limited to the resolution of the system timer, which - ** is typically in the range of 10 milliseconds to 16 milliseconds. - */ struct timeval now; -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && \ - (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)) - ULONGLONG milliseconds = GetTickCount64(); -#else - DWORD milliseconds = GetTickCount(); + if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + now.tv_sec = (long)(count.QuadPart / Curl_freq.QuadPart); + now.tv_usec = (long)((count.QuadPart % Curl_freq.QuadPart) * 1000000 / + Curl_freq.QuadPart); + } + else { + /* Disable /analyze warning that GetTickCount64 is preferred */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:28159) +#endif + DWORD milliseconds = GetTickCount(); +#if defined(_MSC_VER) +#pragma warning(pop) #endif - now.tv_sec = (long)(milliseconds / 1000); - now.tv_usec = (long)((milliseconds % 1000) * 1000); + + now.tv_sec = (long)(milliseconds / 1000); + now.tv_usec = (long)((milliseconds % 1000) * 1000); + } return now; } diff --git a/release/src/router/curl/src/tool_version.h b/release/src/router/curl/src/tool_version.h index d6553b3a312..cf7a94e81ce 100644 --- a/release/src/router/curl/src/tool_version.h +++ b/release/src/router/curl/src/tool_version.h @@ -25,7 +25,7 @@ #define CURL_NAME "curl" #define CURL_COPYRIGHT LIBCURL_COPYRIGHT -#define CURL_VERSION "7.68.0" +#define CURL_VERSION "7.69.1" #define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR #define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR #define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH diff --git a/release/src/router/curl/tests/FILEFORMAT b/release/src/router/curl/tests/FILEFORMAT index 8a9eb3579eb..16e7d30925a 100644 --- a/release/src/router/curl/tests/FILEFORMAT +++ b/release/src/router/curl/tests/FILEFORMAT @@ -156,18 +156,17 @@ auth_required if this is set and a POST/PUT is made without auth, the idle do nothing after receiving the request, just "sit idle" stream continuously send data to the client, never-ending writedelay: [secs] delay this amount between reply packets -skip: [num] instructs the server to ignore reading this many bytes from a PUT - or POST request - +skip: [num] instructs the server to ignore reading this many bytes from a + PUT or POST request rtp: part [num] channel [num] size [num] stream a fake RTP packet for the given part on a chosen channel with the given payload size - connection-monitor When used, this will log [DISCONNECT] to the server.input log when the connection is disconnected. upgrade when an HTTP upgrade header is found, the server will upgrade to http2 swsclose instruct server to close connection after response +no-expect don't read the request body if Expect: is present For TFTP: writedelay: [secs] delay this amount between reply packets (each packet being @@ -217,6 +216,7 @@ SKIPPED. Features testable here are: +alt-svc crypto debug getrlimit @@ -227,6 +227,7 @@ idn ipv6 Kerberos large_file +ld_preload libz manual Metalink @@ -239,14 +240,13 @@ SPNEGO SSL SSLpinning SSPI +threaded-resolver TLS-SRP TrackMemory -threaded-resolver unittest unix-sockets +win32 WinSSL -ld_preload -alt-svc as well as each protocol that curl supports. A protocol only needs to be specified if it is different from the server (useful when the server @@ -366,6 +366,7 @@ Available substitute variables include: %FILE_PWD - Current directory, on windows prefixed with a slash %RTSP6PORT - IPv6 port number of the RTSP server %RTSPPORT - Port number of the RTSP server +%SSHSRVMD5 - MD5 of SSH server's public key %SMTP6PORT - IPv6 port number of the SMTP server %SMTPPORT - Port number of the SMTP server %SOCKSPORT - Port number of the SOCKS4/5 server diff --git a/release/src/router/curl/tests/Makefile.am b/release/src/router/curl/tests/Makefile.am index b4cb9012e59..95ee872b559 100644 --- a/release/src/router/curl/tests/Makefile.am +++ b/release/src/router/curl/tests/Makefile.am @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -38,7 +38,8 @@ EXTRA_DIST = ftpserver.pl httpserver.pl secureserver.pl runtests.pl \ CMakeLists.txt mem-include-scan.pl valgrind.supp extern-scan.pl \ manpage-scan.pl nroff-scan.pl http2-server.pl dictserver.py \ negtelnetserver.py $(SMBDEPS) objnames-test08.sh objnames-test10.sh \ - objnames.inc disable-scan.pl manpage-syntax.pl error-codes.pl + objnames.inc disable-scan.pl manpage-syntax.pl error-codes.pl badsymbols.pl \ + azure.pm appveyor.pm DISTCLEANFILES = configurehelp.pm diff --git a/release/src/router/curl/tests/Makefile.in b/release/src/router/curl/tests/Makefile.in index 19d1a506efc..f165589b313 100644 --- a/release/src/router/curl/tests/Makefile.in +++ b/release/src/router/curl/tests/Makefile.in @@ -21,7 +21,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -361,6 +361,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -439,7 +440,8 @@ EXTRA_DIST = ftpserver.pl httpserver.pl secureserver.pl runtests.pl \ CMakeLists.txt mem-include-scan.pl valgrind.supp extern-scan.pl \ manpage-scan.pl nroff-scan.pl http2-server.pl dictserver.py \ negtelnetserver.py $(SMBDEPS) objnames-test08.sh objnames-test10.sh \ - objnames.inc disable-scan.pl manpage-syntax.pl error-codes.pl + objnames.inc disable-scan.pl manpage-syntax.pl error-codes.pl badsymbols.pl \ + azure.pm appveyor.pm DISTCLEANFILES = configurehelp.pm @BUILD_UNITTESTS_FALSE@BUILD_UNIT = diff --git a/release/src/router/curl/tests/appveyor.pm b/release/src/router/curl/tests/appveyor.pm new file mode 100644 index 00000000000..4906d2c8c23 --- /dev/null +++ b/release/src/router/curl/tests/appveyor.pm @@ -0,0 +1,114 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2020, Daniel Stenberg, , et al. +# Copyright (C) 2020, Marc Hoersken, +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +use strict; +use warnings; + +my %APPVEYOR_TEST_NAMES; + +sub appveyor_check_environment { + if(defined $ENV{'APPVEYOR_API_URL'} && $ENV{'APPVEYOR_API_URL'}) { + return 1; + } + return 0; +} + +sub appveyor_create_test_result { + my ($testnum, $testname)=@_; + $testname =~ s/\\/\\\\/g; + $testname =~ s/\'/\\\'/g; + $testname =~ s/\"/\\\"/g; + my $appveyor_baseurl="$ENV{'APPVEYOR_API_URL'}"; + my $appveyor_result=`curl --silent --noproxy "*" \\ + --header "Content-Type: application/json" \\ + --data " + { + 'testName': '$testname', + 'testFramework': 'runtests.pl', + 'fileName': 'tests/data/test$testnum', + 'outcome': 'Running' + } + " \\ + "$appveyor_baseurl/api/tests"`; + print $appveyor_result; + $APPVEYOR_TEST_NAMES{$testnum}=$testname; +} + +sub appveyor_update_test_result { + my ($testnum, $error, $start, $stop)=@_; + my $testname=$APPVEYOR_TEST_NAMES{$testnum}; + if(!defined $testname) { + return; + } + if(!defined $stop) { + $stop = $start; + } + my $appveyor_duration = sprintf("%.0f", ($stop-$start)*1000); + my $appveyor_outcome; + my $appveyor_category; + if($error == 2) { + $appveyor_outcome = 'Ignored'; + $appveyor_category = 'Warning'; + } + elsif($error < 0) { + $appveyor_outcome = 'NotRunnable'; + $appveyor_category = 'Warning'; + } + elsif(!$error) { + $appveyor_outcome = 'Passed'; + $appveyor_category = 'Information'; + } + else { + $appveyor_outcome = 'Failed'; + $appveyor_category = 'Error'; + } + my $appveyor_baseurl="$ENV{'APPVEYOR_API_URL'}"; + my $appveyor_result=`curl --silent --noproxy "*" --request PUT \\ + --header "Content-Type: application/json" \\ + --data " + { + 'testName': '$testname', + 'testFramework': 'runtests.pl', + 'fileName': 'tests/data/test$testnum', + 'outcome': '$appveyor_outcome', + 'durationMilliseconds': $appveyor_duration + } + " \\ + "$appveyor_baseurl/api/tests"`; + print $appveyor_result; + if($appveyor_category eq 'Error') { + $appveyor_result=`curl --silent --noproxy "*" \\ + --header "Content-Type: application/json" \\ + --data " + { + 'message': '$testname $appveyor_outcome', + 'category': '$appveyor_category', + 'details': 'Test $testnum $appveyor_outcome' + } + " \\ + "$appveyor_baseurl/api/build/messages"`; + print $appveyor_result; + } +} + +1; diff --git a/release/src/router/curl/tests/azure.pm b/release/src/router/curl/tests/azure.pm new file mode 100644 index 00000000000..9dcb56c7860 --- /dev/null +++ b/release/src/router/curl/tests/azure.pm @@ -0,0 +1,146 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2020, Daniel Stenberg, , et al. +# Copyright (C) 2020, Marc Hoersken, +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +use strict; +use warnings; + +use POSIX qw(strftime); + +sub azure_check_environment { + if(defined $ENV{'AZURE_ACCESS_TOKEN'} && $ENV{'AZURE_ACCESS_TOKEN'} && + defined $ENV{'AGENT_JOBNAME'} && $ENV{'BUILD_BUILDID'} && + defined $ENV{'SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'} && + defined $ENV{'SYSTEM_TEAMPROJECTID'}) { + return 1; + } + return 0; +} + +sub azure_create_test_run { + my $azure_baseurl="$ENV{'SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'}$ENV{'SYSTEM_TEAMPROJECTID'}"; + my $azure_run=`curl --silent --noproxy "*" \\ + --header "Authorization: Bearer $ENV{'AZURE_ACCESS_TOKEN'}" \\ + --header "Content-Type: application/json" \\ + --data " + { + 'name': '$ENV{'AGENT_JOBNAME'}', + 'automated': true, + 'build': {'id': '$ENV{'BUILD_BUILDID'}'} + } + " \\ + "$azure_baseurl/_apis/test/runs?api-version=5.0"`; + if($azure_run =~ /"id":(\d+)/) { + return $1; + } + return ""; +} + +sub azure_create_test_result { + my ($azure_run_id, $testnum, $testname)=@_; + $testname =~ s/\\/\\\\/g; + $testname =~ s/\'/\\\'/g; + $testname =~ s/\"/\\\"/g; + my $azure_baseurl="$ENV{'SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'}$ENV{'SYSTEM_TEAMPROJECTID'}"; + my $azure_result=`curl --silent --noproxy "*" \\ + --header "Authorization: Bearer $ENV{'AZURE_ACCESS_TOKEN'}" \\ + --header "Content-Type: application/json" \\ + --data " + [ + { + 'build': {'id': '$ENV{'BUILD_BUILDID'}'}, + 'testCase': {'id': $testnum}, + 'testCaseTitle': '$testname', + 'automatedTestName': 'curl.tests.$testnum', + 'outcome': 'InProgress' + } + ] + " \\ + "$azure_baseurl/_apis/test/runs/$azure_run_id/results?api-version=5.0"`; + if($azure_result =~ /\[\{"id":(\d+)/) { + return $1; + } + return ""; +} + +sub azure_update_test_result { + my ($azure_run_id, $azure_result_id, $testnum, $error, $start, $stop)=@_; + if(!defined $stop) { + $stop = $start; + } + my $azure_start = strftime "%Y-%m-%dT%H:%M:%SZ", gmtime $start; + my $azure_complete = strftime "%Y-%m-%dT%H:%M:%SZ", gmtime $stop; + my $azure_duration = sprintf("%.0f", ($stop-$start)*1000); + my $azure_outcome; + if($error == 2) { + $azure_outcome = 'Not applicable'; + } + elsif($error < 0) { + $azure_outcome = 'Not executed'; + } + elsif(!$error) { + $azure_outcome = 'Passed'; + } + else { + $azure_outcome = 'Failed'; + } + my $azure_baseurl="$ENV{'SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'}$ENV{'SYSTEM_TEAMPROJECTID'}"; + my $azure_result=`curl --silent --noproxy "*" --request PATCH \\ + --header "Authorization: Bearer $ENV{'AZURE_ACCESS_TOKEN'}" \\ + --header "Content-Type: application/json" \\ + --data " + [ + { + 'id': $azure_result_id, + 'outcome': '$azure_outcome', + 'startedDate': '$azure_start', + 'completedDate': '$azure_complete', + 'durationInMs': $azure_duration + } + ] + " \\ + "$azure_baseurl/_apis/test/runs/$azure_run_id/results?api-version=5.0"`; + if($azure_result =~ /\[\{"id":(\d+)/) { + return $1; + } + return ""; +} + +sub azure_update_test_run { + my ($azure_run_id)=@_; + my $azure_baseurl="$ENV{'SYSTEM_TEAMFOUNDATIONCOLLECTIONURI'}$ENV{'SYSTEM_TEAMPROJECTID'}"; + my $azure_run=`curl --silent --noproxy "*" --request PATCH \\ + --header "Authorization: Bearer $ENV{'AZURE_ACCESS_TOKEN'}" \\ + --header "Content-Type: application/json" \\ + --data " + { + 'state': 'Completed' + } + " \\ + "$azure_baseurl/_apis/test/runs/$azure_run_id?api-version=5.0"`; + if($azure_run =~ /"id":(\d+)/) { + return $1; + } + return ""; +} + +1; diff --git a/release/src/router/curl/tests/badsymbols.pl b/release/src/router/curl/tests/badsymbols.pl new file mode 100644 index 00000000000..05d325c3de7 --- /dev/null +++ b/release/src/router/curl/tests/badsymbols.pl @@ -0,0 +1,132 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2010-2020, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +# +# This script grew out of help from Przemyslaw Iskra and Balint Szilakszi +# a late evening in the #curl IRC channel on freenode. +# + +use strict; +use warnings; +use vars qw($Cpreprocessor); + +# +# configurehelp perl module is generated by configure script +# +my $rc = eval { + require configurehelp; + configurehelp->import(qw( + $Cpreprocessor + )); + 1; +}; +# Set default values if configure has not generated a configurehelp.pm file. +# This is the case with cmake. +if (!$rc) { + $Cpreprocessor = 'cpp'; +} + +# we may get the dir root pointed out +my $root=$ARGV[0] || "."; + +# need an include directory when building out-of-tree +my $i = ($ARGV[1]) ? "-I$ARGV[1] " : ''; + +my $incdir = "$root/include/curl"; + +my $verbose=0; +my $summary=0; +my $misses=0; + +my @syms; +my %doc; +my %rem; + +sub scanenums { + my ($file)=@_; + my $skipit = 0; + + open H_IN, "-|", "$Cpreprocessor $i$file" || die "Cannot preprocess $file"; + while ( ) { + if( /^#(line|) (\d+) \"(.*)\"/) { + # if the included file isn't in our incdir, then we skip this section + # until next #line + # + if($3 !~ /^$incdir/) { + $skipit = 1; + next; + } + # parse this! + $skipit = 0, + } + if($skipit) { + next; + } + if ( /enum\s+(\S+\s+)?{/ .. /}/ ) { + s/^\s+//; + chomp; + s/[,\s].*//; + if(($_ !~ /\}(;|)/) && + ($_ ne "typedef") && + ($_ ne "enum") && + ($_ !~ /^[ \t]*$/) && + ($_ ne "#")) { + push @syms, $_; + } + } + } + close H_IN || die "Error preprocessing $file"; +} + +sub scanheader { + my ($f)=@_; + scanenums($f); + open H, "<$f"; + while() { + if (/^#define +([^ \n]*)/) { + push @syms, $1; + } + } + close H; +} + + +opendir(my $dh, $incdir) || die "Can't opendir: $!"; +my @hfiles = grep { /\.h$/ } readdir($dh); +closedir $dh; + +for(@hfiles) { + scanheader("$incdir/$_"); +} + +my $errors = 0; +for my $s (@syms) { + if($s !~ /^(lib|)curl/i) { + print "Bad symbols in public header files:\n" if(!$errors); + $errors++; + print " $s\n"; + } +} +if($errors) { + exit 1; +} +printf "%d fine symbols found\n", scalar(@syms); diff --git a/release/src/router/curl/tests/certs/Makefile.in b/release/src/router/curl/tests/certs/Makefile.in index d055bd5798d..3d70868065f 100644 --- a/release/src/router/curl/tests/certs/Makefile.in +++ b/release/src/router/curl/tests/certs/Makefile.in @@ -340,6 +340,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/tests/certs/scripts/Makefile.in b/release/src/router/curl/tests/certs/scripts/Makefile.in index a230ca2eefb..b2776a750a4 100644 --- a/release/src/router/curl/tests/certs/scripts/Makefile.in +++ b/release/src/router/curl/tests/certs/scripts/Makefile.in @@ -280,6 +280,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/tests/data/Makefile.in b/release/src/router/curl/tests/data/Makefile.in index 8d72ba180a7..018fdae09e5 100644 --- a/release/src/router/curl/tests/data/Makefile.in +++ b/release/src/router/curl/tests/data/Makefile.in @@ -302,6 +302,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -402,7 +403,7 @@ test316 test317 test318 test319 test320 test321 test322 test323 test324 \ test325 test326 test327 test328 test329 test330 test331 test332 test333 \ test334 test335 test336 test337 test338 test339 test340 test341 test342 \ test343 \ -test350 test351 test352 test353 test354 test355 test356 \ +test350 test351 test352 test353 test354 test355 test356 test357 \ test393 test394 test395 \ \ test400 test401 test402 test403 test404 test405 test406 test407 test408 \ @@ -428,7 +429,8 @@ test626 test627 test628 test629 test630 test631 test632 test633 test634 \ test635 test636 test637 test638 test639 test640 test641 test642 \ test643 test644 test645 test646 test647 test648 test649 test650 test651 \ test652 test653 test654 test655 test656 test658 test659 test660 test661 \ -test662 test663 \ +test662 test663 test664 test665 test666 test667 test668 \ +test670 test671 test672 test673 \ \ test700 test701 test702 test703 test704 test705 test706 test707 test708 \ test709 test710 test711 test712 test713 test714 test715 test716 test717 \ @@ -439,12 +441,11 @@ test818 test819 test820 test821 test822 test823 test824 test825 test826 \ test827 test828 test829 test830 test831 test832 test833 test834 test835 \ test836 test837 test838 test839 test840 test841 test842 test843 test844 \ test845 test846 test847 test848 test849 \ -\ test850 test851 test852 test853 test854 test855 test856 test857 test858 \ test859 test860 test861 test862 test863 test864 test865 test866 test867 \ test868 test869 test870 test871 test872 test873 test874 test875 test876 \ test877 test878 test879 test880 test881 test882 test883 test884 test885 \ -test886 test887 test888 test889 test890 test891 test892 test893 \ +test886 test887 test888 test889 test890 test891 test892 test893 test894 \ \ test900 test901 test902 test903 test904 test905 test906 test907 test908 \ test909 test910 test911 test912 test913 test914 test915 test916 test917 \ @@ -452,7 +453,8 @@ test918 test919 test920 test921 test922 test923 test924 test925 test926 \ test927 test928 test929 test930 test931 test932 test933 test934 test935 \ test936 test937 test938 test939 test940 test941 test942 test943 test944 \ test945 test946 test947 test948 test949 test950 test951 test952 test953 \ -test954 \ +test954 test955 test956 test957 test958 test959 test960 test961 test962 \ +test963 test964 test965 test966 test967 test968 test969 \ \ test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ @@ -474,8 +476,9 @@ test1128 test1129 test1130 test1131 test1132 test1133 test1134 test1135 \ test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \ test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \ test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \ -test1160 test1161 test1162 test1163 test1164 test1165 test1166 \ -test1170 test1171 test1172 test1173 test1174 test1175 \ +test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1167 \ +\ +test1170 test1171 test1172 test1173 test1174 test1175 test1176 \ \ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \ @@ -512,7 +515,7 @@ test1424 test1425 test1426 test1427 \ test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \ test1436 test1437 test1438 test1439 test1440 test1441 test1442 test1443 \ test1444 test1445 test1446 test1447 test1448 test1449 test1450 test1451 \ -test1452 test1453 test1454 test1455 test1456 test1457 test1458\ +test1452 test1453 test1454 test1455 test1456 test1457 test1458 test1459 \ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \ @@ -526,7 +529,9 @@ test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \ test1590 test1591 test1592 test1593 test1594 test1595 test1596 \ \ test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \ -test1608 test1609 test1620 test1621 \ +test1608 test1609 test1610 test1611 test1612 \ +\ +test1620 test1621 \ \ test1650 test1651 test1652 test1653 test1654 test1655 \ \ @@ -535,6 +540,7 @@ test1700 test1701 test1702 \ test1800 test1801 \ \ test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ +test1908 \ \ test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \ @@ -550,7 +556,8 @@ test2078 \ test2080 \ test2100 \ \ -test3000 test3001 +test3000 test3001 \ +test3002 test3003 test3004 test3005 test3006 test3007 # TESTCASES are taken from Makefile.inc diff --git a/release/src/router/curl/tests/data/Makefile.inc b/release/src/router/curl/tests/data/Makefile.inc index 09cb057060c..3d8565c365d 100644 --- a/release/src/router/curl/tests/data/Makefile.inc +++ b/release/src/router/curl/tests/data/Makefile.inc @@ -59,7 +59,7 @@ test316 test317 test318 test319 test320 test321 test322 test323 test324 \ test325 test326 test327 test328 test329 test330 test331 test332 test333 \ test334 test335 test336 test337 test338 test339 test340 test341 test342 \ test343 \ -test350 test351 test352 test353 test354 test355 test356 \ +test350 test351 test352 test353 test354 test355 test356 test357 \ test393 test394 test395 \ \ test400 test401 test402 test403 test404 test405 test406 test407 test408 \ @@ -85,7 +85,8 @@ test626 test627 test628 test629 test630 test631 test632 test633 test634 \ test635 test636 test637 test638 test639 test640 test641 test642 \ test643 test644 test645 test646 test647 test648 test649 test650 test651 \ test652 test653 test654 test655 test656 test658 test659 test660 test661 \ -test662 test663 \ +test662 test663 test664 test665 test666 test667 test668 \ +test670 test671 test672 test673 \ \ test700 test701 test702 test703 test704 test705 test706 test707 test708 \ test709 test710 test711 test712 test713 test714 test715 test716 test717 \ @@ -96,12 +97,11 @@ test818 test819 test820 test821 test822 test823 test824 test825 test826 \ test827 test828 test829 test830 test831 test832 test833 test834 test835 \ test836 test837 test838 test839 test840 test841 test842 test843 test844 \ test845 test846 test847 test848 test849 \ -\ test850 test851 test852 test853 test854 test855 test856 test857 test858 \ test859 test860 test861 test862 test863 test864 test865 test866 test867 \ test868 test869 test870 test871 test872 test873 test874 test875 test876 \ test877 test878 test879 test880 test881 test882 test883 test884 test885 \ -test886 test887 test888 test889 test890 test891 test892 test893 \ +test886 test887 test888 test889 test890 test891 test892 test893 test894 \ \ test900 test901 test902 test903 test904 test905 test906 test907 test908 \ test909 test910 test911 test912 test913 test914 test915 test916 test917 \ @@ -109,7 +109,8 @@ test918 test919 test920 test921 test922 test923 test924 test925 test926 \ test927 test928 test929 test930 test931 test932 test933 test934 test935 \ test936 test937 test938 test939 test940 test941 test942 test943 test944 \ test945 test946 test947 test948 test949 test950 test951 test952 test953 \ -test954 \ +test954 test955 test956 test957 test958 test959 test960 test961 test962 \ +test963 test964 test965 test966 test967 test968 test969 \ \ test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ @@ -131,8 +132,9 @@ test1128 test1129 test1130 test1131 test1132 test1133 test1134 test1135 \ test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \ test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \ test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \ -test1160 test1161 test1162 test1163 test1164 test1165 test1166 \ -test1170 test1171 test1172 test1173 test1174 test1175 \ +test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1167 \ +\ +test1170 test1171 test1172 test1173 test1174 test1175 test1176 \ \ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \ @@ -169,7 +171,7 @@ test1424 test1425 test1426 test1427 \ test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \ test1436 test1437 test1438 test1439 test1440 test1441 test1442 test1443 \ test1444 test1445 test1446 test1447 test1448 test1449 test1450 test1451 \ -test1452 test1453 test1454 test1455 test1456 test1457 test1458\ +test1452 test1453 test1454 test1455 test1456 test1457 test1458 test1459 \ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \ @@ -183,7 +185,9 @@ test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \ test1590 test1591 test1592 test1593 test1594 test1595 test1596 \ \ test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \ -test1608 test1609 test1620 test1621 \ +test1608 test1609 test1610 test1611 test1612 \ +\ +test1620 test1621 \ \ test1650 test1651 test1652 test1653 test1654 test1655 \ \ @@ -192,6 +196,7 @@ test1700 test1701 test1702 \ test1800 test1801 \ \ test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ +test1908 \ \ test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \ @@ -207,4 +212,5 @@ test2078 \ test2080 \ test2100 \ \ -test3000 test3001 +test3000 test3001 \ +test3002 test3003 test3004 test3005 test3006 test3007 diff --git a/release/src/router/curl/tests/data/test1070 b/release/src/router/curl/tests/data/test1070 index d202a9c074e..81b473de450 100644 --- a/release/src/router/curl/tests/data/test1070 +++ b/release/src/router/curl/tests/data/test1070 @@ -32,7 +32,7 @@ http HTTP POST with server closing connection before (all) data is received - -d @log/input1070 http://%HOSTIP:%HTTPPORT/1070 + -d @log/input1070 http://%HOSTIP:%HTTPPORT/1070 -H "Expect: 100-continue" This creates the named file with this content before the test case is run, @@ -55,9 +55,9 @@ OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO POST /1070 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* +Expect: 100-continue Content-Length: 2313 Content-Type: application/x-www-form-urlencoded -Expect: 100-continue This creates diff --git a/release/src/router/curl/tests/data/test1129 b/release/src/router/curl/tests/data/test1129 index f47141cd315..cc52367336c 100644 --- a/release/src/router/curl/tests/data/test1129 +++ b/release/src/router/curl/tests/data/test1129 @@ -33,16 +33,16 @@ Content-Type: text/html # we use skip to make the test server never read the full payload off # the socket and instead return the response at once -skip: 1025 +skip: 1053700 # # Client-side -# 1025 x 'x' +# 1053700 x 'x' -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX http @@ -81,14 +81,14 @@ Content-Type: text/html POST /1129 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Content-Length: 1025 +Content-Length: 1053700 Content-Type: application/x-www-form-urlencoded Expect: 100-continue POST /11290001 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Content-Length: 1025 +Content-Length: 1053700 Content-Type: application/x-www-form-urlencoded Expect: 100-continue diff --git a/release/src/router/curl/tests/data/test1133 b/release/src/router/curl/tests/data/test1133 index 737f9d9e2cb..738e806143d 100644 --- a/release/src/router/curl/tests/data/test1133 +++ b/release/src/router/curl/tests/data/test1133 @@ -48,7 +48,6 @@ User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 z Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 1264 -Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32 ------------------------------24e78000bd32 diff --git a/release/src/router/curl/tests/data/test1167 b/release/src/router/curl/tests/data/test1167 new file mode 100644 index 00000000000..9eebe1c4e8f --- /dev/null +++ b/release/src/router/curl/tests/data/test1167 @@ -0,0 +1,24 @@ + + + +source analysis + + + +# +# Client-side + + +none + + + +Verify curl prefix of public symbols in header files + + + +%SRCDIR/badsymbols.pl %SRCDIR/.. + + + + diff --git a/release/src/router/curl/tests/data/test1176 b/release/src/router/curl/tests/data/test1176 new file mode 100644 index 00000000000..491bee16f0a --- /dev/null +++ b/release/src/router/curl/tests/data/test1176 @@ -0,0 +1,68 @@ + + + +globbing + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP GET + + +http://%HOSTIP:%HTTPPORT/1176 -o 'log/base-#0' + + + +# +# Verify data after the test has been "shot" + + +^User-Agent:.* + + +GET /1176 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* + + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + diff --git a/release/src/router/curl/tests/data/test1293 b/release/src/router/curl/tests/data/test1293 index 11a28a32653..e2143d1033d 100644 --- a/release/src/router/curl/tests/data/test1293 +++ b/release/src/router/curl/tests/data/test1293 @@ -52,7 +52,7 @@ s/boundary=------------------------[a-z0-9]*/boundary=-------------------------- POST /1293 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 126 Content-Type: multipart/form-data; boundary=---------------------------- diff --git a/release/src/router/curl/tests/data/test1300 b/release/src/router/curl/tests/data/test1300 index 1008885616e..11834121301 100644 --- a/release/src/router/curl/tests/data/test1300 +++ b/release/src/router/curl/tests/data/test1300 @@ -18,9 +18,5 @@ unittest llist unit tests - -unit1300 - - diff --git a/release/src/router/curl/tests/data/test1301 b/release/src/router/curl/tests/data/test1301 index 8506c0005ee..5aea24b654a 100644 --- a/release/src/router/curl/tests/data/test1301 +++ b/release/src/router/curl/tests/data/test1301 @@ -18,9 +18,5 @@ unittest curl_strcasecompare unit tests - -unit1301 - - diff --git a/release/src/router/curl/tests/data/test1302 b/release/src/router/curl/tests/data/test1302 index 27ea8624856..9e9039cac6c 100644 --- a/release/src/router/curl/tests/data/test1302 +++ b/release/src/router/curl/tests/data/test1302 @@ -18,9 +18,5 @@ unittest base64 encode/decode unit tests - -unit1302 - - diff --git a/release/src/router/curl/tests/data/test1303 b/release/src/router/curl/tests/data/test1303 index 925b47e15db..bb23352df13 100644 --- a/release/src/router/curl/tests/data/test1303 +++ b/release/src/router/curl/tests/data/test1303 @@ -18,9 +18,5 @@ unittest Curl_timeleft unit tests - -unit1303 - - diff --git a/release/src/router/curl/tests/data/test1304 b/release/src/router/curl/tests/data/test1304 index d518de9e4cb..b402bfc8bec 100644 --- a/release/src/router/curl/tests/data/test1304 +++ b/release/src/router/curl/tests/data/test1304 @@ -18,13 +18,9 @@ unittest netrc parsing unit tests - -unit1304 - machine example.com login admin password passwd machine curl.example.com login none password none - diff --git a/release/src/router/curl/tests/data/test1305 b/release/src/router/curl/tests/data/test1305 index 91149b3ad57..52efbcbb012 100644 --- a/release/src/router/curl/tests/data/test1305 +++ b/release/src/router/curl/tests/data/test1305 @@ -19,12 +19,8 @@ unittest internal hash create/destroy testing - -unit1305 - 1305 - diff --git a/release/src/router/curl/tests/data/test1307 b/release/src/router/curl/tests/data/test1307 index c4f7ac7295d..f0e96bfa011 100644 --- a/release/src/router/curl/tests/data/test1307 +++ b/release/src/router/curl/tests/data/test1307 @@ -20,9 +20,5 @@ ftp internal Curl_fnmatch() testing - -unit1307 - - diff --git a/release/src/router/curl/tests/data/test1308 b/release/src/router/curl/tests/data/test1308 index 88e9771ddf2..3755ef8b41f 100644 --- a/release/src/router/curl/tests/data/test1308 +++ b/release/src/router/curl/tests/data/test1308 @@ -20,12 +20,8 @@ http formpost unit tests - -unit1308 - Piece of the file that is to uploaded as a formpost - diff --git a/release/src/router/curl/tests/data/test1309 b/release/src/router/curl/tests/data/test1309 index 0e0cad1e81f..7005d5f13c7 100644 --- a/release/src/router/curl/tests/data/test1309 +++ b/release/src/router/curl/tests/data/test1309 @@ -18,9 +18,6 @@ unittest splay unit tests - -unit1309 - @@ -1564,5 +1561,4 @@ removed payload 1013[1] removed payload 1013[2] - diff --git a/release/src/router/curl/tests/data/test1323 b/release/src/router/curl/tests/data/test1323 index c5e598cc4ad..66bac61ff7d 100644 --- a/release/src/router/curl/tests/data/test1323 +++ b/release/src/router/curl/tests/data/test1323 @@ -17,12 +17,12 @@ curlx_tvdiff none + +unittest + curlx_tvdiff - -unit1323 - # diff --git a/release/src/router/curl/tests/data/test1330 b/release/src/router/curl/tests/data/test1330 index a78dc30b8de..ce04e3331ea 100644 --- a/release/src/router/curl/tests/data/test1330 +++ b/release/src/router/curl/tests/data/test1330 @@ -20,11 +20,6 @@ none unittest TrackMemory -# tool is what to use instead of 'curl' - -unit1330 - - unit tests memory tracking operational @@ -48,5 +43,4 @@ s:^(MEM )(.*/)(.*):$1$3: s/\r\n/\n/ - diff --git a/release/src/router/curl/tests/data/test1394 b/release/src/router/curl/tests/data/test1394 index 34d4a0e370c..d3ffb2d33fa 100644 --- a/release/src/router/curl/tests/data/test1394 +++ b/release/src/router/curl/tests/data/test1394 @@ -17,14 +17,10 @@ unittest unit test for parse_cert_parameter() - -unit1394 - - diff --git a/release/src/router/curl/tests/data/test1395 b/release/src/router/curl/tests/data/test1395 index 967c8d4921a..409e0d631ba 100644 --- a/release/src/router/curl/tests/data/test1395 +++ b/release/src/router/curl/tests/data/test1395 @@ -17,10 +17,5 @@ unittest Curl_dedotdotify - -unit1395 - - - diff --git a/release/src/router/curl/tests/data/test1396 b/release/src/router/curl/tests/data/test1396 index 8ffe35f4caa..d8b432d8b10 100644 --- a/release/src/router/curl/tests/data/test1396 +++ b/release/src/router/curl/tests/data/test1396 @@ -19,9 +19,6 @@ unittest curl_easy_escape and curl_easy_unescape - -unit1396 - diff --git a/release/src/router/curl/tests/data/test1397 b/release/src/router/curl/tests/data/test1397 index 5f479b4685c..84f962abebe 100644 --- a/release/src/router/curl/tests/data/test1397 +++ b/release/src/router/curl/tests/data/test1397 @@ -19,9 +19,6 @@ unittest Check wildcard certificate matching function Curl_cert_hostcheck - -unit1397 - diff --git a/release/src/router/curl/tests/data/test1398 b/release/src/router/curl/tests/data/test1398 index dd50baa6241..436cac82d4b 100644 --- a/release/src/router/curl/tests/data/test1398 +++ b/release/src/router/curl/tests/data/test1398 @@ -18,9 +18,6 @@ unittest curl_msnprintf unit tests - -unit1398 - diff --git a/release/src/router/curl/tests/data/test1399 b/release/src/router/curl/tests/data/test1399 index fe3879df10e..6d6ec7a5b04 100644 --- a/release/src/router/curl/tests/data/test1399 +++ b/release/src/router/curl/tests/data/test1399 @@ -18,9 +18,5 @@ unittest Curl_pgrsTime unit tests - -unit1399 - - diff --git a/release/src/router/curl/tests/data/test1437 b/release/src/router/curl/tests/data/test1437 index 19ccece045c..6a48444fb39 100644 --- a/release/src/router/curl/tests/data/test1437 +++ b/release/src/router/curl/tests/data/test1437 @@ -75,7 +75,7 @@ Accept: */* GET /1437 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="2", uri="/1437", response="4376eb639bf8e7343a6e7b56e1b89c4f", algorithm="MD5" +Authorization: Digest username="testuser", realm="testrealm", nonce="2", uri="/1437", response="4376eb639bf8e7343a6e7b56e1b89c4f", algorithm=MD5 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test1459 b/release/src/router/curl/tests/data/test1459 new file mode 100644 index 00000000000..3e89595e49c --- /dev/null +++ b/release/src/router/curl/tests/data/test1459 @@ -0,0 +1,46 @@ + + + +SFTP +known_hosts + + + +# +# Client-side + + +sftp + + +mkdir -p %PWD/log/test1459.dir/.ssh + + +sftp + + +SFTP with corrupted known_hosts + + +-u : sftp://%HOSTIP:%SSHPORT/ -l + + +|1|qy29Y1x/+/F39AzdG5515YSSw+c=|iB2WX5jrU3ZTWc+ZfGau7HHEvBc= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAynDN8cDJ3xNzRjTNNGciSHSxpubxhZ6YnkLdp1TkrGW8n\ +R93Ey5VtBeBblYTRlFXBWJgKFcTKBRJ/O4qBZwbUgt10AHj31i6h8NehfT19tR8wG/YCmj3KtYLHmwdzmW1edEL9G2NdX2KiKYv7/zuly3QvmP0QA0NhWkAz0KdWNM= + + +CURL_HOME=%PWD/log/test1459.dir + + + +# Verify data after the test has been "shot" + + +60 + + +disable + + + + diff --git a/release/src/router/curl/tests/data/test153 b/release/src/router/curl/tests/data/test153 index 77f7adb01e7..1f55f39b674 100644 --- a/release/src/router/curl/tests/data/test153 +++ b/release/src/router/curl/tests/data/test153 @@ -115,7 +115,7 @@ Accept: */* GET /1530002 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="999999", uri="/1530002", cnonce="MTA4MzIy", nc="00000001", qop="auth", response="25291c357671604a16c0242f56721c07", algorithm="MD5" +Authorization: Digest username="testuser", realm="testrealm", nonce="999999", uri="/1530002", cnonce="MTA4MzIy", nc="00000001", qop="auth", response="25291c357671604a16c0242f56721c07", algorithm=MD5 User-Agent: curl/7.11.0-CVS (i686-pc-linux-gnu) libcurl/7.11.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS Accept: */* diff --git a/release/src/router/curl/tests/data/test1538 b/release/src/router/curl/tests/data/test1538 index 3b22ebc2737..ea8eddbb8c7 100644 --- a/release/src/router/curl/tests/data/test1538 +++ b/release/src/router/curl/tests/data/test1538 @@ -128,7 +128,8 @@ e92: Stream error in the HTTP/2 framing layer e93: API function called from within callback e94: An authentication function returned an error e95: HTTP/3 error -e96: Unknown error +e96: QUIC connection error +e97: Unknown error m-1: Please call curl_multi_perform() soon m0: No error m1: Invalid multi handle @@ -140,7 +141,8 @@ m6: Unknown option m7: The easy handle is already added to a multi handle m8: API function called from within callback m9: Wakeup is unavailable or failed -m10: Unknown error +m10: A libcurl function was given a bad argument +m11: Unknown error s0: No error s1: Unknown share option s2: Share currently in use diff --git a/release/src/router/curl/tests/data/test1600 b/release/src/router/curl/tests/data/test1600 index 88040747a1e..33413d7c39f 100644 --- a/release/src/router/curl/tests/data/test1600 +++ b/release/src/router/curl/tests/data/test1600 @@ -19,9 +19,5 @@ NTLM NTLM unit tests - -unit1600 - - diff --git a/release/src/router/curl/tests/data/test1601 b/release/src/router/curl/tests/data/test1601 index 125493bb016..2065fdd1d84 100644 --- a/release/src/router/curl/tests/data/test1601 +++ b/release/src/router/curl/tests/data/test1601 @@ -18,9 +18,5 @@ unittest MD5 unit tests - -unit1601 - - diff --git a/release/src/router/curl/tests/data/test1602 b/release/src/router/curl/tests/data/test1602 index 4717058ced8..56e243ff8a9 100644 --- a/release/src/router/curl/tests/data/test1602 +++ b/release/src/router/curl/tests/data/test1602 @@ -18,9 +18,5 @@ unittest Internal hash create/add/destroy testing, exercising clean functions - -unit1602 - - diff --git a/release/src/router/curl/tests/data/test1603 b/release/src/router/curl/tests/data/test1603 index 805c9e378cc..406d197eeb6 100644 --- a/release/src/router/curl/tests/data/test1603 +++ b/release/src/router/curl/tests/data/test1603 @@ -18,9 +18,5 @@ unittest Internal hash add, retrieval, deletion testing - -unit1603 - - diff --git a/release/src/router/curl/tests/data/test1604 b/release/src/router/curl/tests/data/test1604 index cf207750de6..39daf9ddc58 100644 --- a/release/src/router/curl/tests/data/test1604 +++ b/release/src/router/curl/tests/data/test1604 @@ -17,9 +17,5 @@ unittest Test WIN32/MSDOS filename sanitization - -unit1604 - - diff --git a/release/src/router/curl/tests/data/test1605 b/release/src/router/curl/tests/data/test1605 index 09ef66942c5..a123b01a1db 100644 --- a/release/src/router/curl/tests/data/test1605 +++ b/release/src/router/curl/tests/data/test1605 @@ -17,9 +17,5 @@ unittest Test negative data lengths as input to libcurl functions - -unit1605 - - diff --git a/release/src/router/curl/tests/data/test1606 b/release/src/router/curl/tests/data/test1606 index 15488d40777..83e98442708 100644 --- a/release/src/router/curl/tests/data/test1606 +++ b/release/src/router/curl/tests/data/test1606 @@ -18,9 +18,5 @@ unittest verify speedcheck - -unit1606 - - diff --git a/release/src/router/curl/tests/data/test1607 b/release/src/router/curl/tests/data/test1607 index 9628324e419..6d28d6eb49f 100644 --- a/release/src/router/curl/tests/data/test1607 +++ b/release/src/router/curl/tests/data/test1607 @@ -18,9 +18,5 @@ unittest CURLOPT_RESOLVE parsing - -unit1607 - - diff --git a/release/src/router/curl/tests/data/test1608 b/release/src/router/curl/tests/data/test1608 index 70231075749..fbc6238958c 100644 --- a/release/src/router/curl/tests/data/test1608 +++ b/release/src/router/curl/tests/data/test1608 @@ -18,9 +18,5 @@ unittest verify DNS shuffling - -unit1608 - - diff --git a/release/src/router/curl/tests/data/test1609 b/release/src/router/curl/tests/data/test1609 index c1b7c7a1114..6d28d6eb49f 100644 --- a/release/src/router/curl/tests/data/test1609 +++ b/release/src/router/curl/tests/data/test1609 @@ -18,9 +18,5 @@ unittest CURLOPT_RESOLVE parsing - -unit1609 - - diff --git a/release/src/router/curl/tests/data/test1610 b/release/src/router/curl/tests/data/test1610 new file mode 100644 index 00000000000..fff973371de --- /dev/null +++ b/release/src/router/curl/tests/data/test1610 @@ -0,0 +1,22 @@ + + + +unittest +SHA256 + + + +# +# Client-side + + +none + + +unittest + + +SHA256 unit tests + + + diff --git a/release/src/router/curl/tests/data/test1611 b/release/src/router/curl/tests/data/test1611 new file mode 100644 index 00000000000..008aea7ec46 --- /dev/null +++ b/release/src/router/curl/tests/data/test1611 @@ -0,0 +1,22 @@ + + + +unittest +MD4 + + + +# +# Client-side + + +none + + +unittest + + +MD4 unit tests + + + diff --git a/release/src/router/curl/tests/data/test1612 b/release/src/router/curl/tests/data/test1612 new file mode 100644 index 00000000000..3e92b679120 --- /dev/null +++ b/release/src/router/curl/tests/data/test1612 @@ -0,0 +1,22 @@ + + + +unittest +HMAC + + + +# +# Client-side + + +none + + +unittest + + +HMAC unit tests + + + diff --git a/release/src/router/curl/tests/data/test1620 b/release/src/router/curl/tests/data/test1620 index 83b08c7a811..038bbcc1b47 100644 --- a/release/src/router/curl/tests/data/test1620 +++ b/release/src/router/curl/tests/data/test1620 @@ -18,9 +18,5 @@ unittest unit tests for url.c - -unit1620 - - diff --git a/release/src/router/curl/tests/data/test1621 b/release/src/router/curl/tests/data/test1621 index 1117d1bd2a5..62c81052ff3 100644 --- a/release/src/router/curl/tests/data/test1621 +++ b/release/src/router/curl/tests/data/test1621 @@ -19,9 +19,5 @@ https unit tests for stripcredentials from URL - -unit1621 - - diff --git a/release/src/router/curl/tests/data/test1650 b/release/src/router/curl/tests/data/test1650 index 7a02a6dac46..6248b9814d6 100644 --- a/release/src/router/curl/tests/data/test1650 +++ b/release/src/router/curl/tests/data/test1650 @@ -19,9 +19,5 @@ DoH DOH - -unit1650 - - diff --git a/release/src/router/curl/tests/data/test1651 b/release/src/router/curl/tests/data/test1651 index 28a9b714c69..d29974bf20f 100644 --- a/release/src/router/curl/tests/data/test1651 +++ b/release/src/router/curl/tests/data/test1651 @@ -18,9 +18,5 @@ unittest x509 parsing - -unit1651 - - diff --git a/release/src/router/curl/tests/data/test1652 b/release/src/router/curl/tests/data/test1652 index c4116901944..678d1951780 100644 --- a/release/src/router/curl/tests/data/test1652 +++ b/release/src/router/curl/tests/data/test1652 @@ -16,8 +16,5 @@ unittest infof - -unit1652 - diff --git a/release/src/router/curl/tests/data/test1653 b/release/src/router/curl/tests/data/test1653 index 0de2c14b5ab..59ec3f39620 100644 --- a/release/src/router/curl/tests/data/test1653 +++ b/release/src/router/curl/tests/data/test1653 @@ -16,8 +16,5 @@ unittest urlapi - -unit1653 - diff --git a/release/src/router/curl/tests/data/test1654 b/release/src/router/curl/tests/data/test1654 index 6a82daa081d..6155635ab01 100644 --- a/release/src/router/curl/tests/data/test1654 +++ b/release/src/router/curl/tests/data/test1654 @@ -26,9 +26,6 @@ alt-svc log/1654 - -unit1654 - h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1 # a comment diff --git a/release/src/router/curl/tests/data/test1655 b/release/src/router/curl/tests/data/test1655 index 2e73f55d9bd..e161fb6621b 100644 --- a/release/src/router/curl/tests/data/test1655 +++ b/release/src/router/curl/tests/data/test1655 @@ -19,9 +19,5 @@ DoH unit test for doh_encode - -unit1655 - - diff --git a/release/src/router/curl/tests/data/test1800 b/release/src/router/curl/tests/data/test1800 index 01101840013..c308c99b0fd 100644 --- a/release/src/router/curl/tests/data/test1800 +++ b/release/src/router/curl/tests/data/test1800 @@ -48,7 +48,7 @@ Host: %HOSTIP:%HTTPPORT Accept: */* Connection: Upgrade, HTTP2-Settings Upgrade: %H2CVER -HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA +HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA diff --git a/release/src/router/curl/tests/data/test1908 b/release/src/router/curl/tests/data/test1908 new file mode 100644 index 00000000000..de34d0ee2d5 --- /dev/null +++ b/release/src/router/curl/tests/data/test1908 @@ -0,0 +1,71 @@ + + + +CURLINFO_EFFECTIVE_URL + + + +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Type: text/html +Funny-head: yesyes swsclose +Content-Length: 0 +alt-svc: h2="3dbbdetxoyw4nsp6c3cc456oj2ays6s43ezxzsfxxri3h5xqd.example:443"; ma=315360000; persist=1 + + + + +# Client-side + + +http + + +# require debug so that alt-svc can work over plain old HTTP + +alt-svc +debug + + +alt-svc cache save after resetting the handle + + +# make debug-curl accept Alt-Svc over plain HTTP +CURL_ALTSVC_HTTP="yeah" + + +lib1908 + + + +%HOSTIP:%HTTPPORT/1908 + + + +# Verify data after the test has been "shot" + + +^User-Agent:.* + + +GET /1908 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* + + + +# strip out the (dynamic) expire date from the file so that the rest +# matches +s/\"([^\"]*)\"/TIMESTAMP/ + + +# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html +# This file was generated by libcurl! Edit at your own risk. +h1 127.0.0.1 8990 h2 3dbbdetxoyw4nsp6c3cc456oj2ays6s43ezxzsfxxri3h5xqd.example 443 TIMESTAMP 1 0 + + + diff --git a/release/src/router/curl/tests/data/test2006 b/release/src/router/curl/tests/data/test2006 index 1f597172692..0b84937ed11 100644 --- a/release/src/router/curl/tests/data/test2006 +++ b/release/src/router/curl/tests/data/test2006 @@ -86,6 +86,10 @@ Accept: */* Some data delivered from an HTTP resource +Content-Length: 496 +Accept-ranges: bytes + + HTTP/1.1 200 OK Date: Thu, 21 Jun 2012 14:49:01 GMT Server: test-server/fake diff --git a/release/src/router/curl/tests/data/test2007 b/release/src/router/curl/tests/data/test2007 index a8e5f1b45a1..c8c023efb03 100644 --- a/release/src/router/curl/tests/data/test2007 +++ b/release/src/router/curl/tests/data/test2007 @@ -90,6 +90,10 @@ Something delivered from an HTTP resource s/Last-Modified:.*// +Content-Length: 496 +Accept-ranges: bytes + + HTTP/1.1 200 OK Date: Thu, 21 Jun 2012 14:50:02 GMT Server: test-server/fake diff --git a/release/src/router/curl/tests/data/test2008 b/release/src/router/curl/tests/data/test2008 index 1a00332853c..570cdba7d31 100644 --- a/release/src/router/curl/tests/data/test2008 +++ b/release/src/router/curl/tests/data/test2008 @@ -82,6 +82,10 @@ Some stuff delivered from an HTTP resource s/Last-Modified:.*// +Content-Length: 496 +Accept-ranges: bytes + + HTTP/1.1 200 OK Date: Thu, 21 Jun 2012 15:23:48 GMT Server: test-server/fake diff --git a/release/src/router/curl/tests/data/test2009 b/release/src/router/curl/tests/data/test2009 index 08308d03e21..10f95df4c76 100644 --- a/release/src/router/curl/tests/data/test2009 +++ b/release/src/router/curl/tests/data/test2009 @@ -83,6 +83,10 @@ Some contents delivered from an HTTP resource s/Last-Modified:.*// +Content-Length: 496 +Accept-ranges: bytes + + HTTP/1.1 200 OK Date: Thu, 21 Jun 2012 16:27:17 GMT Server: test-server/fake diff --git a/release/src/router/curl/tests/data/test2010 b/release/src/router/curl/tests/data/test2010 index 068c481b51a..d43f4f1e1a8 100644 --- a/release/src/router/curl/tests/data/test2010 +++ b/release/src/router/curl/tests/data/test2010 @@ -82,6 +82,10 @@ Contents delivered from an HTTP resource s/Last-Modified:.*// +Content-Length: 496 +Accept-ranges: bytes + + HTTP/1.1 200 OK Date: Thu, 21 Jun 2012 17:37:27 GMT Server: test-server/fake diff --git a/release/src/router/curl/tests/data/test2033 b/release/src/router/curl/tests/data/test2033 index 5293b66e85d..0b33ccaacd7 100644 --- a/release/src/router/curl/tests/data/test2033 +++ b/release/src/router/curl/tests/data/test2033 @@ -101,22 +101,22 @@ chkhostname curlhost GET /20320100 HTTP/1.1 -Host: 127.0.0.1:%HTTPPORT +Host: %HOSTIP:%HTTPPORT Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M= Accept: */* GET /20320100 HTTP/1.1 -Host: 127.0.0.1:%HTTPPORT +Host: %HOSTIP:%HTTPPORT Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M= Accept: */* GET /20320200 HTTP/1.1 -Host: 127.0.0.1:%HTTPPORT +Host: %HOSTIP:%HTTPPORT Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAA= Accept: */* GET /20320200 HTTP/1.1 -Host: 127.0.0.1:%HTTPPORT +Host: %HOSTIP:%HTTPPORT Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAACAAIAHAAAAAIAAgAeAAAAAAAAAAAAAAAhoABAI+/Fp9IERAQ74OsdNPbBpg7o8CVwLSO4DtFyIcZHUMKVktWIu92s2892OVpd2JzqnRlc3R1c2VyY3VybGhvc3Q= Accept: */* diff --git a/release/src/router/curl/tests/data/test2058 b/release/src/router/curl/tests/data/test2058 index 65a907f43a2..613dff00135 100644 --- a/release/src/router/curl/tests/data/test2058 +++ b/release/src/router/curl/tests/data/test2058 @@ -95,7 +95,7 @@ Content-Length: 0 GET http://%HOSTIP:%HTTPPORT/2058 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2058", response="fbed69f9f3fd304c8f1acb1a43eb32688b933c0e28055c16b926cbcec070aeed", algorithm="SHA-256" +Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2058", response="fbed69f9f3fd304c8f1acb1a43eb32688b933c0e28055c16b926cbcec070aeed", algorithm=SHA-256 Content-Range: bytes 2-4/5 Accept: */* Proxy-Connection: Keep-Alive diff --git a/release/src/router/curl/tests/data/test2059 b/release/src/router/curl/tests/data/test2059 index 4272a7b41a3..15799ae07fc 100644 --- a/release/src/router/curl/tests/data/test2059 +++ b/release/src/router/curl/tests/data/test2059 @@ -95,7 +95,7 @@ Content-Length: 0 GET http://%HOSTIP:%HTTPPORT/2059 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", realm="testrealm", nonce="1053604144", uri="/2059", response="fc09be8192851e284e73e8b719b32a2f6f91cca0594e68713da8c49dc2c1656e", algorithm="SHA-512-256", userhash=true +Authorization: Digest username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", realm="testrealm", nonce="1053604144", uri="/2059", response="fc09be8192851e284e73e8b719b32a2f6f91cca0594e68713da8c49dc2c1656e", algorithm=SHA-512-256, userhash=true Content-Range: bytes 2-4/5 Accept: */* Proxy-Connection: Keep-Alive diff --git a/release/src/router/curl/tests/data/test2060 b/release/src/router/curl/tests/data/test2060 index a0b291dc215..05ce35103c1 100644 --- a/release/src/router/curl/tests/data/test2060 +++ b/release/src/router/curl/tests/data/test2060 @@ -95,7 +95,7 @@ Content-Length: 0 GET http://%HOSTIP:%HTTPPORT/2060 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2060", response="3ce1e25ffa611bdbe90e2ab367b9602fa223db9f6de76ac667f0d6157e2178a6", algorithm="SHA-512-256" +Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2060", response="3ce1e25ffa611bdbe90e2ab367b9602fa223db9f6de76ac667f0d6157e2178a6", algorithm=SHA-512-256 Content-Range: bytes 2-4/5 Accept: */* Proxy-Connection: Keep-Alive diff --git a/release/src/router/curl/tests/data/test2061 b/release/src/router/curl/tests/data/test2061 index af3758c97d7..bee88e34a07 100644 --- a/release/src/router/curl/tests/data/test2061 +++ b/release/src/router/curl/tests/data/test2061 @@ -75,7 +75,7 @@ Accept: */* GET /2061 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/2061", response="9dc55255f1a2537b838311674b621d45346b862a81631bb20e4ce356ef25062d", algorithm="SHA-256" +Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/2061", response="9dc55255f1a2537b838311674b621d45346b862a81631bb20e4ce356ef25062d", algorithm=SHA-256 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2062 b/release/src/router/curl/tests/data/test2062 index d5ce6899f7e..f6d4aff24d0 100644 --- a/release/src/router/curl/tests/data/test2062 +++ b/release/src/router/curl/tests/data/test2062 @@ -75,7 +75,7 @@ Accept: */* GET /2062 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/2062", response="2af735ec3508f4dff99248ffbbe9de9002bfd7cc770cfa2b026cb334042a54e3", algorithm="SHA-512-256" +Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/2062", response="2af735ec3508f4dff99248ffbbe9de9002bfd7cc770cfa2b026cb334042a54e3", algorithm=SHA-512-256 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2063 b/release/src/router/curl/tests/data/test2063 index 220fe4ebea7..af9a9f0aa71 100644 --- a/release/src/router/curl/tests/data/test2063 +++ b/release/src/router/curl/tests/data/test2063 @@ -75,7 +75,7 @@ Accept: */* GET /2063 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", realm="testrealm", nonce="1053604145", uri="/2063", response="43f7ab531dff687b5dc75617daa59d1fd67d648341d6d2655ca65ef5064cfb51", algorithm="SHA-512-256", userhash=true +Authorization: Digest username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", realm="testrealm", nonce="1053604145", uri="/2063", response="43f7ab531dff687b5dc75617daa59d1fd67d648341d6d2655ca65ef5064cfb51", algorithm=SHA-512-256, userhash=true User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2064 b/release/src/router/curl/tests/data/test2064 index aa20c0bc0b5..bfaaa05e8f7 100644 --- a/release/src/router/curl/tests/data/test2064 +++ b/release/src/router/curl/tests/data/test2064 @@ -75,7 +75,7 @@ Accept: */* GET /2064 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="2053604145", uri="/2064", response="a9c3ec1036068b336cbabefe9dfcad52ee8b89bc7c91ddbb5bb415c6acdf38a5", algorithm="SHA-256" +Authorization: Digest username="testuser", realm="testrealm", nonce="2053604145", uri="/2064", response="a9c3ec1036068b336cbabefe9dfcad52ee8b89bc7c91ddbb5bb415c6acdf38a5", algorithm=SHA-256 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2065 b/release/src/router/curl/tests/data/test2065 index d3afe0b134c..d18b008ad86 100644 --- a/release/src/router/curl/tests/data/test2065 +++ b/release/src/router/curl/tests/data/test2065 @@ -75,7 +75,7 @@ Accept: */* GET /2065 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="testuser", realm="testrealm", nonce="2053604145", uri="/2065", response="5a5f20b0e601aeddc6f96422c2332d49ff431c49ab143b5f836ef76e9ac78f5e", algorithm="SHA-512-256" +Authorization: Digest username="testuser", realm="testrealm", nonce="2053604145", uri="/2065", response="5a5f20b0e601aeddc6f96422c2332d49ff431c49ab143b5f836ef76e9ac78f5e", algorithm=SHA-512-256 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2066 b/release/src/router/curl/tests/data/test2066 index e6ec28a1e3c..b6effee0e49 100644 --- a/release/src/router/curl/tests/data/test2066 +++ b/release/src/router/curl/tests/data/test2066 @@ -75,7 +75,7 @@ Accept: */* GET /2066 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", realm="testrealm", nonce="2053604145", uri="/2066", response="a2e2ae589f575fb132991d6f550ef14bf7ef697d2fef1242d2498f07eafc77dc", algorithm="SHA-512-256", userhash=true +Authorization: Digest username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", realm="testrealm", nonce="2053604145", uri="/2066", response="a2e2ae589f575fb132991d6f550ef14bf7ef697d2fef1242d2498f07eafc77dc", algorithm=SHA-512-256, userhash=true User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Accept: */* diff --git a/release/src/router/curl/tests/data/test2067 b/release/src/router/curl/tests/data/test2067 index faa7c57fa5d..c203343e60d 100644 --- a/release/src/router/curl/tests/data/test2067 +++ b/release/src/router/curl/tests/data/test2067 @@ -78,7 +78,7 @@ Content-Type: application/x-www-form-urlencoded POST /2067 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2067", response="67b97af219c92fa7e8685e5bebb8e74892f6c6792e911c52bd2dfbf0b49272eb", algorithm="SHA-256" +Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2067", response="67b97af219c92fa7e8685e5bebb8e74892f6c6792e911c52bd2dfbf0b49272eb", algorithm=SHA-256 Accept: */* Content-Length: 11 Content-Type: application/x-www-form-urlencoded diff --git a/release/src/router/curl/tests/data/test2068 b/release/src/router/curl/tests/data/test2068 index 43a50e6262a..5a197ce27d4 100644 --- a/release/src/router/curl/tests/data/test2068 +++ b/release/src/router/curl/tests/data/test2068 @@ -78,7 +78,7 @@ Content-Type: application/x-www-form-urlencoded POST /2068 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2068", response="4bc9c97a72f1856bcec9b0e1518c6b7ee28773f91357d56840bdc30bd89ca68f", algorithm="SHA-512-256" +Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", uri="/2068", response="4bc9c97a72f1856bcec9b0e1518c6b7ee28773f91357d56840bdc30bd89ca68f", algorithm=SHA-512-256 Accept: */* Content-Length: 11 Content-Type: application/x-www-form-urlencoded diff --git a/release/src/router/curl/tests/data/test2069 b/release/src/router/curl/tests/data/test2069 index e8040a5e039..99fd71d0eee 100644 --- a/release/src/router/curl/tests/data/test2069 +++ b/release/src/router/curl/tests/data/test2069 @@ -78,7 +78,7 @@ Content-Type: application/x-www-form-urlencoded POST /2069 HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Digest username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", realm="testrealm", nonce="1053604144", uri="/2069", response="ff13d977110a471f30de75e747976e4de78d7a3d2425cd23ff46e67f4bc9ead7", algorithm="SHA-512-256", userhash=true +Authorization: Digest username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", realm="testrealm", nonce="1053604144", uri="/2069", response="ff13d977110a471f30de75e747976e4de78d7a3d2425cd23ff46e67f4bc9ead7", algorithm=SHA-512-256, userhash=true Accept: */* Content-Length: 11 Content-Type: application/x-www-form-urlencoded diff --git a/release/src/router/curl/tests/data/test2078 b/release/src/router/curl/tests/data/test2078 index 99bc2dbee12..51ace296a67 100644 --- a/release/src/router/curl/tests/data/test2078 +++ b/release/src/router/curl/tests/data/test2078 @@ -43,7 +43,7 @@ http://%HOSTIP:%HTTPPORT/2078 -u : --negotiate --data name=value POST /2078 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 10 Content-Type: application/x-www-form-urlencoded diff --git a/release/src/router/curl/tests/data/test2100 b/release/src/router/curl/tests/data/test2100 index 6dce69b64ea..0deedbd743b 100644 Binary files a/release/src/router/curl/tests/data/test2100 and b/release/src/router/curl/tests/data/test2100 differ diff --git a/release/src/router/curl/tests/data/test3002 b/release/src/router/curl/tests/data/test3002 new file mode 100644 index 00000000000..ac682021443 --- /dev/null +++ b/release/src/router/curl/tests/data/test3002 @@ -0,0 +1,55 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with multiple and invalid (first) --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3002 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt recipient.two@example.com --mail-rcpt recipient.three@example.com --mail-rcpt recipient.four@example.com --mail-rcpt recipient.five@example.com --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 3002 +MAIL FROM: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test3003 b/release/src/router/curl/tests/data/test3003 new file mode 100644 index 00000000000..7515affbc12 --- /dev/null +++ b/release/src/router/curl/tests/data/test3003 @@ -0,0 +1,55 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with multiple and invalid (last) --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3003 --mail-rcpt-allowfails --mail-rcpt recipient.one@example.com --mail-rcpt recipient.two@example.com --mail-rcpt recipient.three@example.com --mail-rcpt recipient.four@example.com --mail-rcpt invalid.five --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 3003 +MAIL FROM: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test3004 b/release/src/router/curl/tests/data/test3004 new file mode 100644 index 00000000000..e021cde41e0 --- /dev/null +++ b/release/src/router/curl/tests/data/test3004 @@ -0,0 +1,55 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with multiple and invalid (middle) --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3004 --mail-rcpt-allowfails --mail-rcpt recipient.one@example.com --mail-rcpt recipient.two@example.com --mail-rcpt invalid.three --mail-rcpt recipient.four@example.com --mail-rcpt recipient.five@example.com --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 3004 +MAIL FROM: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test3005 b/release/src/router/curl/tests/data/test3005 new file mode 100644 index 00000000000..256555ac9db --- /dev/null +++ b/release/src/router/curl/tests/data/test3005 @@ -0,0 +1,55 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with multiple and invalid (all but one) --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3005 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt recipient.two@example.com --mail-rcpt invalid.three --mail-rcpt invalid.four --mail-rcpt invalid.five --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 3005 +MAIL FROM: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test3006 b/release/src/router/curl/tests/data/test3006 new file mode 100644 index 00000000000..f54d71c8d22 --- /dev/null +++ b/release/src/router/curl/tests/data/test3006 @@ -0,0 +1,51 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with multiple invalid (all) --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3006 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt invalid.two --mail-rcpt invalid.three --mail-rcpt invalid.four --mail-rcpt invalid.five --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 3006 +MAIL FROM: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +RCPT TO: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test3007 b/release/src/router/curl/tests/data/test3007 new file mode 100644 index 00000000000..b0d69026294 --- /dev/null +++ b/release/src/router/curl/tests/data/test3007 @@ -0,0 +1,47 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +SMTP with invalid --mail-rcpt and --mail-rcpt-allowfails + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/3007 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 3007 +MAIL FROM: +RCPT TO: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test304 b/release/src/router/curl/tests/data/test304 index fedf18ff5a4..01d3a2d6798 100644 --- a/release/src/router/curl/tests/data/test304 +++ b/release/src/router/curl/tests/data/test304 @@ -49,7 +49,6 @@ User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 z Host: %HOSTIP:%HTTPSPORT Accept: */* Content-Length: 1386 -Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------c3b2ef7f0bb8 ------------------------------c3b2ef7f0bb8 diff --git a/release/src/router/curl/tests/data/test357 b/release/src/router/curl/tests/data/test357 new file mode 100644 index 00000000000..d0437c68519 --- /dev/null +++ b/release/src/router/curl/tests/data/test357 @@ -0,0 +1,97 @@ + + + +HTTP +HTTP PUT +Expect + + +# Server-side + +# 417 means the server didn't like the Expect header + +HTTP/1.1 417 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 + + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 10 + +blablabla + + +HTTP/1.1 417 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 10 + +blablabla + + +no-expect + + + +# Client-side + + +http + + +HTTP PUT with Expect: 100-continue and 417 response + + +http://%HOSTIP:%HTTPPORT/we/want/357 -T log/test357.txt + + +Weird + file + to + upload +for + testing +the + PUT + feature + + + +# Verify data after the test has been "shot" + + +^User-Agent:.* + + +PUT /we/want/357 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 78 +Expect: 100-continue + +PUT /we/want/357 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 78 + +Weird + file + to + upload +for + testing +the + PUT + feature + + + diff --git a/release/src/router/curl/tests/data/test39 b/release/src/router/curl/tests/data/test39 index 1867b6081be..3c6c57328bb 100644 --- a/release/src/router/curl/tests/data/test39 +++ b/release/src/router/curl/tests/data/test39 @@ -48,7 +48,6 @@ User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 z Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 1184 -Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------24e78000bd32 ------------------------------24e78000bd32 diff --git a/release/src/router/curl/tests/data/test490 b/release/src/router/curl/tests/data/test490 index a3383a9d1d0..86ebb011242 100644 --- a/release/src/router/curl/tests/data/test490 +++ b/release/src/router/curl/tests/data/test490 @@ -50,14 +50,14 @@ surprise! PUT /490 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 10 Expect: 100-continue surprise! PUT /490 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 10 Expect: 100-continue diff --git a/release/src/router/curl/tests/data/test491 b/release/src/router/curl/tests/data/test491 index b49c06ce712..c230dfb7824 100644 --- a/release/src/router/curl/tests/data/test491 +++ b/release/src/router/curl/tests/data/test491 @@ -50,7 +50,7 @@ surprise! PUT /491 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 10 Expect: 100-continue diff --git a/release/src/router/curl/tests/data/test492 b/release/src/router/curl/tests/data/test492 index 12edd8bc00f..ddb0405ef72 100644 --- a/release/src/router/curl/tests/data/test492 +++ b/release/src/router/curl/tests/data/test492 @@ -53,7 +53,7 @@ second 492 contents PUT /one/first492 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Testno: 492 Content-Length: 19 @@ -61,7 +61,7 @@ Expect: 100-continue first 492 contents PUT /two/first492 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Testno: 492 Content-Length: 19 @@ -69,7 +69,7 @@ Expect: 100-continue first 492 contents PUT /one/second492 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Testno: 492 Content-Length: 20 @@ -77,7 +77,7 @@ Expect: 100-continue second 492 contents PUT /two/second492 HTTP/1.1 -Host: 127.0.0.1:8990 +Host: %HOSTIP:%HTTPPORT Accept: */* Testno: 492 Content-Length: 20 diff --git a/release/src/router/curl/tests/data/test552 b/release/src/router/curl/tests/data/test552 index 5d1478bd5ba..47dd41abb9c 100644 Binary files a/release/src/router/curl/tests/data/test552 and b/release/src/router/curl/tests/data/test552 differ diff --git a/release/src/router/curl/tests/data/test558 b/release/src/router/curl/tests/data/test558 index 49ef1c70be4..dccb8080a8d 100644 --- a/release/src/router/curl/tests/data/test558 +++ b/release/src/router/curl/tests/data/test558 @@ -36,8 +36,6 @@ nothing # Verify data after the test has been "shot" -FD hostip6.c: socket() -FD connect.c: sclose() MEM lib558.c: malloc() MEM lib558.c: free() MEM escape.c: malloc() diff --git a/release/src/router/curl/tests/data/test643 b/release/src/router/curl/tests/data/test643 index 0eaf22c5fca..e8da2b1c461 100644 --- a/release/src/router/curl/tests/data/test643 +++ b/release/src/router/curl/tests/data/test643 @@ -69,18 +69,18 @@ s/boundary=------------------------[a-z0-9]*/boundary=-------------------------- POST /643 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Content-Length: 718 +Content-Length: 640 Content-Type: multipart/form-data; boundary=---------------------------- ------------------------------ Content-Disposition: form-data; name="sendfile"; filename="postit2.c" -this is what we post to the silly web server +dummy ------------------------------ Content-Disposition: form-data; name="callbackdata" -this is what we post to the silly web server +dummy ------------------------------ Content-Disposition: form-data; name="filename" @@ -99,18 +99,18 @@ blah blah POST /643 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Content-Length: 732 +Content-Length: 654 Content-Type: multipart/form-data; boundary=---------------------------- ------------------------------ Content-Disposition: form-data; name="sendfile alternative"; filename="file name 2" -this is what we post to the silly web server +dummy ------------------------------ Content-Disposition: form-data; name="callbackdata" -this is what we post to the silly web server +dummy ------------------------------ Content-Disposition: form-data; name="filename" diff --git a/release/src/router/curl/tests/data/test644 b/release/src/router/curl/tests/data/test644 index 4c9a501ed0d..99337ae0f8f 100644 --- a/release/src/router/curl/tests/data/test644 +++ b/release/src/router/curl/tests/data/test644 @@ -44,12 +44,13 @@ s/boundary=------------------------[a-z0-9]*/boundary=-------------------------- POST /644 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Content-Length: 718 +Content-Length: 640 Content-Type: multipart/form-data; boundary=---------------------------- ------------------------------ Content-Disposition: form-data; name="sendfile"; filename="postit2.c" + # CURLE_ABORTED_BY_CALLBACK (42) diff --git a/release/src/router/curl/tests/data/test645 b/release/src/router/curl/tests/data/test645 index 6533944b48c..eeb15f99498 100644 --- a/release/src/router/curl/tests/data/test645 +++ b/release/src/router/curl/tests/data/test645 @@ -73,16 +73,42 @@ Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=---------------------------- Expect: 100-continue -2ce +76 ------------------------------ Content-Disposition: form-data; name="sendfile"; filename="postit2.c" -this is what we post to the silly web server +d +1 +u +1 +m +1 +m +1 +y +1 + + +65 ------------------------------ Content-Disposition: form-data; name="callbackdata" -this is what we post to the silly web server + +1 +d +1 +u +1 +m +1 +m +1 +y +1 + + +19a ------------------------------ Content-Disposition: form-data; name="filename" @@ -108,16 +134,42 @@ Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=---------------------------- Expect: 100-continue -2dc +84 ------------------------------ Content-Disposition: form-data; name="sendfile alternative"; filename="file name 2" -this is what we post to the silly web server +d +1 +u +1 +m +1 +m +1 +y +1 + + +65 ------------------------------ Content-Disposition: form-data; name="callbackdata" -this is what we post to the silly web server + +1 +d +1 +u +1 +m +1 +m +1 +y +1 + + +19a ------------------------------ Content-Disposition: form-data; name="filename" diff --git a/release/src/router/curl/tests/data/test650 b/release/src/router/curl/tests/data/test650 index 1a06064c779..03fe43816f8 100644 --- a/release/src/router/curl/tests/data/test650 +++ b/release/src/router/curl/tests/data/test650 @@ -63,7 +63,7 @@ Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=---------------------------- Expect: 100-continue -60a +361 ------------------------------ Content-Disposition: form-data; name="fieldname" Content-Type: text/plain @@ -89,12 +89,16 @@ This is data from a file. Content-Disposition: attachment; filename="test650.filedata" Content-Type: text/whatever + +a5 This is data from a file. ------------------------------ Content-Disposition: attachment; filename="test650.filedata" Content-Type: text/whatever + +af This is data from a file. -------------------------------- @@ -102,6 +106,8 @@ This is data from a file. ------------------------------ Content-Disposition: form-data; name="filecontents" + +10f This is data from a file. ------------------------------ @@ -112,8 +118,12 @@ Content-Disposition: form-data; name="formlength" Content-Disposition: form-data; name="standardinput" Content-Type: application/octet-stream + +16 Some data from stdin +30 + -------------------------------- 0 diff --git a/release/src/router/curl/tests/data/test651 b/release/src/router/curl/tests/data/test651 index ae6409479ff..dd5736a70d8 100644 --- a/release/src/router/curl/tests/data/test651 +++ b/release/src/router/curl/tests/data/test651 @@ -61,7 +61,6 @@ Host: %HOSTIP:%HTTPPORT Accept: */* Content-Length: 17139 Content-Type: multipart/form-data; boundary=---------------------------- -Expect: 100-continue ------------------------------ Content-Disposition: form-data; name="hello" diff --git a/release/src/router/curl/tests/data/test654 b/release/src/router/curl/tests/data/test654 index 21697e76398..9d4bf45a179 100644 --- a/release/src/router/curl/tests/data/test654 +++ b/release/src/router/curl/tests/data/test654 @@ -81,7 +81,7 @@ Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=---------------------------- Expect: 100-continue -20c +1af ------------------------------ Content-Disposition: form-data; name="greeting" Content-Type: application/X-Greeting @@ -98,7 +98,21 @@ This is data from a file ------------------------------ Content-Disposition: form-data -this is what we post to the silly web server + +1 +d +1 +u +1 +m +1 +m +1 +y +1 + + +30 -------------------------------- diff --git a/release/src/router/curl/tests/data/test664 b/release/src/router/curl/tests/data/test664 new file mode 100644 index 00000000000..cb73b248bb0 --- /dev/null +++ b/release/src/router/curl/tests/data/test664 @@ -0,0 +1,44 @@ + + + +SFTP +server key check + + + +# +# Server-side + + +test + + + +# +# Client-side + + +sftp + + +SFTP correct host key + + +--hostpubmd5 %SSHSRVMD5 --key curl_client_key --pubkey curl_client_key.pub -u %USER: sftp://%HOSTIP:%SSHPORT%POSIX_PWD/log/file664.txt + + +test + + + +# +# Verify data after the test has been "shot" + + +0 + + +disable + + + diff --git a/release/src/router/curl/tests/data/test665 b/release/src/router/curl/tests/data/test665 new file mode 100644 index 00000000000..830adb8f62d --- /dev/null +++ b/release/src/router/curl/tests/data/test665 @@ -0,0 +1,44 @@ + + + +SCP +server key check + + + +# +# Server-side + + +test + + + +# +# Client-side + + +scp + + +SCP correct host key + + +--hostpubmd5 %SSHSRVMD5 --key curl_client_key --pubkey curl_client_key.pub -u %USER: scp://%HOSTIP:%SSHPORT%POSIX_PWD/log/file665.txt + + +test + + + +# +# Verify data after the test has been "shot" + + +0 + + +disable + + + diff --git a/release/src/router/curl/tests/data/test666 b/release/src/router/curl/tests/data/test666 new file mode 100644 index 00000000000..bb60caf6d65 --- /dev/null +++ b/release/src/router/curl/tests/data/test666 @@ -0,0 +1,293 @@ + + + +HTTP +HTTP POST +HTTP MIME POST +MIME + + + +# +# Server-side + + +HTTP/1.1 200 OK swsclose +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 3 + +OK + + +HTTP/1.1 200 OK swsclose +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 3 + +OK + + + +# +# Client-side + + +http + + +lib666 + + + +HTTP mime post with binary-encoded huge data contents + + +http://%HOSTIP:%HTTPPORT/666 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + + +POST /666 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 17225 +Content-Type: multipart/form-data; boundary=---------------------------- + +------------------------------ +Content-Disposition: form-data; name="upfile"; filename="myfile.txt" +Content-Type: text/plain +Content-Transfer-Encoding: binary + +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL +NOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK +MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ +LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI +KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH +JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG +IJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF +HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDE +GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCD +FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABC +EFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB +DEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA +CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ +BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY +ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX +ZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW +YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU +WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST +VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS +UVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR +TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ +STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP +RSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO +QRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN +PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM +OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV +-------------------------------- + + + diff --git a/release/src/router/curl/tests/data/test667 b/release/src/router/curl/tests/data/test667 new file mode 100644 index 00000000000..2a183753b21 --- /dev/null +++ b/release/src/router/curl/tests/data/test667 @@ -0,0 +1,85 @@ + + + +HTTP +HTTP POST +HTTP MIME POST + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib667 + + + +HTTP chunked mimepost using single-byte read callback with encoder + + +http://%HOSTIP:%HTTPPORT/667 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + +# Note that the stripping above removes 12 bytes from every occurrence of the +# boundary string and since 5 of them are in the body contents, we see +# (5*12) == 60 bytes less + +POST /667 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Transfer-Encoding: chunked +Content-Type: multipart/form-data; boundary=---------------------------- +Expect: 100-continue + +7f +------------------------------ +Content-Disposition: form-data; name="field" +Content-Transfer-Encoding: base64 + + +4 +ZHVt +34 +bXk= +-------------------------------- + +0 + + + + diff --git a/release/src/router/curl/tests/data/test668 b/release/src/router/curl/tests/data/test668 new file mode 100644 index 00000000000..af0a7205107 --- /dev/null +++ b/release/src/router/curl/tests/data/test668 @@ -0,0 +1,99 @@ + + + +HTTP +HTTP POST +HTTP MIME POST + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib668 + + + +HTTP mimepost early end of data detection + + +http://%HOSTIP:%HTTPPORT/668 + + +This is data from a file + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + +# Note that the stripping above removes 12 bytes from every occurrence of the +# boundary string and since 5 of them are in the body contents, we see +# (5*12) == 60 bytes less + +POST /668 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Transfer-Encoding: chunked +Content-Type: multipart/form-data; boundary=---------------------------- +Expect: 100-continue + +c1 +------------------------------ +Content-Disposition: form-data; name="field1" + +dummy +------------------------------ +Content-Disposition: form-data; name="field2" + + +5 +dummy +91 + +------------------------------ +Content-Disposition: form-data; name="field3"; filename="file668.txt" +Content-Type: text/plain + + +49 +This is data from a file + +-------------------------------- + +0 + + + + diff --git a/release/src/router/curl/tests/data/test670 b/release/src/router/curl/tests/data/test670 new file mode 100644 index 00000000000..19a51a4e08f --- /dev/null +++ b/release/src/router/curl/tests/data/test670 @@ -0,0 +1,72 @@ + + + +HTTP +HTTP POST +MIME + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib670 + + + +Request pause from mime read callback: multi + + +http://%HOSTIP:%HTTPPORT/670 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + + +POST /670 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 142 +Content-Type: multipart/form-data; boundary=---------------------------- + +------------------------------ +Content-Disposition: form-data; name="field" + +AB +-------------------------------- + + + diff --git a/release/src/router/curl/tests/data/test671 b/release/src/router/curl/tests/data/test671 new file mode 100644 index 00000000000..eada50a6e80 --- /dev/null +++ b/release/src/router/curl/tests/data/test671 @@ -0,0 +1,72 @@ + + + +HTTP +HTTP POST +MIME + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib671 + + + +Request pause from mime read callback: easy + + +http://%HOSTIP:%HTTPPORT/671 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + + +POST /671 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 142 +Content-Type: multipart/form-data; boundary=---------------------------- + +------------------------------ +Content-Disposition: form-data; name="field" + +AB +-------------------------------- + + + diff --git a/release/src/router/curl/tests/data/test672 b/release/src/router/curl/tests/data/test672 new file mode 100644 index 00000000000..9c5f24556de --- /dev/null +++ b/release/src/router/curl/tests/data/test672 @@ -0,0 +1,72 @@ + + + +HTTP +HTTP POST +FORM + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib672 + + + +Request pause from form read callback: multi + + +http://%HOSTIP:%HTTPPORT/672 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + + +POST /672 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 142 +Content-Type: multipart/form-data; boundary=---------------------------- + +------------------------------ +Content-Disposition: form-data; name="field" + +AB +-------------------------------- + + + diff --git a/release/src/router/curl/tests/data/test673 b/release/src/router/curl/tests/data/test673 new file mode 100644 index 00000000000..efed2727b66 --- /dev/null +++ b/release/src/router/curl/tests/data/test673 @@ -0,0 +1,72 @@ + + + +HTTP +HTTP POST +FORM + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake swsclose +Connection: close +Content-Type: text/html + +hello + + + +# Client-side + + +http + +# tool is what to use instead of 'curl' + +lib673 + + + +Request pause from form read callback: easy + + +http://%HOSTIP:%HTTPPORT/673 + + + +# +# Verify data after the test has been "shot" + + +s/^--------------------------[a-z0-9]*/------------------------------/ +s/boundary=------------------------[a-z0-9]*/boundary=----------------------------/ + + +POST /673 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* +Content-Length: 142 +Content-Type: multipart/form-data; boundary=---------------------------- + +------------------------------ +Content-Disposition: form-data; name="field" + +AB +-------------------------------- + + + diff --git a/release/src/router/curl/tests/data/test894 b/release/src/router/curl/tests/data/test894 new file mode 100644 index 00000000000..db79830cada --- /dev/null +++ b/release/src/router/curl/tests/data/test894 @@ -0,0 +1,37 @@ + + + +POP3 +Clear Text +RETR + + + +# +# Server-side + + + +# +# Client-side + + +pop3 + + +POP3 with CR in username + + +pop3://user%0dFRIGGING_cmd:secret@%HOSTIP:%POP3PORT/894 + + + +# +# Verify data after the test has been "shot" + +# malformed URL + +3 + + + diff --git a/release/src/router/curl/tests/data/test923 b/release/src/router/curl/tests/data/test923 index cb811bb0efe..9d9722f9aaa 100644 --- a/release/src/router/curl/tests/data/test923 +++ b/release/src/router/curl/tests/data/test923 @@ -9,9 +9,6 @@ VRFY # # Server-side - -250 - # diff --git a/release/src/router/curl/tests/data/test955 b/release/src/router/curl/tests/data/test955 new file mode 100644 index 00000000000..57d618c7d38 --- /dev/null +++ b/release/src/router/curl/tests/data/test955 @@ -0,0 +1,56 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support - UTF-8 based sender (local part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/955 --mail-rcpt recipient@example.com --mail-from Avsändaren@example.com -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 955 +MAIL FROM: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test956 b/release/src/router/curl/tests/data/test956 new file mode 100644 index 00000000000..7fc9bc9afb3 --- /dev/null +++ b/release/src/router/curl/tests/data/test956 @@ -0,0 +1,57 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support - UTF-8 based recipient (local part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/956 --mail-rcpt Stödmottagaren@example.com --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 956 +MAIL FROM: +RCPT TO: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test957 b/release/src/router/curl/tests/data/test957 new file mode 100644 index 00000000000..28c9c478a2c --- /dev/null +++ b/release/src/router/curl/tests/data/test957 @@ -0,0 +1,51 @@ + + + +SMTP +VRFY + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP VRFY without SMTPUTF8 support - UTF-8 based recipient (local part only) + + +smtp://%HOSTIP:%SMTPPORT/957 --mail-rcpt Användaren + + + +# +# Verify data after the test has been "shot" + +# 56 - CURLE_RECV_ERROR + +56 + + +EHLO 957 +VRFY Användaren +QUIT + + + diff --git a/release/src/router/curl/tests/data/test958 b/release/src/router/curl/tests/data/test958 new file mode 100644 index 00000000000..66ba414cbba --- /dev/null +++ b/release/src/router/curl/tests/data/test958 @@ -0,0 +1,51 @@ + + + +SMTP +VRFY + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP external VRFY without SMTPUTF8 support - UTF-8 based recipient (local part only) + + +smtp://%HOSTIP:%SMTPPORT/958 --mail-rcpt Användaren@example.com + + + +# +# Verify data after the test has been "shot" + +# 56 - CURLE_RECV_ERROR + +56 + + +EHLO 958 +VRFY Användaren@example.com +QUIT + + + diff --git a/release/src/router/curl/tests/data/test959 b/release/src/router/curl/tests/data/test959 new file mode 100644 index 00000000000..a61c3d14294 --- /dev/null +++ b/release/src/router/curl/tests/data/test959 @@ -0,0 +1,57 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support - UTF-8 based sender (host part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/959 --mail-rcpt recipient@example.com --mail-from sender@åäö.se -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 959 +MAIL FROM: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test960 b/release/src/router/curl/tests/data/test960 new file mode 100644 index 00000000000..32834cda086 --- /dev/null +++ b/release/src/router/curl/tests/data/test960 @@ -0,0 +1,58 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support - UTF-8 based recipient (host part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/960 --mail-rcpt recipient@åäö.se --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + +# 55 - CURLE_SEND_ERROR + +55 + + +EHLO 960 +MAIL FROM: +RCPT TO: +QUIT + + + diff --git a/release/src/router/curl/tests/data/test961 b/release/src/router/curl/tests/data/test961 new file mode 100644 index 00000000000..2148a0ce551 --- /dev/null +++ b/release/src/router/curl/tests/data/test961 @@ -0,0 +1,52 @@ + + + +SMTP +VRFY + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +!idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP external VRFY without SMTPUTF8 support - UTF-8 based recipient (host part only) + + +smtp://%HOSTIP:%SMTPPORT/961 --mail-rcpt user@åäö.se + + + +# +# Verify data after the test has been "shot" + +# 56 - CURLE_RECV_ERROR + +56 + + +EHLO 961 +VRFY user@åäö.se +QUIT + + + diff --git a/release/src/router/curl/tests/data/test962 b/release/src/router/curl/tests/data/test962 new file mode 100644 index 00000000000..35b368cfd06 --- /dev/null +++ b/release/src/router/curl/tests/data/test962 @@ -0,0 +1,63 @@ + + + +SMTP +IDN + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support - UTF-8 based sender (host part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/962 --mail-rcpt recipient@example.com --mail-from sender@åäö.se -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 962 +MAIL FROM: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test963 b/release/src/router/curl/tests/data/test963 new file mode 100644 index 00000000000..7ea121507df --- /dev/null +++ b/release/src/router/curl/tests/data/test963 @@ -0,0 +1,63 @@ + + + +SMTP +IDN + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP without SMTPUTF8 support (IDN Enabked) - UTF-8 based recipient (host part only) + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/963 --mail-rcpt recipient@åäö.se --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 963 +MAIL FROM: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test964 b/release/src/router/curl/tests/data/test964 new file mode 100644 index 00000000000..5448d0f2109 --- /dev/null +++ b/release/src/router/curl/tests/data/test964 @@ -0,0 +1,49 @@ + + + +SMTP +VRFY +IDN + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP external VRFY without SMTPUTF8 support (IDN Enabled) - UTF-8 based recipient (host part only) + + +smtp://%HOSTIP:%SMTPPORT/964 --mail-rcpt user@åäö.se + + + +# +# Verify data after the test has been "shot" + + +EHLO 964 +VRFY user@xn--4cab6c.se +QUIT + + + diff --git a/release/src/router/curl/tests/data/test965 b/release/src/router/curl/tests/data/test965 new file mode 100644 index 00000000000..8c93bc0c854 --- /dev/null +++ b/release/src/router/curl/tests/data/test965 @@ -0,0 +1,66 @@ + + + +SMTP +IDN + + + +# +# Server-side + + +CAPA SMTPUTF8 + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP with SMTPUTF8 support - UTF-8 based sender + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/965 --mail-rcpt recipient@example.com --mail-from Avsändaren@åäö.se -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 965 +MAIL FROM: SMTPUTF8 +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test966 b/release/src/router/curl/tests/data/test966 new file mode 100644 index 00000000000..499fdda612a --- /dev/null +++ b/release/src/router/curl/tests/data/test966 @@ -0,0 +1,66 @@ + + + +SMTP +IDN + + + +# +# Server-side + + +CAPA SMTPUTF8 + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP with SMTPUTF8 support - UTF-8 based recipient + + +From: different +To: another + +body + + +smtp://%HOSTIP:%SMTPPORT/966 --mail-rcpt Stödmottagaren@åäö.se --mail-from sender@example.com -T - + + + +# +# Verify data after the test has been "shot" + + +EHLO 966 +MAIL FROM: SMTPUTF8 +RCPT TO: +DATA +QUIT + + +From: different +To: another + +body +. + + + diff --git a/release/src/router/curl/tests/data/test967 b/release/src/router/curl/tests/data/test967 new file mode 100644 index 00000000000..2813f508ba1 --- /dev/null +++ b/release/src/router/curl/tests/data/test967 @@ -0,0 +1,55 @@ + + + +SMTP +VRFY +IDN + + + +# +# Server-side + + +CAPA SMTPUTF8 + + +252 Send some mail and I'll try my best + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP external VRFY with SMTPUTF8 support + + +smtp://%HOSTIP:%SMTPPORT/967 --mail-rcpt Användaren@åäö.se + + + +# +# Verify data after the test has been "shot" + + +EHLO 967 +VRFY Användaren@xn--4cab6c.se SMTPUTF8 +QUIT + + + diff --git a/release/src/router/curl/tests/data/test968 b/release/src/router/curl/tests/data/test968 new file mode 100644 index 00000000000..ca58970c280 --- /dev/null +++ b/release/src/router/curl/tests/data/test968 @@ -0,0 +1,52 @@ + + + +SMTP +VRFY +IDN + + + +# +# Server-side + + +CAPA SMTPUTF8 + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +LC_ALL=en_US.UTF-8 +LC_CTYPE=en_US.UTF-8 + + +perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' + + +SMTP VRFY with SMTPUTF8 support + + +smtp://%HOSTIP:%SMTPPORT/968 --mail-rcpt Användaren + + + +# +# Verify data after the test has been "shot" + + +EHLO 968 +VRFY Användaren SMTPUTF8 +QUIT + + + diff --git a/release/src/router/curl/tests/data/test969 b/release/src/router/curl/tests/data/test969 new file mode 100644 index 00000000000..9d3fa93e8eb --- /dev/null +++ b/release/src/router/curl/tests/data/test969 @@ -0,0 +1,51 @@ + + + +SMTP +EXPN +CUSTOMREQUEST +IDN + + + +# +# Server-side + + +CAPA SMTPUTF8 + + +250-Joe Smith +250-Harry Smith +250 Melvin Smith + + + +# +# Client-side + + +smtp + + +idn +!win32 + + +SMTP mailing list EXPN (CUSTOMREQUEST) with SMTPUTF8 support + + +smtp://%HOSTIP:%SMTPPORT/969 --mail-rcpt Friends -X EXPN + + + +# +# Verify data after the test has been "shot" + + +EHLO 969 +EXPN Friends SMTPUTF8 +QUIT + + + diff --git a/release/src/router/curl/tests/ftp.pm b/release/src/router/curl/tests/ftp.pm index f4a4acedd43..5e92ce7f94b 100644 --- a/release/src/router/curl/tests/ftp.pm +++ b/release/src/router/curl/tests/ftp.pm @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -20,6 +20,19 @@ # ########################################################################### +BEGIN { + # portable sleeping needs Time::HiRes + eval { + no warnings "all"; + require Time::HiRes; + }; + # portable sleeping falls back to native Sleep on Win32 + eval { + no warnings "all"; + require Win32; + } +} + use strict; use warnings; @@ -29,6 +42,27 @@ use serverhelp qw( datasockf_pidfilename ); +####################################################################### +# portable_sleep uses Time::HiRes::sleep if available and falls back +# to the classic approach of using select(undef, undef, undef, ...). +# even though that one is not portable due to being implemented using +# select on Windows: https://perldoc.perl.org/perlport.html#select +# On Windows it also just uses full-second sleep for waits >1 second. +# +sub portable_sleep { + my ($seconds) = @_; + + if($Time::HiRes::VERSION) { + Time::HiRes::sleep($seconds); + } + elsif ($^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys') { + Win32::Sleep($seconds*1000); + } + else { + select(undef, undef, undef, $seconds); + } +} + ####################################################################### # pidfromfile returns the pid stored in the given pidfile. The value # of the returned pid will never be a negative value. It will be zero @@ -216,7 +250,7 @@ sub killpid { } } last if(not scalar(@signalled)); - select(undef, undef, undef, 0.05); + portable_sleep(0.05); } } diff --git a/release/src/router/curl/tests/ftpserver.pl b/release/src/router/curl/tests/ftpserver.pl index ac02722e955..431bd258627 100755 --- a/release/src/router/curl/tests/ftpserver.pl +++ b/release/src/router/curl/tests/ftpserver.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -493,7 +493,7 @@ sub sendcontrol { for(@a) { sockfilt $_; - select(undef, undef, undef, 0.01); + portable_sleep(0.01); } } my $log; @@ -530,7 +530,7 @@ sub senddata { # pause between each byte for (split(//,$l)) { sockfiltsecondary $_; - select(undef, undef, undef, 0.01); + portable_sleep(0.01); } } } @@ -813,6 +813,7 @@ sub MAIL_smtp { else { my $from; my $size; + my $smtputf8 = grep /^SMTPUTF8$/, @capabilities; my @elements = split(/ /, $args); # Get the FROM and SIZE parameters @@ -827,11 +828,11 @@ sub MAIL_smtp { # Validate the from address (only <> and a valid email address inside # <> are allowed, such as ) - if ((!$from) || (($from ne "<>") && ($from !~ - /^<([a-zA-Z0-9._%+-]+)\@([a-zA-Z0-9.-]+).([a-zA-Z]{2,4})>$/))) { - sendcontrol "501 Invalid address\r\n"; - } - else { + if (($from eq "<>") || + (!$smtputf8 && $from =~ + /^<([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})>$/) || + ($smtputf8 && $from =~ + /^<([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4})>$/)) { my @found; my $valid = 1; @@ -852,6 +853,9 @@ sub MAIL_smtp { sendcontrol "250 Sender OK\r\n"; } } + else { + sendcontrol "501 Invalid address\r\n"; + } } return 0; @@ -867,16 +871,19 @@ sub RCPT_smtp { sendcontrol "501 Unrecognized parameter\r\n"; } else { + my $smtputf8 = grep /^SMTPUTF8$/, @capabilities; my $to = $1; # Validate the to address (only a valid email address inside <> is # allowed, such as ) - if ($to !~ - /^<([a-zA-Z0-9._%+-]+)\@([a-zA-Z0-9.-]+).([a-zA-Z]{2,4})>$/) { - sendcontrol "501 Invalid address\r\n"; + if ((!$smtputf8 && $to =~ + /^<([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})>$/) || + ($smtputf8 && $to =~ + /^<([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4})>$/)) { + sendcontrol "250 Recipient OK\r\n"; } else { - sendcontrol "250 Recipient OK\r\n"; + sendcontrol "501 Invalid address\r\n"; } } @@ -1030,10 +1037,33 @@ sub VRFY_smtp { sendcontrol "501 Unrecognized parameter\r\n"; } else { - my @data = getreplydata($smtp_client); + my $smtputf8 = grep /^SMTPUTF8$/, @capabilities; - for my $d (@data) { - sendcontrol $d; + # Validate the username (only a valid local or external username is + # allowed, such as user or user@example.com) + if ((!$smtputf8 && $username =~ + /^([a-zA-Z0-9._%+-]+)(\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4}))?$/) || + ($smtputf8 && $username =~ + /^([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)(\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4}))?$/)) { + + my @data = getreplydata($smtp_client); + + if(!@data) { + if ($username !~ + /^([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})$/) { + push @data, "250 <$username\@example.com>\r\n" + } + else { + push @data, "250 <$username>\r\n" + } + } + + for my $d (@data) { + sendcontrol $d; + } + } + else { + sendcontrol "501 Invalid address\r\n"; } } @@ -3169,7 +3199,7 @@ sub customize { logmsg("Sleep for $delay seconds\n"); my $twentieths = $delay * 20; while($twentieths--) { - select(undef, undef, undef, 0.05) unless($got_exit_signal); + portable_sleep(0.05) unless($got_exit_signal); } } diff --git a/release/src/router/curl/tests/libtest/Makefile.in b/release/src/router/curl/tests/libtest/Makefile.in index 684f2813946..f9f2c27795a 100644 --- a/release/src/router/curl/tests/libtest/Makefile.in +++ b/release/src/router/curl/tests/libtest/Makefile.in @@ -121,27 +121,30 @@ noinst_PROGRAMS = chkhostname$(EXEEXT) libauthretry$(EXEEXT) \ lib650$(EXEEXT) lib651$(EXEEXT) lib652$(EXEEXT) \ lib653$(EXEEXT) lib654$(EXEEXT) lib655$(EXEEXT) \ lib658$(EXEEXT) lib659$(EXEEXT) lib661$(EXEEXT) \ - lib1156$(EXEEXT) lib1500$(EXEEXT) lib1501$(EXEEXT) \ - lib1502$(EXEEXT) lib1503$(EXEEXT) lib1504$(EXEEXT) \ - lib1505$(EXEEXT) lib1506$(EXEEXT) lib1507$(EXEEXT) \ - lib1508$(EXEEXT) lib1509$(EXEEXT) lib1510$(EXEEXT) \ - lib1511$(EXEEXT) lib1512$(EXEEXT) lib1513$(EXEEXT) \ - lib1514$(EXEEXT) lib1515$(EXEEXT) lib1517$(EXEEXT) \ - lib1518$(EXEEXT) lib1520$(EXEEXT) lib1521$(EXEEXT) \ - lib1522$(EXEEXT) lib1523$(EXEEXT) lib1525$(EXEEXT) \ - lib1526$(EXEEXT) lib1527$(EXEEXT) lib1528$(EXEEXT) \ - lib1529$(EXEEXT) lib1530$(EXEEXT) lib1531$(EXEEXT) \ - lib1532$(EXEEXT) lib1533$(EXEEXT) lib1534$(EXEEXT) \ - lib1535$(EXEEXT) lib1536$(EXEEXT) lib1537$(EXEEXT) \ - lib1538$(EXEEXT) lib1540$(EXEEXT) lib1541$(EXEEXT) \ - lib1550$(EXEEXT) lib1551$(EXEEXT) lib1552$(EXEEXT) \ - lib1553$(EXEEXT) lib1554$(EXEEXT) lib1555$(EXEEXT) \ - lib1556$(EXEEXT) lib1557$(EXEEXT) lib1558$(EXEEXT) \ - lib1559$(EXEEXT) lib1560$(EXEEXT) lib1564$(EXEEXT) \ - lib1565$(EXEEXT) lib1591$(EXEEXT) lib1592$(EXEEXT) \ - lib1593$(EXEEXT) lib1594$(EXEEXT) lib1596$(EXEEXT) \ - lib1900$(EXEEXT) lib1905$(EXEEXT) lib1906$(EXEEXT) \ - lib1907$(EXEEXT) lib2033$(EXEEXT) + lib666$(EXEEXT) lib667$(EXEEXT) lib668$(EXEEXT) \ + lib670$(EXEEXT) lib671$(EXEEXT) lib672$(EXEEXT) \ + lib673$(EXEEXT) lib1156$(EXEEXT) lib1500$(EXEEXT) \ + lib1501$(EXEEXT) lib1502$(EXEEXT) lib1503$(EXEEXT) \ + lib1504$(EXEEXT) lib1505$(EXEEXT) lib1506$(EXEEXT) \ + lib1507$(EXEEXT) lib1508$(EXEEXT) lib1509$(EXEEXT) \ + lib1510$(EXEEXT) lib1511$(EXEEXT) lib1512$(EXEEXT) \ + lib1513$(EXEEXT) lib1514$(EXEEXT) lib1515$(EXEEXT) \ + lib1517$(EXEEXT) lib1518$(EXEEXT) lib1520$(EXEEXT) \ + lib1521$(EXEEXT) lib1522$(EXEEXT) lib1523$(EXEEXT) \ + lib1525$(EXEEXT) lib1526$(EXEEXT) lib1527$(EXEEXT) \ + lib1528$(EXEEXT) lib1529$(EXEEXT) lib1530$(EXEEXT) \ + lib1531$(EXEEXT) lib1532$(EXEEXT) lib1533$(EXEEXT) \ + lib1534$(EXEEXT) lib1535$(EXEEXT) lib1536$(EXEEXT) \ + lib1537$(EXEEXT) lib1538$(EXEEXT) lib1540$(EXEEXT) \ + lib1541$(EXEEXT) lib1550$(EXEEXT) lib1551$(EXEEXT) \ + lib1552$(EXEEXT) lib1553$(EXEEXT) lib1554$(EXEEXT) \ + lib1555$(EXEEXT) lib1556$(EXEEXT) lib1557$(EXEEXT) \ + lib1558$(EXEEXT) lib1559$(EXEEXT) lib1560$(EXEEXT) \ + lib1564$(EXEEXT) lib1565$(EXEEXT) lib1591$(EXEEXT) \ + lib1592$(EXEEXT) lib1593$(EXEEXT) lib1594$(EXEEXT) \ + lib1596$(EXEEXT) lib1900$(EXEEXT) lib1905$(EXEEXT) \ + lib1906$(EXEEXT) lib1907$(EXEEXT) lib1908$(EXEEXT) \ + lib2033$(EXEEXT) @USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_1 = -DCURL_STATICLIB @CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_2 = -no-undefined @CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_3 = -mimpure-text @@ -608,533 +611,587 @@ am_lib1907_OBJECTS = lib1907-lib1907.$(OBJEXT) $(am__objects_148) \ $(am__objects_149) $(am__objects_150) lib1907_OBJECTS = $(am_lib1907_OBJECTS) lib1907_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_151 = lib2033-first.$(OBJEXT) -am__objects_152 = lib2033-testutil.$(OBJEXT) -am__objects_153 = ../../lib/lib2033-warnless.$(OBJEXT) +am__objects_151 = lib1908-first.$(OBJEXT) +am__objects_152 = lib1908-testutil.$(OBJEXT) +am__objects_153 = ../../lib/lib1908-warnless.$(OBJEXT) +am_lib1908_OBJECTS = lib1908-lib1908.$(OBJEXT) $(am__objects_151) \ + $(am__objects_152) $(am__objects_153) +lib1908_OBJECTS = $(am_lib1908_OBJECTS) +lib1908_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_154 = lib2033-first.$(OBJEXT) +am__objects_155 = lib2033-testutil.$(OBJEXT) +am__objects_156 = ../../lib/lib2033-warnless.$(OBJEXT) am_lib2033_OBJECTS = lib2033-libntlmconnect.$(OBJEXT) \ - $(am__objects_151) $(am__objects_152) $(am__objects_153) + $(am__objects_154) $(am__objects_155) $(am__objects_156) lib2033_OBJECTS = $(am_lib2033_OBJECTS) lib2033_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_154 = lib500-first.$(OBJEXT) -am__objects_155 = lib500-testutil.$(OBJEXT) -am__objects_156 = lib500-testtrace.$(OBJEXT) -am_lib500_OBJECTS = lib500-lib500.$(OBJEXT) $(am__objects_154) \ - $(am__objects_155) $(am__objects_156) +am__objects_157 = lib500-first.$(OBJEXT) +am__objects_158 = lib500-testutil.$(OBJEXT) +am__objects_159 = lib500-testtrace.$(OBJEXT) +am_lib500_OBJECTS = lib500-lib500.$(OBJEXT) $(am__objects_157) \ + $(am__objects_158) $(am__objects_159) lib500_OBJECTS = $(am_lib500_OBJECTS) lib500_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_157 = lib501-first.$(OBJEXT) -am_lib501_OBJECTS = lib501-lib501.$(OBJEXT) $(am__objects_157) +am__objects_160 = lib501-first.$(OBJEXT) +am_lib501_OBJECTS = lib501-lib501.$(OBJEXT) $(am__objects_160) lib501_OBJECTS = $(am_lib501_OBJECTS) lib501_LDADD = $(LDADD) lib501_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_158 = lib502-first.$(OBJEXT) -am__objects_159 = lib502-testutil.$(OBJEXT) -am__objects_160 = ../../lib/lib502-warnless.$(OBJEXT) -am_lib502_OBJECTS = lib502-lib502.$(OBJEXT) $(am__objects_158) \ - $(am__objects_159) $(am__objects_160) +am__objects_161 = lib502-first.$(OBJEXT) +am__objects_162 = lib502-testutil.$(OBJEXT) +am__objects_163 = ../../lib/lib502-warnless.$(OBJEXT) +am_lib502_OBJECTS = lib502-lib502.$(OBJEXT) $(am__objects_161) \ + $(am__objects_162) $(am__objects_163) lib502_OBJECTS = $(am_lib502_OBJECTS) lib502_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_161 = lib503-first.$(OBJEXT) -am__objects_162 = lib503-testutil.$(OBJEXT) -am__objects_163 = ../../lib/lib503-warnless.$(OBJEXT) -am_lib503_OBJECTS = lib503-lib503.$(OBJEXT) $(am__objects_161) \ - $(am__objects_162) $(am__objects_163) +am__objects_164 = lib503-first.$(OBJEXT) +am__objects_165 = lib503-testutil.$(OBJEXT) +am__objects_166 = ../../lib/lib503-warnless.$(OBJEXT) +am_lib503_OBJECTS = lib503-lib503.$(OBJEXT) $(am__objects_164) \ + $(am__objects_165) $(am__objects_166) lib503_OBJECTS = $(am_lib503_OBJECTS) lib503_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_164 = lib504-first.$(OBJEXT) -am__objects_165 = lib504-testutil.$(OBJEXT) -am__objects_166 = ../../lib/lib504-warnless.$(OBJEXT) -am_lib504_OBJECTS = lib504-lib504.$(OBJEXT) $(am__objects_164) \ - $(am__objects_165) $(am__objects_166) +am__objects_167 = lib504-first.$(OBJEXT) +am__objects_168 = lib504-testutil.$(OBJEXT) +am__objects_169 = ../../lib/lib504-warnless.$(OBJEXT) +am_lib504_OBJECTS = lib504-lib504.$(OBJEXT) $(am__objects_167) \ + $(am__objects_168) $(am__objects_169) lib504_OBJECTS = $(am_lib504_OBJECTS) lib504_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_167 = lib505-first.$(OBJEXT) -am_lib505_OBJECTS = lib505-lib505.$(OBJEXT) $(am__objects_167) +am__objects_170 = lib505-first.$(OBJEXT) +am_lib505_OBJECTS = lib505-lib505.$(OBJEXT) $(am__objects_170) lib505_OBJECTS = $(am_lib505_OBJECTS) lib505_LDADD = $(LDADD) lib505_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_168 = lib506-first.$(OBJEXT) -am_lib506_OBJECTS = lib506-lib506.$(OBJEXT) $(am__objects_168) +am__objects_171 = lib506-first.$(OBJEXT) +am_lib506_OBJECTS = lib506-lib506.$(OBJEXT) $(am__objects_171) lib506_OBJECTS = $(am_lib506_OBJECTS) lib506_LDADD = $(LDADD) lib506_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_169 = lib507-first.$(OBJEXT) -am__objects_170 = lib507-testutil.$(OBJEXT) -am__objects_171 = ../../lib/lib507-warnless.$(OBJEXT) -am_lib507_OBJECTS = lib507-lib507.$(OBJEXT) $(am__objects_169) \ - $(am__objects_170) $(am__objects_171) +am__objects_172 = lib507-first.$(OBJEXT) +am__objects_173 = lib507-testutil.$(OBJEXT) +am__objects_174 = ../../lib/lib507-warnless.$(OBJEXT) +am_lib507_OBJECTS = lib507-lib507.$(OBJEXT) $(am__objects_172) \ + $(am__objects_173) $(am__objects_174) lib507_OBJECTS = $(am_lib507_OBJECTS) lib507_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_172 = lib508-first.$(OBJEXT) -am_lib508_OBJECTS = lib508-lib508.$(OBJEXT) $(am__objects_172) +am__objects_175 = lib508-first.$(OBJEXT) +am_lib508_OBJECTS = lib508-lib508.$(OBJEXT) $(am__objects_175) lib508_OBJECTS = $(am_lib508_OBJECTS) lib508_LDADD = $(LDADD) lib508_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_173 = lib509-first.$(OBJEXT) -am_lib509_OBJECTS = lib509-lib509.$(OBJEXT) $(am__objects_173) +am__objects_176 = lib509-first.$(OBJEXT) +am_lib509_OBJECTS = lib509-lib509.$(OBJEXT) $(am__objects_176) lib509_OBJECTS = $(am_lib509_OBJECTS) lib509_LDADD = $(LDADD) lib509_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_174 = lib510-first.$(OBJEXT) -am_lib510_OBJECTS = lib510-lib510.$(OBJEXT) $(am__objects_174) +am__objects_177 = lib510-first.$(OBJEXT) +am_lib510_OBJECTS = lib510-lib510.$(OBJEXT) $(am__objects_177) lib510_OBJECTS = $(am_lib510_OBJECTS) lib510_LDADD = $(LDADD) lib510_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_175 = lib511-first.$(OBJEXT) -am_lib511_OBJECTS = lib511-lib511.$(OBJEXT) $(am__objects_175) +am__objects_178 = lib511-first.$(OBJEXT) +am_lib511_OBJECTS = lib511-lib511.$(OBJEXT) $(am__objects_178) lib511_OBJECTS = $(am_lib511_OBJECTS) lib511_LDADD = $(LDADD) lib511_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_176 = lib512-first.$(OBJEXT) -am_lib512_OBJECTS = lib512-lib512.$(OBJEXT) $(am__objects_176) +am__objects_179 = lib512-first.$(OBJEXT) +am_lib512_OBJECTS = lib512-lib512.$(OBJEXT) $(am__objects_179) lib512_OBJECTS = $(am_lib512_OBJECTS) lib512_LDADD = $(LDADD) lib512_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_177 = lib513-first.$(OBJEXT) -am_lib513_OBJECTS = lib513-lib513.$(OBJEXT) $(am__objects_177) +am__objects_180 = lib513-first.$(OBJEXT) +am_lib513_OBJECTS = lib513-lib513.$(OBJEXT) $(am__objects_180) lib513_OBJECTS = $(am_lib513_OBJECTS) lib513_LDADD = $(LDADD) lib513_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_178 = lib514-first.$(OBJEXT) -am_lib514_OBJECTS = lib514-lib514.$(OBJEXT) $(am__objects_178) +am__objects_181 = lib514-first.$(OBJEXT) +am_lib514_OBJECTS = lib514-lib514.$(OBJEXT) $(am__objects_181) lib514_OBJECTS = $(am_lib514_OBJECTS) lib514_LDADD = $(LDADD) lib514_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_179 = lib515-first.$(OBJEXT) -am_lib515_OBJECTS = lib515-lib515.$(OBJEXT) $(am__objects_179) +am__objects_182 = lib515-first.$(OBJEXT) +am_lib515_OBJECTS = lib515-lib515.$(OBJEXT) $(am__objects_182) lib515_OBJECTS = $(am_lib515_OBJECTS) lib515_LDADD = $(LDADD) lib515_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_180 = lib516-first.$(OBJEXT) -am_lib516_OBJECTS = lib516-lib516.$(OBJEXT) $(am__objects_180) +am__objects_183 = lib516-first.$(OBJEXT) +am_lib516_OBJECTS = lib516-lib516.$(OBJEXT) $(am__objects_183) lib516_OBJECTS = $(am_lib516_OBJECTS) lib516_LDADD = $(LDADD) lib516_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_181 = lib517-first.$(OBJEXT) -am_lib517_OBJECTS = lib517-lib517.$(OBJEXT) $(am__objects_181) +am__objects_184 = lib517-first.$(OBJEXT) +am_lib517_OBJECTS = lib517-lib517.$(OBJEXT) $(am__objects_184) lib517_OBJECTS = $(am_lib517_OBJECTS) lib517_LDADD = $(LDADD) lib517_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_182 = lib518-first.$(OBJEXT) -am__objects_183 = ../../lib/lib518-warnless.$(OBJEXT) -am_lib518_OBJECTS = lib518-lib518.$(OBJEXT) $(am__objects_182) \ - $(am__objects_183) +am__objects_185 = lib518-first.$(OBJEXT) +am__objects_186 = ../../lib/lib518-warnless.$(OBJEXT) +am_lib518_OBJECTS = lib518-lib518.$(OBJEXT) $(am__objects_185) \ + $(am__objects_186) lib518_OBJECTS = $(am_lib518_OBJECTS) lib518_LDADD = $(LDADD) lib518_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_184 = lib519-first.$(OBJEXT) -am_lib519_OBJECTS = lib519-lib519.$(OBJEXT) $(am__objects_184) +am__objects_187 = lib519-first.$(OBJEXT) +am_lib519_OBJECTS = lib519-lib519.$(OBJEXT) $(am__objects_187) lib519_OBJECTS = $(am_lib519_OBJECTS) lib519_LDADD = $(LDADD) lib519_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_185 = lib520-first.$(OBJEXT) -am_lib520_OBJECTS = lib520-lib520.$(OBJEXT) $(am__objects_185) +am__objects_188 = lib520-first.$(OBJEXT) +am_lib520_OBJECTS = lib520-lib520.$(OBJEXT) $(am__objects_188) lib520_OBJECTS = $(am_lib520_OBJECTS) lib520_LDADD = $(LDADD) lib520_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_186 = lib521-first.$(OBJEXT) -am_lib521_OBJECTS = lib521-lib521.$(OBJEXT) $(am__objects_186) +am__objects_189 = lib521-first.$(OBJEXT) +am_lib521_OBJECTS = lib521-lib521.$(OBJEXT) $(am__objects_189) lib521_OBJECTS = $(am_lib521_OBJECTS) lib521_LDADD = $(LDADD) lib521_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_187 = lib523-first.$(OBJEXT) -am_lib523_OBJECTS = lib523-lib523.$(OBJEXT) $(am__objects_187) +am__objects_190 = lib523-first.$(OBJEXT) +am_lib523_OBJECTS = lib523-lib523.$(OBJEXT) $(am__objects_190) lib523_OBJECTS = $(am_lib523_OBJECTS) lib523_LDADD = $(LDADD) lib523_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_188 = lib524-first.$(OBJEXT) -am_lib524_OBJECTS = lib524-lib524.$(OBJEXT) $(am__objects_188) +am__objects_191 = lib524-first.$(OBJEXT) +am_lib524_OBJECTS = lib524-lib524.$(OBJEXT) $(am__objects_191) lib524_OBJECTS = $(am_lib524_OBJECTS) lib524_LDADD = $(LDADD) lib524_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_189 = lib525-first.$(OBJEXT) -am__objects_190 = lib525-testutil.$(OBJEXT) -am__objects_191 = ../../lib/lib525-warnless.$(OBJEXT) -am_lib525_OBJECTS = lib525-lib525.$(OBJEXT) $(am__objects_189) \ - $(am__objects_190) $(am__objects_191) +am__objects_192 = lib525-first.$(OBJEXT) +am__objects_193 = lib525-testutil.$(OBJEXT) +am__objects_194 = ../../lib/lib525-warnless.$(OBJEXT) +am_lib525_OBJECTS = lib525-lib525.$(OBJEXT) $(am__objects_192) \ + $(am__objects_193) $(am__objects_194) lib525_OBJECTS = $(am_lib525_OBJECTS) lib525_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_192 = lib526-first.$(OBJEXT) -am__objects_193 = lib526-testutil.$(OBJEXT) -am__objects_194 = ../../lib/lib526-warnless.$(OBJEXT) -am_lib526_OBJECTS = lib526-lib526.$(OBJEXT) $(am__objects_192) \ - $(am__objects_193) $(am__objects_194) +am__objects_195 = lib526-first.$(OBJEXT) +am__objects_196 = lib526-testutil.$(OBJEXT) +am__objects_197 = ../../lib/lib526-warnless.$(OBJEXT) +am_lib526_OBJECTS = lib526-lib526.$(OBJEXT) $(am__objects_195) \ + $(am__objects_196) $(am__objects_197) lib526_OBJECTS = $(am_lib526_OBJECTS) lib526_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_195 = lib527-first.$(OBJEXT) -am__objects_196 = lib527-testutil.$(OBJEXT) -am__objects_197 = ../../lib/lib527-warnless.$(OBJEXT) -am_lib527_OBJECTS = lib527-lib526.$(OBJEXT) $(am__objects_195) \ - $(am__objects_196) $(am__objects_197) +am__objects_198 = lib527-first.$(OBJEXT) +am__objects_199 = lib527-testutil.$(OBJEXT) +am__objects_200 = ../../lib/lib527-warnless.$(OBJEXT) +am_lib527_OBJECTS = lib527-lib526.$(OBJEXT) $(am__objects_198) \ + $(am__objects_199) $(am__objects_200) lib527_OBJECTS = $(am_lib527_OBJECTS) lib527_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_198 = lib529-first.$(OBJEXT) -am__objects_199 = lib529-testutil.$(OBJEXT) -am__objects_200 = ../../lib/lib529-warnless.$(OBJEXT) -am_lib529_OBJECTS = lib529-lib525.$(OBJEXT) $(am__objects_198) \ - $(am__objects_199) $(am__objects_200) +am__objects_201 = lib529-first.$(OBJEXT) +am__objects_202 = lib529-testutil.$(OBJEXT) +am__objects_203 = ../../lib/lib529-warnless.$(OBJEXT) +am_lib529_OBJECTS = lib529-lib525.$(OBJEXT) $(am__objects_201) \ + $(am__objects_202) $(am__objects_203) lib529_OBJECTS = $(am_lib529_OBJECTS) lib529_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_201 = lib530-first.$(OBJEXT) -am__objects_202 = lib530-testutil.$(OBJEXT) -am__objects_203 = ../../lib/lib530-warnless.$(OBJEXT) -am_lib530_OBJECTS = lib530-lib530.$(OBJEXT) $(am__objects_201) \ - $(am__objects_202) $(am__objects_203) +am__objects_204 = lib530-first.$(OBJEXT) +am__objects_205 = lib530-testutil.$(OBJEXT) +am__objects_206 = ../../lib/lib530-warnless.$(OBJEXT) +am_lib530_OBJECTS = lib530-lib530.$(OBJEXT) $(am__objects_204) \ + $(am__objects_205) $(am__objects_206) lib530_OBJECTS = $(am_lib530_OBJECTS) lib530_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_204 = lib532-first.$(OBJEXT) -am__objects_205 = lib532-testutil.$(OBJEXT) -am__objects_206 = ../../lib/lib532-warnless.$(OBJEXT) -am_lib532_OBJECTS = lib532-lib526.$(OBJEXT) $(am__objects_204) \ - $(am__objects_205) $(am__objects_206) +am__objects_207 = lib532-first.$(OBJEXT) +am__objects_208 = lib532-testutil.$(OBJEXT) +am__objects_209 = ../../lib/lib532-warnless.$(OBJEXT) +am_lib532_OBJECTS = lib532-lib526.$(OBJEXT) $(am__objects_207) \ + $(am__objects_208) $(am__objects_209) lib532_OBJECTS = $(am_lib532_OBJECTS) lib532_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_207 = lib533-first.$(OBJEXT) -am__objects_208 = lib533-testutil.$(OBJEXT) -am__objects_209 = ../../lib/lib533-warnless.$(OBJEXT) -am_lib533_OBJECTS = lib533-lib533.$(OBJEXT) $(am__objects_207) \ - $(am__objects_208) $(am__objects_209) +am__objects_210 = lib533-first.$(OBJEXT) +am__objects_211 = lib533-testutil.$(OBJEXT) +am__objects_212 = ../../lib/lib533-warnless.$(OBJEXT) +am_lib533_OBJECTS = lib533-lib533.$(OBJEXT) $(am__objects_210) \ + $(am__objects_211) $(am__objects_212) lib533_OBJECTS = $(am_lib533_OBJECTS) lib533_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_210 = lib537-first.$(OBJEXT) -am__objects_211 = ../../lib/lib537-warnless.$(OBJEXT) -am_lib537_OBJECTS = lib537-lib537.$(OBJEXT) $(am__objects_210) \ - $(am__objects_211) +am__objects_213 = lib537-first.$(OBJEXT) +am__objects_214 = ../../lib/lib537-warnless.$(OBJEXT) +am_lib537_OBJECTS = lib537-lib537.$(OBJEXT) $(am__objects_213) \ + $(am__objects_214) lib537_OBJECTS = $(am_lib537_OBJECTS) lib537_LDADD = $(LDADD) lib537_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_212 = lib539-first.$(OBJEXT) -am_lib539_OBJECTS = lib539-lib539.$(OBJEXT) $(am__objects_212) +am__objects_215 = lib539-first.$(OBJEXT) +am_lib539_OBJECTS = lib539-lib539.$(OBJEXT) $(am__objects_215) lib539_OBJECTS = $(am_lib539_OBJECTS) lib539_LDADD = $(LDADD) lib539_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_213 = lib540-first.$(OBJEXT) -am__objects_214 = lib540-testutil.$(OBJEXT) -am__objects_215 = ../../lib/lib540-warnless.$(OBJEXT) -am_lib540_OBJECTS = lib540-lib540.$(OBJEXT) $(am__objects_213) \ - $(am__objects_214) $(am__objects_215) +am__objects_216 = lib540-first.$(OBJEXT) +am__objects_217 = lib540-testutil.$(OBJEXT) +am__objects_218 = ../../lib/lib540-warnless.$(OBJEXT) +am_lib540_OBJECTS = lib540-lib540.$(OBJEXT) $(am__objects_216) \ + $(am__objects_217) $(am__objects_218) lib540_OBJECTS = $(am_lib540_OBJECTS) lib540_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_216 = lib541-first.$(OBJEXT) -am_lib541_OBJECTS = lib541-lib541.$(OBJEXT) $(am__objects_216) +am__objects_219 = lib541-first.$(OBJEXT) +am_lib541_OBJECTS = lib541-lib541.$(OBJEXT) $(am__objects_219) lib541_OBJECTS = $(am_lib541_OBJECTS) lib541_LDADD = $(LDADD) lib541_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_217 = lib542-first.$(OBJEXT) -am_lib542_OBJECTS = lib542-lib542.$(OBJEXT) $(am__objects_217) +am__objects_220 = lib542-first.$(OBJEXT) +am_lib542_OBJECTS = lib542-lib542.$(OBJEXT) $(am__objects_220) lib542_OBJECTS = $(am_lib542_OBJECTS) lib542_LDADD = $(LDADD) lib542_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_218 = lib543-first.$(OBJEXT) -am_lib543_OBJECTS = lib543-lib543.$(OBJEXT) $(am__objects_218) +am__objects_221 = lib543-first.$(OBJEXT) +am_lib543_OBJECTS = lib543-lib543.$(OBJEXT) $(am__objects_221) lib543_OBJECTS = $(am_lib543_OBJECTS) lib543_LDADD = $(LDADD) lib543_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_219 = lib544-first.$(OBJEXT) -am_lib544_OBJECTS = lib544-lib544.$(OBJEXT) $(am__objects_219) +am__objects_222 = lib544-first.$(OBJEXT) +am_lib544_OBJECTS = lib544-lib544.$(OBJEXT) $(am__objects_222) lib544_OBJECTS = $(am_lib544_OBJECTS) lib544_LDADD = $(LDADD) lib544_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_220 = lib545-first.$(OBJEXT) -am_lib545_OBJECTS = lib545-lib544.$(OBJEXT) $(am__objects_220) +am__objects_223 = lib545-first.$(OBJEXT) +am_lib545_OBJECTS = lib545-lib544.$(OBJEXT) $(am__objects_223) lib545_OBJECTS = $(am_lib545_OBJECTS) lib545_LDADD = $(LDADD) lib545_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_221 = lib547-first.$(OBJEXT) -am_lib547_OBJECTS = lib547-lib547.$(OBJEXT) $(am__objects_221) +am__objects_224 = lib547-first.$(OBJEXT) +am_lib547_OBJECTS = lib547-lib547.$(OBJEXT) $(am__objects_224) lib547_OBJECTS = $(am_lib547_OBJECTS) lib547_LDADD = $(LDADD) lib547_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_222 = lib548-first.$(OBJEXT) -am_lib548_OBJECTS = lib548-lib547.$(OBJEXT) $(am__objects_222) +am__objects_225 = lib548-first.$(OBJEXT) +am_lib548_OBJECTS = lib548-lib547.$(OBJEXT) $(am__objects_225) lib548_OBJECTS = $(am_lib548_OBJECTS) lib548_LDADD = $(LDADD) lib548_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_223 = lib549-first.$(OBJEXT) -am_lib549_OBJECTS = lib549-lib549.$(OBJEXT) $(am__objects_223) +am__objects_226 = lib549-first.$(OBJEXT) +am_lib549_OBJECTS = lib549-lib549.$(OBJEXT) $(am__objects_226) lib549_OBJECTS = $(am_lib549_OBJECTS) lib549_LDADD = $(LDADD) lib549_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_224 = lib552-first.$(OBJEXT) -am__objects_225 = ../../lib/lib552-warnless.$(OBJEXT) -am_lib552_OBJECTS = lib552-lib552.$(OBJEXT) $(am__objects_224) \ - $(am__objects_225) +am__objects_227 = lib552-first.$(OBJEXT) +am__objects_228 = ../../lib/lib552-warnless.$(OBJEXT) +am_lib552_OBJECTS = lib552-lib552.$(OBJEXT) $(am__objects_227) \ + $(am__objects_228) lib552_OBJECTS = $(am_lib552_OBJECTS) lib552_LDADD = $(LDADD) lib552_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_226 = lib553-first.$(OBJEXT) -am_lib553_OBJECTS = lib553-lib553.$(OBJEXT) $(am__objects_226) +am__objects_229 = lib553-first.$(OBJEXT) +am_lib553_OBJECTS = lib553-lib553.$(OBJEXT) $(am__objects_229) lib553_OBJECTS = $(am_lib553_OBJECTS) lib553_LDADD = $(LDADD) lib553_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_227 = lib554-first.$(OBJEXT) -am_lib554_OBJECTS = lib554-lib554.$(OBJEXT) $(am__objects_227) +am__objects_230 = lib554-first.$(OBJEXT) +am_lib554_OBJECTS = lib554-lib554.$(OBJEXT) $(am__objects_230) lib554_OBJECTS = $(am_lib554_OBJECTS) lib554_LDADD = $(LDADD) lib554_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_228 = lib555-first.$(OBJEXT) -am__objects_229 = lib555-testutil.$(OBJEXT) -am__objects_230 = ../../lib/lib555-warnless.$(OBJEXT) -am_lib555_OBJECTS = lib555-lib555.$(OBJEXT) $(am__objects_228) \ - $(am__objects_229) $(am__objects_230) +am__objects_231 = lib555-first.$(OBJEXT) +am__objects_232 = lib555-testutil.$(OBJEXT) +am__objects_233 = ../../lib/lib555-warnless.$(OBJEXT) +am_lib555_OBJECTS = lib555-lib555.$(OBJEXT) $(am__objects_231) \ + $(am__objects_232) $(am__objects_233) lib555_OBJECTS = $(am_lib555_OBJECTS) lib555_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_231 = lib556-first.$(OBJEXT) -am__objects_232 = ../../lib/lib556-warnless.$(OBJEXT) -am_lib556_OBJECTS = lib556-lib556.$(OBJEXT) $(am__objects_231) \ - $(am__objects_232) +am__objects_234 = lib556-first.$(OBJEXT) +am__objects_235 = ../../lib/lib556-warnless.$(OBJEXT) +am_lib556_OBJECTS = lib556-lib556.$(OBJEXT) $(am__objects_234) \ + $(am__objects_235) lib556_OBJECTS = $(am_lib556_OBJECTS) lib556_LDADD = $(LDADD) lib556_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_233 = lib557-first.$(OBJEXT) -am_lib557_OBJECTS = lib557-lib557.$(OBJEXT) $(am__objects_233) +am__objects_236 = lib557-first.$(OBJEXT) +am_lib557_OBJECTS = lib557-lib557.$(OBJEXT) $(am__objects_236) lib557_OBJECTS = $(am_lib557_OBJECTS) lib557_LDADD = $(LDADD) lib557_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_234 = lib558-first.$(OBJEXT) -am_lib558_OBJECTS = lib558-lib558.$(OBJEXT) $(am__objects_234) +am__objects_237 = lib558-first.$(OBJEXT) +am_lib558_OBJECTS = lib558-lib558.$(OBJEXT) $(am__objects_237) lib558_OBJECTS = $(am_lib558_OBJECTS) lib558_LDADD = $(LDADD) lib558_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_235 = lib559-first.$(OBJEXT) -am_lib559_OBJECTS = lib559-lib559.$(OBJEXT) $(am__objects_235) +am__objects_238 = lib559-first.$(OBJEXT) +am_lib559_OBJECTS = lib559-lib559.$(OBJEXT) $(am__objects_238) lib559_OBJECTS = $(am_lib559_OBJECTS) lib559_LDADD = $(LDADD) lib559_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_236 = lib560-first.$(OBJEXT) -am__objects_237 = lib560-testutil.$(OBJEXT) -am__objects_238 = ../../lib/lib560-warnless.$(OBJEXT) -am_lib560_OBJECTS = lib560-lib560.$(OBJEXT) $(am__objects_236) \ - $(am__objects_237) $(am__objects_238) +am__objects_239 = lib560-first.$(OBJEXT) +am__objects_240 = lib560-testutil.$(OBJEXT) +am__objects_241 = ../../lib/lib560-warnless.$(OBJEXT) +am_lib560_OBJECTS = lib560-lib560.$(OBJEXT) $(am__objects_239) \ + $(am__objects_240) $(am__objects_241) lib560_OBJECTS = $(am_lib560_OBJECTS) lib560_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_239 = lib562-first.$(OBJEXT) -am_lib562_OBJECTS = lib562-lib562.$(OBJEXT) $(am__objects_239) +am__objects_242 = lib562-first.$(OBJEXT) +am_lib562_OBJECTS = lib562-lib562.$(OBJEXT) $(am__objects_242) lib562_OBJECTS = $(am_lib562_OBJECTS) lib562_LDADD = $(LDADD) lib562_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_240 = lib564-first.$(OBJEXT) -am__objects_241 = lib564-testutil.$(OBJEXT) -am__objects_242 = ../../lib/lib564-warnless.$(OBJEXT) -am_lib564_OBJECTS = lib564-lib564.$(OBJEXT) $(am__objects_240) \ - $(am__objects_241) $(am__objects_242) +am__objects_243 = lib564-first.$(OBJEXT) +am__objects_244 = lib564-testutil.$(OBJEXT) +am__objects_245 = ../../lib/lib564-warnless.$(OBJEXT) +am_lib564_OBJECTS = lib564-lib564.$(OBJEXT) $(am__objects_243) \ + $(am__objects_244) $(am__objects_245) lib564_OBJECTS = $(am_lib564_OBJECTS) lib564_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_243 = lib565-first.$(OBJEXT) -am_lib565_OBJECTS = lib565-lib510.$(OBJEXT) $(am__objects_243) +am__objects_246 = lib565-first.$(OBJEXT) +am_lib565_OBJECTS = lib565-lib510.$(OBJEXT) $(am__objects_246) lib565_OBJECTS = $(am_lib565_OBJECTS) lib565_LDADD = $(LDADD) lib565_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_244 = lib566-first.$(OBJEXT) -am_lib566_OBJECTS = lib566-lib566.$(OBJEXT) $(am__objects_244) +am__objects_247 = lib566-first.$(OBJEXT) +am_lib566_OBJECTS = lib566-lib566.$(OBJEXT) $(am__objects_247) lib566_OBJECTS = $(am_lib566_OBJECTS) lib566_LDADD = $(LDADD) lib566_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_245 = lib567-first.$(OBJEXT) -am_lib567_OBJECTS = lib567-lib567.$(OBJEXT) $(am__objects_245) +am__objects_248 = lib567-first.$(OBJEXT) +am_lib567_OBJECTS = lib567-lib567.$(OBJEXT) $(am__objects_248) lib567_OBJECTS = $(am_lib567_OBJECTS) lib567_LDADD = $(LDADD) lib567_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_246 = lib568-first.$(OBJEXT) -am_lib568_OBJECTS = lib568-lib568.$(OBJEXT) $(am__objects_246) +am__objects_249 = lib568-first.$(OBJEXT) +am_lib568_OBJECTS = lib568-lib568.$(OBJEXT) $(am__objects_249) lib568_OBJECTS = $(am_lib568_OBJECTS) lib568_LDADD = $(LDADD) lib568_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_247 = lib569-first.$(OBJEXT) -am_lib569_OBJECTS = lib569-lib569.$(OBJEXT) $(am__objects_247) +am__objects_250 = lib569-first.$(OBJEXT) +am_lib569_OBJECTS = lib569-lib569.$(OBJEXT) $(am__objects_250) lib569_OBJECTS = $(am_lib569_OBJECTS) lib569_LDADD = $(LDADD) lib569_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_248 = lib570-first.$(OBJEXT) -am_lib570_OBJECTS = lib570-lib570.$(OBJEXT) $(am__objects_248) +am__objects_251 = lib570-first.$(OBJEXT) +am_lib570_OBJECTS = lib570-lib570.$(OBJEXT) $(am__objects_251) lib570_OBJECTS = $(am_lib570_OBJECTS) lib570_LDADD = $(LDADD) lib570_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_249 = lib571-first.$(OBJEXT) -am__objects_250 = ../../lib/lib571-warnless.$(OBJEXT) -am_lib571_OBJECTS = lib571-lib571.$(OBJEXT) $(am__objects_249) \ - $(am__objects_250) +am__objects_252 = lib571-first.$(OBJEXT) +am__objects_253 = ../../lib/lib571-warnless.$(OBJEXT) +am_lib571_OBJECTS = lib571-lib571.$(OBJEXT) $(am__objects_252) \ + $(am__objects_253) lib571_OBJECTS = $(am_lib571_OBJECTS) lib571_LDADD = $(LDADD) lib571_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_251 = lib572-first.$(OBJEXT) -am_lib572_OBJECTS = lib572-lib572.$(OBJEXT) $(am__objects_251) +am__objects_254 = lib572-first.$(OBJEXT) +am_lib572_OBJECTS = lib572-lib572.$(OBJEXT) $(am__objects_254) lib572_OBJECTS = $(am_lib572_OBJECTS) lib572_LDADD = $(LDADD) lib572_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_252 = lib573-first.$(OBJEXT) -am__objects_253 = lib573-testutil.$(OBJEXT) -am__objects_254 = ../../lib/lib573-warnless.$(OBJEXT) -am__objects_255 = lib573-testtrace.$(OBJEXT) -am_lib573_OBJECTS = lib573-lib573.$(OBJEXT) $(am__objects_252) \ - $(am__objects_253) $(am__objects_254) $(am__objects_255) +am__objects_255 = lib573-first.$(OBJEXT) +am__objects_256 = lib573-testutil.$(OBJEXT) +am__objects_257 = ../../lib/lib573-warnless.$(OBJEXT) +am__objects_258 = lib573-testtrace.$(OBJEXT) +am_lib573_OBJECTS = lib573-lib573.$(OBJEXT) $(am__objects_255) \ + $(am__objects_256) $(am__objects_257) $(am__objects_258) lib573_OBJECTS = $(am_lib573_OBJECTS) lib573_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_256 = lib574-first.$(OBJEXT) -am_lib574_OBJECTS = lib574-lib574.$(OBJEXT) $(am__objects_256) +am__objects_259 = lib574-first.$(OBJEXT) +am_lib574_OBJECTS = lib574-lib574.$(OBJEXT) $(am__objects_259) lib574_OBJECTS = $(am_lib574_OBJECTS) lib574_LDADD = $(LDADD) lib574_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_257 = lib575-first.$(OBJEXT) -am__objects_258 = lib575-testutil.$(OBJEXT) -am__objects_259 = ../../lib/lib575-warnless.$(OBJEXT) -am_lib575_OBJECTS = lib575-lib575.$(OBJEXT) $(am__objects_257) \ - $(am__objects_258) $(am__objects_259) +am__objects_260 = lib575-first.$(OBJEXT) +am__objects_261 = lib575-testutil.$(OBJEXT) +am__objects_262 = ../../lib/lib575-warnless.$(OBJEXT) +am_lib575_OBJECTS = lib575-lib575.$(OBJEXT) $(am__objects_260) \ + $(am__objects_261) $(am__objects_262) lib575_OBJECTS = $(am_lib575_OBJECTS) lib575_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_260 = lib576-first.$(OBJEXT) -am_lib576_OBJECTS = lib576-lib576.$(OBJEXT) $(am__objects_260) +am__objects_263 = lib576-first.$(OBJEXT) +am_lib576_OBJECTS = lib576-lib576.$(OBJEXT) $(am__objects_263) lib576_OBJECTS = $(am_lib576_OBJECTS) lib576_LDADD = $(LDADD) lib576_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_261 = lib578-first.$(OBJEXT) -am_lib578_OBJECTS = lib578-lib578.$(OBJEXT) $(am__objects_261) +am__objects_264 = lib578-first.$(OBJEXT) +am_lib578_OBJECTS = lib578-lib578.$(OBJEXT) $(am__objects_264) lib578_OBJECTS = $(am_lib578_OBJECTS) lib578_LDADD = $(LDADD) lib578_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_262 = lib579-first.$(OBJEXT) -am_lib579_OBJECTS = lib579-lib579.$(OBJEXT) $(am__objects_262) +am__objects_265 = lib579-first.$(OBJEXT) +am_lib579_OBJECTS = lib579-lib579.$(OBJEXT) $(am__objects_265) lib579_OBJECTS = $(am_lib579_OBJECTS) lib579_LDADD = $(LDADD) lib579_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_263 = lib582-first.$(OBJEXT) -am__objects_264 = lib582-testutil.$(OBJEXT) -am__objects_265 = ../../lib/lib582-warnless.$(OBJEXT) -am_lib582_OBJECTS = lib582-lib582.$(OBJEXT) $(am__objects_263) \ - $(am__objects_264) $(am__objects_265) +am__objects_266 = lib582-first.$(OBJEXT) +am__objects_267 = lib582-testutil.$(OBJEXT) +am__objects_268 = ../../lib/lib582-warnless.$(OBJEXT) +am_lib582_OBJECTS = lib582-lib582.$(OBJEXT) $(am__objects_266) \ + $(am__objects_267) $(am__objects_268) lib582_OBJECTS = $(am_lib582_OBJECTS) lib582_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_266 = lib583-first.$(OBJEXT) -am_lib583_OBJECTS = lib583-lib583.$(OBJEXT) $(am__objects_266) +am__objects_269 = lib583-first.$(OBJEXT) +am_lib583_OBJECTS = lib583-lib583.$(OBJEXT) $(am__objects_269) lib583_OBJECTS = $(am_lib583_OBJECTS) lib583_LDADD = $(LDADD) lib583_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_267 = lib585-first.$(OBJEXT) -am__objects_268 = lib585-testutil.$(OBJEXT) -am__objects_269 = lib585-testtrace.$(OBJEXT) -am_lib585_OBJECTS = lib585-lib500.$(OBJEXT) $(am__objects_267) \ - $(am__objects_268) $(am__objects_269) +am__objects_270 = lib585-first.$(OBJEXT) +am__objects_271 = lib585-testutil.$(OBJEXT) +am__objects_272 = lib585-testtrace.$(OBJEXT) +am_lib585_OBJECTS = lib585-lib500.$(OBJEXT) $(am__objects_270) \ + $(am__objects_271) $(am__objects_272) lib585_OBJECTS = $(am_lib585_OBJECTS) lib585_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_270 = lib586-first.$(OBJEXT) -am_lib586_OBJECTS = lib586-lib586.$(OBJEXT) $(am__objects_270) +am__objects_273 = lib586-first.$(OBJEXT) +am_lib586_OBJECTS = lib586-lib586.$(OBJEXT) $(am__objects_273) lib586_OBJECTS = $(am_lib586_OBJECTS) lib586_LDADD = $(LDADD) lib586_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_271 = lib587-first.$(OBJEXT) -am_lib587_OBJECTS = lib587-lib554.$(OBJEXT) $(am__objects_271) +am__objects_274 = lib587-first.$(OBJEXT) +am_lib587_OBJECTS = lib587-lib554.$(OBJEXT) $(am__objects_274) lib587_OBJECTS = $(am_lib587_OBJECTS) lib587_LDADD = $(LDADD) lib587_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_272 = lib589-first.$(OBJEXT) -am_lib589_OBJECTS = lib589-lib589.$(OBJEXT) $(am__objects_272) +am__objects_275 = lib589-first.$(OBJEXT) +am_lib589_OBJECTS = lib589-lib589.$(OBJEXT) $(am__objects_275) lib589_OBJECTS = $(am_lib589_OBJECTS) lib589_LDADD = $(LDADD) lib589_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_273 = lib590-first.$(OBJEXT) -am_lib590_OBJECTS = lib590-lib590.$(OBJEXT) $(am__objects_273) +am__objects_276 = lib590-first.$(OBJEXT) +am_lib590_OBJECTS = lib590-lib590.$(OBJEXT) $(am__objects_276) lib590_OBJECTS = $(am_lib590_OBJECTS) lib590_LDADD = $(LDADD) lib590_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_274 = lib591-first.$(OBJEXT) -am__objects_275 = lib591-testutil.$(OBJEXT) -am__objects_276 = ../../lib/lib591-warnless.$(OBJEXT) -am_lib591_OBJECTS = lib591-lib591.$(OBJEXT) $(am__objects_274) \ - $(am__objects_275) $(am__objects_276) +am__objects_277 = lib591-first.$(OBJEXT) +am__objects_278 = lib591-testutil.$(OBJEXT) +am__objects_279 = ../../lib/lib591-warnless.$(OBJEXT) +am_lib591_OBJECTS = lib591-lib591.$(OBJEXT) $(am__objects_277) \ + $(am__objects_278) $(am__objects_279) lib591_OBJECTS = $(am_lib591_OBJECTS) lib591_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_277 = lib597-first.$(OBJEXT) -am__objects_278 = lib597-testutil.$(OBJEXT) -am__objects_279 = ../../lib/lib597-warnless.$(OBJEXT) -am_lib597_OBJECTS = lib597-lib597.$(OBJEXT) $(am__objects_277) \ - $(am__objects_278) $(am__objects_279) +am__objects_280 = lib597-first.$(OBJEXT) +am__objects_281 = lib597-testutil.$(OBJEXT) +am__objects_282 = ../../lib/lib597-warnless.$(OBJEXT) +am_lib597_OBJECTS = lib597-lib597.$(OBJEXT) $(am__objects_280) \ + $(am__objects_281) $(am__objects_282) lib597_OBJECTS = $(am_lib597_OBJECTS) lib597_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_280 = lib598-first.$(OBJEXT) -am_lib598_OBJECTS = lib598-lib598.$(OBJEXT) $(am__objects_280) +am__objects_283 = lib598-first.$(OBJEXT) +am_lib598_OBJECTS = lib598-lib598.$(OBJEXT) $(am__objects_283) lib598_OBJECTS = $(am_lib598_OBJECTS) lib598_LDADD = $(LDADD) lib598_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_281 = lib599-first.$(OBJEXT) -am_lib599_OBJECTS = lib599-lib599.$(OBJEXT) $(am__objects_281) +am__objects_284 = lib599-first.$(OBJEXT) +am_lib599_OBJECTS = lib599-lib599.$(OBJEXT) $(am__objects_284) lib599_OBJECTS = $(am_lib599_OBJECTS) lib599_LDADD = $(LDADD) lib599_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_282 = lib643-first.$(OBJEXT) -am_lib643_OBJECTS = lib643-lib643.$(OBJEXT) $(am__objects_282) +am__objects_285 = lib643-first.$(OBJEXT) +am_lib643_OBJECTS = lib643-lib643.$(OBJEXT) $(am__objects_285) lib643_OBJECTS = $(am_lib643_OBJECTS) lib643_LDADD = $(LDADD) lib643_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_283 = lib644-first.$(OBJEXT) -am_lib644_OBJECTS = lib644-lib643.$(OBJEXT) $(am__objects_283) +am__objects_286 = lib644-first.$(OBJEXT) +am_lib644_OBJECTS = lib644-lib643.$(OBJEXT) $(am__objects_286) lib644_OBJECTS = $(am_lib644_OBJECTS) lib644_LDADD = $(LDADD) lib644_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_284 = lib645-first.$(OBJEXT) -am_lib645_OBJECTS = lib645-lib643.$(OBJEXT) $(am__objects_284) +am__objects_287 = lib645-first.$(OBJEXT) +am_lib645_OBJECTS = lib645-lib643.$(OBJEXT) $(am__objects_287) lib645_OBJECTS = $(am_lib645_OBJECTS) lib645_LDADD = $(LDADD) lib645_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_285 = lib650-first.$(OBJEXT) -am_lib650_OBJECTS = lib650-lib650.$(OBJEXT) $(am__objects_285) +am__objects_288 = lib650-first.$(OBJEXT) +am_lib650_OBJECTS = lib650-lib650.$(OBJEXT) $(am__objects_288) lib650_OBJECTS = $(am_lib650_OBJECTS) lib650_LDADD = $(LDADD) lib650_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_286 = lib651-first.$(OBJEXT) -am_lib651_OBJECTS = lib651-lib651.$(OBJEXT) $(am__objects_286) +am__objects_289 = lib651-first.$(OBJEXT) +am_lib651_OBJECTS = lib651-lib651.$(OBJEXT) $(am__objects_289) lib651_OBJECTS = $(am_lib651_OBJECTS) lib651_LDADD = $(LDADD) lib651_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_287 = lib652-first.$(OBJEXT) -am_lib652_OBJECTS = lib652-lib652.$(OBJEXT) $(am__objects_287) +am__objects_290 = lib652-first.$(OBJEXT) +am_lib652_OBJECTS = lib652-lib652.$(OBJEXT) $(am__objects_290) lib652_OBJECTS = $(am_lib652_OBJECTS) lib652_LDADD = $(LDADD) lib652_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_288 = lib653-first.$(OBJEXT) -am_lib653_OBJECTS = lib653-lib653.$(OBJEXT) $(am__objects_288) +am__objects_291 = lib653-first.$(OBJEXT) +am_lib653_OBJECTS = lib653-lib653.$(OBJEXT) $(am__objects_291) lib653_OBJECTS = $(am_lib653_OBJECTS) lib653_LDADD = $(LDADD) lib653_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_289 = lib654-first.$(OBJEXT) -am_lib654_OBJECTS = lib654-lib654.$(OBJEXT) $(am__objects_289) +am__objects_292 = lib654-first.$(OBJEXT) +am_lib654_OBJECTS = lib654-lib654.$(OBJEXT) $(am__objects_292) lib654_OBJECTS = $(am_lib654_OBJECTS) lib654_LDADD = $(LDADD) lib654_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_290 = lib655-first.$(OBJEXT) -am_lib655_OBJECTS = lib655-lib655.$(OBJEXT) $(am__objects_290) +am__objects_293 = lib655-first.$(OBJEXT) +am_lib655_OBJECTS = lib655-lib655.$(OBJEXT) $(am__objects_293) lib655_OBJECTS = $(am_lib655_OBJECTS) lib655_LDADD = $(LDADD) lib655_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_291 = lib658-first.$(OBJEXT) -am__objects_292 = lib658-testutil.$(OBJEXT) -am__objects_293 = ../../lib/lib658-warnless.$(OBJEXT) -am_lib658_OBJECTS = lib658-lib658.$(OBJEXT) $(am__objects_291) \ - $(am__objects_292) $(am__objects_293) +am__objects_294 = lib658-first.$(OBJEXT) +am__objects_295 = lib658-testutil.$(OBJEXT) +am__objects_296 = ../../lib/lib658-warnless.$(OBJEXT) +am_lib658_OBJECTS = lib658-lib658.$(OBJEXT) $(am__objects_294) \ + $(am__objects_295) $(am__objects_296) lib658_OBJECTS = $(am_lib658_OBJECTS) lib658_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_294 = lib659-first.$(OBJEXT) -am__objects_295 = lib659-testutil.$(OBJEXT) -am__objects_296 = ../../lib/lib659-warnless.$(OBJEXT) -am_lib659_OBJECTS = lib659-lib659.$(OBJEXT) $(am__objects_294) \ - $(am__objects_295) $(am__objects_296) +am__objects_297 = lib659-first.$(OBJEXT) +am__objects_298 = lib659-testutil.$(OBJEXT) +am__objects_299 = ../../lib/lib659-warnless.$(OBJEXT) +am_lib659_OBJECTS = lib659-lib659.$(OBJEXT) $(am__objects_297) \ + $(am__objects_298) $(am__objects_299) lib659_OBJECTS = $(am_lib659_OBJECTS) lib659_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_297 = lib661-first.$(OBJEXT) -am_lib661_OBJECTS = lib661-lib661.$(OBJEXT) $(am__objects_297) +am__objects_300 = lib661-first.$(OBJEXT) +am_lib661_OBJECTS = lib661-lib661.$(OBJEXT) $(am__objects_300) lib661_OBJECTS = $(am_lib661_OBJECTS) lib661_LDADD = $(LDADD) lib661_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_298 = libauthretry-first.$(OBJEXT) +am__objects_301 = lib666-first.$(OBJEXT) +am_lib666_OBJECTS = lib666-lib666.$(OBJEXT) $(am__objects_301) +lib666_OBJECTS = $(am_lib666_OBJECTS) +lib666_LDADD = $(LDADD) +lib666_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_302 = lib667-first.$(OBJEXT) +am__objects_303 = lib667-testutil.$(OBJEXT) +am__objects_304 = ../../lib/lib667-warnless.$(OBJEXT) +am_lib667_OBJECTS = lib667-lib667.$(OBJEXT) $(am__objects_302) \ + $(am__objects_303) $(am__objects_304) +lib667_OBJECTS = $(am_lib667_OBJECTS) +lib667_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_305 = lib668-first.$(OBJEXT) +am__objects_306 = lib668-testutil.$(OBJEXT) +am__objects_307 = ../../lib/lib668-warnless.$(OBJEXT) +am_lib668_OBJECTS = lib668-lib668.$(OBJEXT) $(am__objects_305) \ + $(am__objects_306) $(am__objects_307) +lib668_OBJECTS = $(am_lib668_OBJECTS) +lib668_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_308 = lib670-first.$(OBJEXT) +am__objects_309 = lib670-testutil.$(OBJEXT) +am__objects_310 = ../../lib/lib670-warnless.$(OBJEXT) +am_lib670_OBJECTS = lib670-lib670.$(OBJEXT) $(am__objects_308) \ + $(am__objects_309) $(am__objects_310) +lib670_OBJECTS = $(am_lib670_OBJECTS) +lib670_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_311 = lib671-first.$(OBJEXT) +am__objects_312 = lib671-testutil.$(OBJEXT) +am__objects_313 = ../../lib/lib671-warnless.$(OBJEXT) +am_lib671_OBJECTS = lib671-lib670.$(OBJEXT) $(am__objects_311) \ + $(am__objects_312) $(am__objects_313) +lib671_OBJECTS = $(am_lib671_OBJECTS) +lib671_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_314 = lib672-first.$(OBJEXT) +am__objects_315 = lib672-testutil.$(OBJEXT) +am__objects_316 = ../../lib/lib672-warnless.$(OBJEXT) +am_lib672_OBJECTS = lib672-lib670.$(OBJEXT) $(am__objects_314) \ + $(am__objects_315) $(am__objects_316) +lib672_OBJECTS = $(am_lib672_OBJECTS) +lib672_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_317 = lib673-first.$(OBJEXT) +am__objects_318 = lib673-testutil.$(OBJEXT) +am__objects_319 = ../../lib/lib673-warnless.$(OBJEXT) +am_lib673_OBJECTS = lib673-lib670.$(OBJEXT) $(am__objects_317) \ + $(am__objects_318) $(am__objects_319) +lib673_OBJECTS = $(am_lib673_OBJECTS) +lib673_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_320 = libauthretry-first.$(OBJEXT) am_libauthretry_OBJECTS = libauthretry-libauthretry.$(OBJEXT) \ - $(am__objects_298) + $(am__objects_320) libauthretry_OBJECTS = $(am_libauthretry_OBJECTS) libauthretry_LDADD = $(LDADD) libauthretry_DEPENDENCIES = $(am__DEPENDENCIES_1) -am__objects_299 = libntlmconnect-first.$(OBJEXT) -am__objects_300 = libntlmconnect-testutil.$(OBJEXT) -am__objects_301 = ../../lib/libntlmconnect-warnless.$(OBJEXT) +am__objects_321 = libntlmconnect-first.$(OBJEXT) +am__objects_322 = libntlmconnect-testutil.$(OBJEXT) +am__objects_323 = ../../lib/libntlmconnect-warnless.$(OBJEXT) am_libntlmconnect_OBJECTS = libntlmconnect-libntlmconnect.$(OBJEXT) \ - $(am__objects_299) $(am__objects_300) $(am__objects_301) + $(am__objects_321) $(am__objects_322) $(am__objects_323) libntlmconnect_OBJECTS = $(am_libntlmconnect_OBJECTS) libntlmconnect_DEPENDENCIES = $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) @@ -1200,6 +1257,7 @@ am__depfiles_remade = \ ../../lib/$(DEPDIR)/lib1905-warnless.Po \ ../../lib/$(DEPDIR)/lib1906-warnless.Po \ ../../lib/$(DEPDIR)/lib1907-warnless.Po \ + ../../lib/$(DEPDIR)/lib1908-warnless.Po \ ../../lib/$(DEPDIR)/lib2033-warnless.Po \ ../../lib/$(DEPDIR)/lib502-warnless.Po \ ../../lib/$(DEPDIR)/lib503-warnless.Po \ @@ -1228,6 +1286,12 @@ am__depfiles_remade = \ ../../lib/$(DEPDIR)/lib597-warnless.Po \ ../../lib/$(DEPDIR)/lib658-warnless.Po \ ../../lib/$(DEPDIR)/lib659-warnless.Po \ + ../../lib/$(DEPDIR)/lib667-warnless.Po \ + ../../lib/$(DEPDIR)/lib668-warnless.Po \ + ../../lib/$(DEPDIR)/lib670-warnless.Po \ + ../../lib/$(DEPDIR)/lib671-warnless.Po \ + ../../lib/$(DEPDIR)/lib672-warnless.Po \ + ../../lib/$(DEPDIR)/lib673-warnless.Po \ ../../lib/$(DEPDIR)/libntlmconnect-warnless.Po \ ../../lib/$(DEPDIR)/warnless.Po \ ./$(DEPDIR)/chkdecimalpoint-chkdecimalpoint.Po \ @@ -1314,7 +1378,8 @@ am__depfiles_remade = \ ./$(DEPDIR)/lib1906-first.Po ./$(DEPDIR)/lib1906-lib1906.Po \ ./$(DEPDIR)/lib1906-testutil.Po ./$(DEPDIR)/lib1907-first.Po \ ./$(DEPDIR)/lib1907-lib1907.Po ./$(DEPDIR)/lib1907-testutil.Po \ - ./$(DEPDIR)/lib2033-first.Po \ + ./$(DEPDIR)/lib1908-first.Po ./$(DEPDIR)/lib1908-lib1908.Po \ + ./$(DEPDIR)/lib1908-testutil.Po ./$(DEPDIR)/lib2033-first.Po \ ./$(DEPDIR)/lib2033-libntlmconnect.Po \ ./$(DEPDIR)/lib2033-testutil.Po ./$(DEPDIR)/lib500-first.Po \ ./$(DEPDIR)/lib500-lib500.Po ./$(DEPDIR)/lib500-testtrace.Po \ @@ -1420,6 +1485,16 @@ am__depfiles_remade = \ ./$(DEPDIR)/lib658-testutil.Po ./$(DEPDIR)/lib659-first.Po \ ./$(DEPDIR)/lib659-lib659.Po ./$(DEPDIR)/lib659-testutil.Po \ ./$(DEPDIR)/lib661-first.Po ./$(DEPDIR)/lib661-lib661.Po \ + ./$(DEPDIR)/lib666-first.Po ./$(DEPDIR)/lib666-lib666.Po \ + ./$(DEPDIR)/lib667-first.Po ./$(DEPDIR)/lib667-lib667.Po \ + ./$(DEPDIR)/lib667-testutil.Po ./$(DEPDIR)/lib668-first.Po \ + ./$(DEPDIR)/lib668-lib668.Po ./$(DEPDIR)/lib668-testutil.Po \ + ./$(DEPDIR)/lib670-first.Po ./$(DEPDIR)/lib670-lib670.Po \ + ./$(DEPDIR)/lib670-testutil.Po ./$(DEPDIR)/lib671-first.Po \ + ./$(DEPDIR)/lib671-lib670.Po ./$(DEPDIR)/lib671-testutil.Po \ + ./$(DEPDIR)/lib672-first.Po ./$(DEPDIR)/lib672-lib670.Po \ + ./$(DEPDIR)/lib672-testutil.Po ./$(DEPDIR)/lib673-first.Po \ + ./$(DEPDIR)/lib673-lib670.Po ./$(DEPDIR)/lib673-testutil.Po \ ./$(DEPDIR)/libauthretry-first.Po \ ./$(DEPDIR)/libauthretry-libauthretry.Po \ ./$(DEPDIR)/libhostname_la-sethostname.Plo \ @@ -1470,61 +1545,7 @@ SOURCES = $(libhostname_la_SOURCES) $(libstubgss_la_SOURCES) \ $(lib1591_SOURCES) $(lib1592_SOURCES) $(lib1593_SOURCES) \ $(lib1594_SOURCES) $(lib1596_SOURCES) $(lib1900_SOURCES) \ $(lib1905_SOURCES) $(lib1906_SOURCES) $(lib1907_SOURCES) \ - $(lib2033_SOURCES) $(lib500_SOURCES) $(lib501_SOURCES) \ - $(lib502_SOURCES) $(lib503_SOURCES) $(lib504_SOURCES) \ - $(lib505_SOURCES) $(lib506_SOURCES) $(lib507_SOURCES) \ - $(lib508_SOURCES) $(lib509_SOURCES) $(lib510_SOURCES) \ - $(lib511_SOURCES) $(lib512_SOURCES) $(lib513_SOURCES) \ - $(lib514_SOURCES) $(lib515_SOURCES) $(lib516_SOURCES) \ - $(lib517_SOURCES) $(lib518_SOURCES) $(lib519_SOURCES) \ - $(lib520_SOURCES) $(lib521_SOURCES) $(lib523_SOURCES) \ - $(lib524_SOURCES) $(lib525_SOURCES) $(lib526_SOURCES) \ - $(lib527_SOURCES) $(lib529_SOURCES) $(lib530_SOURCES) \ - $(lib532_SOURCES) $(lib533_SOURCES) $(lib537_SOURCES) \ - $(lib539_SOURCES) $(lib540_SOURCES) $(lib541_SOURCES) \ - $(lib542_SOURCES) $(lib543_SOURCES) $(lib544_SOURCES) \ - $(lib545_SOURCES) $(lib547_SOURCES) $(lib548_SOURCES) \ - $(lib549_SOURCES) $(lib552_SOURCES) $(lib553_SOURCES) \ - $(lib554_SOURCES) $(lib555_SOURCES) $(lib556_SOURCES) \ - $(lib557_SOURCES) $(lib558_SOURCES) $(lib559_SOURCES) \ - $(lib560_SOURCES) $(lib562_SOURCES) $(lib564_SOURCES) \ - $(lib565_SOURCES) $(lib566_SOURCES) $(lib567_SOURCES) \ - $(lib568_SOURCES) $(lib569_SOURCES) $(lib570_SOURCES) \ - $(lib571_SOURCES) $(lib572_SOURCES) $(lib573_SOURCES) \ - $(lib574_SOURCES) $(lib575_SOURCES) $(lib576_SOURCES) \ - $(lib578_SOURCES) $(lib579_SOURCES) $(lib582_SOURCES) \ - $(lib583_SOURCES) $(lib585_SOURCES) $(lib586_SOURCES) \ - $(lib587_SOURCES) $(lib589_SOURCES) $(lib590_SOURCES) \ - $(lib591_SOURCES) $(lib597_SOURCES) $(lib598_SOURCES) \ - $(lib599_SOURCES) $(lib643_SOURCES) $(lib644_SOURCES) \ - $(lib645_SOURCES) $(lib650_SOURCES) $(lib651_SOURCES) \ - $(lib652_SOURCES) $(lib653_SOURCES) $(lib654_SOURCES) \ - $(lib655_SOURCES) $(lib658_SOURCES) $(lib659_SOURCES) \ - $(lib661_SOURCES) $(libauthretry_SOURCES) \ - $(libntlmconnect_SOURCES) -DIST_SOURCES = $(libhostname_la_SOURCES) \ - $(am__libstubgss_la_SOURCES_DIST) $(chkdecimalpoint_SOURCES) \ - $(chkhostname_SOURCES) $(lib1156_SOURCES) $(lib1500_SOURCES) \ - $(lib1501_SOURCES) $(lib1502_SOURCES) $(lib1503_SOURCES) \ - $(lib1504_SOURCES) $(lib1505_SOURCES) $(lib1506_SOURCES) \ - $(lib1507_SOURCES) $(lib1508_SOURCES) $(lib1509_SOURCES) \ - $(lib1510_SOURCES) $(lib1511_SOURCES) $(lib1512_SOURCES) \ - $(lib1513_SOURCES) $(lib1514_SOURCES) $(lib1515_SOURCES) \ - $(lib1517_SOURCES) $(lib1518_SOURCES) $(lib1520_SOURCES) \ - $(lib1522_SOURCES) $(lib1523_SOURCES) $(lib1525_SOURCES) \ - $(lib1526_SOURCES) $(lib1527_SOURCES) $(lib1528_SOURCES) \ - $(lib1529_SOURCES) $(lib1530_SOURCES) $(lib1531_SOURCES) \ - $(lib1532_SOURCES) $(lib1533_SOURCES) $(lib1534_SOURCES) \ - $(lib1535_SOURCES) $(lib1536_SOURCES) $(lib1537_SOURCES) \ - $(lib1538_SOURCES) $(lib1540_SOURCES) $(lib1541_SOURCES) \ - $(lib1550_SOURCES) $(lib1551_SOURCES) $(lib1552_SOURCES) \ - $(lib1553_SOURCES) $(lib1554_SOURCES) $(lib1555_SOURCES) \ - $(lib1556_SOURCES) $(lib1557_SOURCES) $(lib1558_SOURCES) \ - $(lib1559_SOURCES) $(lib1560_SOURCES) $(lib1564_SOURCES) \ - $(lib1565_SOURCES) $(lib1591_SOURCES) $(lib1592_SOURCES) \ - $(lib1593_SOURCES) $(lib1594_SOURCES) $(lib1596_SOURCES) \ - $(lib1900_SOURCES) $(lib1905_SOURCES) $(lib1906_SOURCES) \ - $(lib1907_SOURCES) $(lib2033_SOURCES) $(lib500_SOURCES) \ + $(lib1908_SOURCES) $(lib2033_SOURCES) $(lib500_SOURCES) \ $(lib501_SOURCES) $(lib502_SOURCES) $(lib503_SOURCES) \ $(lib504_SOURCES) $(lib505_SOURCES) $(lib506_SOURCES) \ $(lib507_SOURCES) $(lib508_SOURCES) $(lib509_SOURCES) \ @@ -1554,7 +1575,66 @@ DIST_SOURCES = $(libhostname_la_SOURCES) \ $(lib644_SOURCES) $(lib645_SOURCES) $(lib650_SOURCES) \ $(lib651_SOURCES) $(lib652_SOURCES) $(lib653_SOURCES) \ $(lib654_SOURCES) $(lib655_SOURCES) $(lib658_SOURCES) \ - $(lib659_SOURCES) $(lib661_SOURCES) $(libauthretry_SOURCES) \ + $(lib659_SOURCES) $(lib661_SOURCES) $(lib666_SOURCES) \ + $(lib667_SOURCES) $(lib668_SOURCES) $(lib670_SOURCES) \ + $(lib671_SOURCES) $(lib672_SOURCES) $(lib673_SOURCES) \ + $(libauthretry_SOURCES) $(libntlmconnect_SOURCES) +DIST_SOURCES = $(libhostname_la_SOURCES) \ + $(am__libstubgss_la_SOURCES_DIST) $(chkdecimalpoint_SOURCES) \ + $(chkhostname_SOURCES) $(lib1156_SOURCES) $(lib1500_SOURCES) \ + $(lib1501_SOURCES) $(lib1502_SOURCES) $(lib1503_SOURCES) \ + $(lib1504_SOURCES) $(lib1505_SOURCES) $(lib1506_SOURCES) \ + $(lib1507_SOURCES) $(lib1508_SOURCES) $(lib1509_SOURCES) \ + $(lib1510_SOURCES) $(lib1511_SOURCES) $(lib1512_SOURCES) \ + $(lib1513_SOURCES) $(lib1514_SOURCES) $(lib1515_SOURCES) \ + $(lib1517_SOURCES) $(lib1518_SOURCES) $(lib1520_SOURCES) \ + $(lib1522_SOURCES) $(lib1523_SOURCES) $(lib1525_SOURCES) \ + $(lib1526_SOURCES) $(lib1527_SOURCES) $(lib1528_SOURCES) \ + $(lib1529_SOURCES) $(lib1530_SOURCES) $(lib1531_SOURCES) \ + $(lib1532_SOURCES) $(lib1533_SOURCES) $(lib1534_SOURCES) \ + $(lib1535_SOURCES) $(lib1536_SOURCES) $(lib1537_SOURCES) \ + $(lib1538_SOURCES) $(lib1540_SOURCES) $(lib1541_SOURCES) \ + $(lib1550_SOURCES) $(lib1551_SOURCES) $(lib1552_SOURCES) \ + $(lib1553_SOURCES) $(lib1554_SOURCES) $(lib1555_SOURCES) \ + $(lib1556_SOURCES) $(lib1557_SOURCES) $(lib1558_SOURCES) \ + $(lib1559_SOURCES) $(lib1560_SOURCES) $(lib1564_SOURCES) \ + $(lib1565_SOURCES) $(lib1591_SOURCES) $(lib1592_SOURCES) \ + $(lib1593_SOURCES) $(lib1594_SOURCES) $(lib1596_SOURCES) \ + $(lib1900_SOURCES) $(lib1905_SOURCES) $(lib1906_SOURCES) \ + $(lib1907_SOURCES) $(lib1908_SOURCES) $(lib2033_SOURCES) \ + $(lib500_SOURCES) $(lib501_SOURCES) $(lib502_SOURCES) \ + $(lib503_SOURCES) $(lib504_SOURCES) $(lib505_SOURCES) \ + $(lib506_SOURCES) $(lib507_SOURCES) $(lib508_SOURCES) \ + $(lib509_SOURCES) $(lib510_SOURCES) $(lib511_SOURCES) \ + $(lib512_SOURCES) $(lib513_SOURCES) $(lib514_SOURCES) \ + $(lib515_SOURCES) $(lib516_SOURCES) $(lib517_SOURCES) \ + $(lib518_SOURCES) $(lib519_SOURCES) $(lib520_SOURCES) \ + $(lib521_SOURCES) $(lib523_SOURCES) $(lib524_SOURCES) \ + $(lib525_SOURCES) $(lib526_SOURCES) $(lib527_SOURCES) \ + $(lib529_SOURCES) $(lib530_SOURCES) $(lib532_SOURCES) \ + $(lib533_SOURCES) $(lib537_SOURCES) $(lib539_SOURCES) \ + $(lib540_SOURCES) $(lib541_SOURCES) $(lib542_SOURCES) \ + $(lib543_SOURCES) $(lib544_SOURCES) $(lib545_SOURCES) \ + $(lib547_SOURCES) $(lib548_SOURCES) $(lib549_SOURCES) \ + $(lib552_SOURCES) $(lib553_SOURCES) $(lib554_SOURCES) \ + $(lib555_SOURCES) $(lib556_SOURCES) $(lib557_SOURCES) \ + $(lib558_SOURCES) $(lib559_SOURCES) $(lib560_SOURCES) \ + $(lib562_SOURCES) $(lib564_SOURCES) $(lib565_SOURCES) \ + $(lib566_SOURCES) $(lib567_SOURCES) $(lib568_SOURCES) \ + $(lib569_SOURCES) $(lib570_SOURCES) $(lib571_SOURCES) \ + $(lib572_SOURCES) $(lib573_SOURCES) $(lib574_SOURCES) \ + $(lib575_SOURCES) $(lib576_SOURCES) $(lib578_SOURCES) \ + $(lib579_SOURCES) $(lib582_SOURCES) $(lib583_SOURCES) \ + $(lib585_SOURCES) $(lib586_SOURCES) $(lib587_SOURCES) \ + $(lib589_SOURCES) $(lib590_SOURCES) $(lib591_SOURCES) \ + $(lib597_SOURCES) $(lib598_SOURCES) $(lib599_SOURCES) \ + $(lib643_SOURCES) $(lib644_SOURCES) $(lib645_SOURCES) \ + $(lib650_SOURCES) $(lib651_SOURCES) $(lib652_SOURCES) \ + $(lib653_SOURCES) $(lib654_SOURCES) $(lib655_SOURCES) \ + $(lib658_SOURCES) $(lib659_SOURCES) $(lib661_SOURCES) \ + $(lib666_SOURCES) $(lib667_SOURCES) $(lib668_SOURCES) \ + $(lib670_SOURCES) $(lib671_SOURCES) $(lib672_SOURCES) \ + $(lib673_SOURCES) $(libauthretry_SOURCES) \ $(libntlmconnect_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ @@ -1729,6 +1809,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -2074,6 +2155,26 @@ lib659_LDADD = $(TESTUTIL_LIBS) lib659_CPPFLAGS = $(AM_CPPFLAGS) lib661_SOURCES = lib661.c $(SUPPORTFILES) lib661_CPPFLAGS = $(AM_CPPFLAGS) +lib666_SOURCES = lib666.c $(SUPPORTFILES) +lib666_CPPFLAGS = $(AM_CPPFLAGS) +lib667_SOURCES = lib667.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib667_LDADD = $(TESTUTIL_LIBS) +lib667_CPPFLAGS = $(AM_CPPFLAGS) +lib668_SOURCES = lib668.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib668_LDADD = $(TESTUTIL_LIBS) +lib668_CPPFLAGS = $(AM_CPPFLAGS) +lib670_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib670_LDADD = $(TESTUTIL_LIBS) +lib670_CPPFLAGS = $(AM_CPPFLAGS) -DLIB670 +lib671_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib671_LDADD = $(TESTUTIL_LIBS) +lib671_CPPFLAGS = $(AM_CPPFLAGS) -DLIB671 +lib672_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib672_LDADD = $(TESTUTIL_LIBS) +lib672_CPPFLAGS = $(AM_CPPFLAGS) -DLIB672 +lib673_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib673_LDADD = $(TESTUTIL_LIBS) +lib673_CPPFLAGS = $(AM_CPPFLAGS) -DLIB673 lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL) lib1500_LDADD = $(TESTUTIL_LIBS) lib1500_CPPFLAGS = $(AM_CPPFLAGS) @@ -2243,6 +2344,9 @@ lib1906_CPPFLAGS = $(AM_CPPFLAGS) lib1907_SOURCES = lib1907.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1907_LDADD = $(TESTUTIL_LIBS) lib1907_CPPFLAGS = $(AM_CPPFLAGS) +lib1908_SOURCES = lib1908.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib1908_LDADD = $(TESTUTIL_LIBS) +lib1908_CPPFLAGS = $(AM_CPPFLAGS) lib2033_SOURCES = libntlmconnect.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib2033_LDADD = $(TESTUTIL_LIBS) lib2033_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_PIPELINING @@ -2691,6 +2795,12 @@ lib1906$(EXEEXT): $(lib1906_OBJECTS) $(lib1906_DEPENDENCIES) $(EXTRA_lib1906_DEP lib1907$(EXEEXT): $(lib1907_OBJECTS) $(lib1907_DEPENDENCIES) $(EXTRA_lib1907_DEPENDENCIES) @rm -f lib1907$(EXEEXT) $(AM_V_CCLD)$(LINK) $(lib1907_OBJECTS) $(lib1907_LDADD) $(LIBS) +../../lib/lib1908-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib1908$(EXEEXT): $(lib1908_OBJECTS) $(lib1908_DEPENDENCIES) $(EXTRA_lib1908_DEPENDENCIES) + @rm -f lib1908$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib1908_OBJECTS) $(lib1908_LDADD) $(LIBS) ../../lib/lib2033-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ ../../lib/$(DEPDIR)/$(am__dirstamp) @@ -3112,6 +3222,46 @@ lib661$(EXEEXT): $(lib661_OBJECTS) $(lib661_DEPENDENCIES) $(EXTRA_lib661_DEPENDE @rm -f lib661$(EXEEXT) $(AM_V_CCLD)$(LINK) $(lib661_OBJECTS) $(lib661_LDADD) $(LIBS) +lib666$(EXEEXT): $(lib666_OBJECTS) $(lib666_DEPENDENCIES) $(EXTRA_lib666_DEPENDENCIES) + @rm -f lib666$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib666_OBJECTS) $(lib666_LDADD) $(LIBS) +../../lib/lib667-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib667$(EXEEXT): $(lib667_OBJECTS) $(lib667_DEPENDENCIES) $(EXTRA_lib667_DEPENDENCIES) + @rm -f lib667$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib667_OBJECTS) $(lib667_LDADD) $(LIBS) +../../lib/lib668-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib668$(EXEEXT): $(lib668_OBJECTS) $(lib668_DEPENDENCIES) $(EXTRA_lib668_DEPENDENCIES) + @rm -f lib668$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib668_OBJECTS) $(lib668_LDADD) $(LIBS) +../../lib/lib670-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib670$(EXEEXT): $(lib670_OBJECTS) $(lib670_DEPENDENCIES) $(EXTRA_lib670_DEPENDENCIES) + @rm -f lib670$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib670_OBJECTS) $(lib670_LDADD) $(LIBS) +../../lib/lib671-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib671$(EXEEXT): $(lib671_OBJECTS) $(lib671_DEPENDENCIES) $(EXTRA_lib671_DEPENDENCIES) + @rm -f lib671$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib671_OBJECTS) $(lib671_LDADD) $(LIBS) +../../lib/lib672-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib672$(EXEEXT): $(lib672_OBJECTS) $(lib672_DEPENDENCIES) $(EXTRA_lib672_DEPENDENCIES) + @rm -f lib672$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib672_OBJECTS) $(lib672_LDADD) $(LIBS) +../../lib/lib673-warnless.$(OBJEXT): ../../lib/$(am__dirstamp) \ + ../../lib/$(DEPDIR)/$(am__dirstamp) + +lib673$(EXEEXT): $(lib673_OBJECTS) $(lib673_DEPENDENCIES) $(EXTRA_lib673_DEPENDENCIES) + @rm -f lib673$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib673_OBJECTS) $(lib673_LDADD) $(LIBS) + libauthretry$(EXEEXT): $(libauthretry_OBJECTS) $(libauthretry_DEPENDENCIES) $(EXTRA_libauthretry_DEPENDENCIES) @rm -f libauthretry$(EXEEXT) $(AM_V_CCLD)$(LINK) $(libauthretry_OBJECTS) $(libauthretry_LDADD) $(LIBS) @@ -3176,6 +3326,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib1905-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib1906-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib1907-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib1908-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib2033-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib502-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib503-warnless.Po@am__quote@ # am--include-marker @@ -3204,6 +3355,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib597-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib658-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib659-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib667-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib668-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib670-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib671-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib672-warnless.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib673-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/libntlmconnect-warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chkdecimalpoint-chkdecimalpoint.Po@am__quote@ # am--include-marker @@ -3373,6 +3530,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1907-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1907-lib1907.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1907-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1908-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1908-lib1908.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1908-testutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib2033-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib2033-libntlmconnect.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib2033-testutil.Po@am__quote@ # am--include-marker @@ -3583,6 +3743,26 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib659-testutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib661-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib661-lib661.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib666-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib666-lib666.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib667-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib667-lib667.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib667-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib668-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib668-lib668.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib668-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib670-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib670-lib670.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib670-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib671-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib671-lib670.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib671-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib672-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib672-lib670.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib672-testutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib673-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib673-lib670.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib673-testutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libauthretry-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libauthretry-libauthretry.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhostname_la-sethostname.Plo@am__quote@ # am--include-marker @@ -6548,6 +6728,62 @@ lib1907-testutil.obj: testutil.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1907_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib1907-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +lib1908-lib1908.o: lib1908.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-lib1908.o -MD -MP -MF $(DEPDIR)/lib1908-lib1908.Tpo -c -o lib1908-lib1908.o `test -f 'lib1908.c' || echo '$(srcdir)/'`lib1908.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-lib1908.Tpo $(DEPDIR)/lib1908-lib1908.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib1908.c' object='lib1908-lib1908.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-lib1908.o `test -f 'lib1908.c' || echo '$(srcdir)/'`lib1908.c + +lib1908-lib1908.obj: lib1908.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-lib1908.obj -MD -MP -MF $(DEPDIR)/lib1908-lib1908.Tpo -c -o lib1908-lib1908.obj `if test -f 'lib1908.c'; then $(CYGPATH_W) 'lib1908.c'; else $(CYGPATH_W) '$(srcdir)/lib1908.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-lib1908.Tpo $(DEPDIR)/lib1908-lib1908.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib1908.c' object='lib1908-lib1908.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-lib1908.obj `if test -f 'lib1908.c'; then $(CYGPATH_W) 'lib1908.c'; else $(CYGPATH_W) '$(srcdir)/lib1908.c'; fi` + +lib1908-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-first.o -MD -MP -MF $(DEPDIR)/lib1908-first.Tpo -c -o lib1908-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-first.Tpo $(DEPDIR)/lib1908-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib1908-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib1908-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-first.obj -MD -MP -MF $(DEPDIR)/lib1908-first.Tpo -c -o lib1908-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-first.Tpo $(DEPDIR)/lib1908-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib1908-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib1908-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-testutil.o -MD -MP -MF $(DEPDIR)/lib1908-testutil.Tpo -c -o lib1908-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-testutil.Tpo $(DEPDIR)/lib1908-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib1908-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib1908-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib1908-testutil.obj -MD -MP -MF $(DEPDIR)/lib1908-testutil.Tpo -c -o lib1908-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib1908-testutil.Tpo $(DEPDIR)/lib1908-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib1908-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib1908-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib1908-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib1908-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib1908-warnless.Tpo -c -o ../../lib/lib1908-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib1908-warnless.Tpo ../../lib/$(DEPDIR)/lib1908-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib1908-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib1908-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib1908-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib1908-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib1908-warnless.Tpo -c -o ../../lib/lib1908-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib1908-warnless.Tpo ../../lib/$(DEPDIR)/lib1908-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib1908-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib1908_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib1908-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + lib2033-libntlmconnect.o: libntlmconnect.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib2033_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib2033-libntlmconnect.o -MD -MP -MF $(DEPDIR)/lib2033-libntlmconnect.Tpo -c -o lib2033-libntlmconnect.o `test -f 'libntlmconnect.c' || echo '$(srcdir)/'`libntlmconnect.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib2033-libntlmconnect.Tpo $(DEPDIR)/lib2033-libntlmconnect.Po @@ -9880,6 +10116,370 @@ lib661-first.obj: first.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib661_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib661-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +lib666-lib666.o: lib666.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib666-lib666.o -MD -MP -MF $(DEPDIR)/lib666-lib666.Tpo -c -o lib666-lib666.o `test -f 'lib666.c' || echo '$(srcdir)/'`lib666.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib666-lib666.Tpo $(DEPDIR)/lib666-lib666.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib666.c' object='lib666-lib666.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib666-lib666.o `test -f 'lib666.c' || echo '$(srcdir)/'`lib666.c + +lib666-lib666.obj: lib666.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib666-lib666.obj -MD -MP -MF $(DEPDIR)/lib666-lib666.Tpo -c -o lib666-lib666.obj `if test -f 'lib666.c'; then $(CYGPATH_W) 'lib666.c'; else $(CYGPATH_W) '$(srcdir)/lib666.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib666-lib666.Tpo $(DEPDIR)/lib666-lib666.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib666.c' object='lib666-lib666.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib666-lib666.obj `if test -f 'lib666.c'; then $(CYGPATH_W) 'lib666.c'; else $(CYGPATH_W) '$(srcdir)/lib666.c'; fi` + +lib666-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib666-first.o -MD -MP -MF $(DEPDIR)/lib666-first.Tpo -c -o lib666-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib666-first.Tpo $(DEPDIR)/lib666-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib666-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib666-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib666-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib666-first.obj -MD -MP -MF $(DEPDIR)/lib666-first.Tpo -c -o lib666-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib666-first.Tpo $(DEPDIR)/lib666-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib666-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib666_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib666-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib667-lib667.o: lib667.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-lib667.o -MD -MP -MF $(DEPDIR)/lib667-lib667.Tpo -c -o lib667-lib667.o `test -f 'lib667.c' || echo '$(srcdir)/'`lib667.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-lib667.Tpo $(DEPDIR)/lib667-lib667.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib667.c' object='lib667-lib667.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-lib667.o `test -f 'lib667.c' || echo '$(srcdir)/'`lib667.c + +lib667-lib667.obj: lib667.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-lib667.obj -MD -MP -MF $(DEPDIR)/lib667-lib667.Tpo -c -o lib667-lib667.obj `if test -f 'lib667.c'; then $(CYGPATH_W) 'lib667.c'; else $(CYGPATH_W) '$(srcdir)/lib667.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-lib667.Tpo $(DEPDIR)/lib667-lib667.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib667.c' object='lib667-lib667.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-lib667.obj `if test -f 'lib667.c'; then $(CYGPATH_W) 'lib667.c'; else $(CYGPATH_W) '$(srcdir)/lib667.c'; fi` + +lib667-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-first.o -MD -MP -MF $(DEPDIR)/lib667-first.Tpo -c -o lib667-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-first.Tpo $(DEPDIR)/lib667-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib667-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib667-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-first.obj -MD -MP -MF $(DEPDIR)/lib667-first.Tpo -c -o lib667-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-first.Tpo $(DEPDIR)/lib667-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib667-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib667-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-testutil.o -MD -MP -MF $(DEPDIR)/lib667-testutil.Tpo -c -o lib667-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-testutil.Tpo $(DEPDIR)/lib667-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib667-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib667-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib667-testutil.obj -MD -MP -MF $(DEPDIR)/lib667-testutil.Tpo -c -o lib667-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib667-testutil.Tpo $(DEPDIR)/lib667-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib667-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib667-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib667-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib667-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib667-warnless.Tpo -c -o ../../lib/lib667-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib667-warnless.Tpo ../../lib/$(DEPDIR)/lib667-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib667-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib667-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib667-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib667-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib667-warnless.Tpo -c -o ../../lib/lib667-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib667-warnless.Tpo ../../lib/$(DEPDIR)/lib667-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib667-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib667_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib667-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + +lib668-lib668.o: lib668.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-lib668.o -MD -MP -MF $(DEPDIR)/lib668-lib668.Tpo -c -o lib668-lib668.o `test -f 'lib668.c' || echo '$(srcdir)/'`lib668.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-lib668.Tpo $(DEPDIR)/lib668-lib668.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib668.c' object='lib668-lib668.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-lib668.o `test -f 'lib668.c' || echo '$(srcdir)/'`lib668.c + +lib668-lib668.obj: lib668.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-lib668.obj -MD -MP -MF $(DEPDIR)/lib668-lib668.Tpo -c -o lib668-lib668.obj `if test -f 'lib668.c'; then $(CYGPATH_W) 'lib668.c'; else $(CYGPATH_W) '$(srcdir)/lib668.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-lib668.Tpo $(DEPDIR)/lib668-lib668.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib668.c' object='lib668-lib668.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-lib668.obj `if test -f 'lib668.c'; then $(CYGPATH_W) 'lib668.c'; else $(CYGPATH_W) '$(srcdir)/lib668.c'; fi` + +lib668-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-first.o -MD -MP -MF $(DEPDIR)/lib668-first.Tpo -c -o lib668-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-first.Tpo $(DEPDIR)/lib668-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib668-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib668-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-first.obj -MD -MP -MF $(DEPDIR)/lib668-first.Tpo -c -o lib668-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-first.Tpo $(DEPDIR)/lib668-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib668-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib668-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-testutil.o -MD -MP -MF $(DEPDIR)/lib668-testutil.Tpo -c -o lib668-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-testutil.Tpo $(DEPDIR)/lib668-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib668-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib668-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib668-testutil.obj -MD -MP -MF $(DEPDIR)/lib668-testutil.Tpo -c -o lib668-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib668-testutil.Tpo $(DEPDIR)/lib668-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib668-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib668-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib668-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib668-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib668-warnless.Tpo -c -o ../../lib/lib668-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib668-warnless.Tpo ../../lib/$(DEPDIR)/lib668-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib668-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib668-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib668-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib668-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib668-warnless.Tpo -c -o ../../lib/lib668-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib668-warnless.Tpo ../../lib/$(DEPDIR)/lib668-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib668-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib668_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib668-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + +lib670-lib670.o: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-lib670.o -MD -MP -MF $(DEPDIR)/lib670-lib670.Tpo -c -o lib670-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-lib670.Tpo $(DEPDIR)/lib670-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib670-lib670.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c + +lib670-lib670.obj: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-lib670.obj -MD -MP -MF $(DEPDIR)/lib670-lib670.Tpo -c -o lib670-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-lib670.Tpo $(DEPDIR)/lib670-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib670-lib670.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` + +lib670-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-first.o -MD -MP -MF $(DEPDIR)/lib670-first.Tpo -c -o lib670-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-first.Tpo $(DEPDIR)/lib670-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib670-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib670-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-first.obj -MD -MP -MF $(DEPDIR)/lib670-first.Tpo -c -o lib670-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-first.Tpo $(DEPDIR)/lib670-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib670-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib670-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-testutil.o -MD -MP -MF $(DEPDIR)/lib670-testutil.Tpo -c -o lib670-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-testutil.Tpo $(DEPDIR)/lib670-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib670-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib670-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib670-testutil.obj -MD -MP -MF $(DEPDIR)/lib670-testutil.Tpo -c -o lib670-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib670-testutil.Tpo $(DEPDIR)/lib670-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib670-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib670-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib670-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib670-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib670-warnless.Tpo -c -o ../../lib/lib670-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib670-warnless.Tpo ../../lib/$(DEPDIR)/lib670-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib670-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib670-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib670-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib670-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib670-warnless.Tpo -c -o ../../lib/lib670-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib670-warnless.Tpo ../../lib/$(DEPDIR)/lib670-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib670-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib670_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib670-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + +lib671-lib670.o: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-lib670.o -MD -MP -MF $(DEPDIR)/lib671-lib670.Tpo -c -o lib671-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-lib670.Tpo $(DEPDIR)/lib671-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib671-lib670.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c + +lib671-lib670.obj: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-lib670.obj -MD -MP -MF $(DEPDIR)/lib671-lib670.Tpo -c -o lib671-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-lib670.Tpo $(DEPDIR)/lib671-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib671-lib670.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` + +lib671-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-first.o -MD -MP -MF $(DEPDIR)/lib671-first.Tpo -c -o lib671-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-first.Tpo $(DEPDIR)/lib671-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib671-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib671-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-first.obj -MD -MP -MF $(DEPDIR)/lib671-first.Tpo -c -o lib671-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-first.Tpo $(DEPDIR)/lib671-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib671-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib671-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-testutil.o -MD -MP -MF $(DEPDIR)/lib671-testutil.Tpo -c -o lib671-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-testutil.Tpo $(DEPDIR)/lib671-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib671-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib671-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib671-testutil.obj -MD -MP -MF $(DEPDIR)/lib671-testutil.Tpo -c -o lib671-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib671-testutil.Tpo $(DEPDIR)/lib671-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib671-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib671-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib671-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib671-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib671-warnless.Tpo -c -o ../../lib/lib671-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib671-warnless.Tpo ../../lib/$(DEPDIR)/lib671-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib671-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib671-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib671-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib671-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib671-warnless.Tpo -c -o ../../lib/lib671-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib671-warnless.Tpo ../../lib/$(DEPDIR)/lib671-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib671-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib671_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib671-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + +lib672-lib670.o: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-lib670.o -MD -MP -MF $(DEPDIR)/lib672-lib670.Tpo -c -o lib672-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-lib670.Tpo $(DEPDIR)/lib672-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib672-lib670.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c + +lib672-lib670.obj: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-lib670.obj -MD -MP -MF $(DEPDIR)/lib672-lib670.Tpo -c -o lib672-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-lib670.Tpo $(DEPDIR)/lib672-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib672-lib670.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` + +lib672-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-first.o -MD -MP -MF $(DEPDIR)/lib672-first.Tpo -c -o lib672-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-first.Tpo $(DEPDIR)/lib672-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib672-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib672-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-first.obj -MD -MP -MF $(DEPDIR)/lib672-first.Tpo -c -o lib672-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-first.Tpo $(DEPDIR)/lib672-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib672-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib672-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-testutil.o -MD -MP -MF $(DEPDIR)/lib672-testutil.Tpo -c -o lib672-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-testutil.Tpo $(DEPDIR)/lib672-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib672-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib672-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib672-testutil.obj -MD -MP -MF $(DEPDIR)/lib672-testutil.Tpo -c -o lib672-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib672-testutil.Tpo $(DEPDIR)/lib672-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib672-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib672-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib672-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib672-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib672-warnless.Tpo -c -o ../../lib/lib672-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib672-warnless.Tpo ../../lib/$(DEPDIR)/lib672-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib672-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib672-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib672-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib672-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib672-warnless.Tpo -c -o ../../lib/lib672-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib672-warnless.Tpo ../../lib/$(DEPDIR)/lib672-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib672-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib672_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib672-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + +lib673-lib670.o: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-lib670.o -MD -MP -MF $(DEPDIR)/lib673-lib670.Tpo -c -o lib673-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-lib670.Tpo $(DEPDIR)/lib673-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib673-lib670.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-lib670.o `test -f 'lib670.c' || echo '$(srcdir)/'`lib670.c + +lib673-lib670.obj: lib670.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-lib670.obj -MD -MP -MF $(DEPDIR)/lib673-lib670.Tpo -c -o lib673-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-lib670.Tpo $(DEPDIR)/lib673-lib670.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib670.c' object='lib673-lib670.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-lib670.obj `if test -f 'lib670.c'; then $(CYGPATH_W) 'lib670.c'; else $(CYGPATH_W) '$(srcdir)/lib670.c'; fi` + +lib673-first.o: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-first.o -MD -MP -MF $(DEPDIR)/lib673-first.Tpo -c -o lib673-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-first.Tpo $(DEPDIR)/lib673-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib673-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-first.o `test -f 'first.c' || echo '$(srcdir)/'`first.c + +lib673-first.obj: first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-first.obj -MD -MP -MF $(DEPDIR)/lib673-first.Tpo -c -o lib673-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-first.Tpo $(DEPDIR)/lib673-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='first.c' object='lib673-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-first.obj `if test -f 'first.c'; then $(CYGPATH_W) 'first.c'; else $(CYGPATH_W) '$(srcdir)/first.c'; fi` + +lib673-testutil.o: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-testutil.o -MD -MP -MF $(DEPDIR)/lib673-testutil.Tpo -c -o lib673-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-testutil.Tpo $(DEPDIR)/lib673-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib673-testutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-testutil.o `test -f 'testutil.c' || echo '$(srcdir)/'`testutil.c + +lib673-testutil.obj: testutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib673-testutil.obj -MD -MP -MF $(DEPDIR)/lib673-testutil.Tpo -c -o lib673-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib673-testutil.Tpo $(DEPDIR)/lib673-testutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testutil.c' object='lib673-testutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib673-testutil.obj `if test -f 'testutil.c'; then $(CYGPATH_W) 'testutil.c'; else $(CYGPATH_W) '$(srcdir)/testutil.c'; fi` + +../../lib/lib673-warnless.o: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib673-warnless.o -MD -MP -MF ../../lib/$(DEPDIR)/lib673-warnless.Tpo -c -o ../../lib/lib673-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib673-warnless.Tpo ../../lib/$(DEPDIR)/lib673-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib673-warnless.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib673-warnless.o `test -f '../../lib/warnless.c' || echo '$(srcdir)/'`../../lib/warnless.c + +../../lib/lib673-warnless.obj: ../../lib/warnless.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../../lib/lib673-warnless.obj -MD -MP -MF ../../lib/$(DEPDIR)/lib673-warnless.Tpo -c -o ../../lib/lib673-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../../lib/$(DEPDIR)/lib673-warnless.Tpo ../../lib/$(DEPDIR)/lib673-warnless.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../../lib/warnless.c' object='../../lib/lib673-warnless.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib673_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../lib/lib673-warnless.obj `if test -f '../../lib/warnless.c'; then $(CYGPATH_W) '../../lib/warnless.c'; else $(CYGPATH_W) '$(srcdir)/../../lib/warnless.c'; fi` + libauthretry-libauthretry.o: libauthretry.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libauthretry_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libauthretry-libauthretry.o -MD -MP -MF $(DEPDIR)/libauthretry-libauthretry.Tpo -c -o libauthretry-libauthretry.o `test -f 'libauthretry.c' || echo '$(srcdir)/'`libauthretry.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libauthretry-libauthretry.Tpo $(DEPDIR)/libauthretry-libauthretry.Po @@ -10146,6 +10746,7 @@ distclean: distclean-am -rm -f ../../lib/$(DEPDIR)/lib1905-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib1906-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib1907-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib1908-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib2033-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib502-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib503-warnless.Po @@ -10174,6 +10775,12 @@ distclean: distclean-am -rm -f ../../lib/$(DEPDIR)/lib597-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib658-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib659-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib667-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib668-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib670-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib671-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib673-warnless.Po -rm -f ../../lib/$(DEPDIR)/libntlmconnect-warnless.Po -rm -f ../../lib/$(DEPDIR)/warnless.Po -rm -f ./$(DEPDIR)/chkdecimalpoint-chkdecimalpoint.Po @@ -10343,6 +10950,9 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/lib1907-first.Po -rm -f ./$(DEPDIR)/lib1907-lib1907.Po -rm -f ./$(DEPDIR)/lib1907-testutil.Po + -rm -f ./$(DEPDIR)/lib1908-first.Po + -rm -f ./$(DEPDIR)/lib1908-lib1908.Po + -rm -f ./$(DEPDIR)/lib1908-testutil.Po -rm -f ./$(DEPDIR)/lib2033-first.Po -rm -f ./$(DEPDIR)/lib2033-libntlmconnect.Po -rm -f ./$(DEPDIR)/lib2033-testutil.Po @@ -10553,6 +11163,26 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/lib659-testutil.Po -rm -f ./$(DEPDIR)/lib661-first.Po -rm -f ./$(DEPDIR)/lib661-lib661.Po + -rm -f ./$(DEPDIR)/lib666-first.Po + -rm -f ./$(DEPDIR)/lib666-lib666.Po + -rm -f ./$(DEPDIR)/lib667-first.Po + -rm -f ./$(DEPDIR)/lib667-lib667.Po + -rm -f ./$(DEPDIR)/lib667-testutil.Po + -rm -f ./$(DEPDIR)/lib668-first.Po + -rm -f ./$(DEPDIR)/lib668-lib668.Po + -rm -f ./$(DEPDIR)/lib668-testutil.Po + -rm -f ./$(DEPDIR)/lib670-first.Po + -rm -f ./$(DEPDIR)/lib670-lib670.Po + -rm -f ./$(DEPDIR)/lib670-testutil.Po + -rm -f ./$(DEPDIR)/lib671-first.Po + -rm -f ./$(DEPDIR)/lib671-lib670.Po + -rm -f ./$(DEPDIR)/lib671-testutil.Po + -rm -f ./$(DEPDIR)/lib672-first.Po + -rm -f ./$(DEPDIR)/lib672-lib670.Po + -rm -f ./$(DEPDIR)/lib672-testutil.Po + -rm -f ./$(DEPDIR)/lib673-first.Po + -rm -f ./$(DEPDIR)/lib673-lib670.Po + -rm -f ./$(DEPDIR)/lib673-testutil.Po -rm -f ./$(DEPDIR)/libauthretry-first.Po -rm -f ./$(DEPDIR)/libauthretry-libauthretry.Po -rm -f ./$(DEPDIR)/libhostname_la-sethostname.Plo @@ -10653,6 +11283,7 @@ maintainer-clean: maintainer-clean-am -rm -f ../../lib/$(DEPDIR)/lib1905-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib1906-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib1907-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib1908-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib2033-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib502-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib503-warnless.Po @@ -10681,6 +11312,12 @@ maintainer-clean: maintainer-clean-am -rm -f ../../lib/$(DEPDIR)/lib597-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib658-warnless.Po -rm -f ../../lib/$(DEPDIR)/lib659-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib667-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib668-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib670-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib671-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po + -rm -f ../../lib/$(DEPDIR)/lib673-warnless.Po -rm -f ../../lib/$(DEPDIR)/libntlmconnect-warnless.Po -rm -f ../../lib/$(DEPDIR)/warnless.Po -rm -f ./$(DEPDIR)/chkdecimalpoint-chkdecimalpoint.Po @@ -10850,6 +11487,9 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/lib1907-first.Po -rm -f ./$(DEPDIR)/lib1907-lib1907.Po -rm -f ./$(DEPDIR)/lib1907-testutil.Po + -rm -f ./$(DEPDIR)/lib1908-first.Po + -rm -f ./$(DEPDIR)/lib1908-lib1908.Po + -rm -f ./$(DEPDIR)/lib1908-testutil.Po -rm -f ./$(DEPDIR)/lib2033-first.Po -rm -f ./$(DEPDIR)/lib2033-libntlmconnect.Po -rm -f ./$(DEPDIR)/lib2033-testutil.Po @@ -11060,6 +11700,26 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/lib659-testutil.Po -rm -f ./$(DEPDIR)/lib661-first.Po -rm -f ./$(DEPDIR)/lib661-lib661.Po + -rm -f ./$(DEPDIR)/lib666-first.Po + -rm -f ./$(DEPDIR)/lib666-lib666.Po + -rm -f ./$(DEPDIR)/lib667-first.Po + -rm -f ./$(DEPDIR)/lib667-lib667.Po + -rm -f ./$(DEPDIR)/lib667-testutil.Po + -rm -f ./$(DEPDIR)/lib668-first.Po + -rm -f ./$(DEPDIR)/lib668-lib668.Po + -rm -f ./$(DEPDIR)/lib668-testutil.Po + -rm -f ./$(DEPDIR)/lib670-first.Po + -rm -f ./$(DEPDIR)/lib670-lib670.Po + -rm -f ./$(DEPDIR)/lib670-testutil.Po + -rm -f ./$(DEPDIR)/lib671-first.Po + -rm -f ./$(DEPDIR)/lib671-lib670.Po + -rm -f ./$(DEPDIR)/lib671-testutil.Po + -rm -f ./$(DEPDIR)/lib672-first.Po + -rm -f ./$(DEPDIR)/lib672-lib670.Po + -rm -f ./$(DEPDIR)/lib672-testutil.Po + -rm -f ./$(DEPDIR)/lib673-first.Po + -rm -f ./$(DEPDIR)/lib673-lib670.Po + -rm -f ./$(DEPDIR)/lib673-testutil.Po -rm -f ./$(DEPDIR)/libauthretry-first.Po -rm -f ./$(DEPDIR)/libauthretry-libauthretry.Po -rm -f ./$(DEPDIR)/libhostname_la-sethostname.Plo diff --git a/release/src/router/curl/tests/libtest/Makefile.inc b/release/src/router/curl/tests/libtest/Makefile.inc index 374a66747b6..ab2680c9773 100644 --- a/release/src/router/curl/tests/libtest/Makefile.inc +++ b/release/src/router/curl/tests/libtest/Makefile.inc @@ -22,7 +22,8 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \ lib571 lib572 lib573 lib574 lib575 lib576 lib578 lib579 lib582 \ lib583 lib585 lib586 lib587 lib589 lib590 lib591 lib597 lib598 lib599 \ lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658 \ - lib659 lib661 \ + lib659 lib661 lib666 lib667 lib668 \ + lib670 lib671 lib672 lib673 \ lib1156 \ lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \ lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \ @@ -33,7 +34,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \ lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \ lib1558 lib1559 lib1560 lib1564 lib1565 \ lib1591 lib1592 lib1593 lib1594 lib1596 \ - lib1900 lib1905 lib1906 lib1907 \ + lib1900 lib1905 lib1906 lib1907 lib1908 \ lib2033 chkdecimalpoint_SOURCES = chkdecimalpoint.c ../../lib/mprintf.c \ @@ -348,6 +349,33 @@ lib659_CPPFLAGS = $(AM_CPPFLAGS) lib661_SOURCES = lib661.c $(SUPPORTFILES) lib661_CPPFLAGS = $(AM_CPPFLAGS) +lib666_SOURCES = lib666.c $(SUPPORTFILES) +lib666_CPPFLAGS = $(AM_CPPFLAGS) + +lib667_SOURCES = lib667.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib667_LDADD = $(TESTUTIL_LIBS) +lib667_CPPFLAGS = $(AM_CPPFLAGS) + +lib668_SOURCES = lib668.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib668_LDADD = $(TESTUTIL_LIBS) +lib668_CPPFLAGS = $(AM_CPPFLAGS) + +lib670_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib670_LDADD = $(TESTUTIL_LIBS) +lib670_CPPFLAGS = $(AM_CPPFLAGS) -DLIB670 + +lib671_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib671_LDADD = $(TESTUTIL_LIBS) +lib671_CPPFLAGS = $(AM_CPPFLAGS) -DLIB671 + +lib672_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib672_LDADD = $(TESTUTIL_LIBS) +lib672_CPPFLAGS = $(AM_CPPFLAGS) -DLIB672 + +lib673_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib673_LDADD = $(TESTUTIL_LIBS) +lib673_CPPFLAGS = $(AM_CPPFLAGS) -DLIB673 + lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL) lib1500_LDADD = $(TESTUTIL_LIBS) lib1500_CPPFLAGS = $(AM_CPPFLAGS) @@ -578,6 +606,10 @@ lib1907_SOURCES = lib1907.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1907_LDADD = $(TESTUTIL_LIBS) lib1907_CPPFLAGS = $(AM_CPPFLAGS) +lib1908_SOURCES = lib1908.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib1908_LDADD = $(TESTUTIL_LIBS) +lib1908_CPPFLAGS = $(AM_CPPFLAGS) + lib2033_SOURCES = libntlmconnect.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib2033_LDADD = $(TESTUTIL_LIBS) lib2033_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_PIPELINING diff --git a/release/src/router/curl/tests/libtest/lib1515.c b/release/src/router/curl/tests/libtest/lib1515.c index c72554a3ba3..b879836f964 100644 --- a/release/src/router/curl/tests/libtest/lib1515.c +++ b/release/src/router/curl/tests/libtest/lib1515.c @@ -36,7 +36,7 @@ #define DNS_TIMEOUT 1 #if defined(WIN32) || defined(_WIN32) -#define sleep(s) Sleep(s * 1000) +#define sleep(sec) Sleep ((sec)*1000) #endif static int debug_callback(CURL *curl, curl_infotype info, char *msg, diff --git a/release/src/router/curl/tests/libtest/lib1531.c b/release/src/router/curl/tests/libtest/lib1531.c index 4a4dc133ac7..5c939955987 100644 --- a/release/src/router/curl/tests/libtest/lib1531.c +++ b/release/src/router/curl/tests/libtest/lib1531.c @@ -107,7 +107,7 @@ int test(char *URL) curl_multi_fdset() doc. */ if(maxfd == -1) { -#ifdef _WIN32 +#if defined(WIN32) || defined(_WIN32) Sleep(100); rc = 0; #else diff --git a/release/src/router/curl/tests/libtest/lib1560.c b/release/src/router/curl/tests/libtest/lib1560.c index 7f8accc7dc6..fbe642c20fb 100644 --- a/release/src/router/curl/tests/libtest/lib1560.c +++ b/release/src/router/curl/tests/libtest/lib1560.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -60,7 +60,7 @@ static int checkparts(CURLU *u, const char *in, const char *wanted, {CURLUPART_FRAGMENT, "fragment"}, {0, NULL} }; - buf[0] = 0; + memset(buf, 0, sizeof(buf)); for(i = 0; parts[i].name; i++) { char *p = NULL; @@ -129,6 +129,14 @@ struct querycase { }; static struct testcase get_parts_list[] ={ + {"user:moo@ftp.example.com/color/#green?no-black", + "ftp | user | moo | [13] | ftp.example.com | [15] | /color/ | [16] | " + "green?no-black", + CURLU_GUESS_SCHEME, 0, CURLUE_OK }, + {"ftp.user:moo@example.com/color/#green?no-black", + "http | ftp.user | moo | [13] | example.com | [15] | /color/ | [16] | " + "green?no-black", + CURLU_GUESS_SCHEME, 0, CURLUE_OK }, #ifdef WIN32 {"file:/C:\\programs\\foo", "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]", @@ -637,6 +645,9 @@ static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags) char buf[80]; char part[80]; char value[80]; + + memset(part, 0, sizeof(part)); /* Avoid valgrind false positive. */ + memset(value, 0, sizeof(value)); /* Avoid valgrind false positive. */ memcpy(buf, p, n); buf[n] = 0; if(2 == sscanf(buf, "%79[^=]=%79[^,]", part, value)) { diff --git a/release/src/router/curl/tests/libtest/lib1564.c b/release/src/router/curl/tests/libtest/lib1564.c index 225c8c6d7b2..13ac5b01e21 100644 --- a/release/src/router/curl/tests/libtest/lib1564.c +++ b/release/src/router/curl/tests/libtest/lib1564.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ #include "memdebug.h" #define TEST_HANG_TIMEOUT 60 * 1000 -#define WAKEUP_NUM 1234567 +#define WAKEUP_NUM 10 int test(char *URL) { diff --git a/release/src/router/curl/tests/libtest/lib1908.c b/release/src/router/curl/tests/libtest/lib1908.c new file mode 100644 index 00000000000..bacbc97107e --- /dev/null +++ b/release/src/router/curl/tests/libtest/lib1908.c @@ -0,0 +1,47 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2013 - 2020, Linus Nielsen Feltzing, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include "testutil.h" +#include "warnless.h" +#include "memdebug.h" + +int test(char *URL) +{ + CURLcode ret = CURLE_OK; + CURL *hnd; + start_test_timing(); + + curl_global_init(CURL_GLOBAL_ALL); + + hnd = curl_easy_init(); + if(hnd) { + curl_easy_setopt(hnd, CURLOPT_URL, URL); + curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(hnd, CURLOPT_ALTSVC, "log/altsvc-1908"); + ret = curl_easy_perform(hnd); + curl_easy_reset(hnd); + curl_easy_cleanup(hnd); + } + curl_global_cleanup(); + return (int)ret; +} diff --git a/release/src/router/curl/tests/libtest/lib643.c b/release/src/router/curl/tests/libtest/lib643.c index 7432dfce856..5af0f4a14dd 100644 --- a/release/src/router/curl/tests/libtest/lib643.c +++ b/release/src/router/curl/tests/libtest/lib643.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,11 +26,9 @@ static char data[]= #ifdef CURL_DOES_CONVERSIONS /* ASCII representation with escape sequences for non-ASCII platforms */ - "\x74\x68\x69\x73\x20\x69\x73\x20\x77\x68\x61\x74\x20\x77\x65\x20\x70" - "\x6f\x73\x74\x20\x74\x6f\x20\x74\x68\x65\x20\x73\x69\x6c\x6c\x79\x20" - "\x77\x65\x62\x20\x73\x65\x72\x76\x65\x72\x0a"; + "\x64\x75\x6d\x6d\x79\x0a"; #else - "this is what we post to the silly web server\n"; + "dummy\n"; #endif struct WriteThis { @@ -41,11 +39,20 @@ struct WriteThis { static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) { #ifdef LIB644 + static int count = 0; (void)ptr; (void)size; (void)nmemb; (void)userp; - return CURL_READFUNC_ABORT; + switch(count++) { + case 0: /* Return a single byte. */ + *ptr = '\n'; + return 1; + case 1: /* Request abort. */ + return CURL_READFUNC_ABORT; + } + printf("Wrongly called >2 times\n"); + exit(1); /* trigger major failure */ #else struct WriteThis *pooh = (struct WriteThis *)userp; diff --git a/release/src/router/curl/tests/libtest/lib652.c b/release/src/router/curl/tests/libtest/lib652.c index 5c9cba5fb47..3d247d27b36 100644 --- a/release/src/router/curl/tests/libtest/lib652.c +++ b/release/src/router/curl/tests/libtest/lib652.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -105,6 +105,9 @@ int test(char *URL) /* send a multi-part mail */ test_setopt(curl, CURLOPT_MIMEPOST, mime); + /* Shorten upload buffer. */ + test_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 16411L); + /* get verbose debug output please */ test_setopt(curl, CURLOPT_VERBOSE, 1L); diff --git a/release/src/router/curl/tests/libtest/lib654.c b/release/src/router/curl/tests/libtest/lib654.c index 45051a9c7e6..f9c8b91187c 100644 --- a/release/src/router/curl/tests/libtest/lib654.c +++ b/release/src/router/curl/tests/libtest/lib654.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,11 +26,9 @@ static char data[]= #ifdef CURL_DOES_CONVERSIONS /* ASCII representation with escape sequences for non-ASCII platforms */ - "\x74\x68\x69\x73\x20\x69\x73\x20\x77\x68\x61\x74\x20\x77\x65\x20\x70" - "\x6f\x73\x74\x20\x74\x6f\x20\x74\x68\x65\x20\x73\x69\x6c\x6c\x79\x20" - "\x77\x65\x62\x20\x73\x65\x72\x76\x65\x72\x0a"; + "\x64\x75\x6d\x6d\x79\x0a"; #else - "this is what we post to the silly web server\n"; + "dummy\n"; #endif struct WriteThis { diff --git a/release/src/router/curl/tests/libtest/lib666.c b/release/src/router/curl/tests/libtest/lib666.c new file mode 100644 index 00000000000..c75936eeb09 --- /dev/null +++ b/release/src/router/curl/tests/libtest/lib666.c @@ -0,0 +1,120 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include "memdebug.h" + +static char buffer[17000]; /* more than 16K */ + +int test(char *URL) +{ + CURL *curl = NULL; + CURLcode res = CURLE_OK; + curl_mime *mime = NULL; + curl_mimepart *part; + size_t i; + + /* Checks huge binary-encoded mime post. */ + + /* Create a buffer with pseudo-binary data. */ + for(i = 0; i < sizeof(buffer); i++) + if(i % 77 == 76) + buffer[i] = '\n'; + else + buffer[i] = (char) (0x41 + i % 26); /* A...Z */ + + if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + curl = curl_easy_init(); + if(!curl) { + fprintf(stderr, "curl_easy_init() failed\n"); + res = (CURLcode) TEST_ERR_MAJOR_BAD; + goto test_cleanup; + } + + /* Build mime structure. */ + mime = curl_mime_init(curl); + if(!mime) { + fprintf(stderr, "curl_mime_init() failed\n"); + res = (CURLcode) TEST_ERR_MAJOR_BAD; + goto test_cleanup; + } + part = curl_mime_addpart(mime); + if(!part) { + fprintf(stderr, "curl_mime_addpart() failed\n"); + res = (CURLcode) TEST_ERR_MAJOR_BAD; + goto test_cleanup; + } + res = curl_mime_name(part, "upfile"); + if(res) { + fprintf(stderr, "curl_mime_name() failed\n"); + goto test_cleanup; + } + res = curl_mime_filename(part, "myfile.txt"); + if(res) { + fprintf(stderr, "curl_mime_filename() failed\n"); + goto test_cleanup; + } + res = curl_mime_data(part, buffer, sizeof(buffer)); + if(res) { + fprintf(stderr, "curl_mime_data() failed\n"); + goto test_cleanup; + } + res = curl_mime_encoder(part, "binary"); + if(res) { + fprintf(stderr, "curl_mime_encoder() failed\n"); + goto test_cleanup; + } + + /* First set the URL that is about to receive our mime mail. */ + test_setopt(curl, CURLOPT_URL, URL); + + /* Post form */ + test_setopt(curl, CURLOPT_MIMEPOST, mime); + + /* Shorten upload buffer. */ + test_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 16411L); + + /* get verbose debug output please */ + test_setopt(curl, CURLOPT_VERBOSE, 1L); + + /* include headers in the output */ + test_setopt(curl, CURLOPT_HEADER, 1L); + + /* Perform the request, res will get the return code */ + res = curl_easy_perform(curl); + +test_cleanup: + + /* always cleanup */ + curl_easy_cleanup(curl); + + /* now cleanup the mime structure */ + curl_mime_free(mime); + + curl_global_cleanup(); + + return res; +} diff --git a/release/src/router/curl/tests/libtest/lib667.c b/release/src/router/curl/tests/libtest/lib667.c new file mode 100644 index 00000000000..8bf7be43f27 --- /dev/null +++ b/release/src/router/curl/tests/libtest/lib667.c @@ -0,0 +1,117 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include "memdebug.h" + +static char data[]= +#ifdef CURL_DOES_CONVERSIONS + /* ASCII representation with escape sequences for non-ASCII platforms */ + "\x64\x75\x6d\x6d\x79"; +#else + "dummy"; +#endif + +struct WriteThis { + char *readptr; + curl_off_t sizeleft; +}; + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct WriteThis *pooh = (struct WriteThis *)userp; + int eof = !*pooh->readptr; + + if(size*nmemb < 1) + return 0; + + eof = pooh->sizeleft <= 0; + if(!eof) + pooh->sizeleft--; + + if(!eof) { + *ptr = *pooh->readptr; /* copy one single byte */ + pooh->readptr++; /* advance pointer */ + return 1; /* we return 1 byte at a time! */ + } + + return 0; /* no more data left to deliver */ +} + +int test(char *URL) +{ + CURL *easy = NULL; + curl_mime *mime = NULL; + curl_mimepart *part; + CURLcode result; + int res = TEST_ERR_FAILURE; + struct WriteThis pooh; + + /* + * Check proper handling of mime encoder feature when the part read callback + * delivers data bytes one at a time. Use chunked encoding for accurate test. + */ + + if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + easy = curl_easy_init(); + + /* First set the URL that is about to receive our POST. */ + test_setopt(easy, CURLOPT_URL, URL); + + /* get verbose debug output please */ + test_setopt(easy, CURLOPT_VERBOSE, 1L); + + /* include headers in the output */ + test_setopt(easy, CURLOPT_HEADER, 1L); + + /* Prepare the callback structure. */ + pooh.readptr = data; + pooh.sizeleft = (curl_off_t) strlen(data); + + /* Build the mime tree. */ + mime = curl_mime_init(easy); + part = curl_mime_addpart(mime); + curl_mime_name(part, "field"); + curl_mime_encoder(part, "base64"); + /* Using an undefined length forces chunked transfer. */ + curl_mime_data_cb(part, (curl_off_t) -1, read_callback, NULL, NULL, &pooh); + + /* Bind mime data to its easy handle. */ + test_setopt(easy, CURLOPT_MIMEPOST, mime); + + /* Send data. */ + result = curl_easy_perform(easy); + if(result) { + fprintf(stderr, "curl_easy_perform() failed\n"); + res = (int) result; + } + +test_cleanup: + curl_easy_cleanup(easy); + curl_mime_free(mime); + curl_global_cleanup(); + return res; +} diff --git a/release/src/router/curl/tests/libtest/lib668.c b/release/src/router/curl/tests/libtest/lib668.c new file mode 100644 index 00000000000..c0b608a0ac1 --- /dev/null +++ b/release/src/router/curl/tests/libtest/lib668.c @@ -0,0 +1,122 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include "memdebug.h" + +static char data[]= +#ifdef CURL_DOES_CONVERSIONS + /* ASCII representation with escape sequences for non-ASCII platforms */ + "\x64\x75\x6d\x6d\x79"; +#else + "dummy"; +#endif + +struct WriteThis { + char *readptr; + curl_off_t sizeleft; +}; + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct WriteThis *pooh = (struct WriteThis *)userp; + size_t len = strlen(pooh->readptr); + + (void) size; /* Always 1.*/ + + if(len > nmemb) + len = nmemb; + if(len) { + memcpy(ptr, pooh->readptr, len); + pooh->readptr += len; + } + return len; +} + +int test(char *URL) +{ + CURL *easy = NULL; + curl_mime *mime = NULL; + curl_mimepart *part; + CURLcode result; + int res = TEST_ERR_FAILURE; + struct WriteThis pooh1, pooh2; + + /* + * Check early end of part data detection. + */ + + if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + easy = curl_easy_init(); + + /* First set the URL that is about to receive our POST. */ + test_setopt(easy, CURLOPT_URL, URL); + + /* get verbose debug output please */ + test_setopt(easy, CURLOPT_VERBOSE, 1L); + + /* include headers in the output */ + test_setopt(easy, CURLOPT_HEADER, 1L); + + /* Prepare the callback structures. */ + pooh1.readptr = data; + pooh1.sizeleft = (curl_off_t) strlen(data); + pooh2 = pooh1; + + /* Build the mime tree. */ + mime = curl_mime_init(easy); + part = curl_mime_addpart(mime); + curl_mime_name(part, "field1"); + /* Early end of data detection can be done because the data size is known. */ + curl_mime_data_cb(part, (curl_off_t) strlen(data), + read_callback, NULL, NULL, &pooh1); + part = curl_mime_addpart(mime); + curl_mime_name(part, "field2"); + /* Using an undefined length forces chunked transfer and disables early + end of data detection for this part. */ + curl_mime_data_cb(part, (curl_off_t) -1, read_callback, NULL, NULL, &pooh2); + part = curl_mime_addpart(mime); + curl_mime_name(part, "field3"); + /* Regular file part sources early end of data can be detected because + the file size is known. In addition, and EOF test is performed. */ + curl_mime_filedata(part, "log/file668.txt"); + + /* Bind mime data to its easy handle. */ + test_setopt(easy, CURLOPT_MIMEPOST, mime); + + /* Send data. */ + result = curl_easy_perform(easy); + if(result) { + fprintf(stderr, "curl_easy_perform() failed\n"); + res = (int) result; + } + +test_cleanup: + curl_easy_cleanup(easy); + curl_mime_free(mime); + curl_global_cleanup(); + return res; +} diff --git a/release/src/router/curl/tests/libtest/lib670.c b/release/src/router/curl/tests/libtest/lib670.c new file mode 100644 index 00000000000..2e604071459 --- /dev/null +++ b/release/src/router/curl/tests/libtest/lib670.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +#include "test.h" + +#include "memdebug.h" + +#define PAUSE_TIME 2 + + +static const char name[] = "field"; + +struct ReadThis { + CURL *easy; + time_t origin; + int count; +}; + + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct ReadThis *pooh = (struct ReadThis *) userp; + time_t delta; + + if(size * nmemb < 1) + return 0; + + switch(pooh->count++) { + case 0: + *ptr = '\x41'; /* ASCII A. */ + return 1; + case 1: + pooh->origin = time(NULL); + return CURL_READFUNC_PAUSE; + case 2: + delta = time(NULL) - pooh->origin; + *ptr = delta >= PAUSE_TIME? '\x42': '\x41'; /* ASCII A or B. */ + return 1; + case 3: + return 0; + } + fprintf(stderr, "Read callback called after EOF\n"); + exit(1); +} + +#if !defined(LIB670) && !defined(LIB672) +static int xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct ReadThis *pooh = (struct ReadThis *) clientp; + + (void) dltotal; + (void) dlnow; + (void) ultotal; + (void) ulnow; + + if(pooh->origin) { + time_t delta = time(NULL) - pooh->origin; + + if(delta >= 4 * PAUSE_TIME) { + fprintf(stderr, "unpausing failed: drain problem?\n"); + return CURLE_ABORTED_BY_CALLBACK; + } + + if(delta >= PAUSE_TIME) + curl_easy_pause(pooh->easy, CURLPAUSE_CONT); + } + + return 0; +} +#endif + +int test(char *URL) +{ +#if defined(LIB670) || defined(LIB671) + curl_mime *mime = NULL; + curl_mimepart *part; +#else + CURLFORMcode formrc; + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; +#endif +#if defined(LIB670) || defined(LIB672) + CURLM *multi = NULL; + CURLMcode mres; + CURLMsg *msg; + int msgs_left; + int still_running = 0; +#endif + + struct ReadThis pooh; + CURLcode result; + int res = TEST_ERR_FAILURE; + + /* + * Check proper pausing/unpausing from a mime or form read callback. + */ + + if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + pooh.origin = (time_t) 0; + pooh.count = 0; + pooh.easy = curl_easy_init(); + + /* First set the URL that is about to receive our POST. */ + test_setopt(pooh.easy, CURLOPT_URL, URL); + + /* get verbose debug output please */ + test_setopt(pooh.easy, CURLOPT_VERBOSE, 1L); + + /* include headers in the output */ + test_setopt(pooh.easy, CURLOPT_HEADER, 1L); + +#if defined(LIB670) || defined(LIB671) + /* Build the mime tree. */ + mime = curl_mime_init(pooh.easy); + part = curl_mime_addpart(mime); + result = curl_mime_name(part, name); + if(!result) + res = curl_mime_data_cb(part, (curl_off_t) 2, read_callback, + NULL, NULL, &pooh); + + if(result) { + fprintf(stderr, + "Something went wrong when building the mime structure: %d\n", + (int) result); + goto test_cleanup; + } + + /* Bind mime data to its easy handle. */ + if(!res) + test_setopt(pooh.easy, CURLOPT_MIMEPOST, mime); +#else + /* Build the form. */ + formrc = curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, name, + CURLFORM_STREAM, &pooh, + CURLFORM_CONTENTLEN, (curl_off_t) 2, + CURLFORM_END); + if(formrc) { + fprintf(stderr, "curl_formadd() = %d\n", (int) formrc); + goto test_cleanup; + } + + /* We want to use our own read function. */ + test_setopt(pooh.easy, CURLOPT_READFUNCTION, read_callback); + + /* Send a multi-part formpost. */ + test_setopt(pooh.easy, CURLOPT_HTTPPOST, formpost); +#endif + +#if defined(LIB670) || defined(LIB672) + /* Use the multi interface. */ + multi = curl_multi_init(); + mres = curl_multi_add_handle(multi, pooh.easy); + while(!mres) { + struct timeval timeout; + int rc = 0; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcept; + int maxfd = -1; + + mres = curl_multi_perform(multi, &still_running); + if(!still_running || mres != CURLM_OK) + break; + + if(pooh.origin) { + time_t delta = time(NULL) - pooh.origin; + + if(delta >= 4 * PAUSE_TIME) { + fprintf(stderr, "unpausing failed: drain problem?\n"); + res = CURLE_OPERATION_TIMEDOUT; + break; + } + + if(delta >= PAUSE_TIME) + curl_easy_pause(pooh.easy, CURLPAUSE_CONT); + } + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcept); + timeout.tv_sec = 0; + timeout.tv_usec = 1000000 * PAUSE_TIME / 10; + mres = curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcept, &maxfd); + if(mres) + break; +#ifdef _WIN32 + if(maxfd == -1) + Sleep(100); + else +#endif + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcept, &timeout); + if(rc == -1) { + fprintf(stderr, "Select error\n"); + break; + } + } + + if(mres != CURLM_OK) + for(;;) { + msg = curl_multi_info_read(multi, &msgs_left); + if(!msg) + break; + if(msg->msg == CURLMSG_DONE) { + result = msg->data.result; + res = (int) result; + } + } + + curl_multi_remove_handle(multi, pooh.easy); + curl_multi_cleanup(multi); + +#else + /* Use the easy interface. */ + test_setopt(pooh.easy, CURLOPT_XFERINFODATA, &pooh); + test_setopt(pooh.easy, CURLOPT_XFERINFOFUNCTION, xferinfo); + test_setopt(pooh.easy, CURLOPT_NOPROGRESS, 0L); + result = curl_easy_perform(pooh.easy); + res = (int) result; +#endif + + +test_cleanup: + curl_easy_cleanup(pooh.easy); +#if defined(LIB670) || defined(LIB671) + curl_mime_free(mime); +#else + curl_formfree(formpost); +#endif + + curl_global_cleanup(); + return res; +} diff --git a/release/src/router/curl/tests/libtest/mk-lib1521.pl b/release/src/router/curl/tests/libtest/mk-lib1521.pl index f4add1a02ad..e4ac6a1c5aa 100644 --- a/release/src/router/curl/tests/libtest/mk-lib1521.pl +++ b/release/src/router/curl/tests/libtest/mk-lib1521.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 2017 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 2017 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -173,45 +173,45 @@ ; while() { - if($_ =~ /^ CINIT\(([^ ]*), ([^ ]*), (\d*)\)/) { + if($_ =~ /^ CURLOPT\(([^ ]*), ([^ ]*), (\d*)\)/) { my ($name, $type, $val)=($1, $2, $3); my $w=" "; - my $pref = "${w}res = curl_easy_setopt(curl, CURLOPT_$name,"; + my $pref = "${w}res = curl_easy_setopt(curl, $name,"; my $i = ' ' x (length($w) + 23); - my $check = " if(UNEX(res)) {\n err(\"$name\", res, __LINE__); goto test_cleanup; }\n"; - if($type eq "STRINGPOINT") { + my $check = " if(UNEX(res)) {\n err(\"$name\", res, __LINE__);\n goto test_cleanup;\n }\n"; + if($type eq "CURLOPTTYPE_STRINGPOINT") { print "${pref} \"string\");\n$check"; print "${pref} NULL);\n$check"; } - elsif($type eq "LONG") { + elsif($type eq "CURLOPTTYPE_LONG") { print "${pref} 0L);\n$check"; print "${pref} 22L);\n$check"; print "${pref} LO);\n$check"; print "${pref} HI);\n$check"; } - elsif($type eq "OBJECTPOINT") { + elsif($type eq "CURLOPTTYPE_OBJECTPOINT") { if($name =~ /DEPENDS/) { print "${pref} dep);\n$check"; } elsif($name =~ "SHARE") { print "${pref} share);\n$check"; } - elsif($name eq "ERRORBUFFER") { + elsif($name eq "CURLOPT_ERRORBUFFER") { print "${pref} errorbuffer);\n$check"; } - elsif(($name eq "POSTFIELDS") || - ($name eq "COPYPOSTFIELDS")) { - # set size to zero to avoid it being "illegal" - print " (void)curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);\n"; - print "${pref} stringpointerextra);\n$check"; + elsif(($name eq "CURLOPT_POSTFIELDS") || + ($name eq "CURLOPT_COPYPOSTFIELDS")) { + # set size to zero to avoid it being "illegal" + print " (void)curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);\n"; + print "${pref} stringpointerextra);\n$check"; } - elsif($name eq "HTTPPOST") { + elsif($name eq "CURLOPT_HTTPPOST") { print "${pref} httppost);\n$check"; } - elsif($name eq "MIMEPOST") { + elsif($name eq "CURLOPT_MIMEPOST") { print "${pref} mimepost);\n$check"; } - elsif($name eq "STDERR") { + elsif($name eq "CURLOPT_STDERR") { print "${pref} stream);\n$check"; } else { @@ -219,20 +219,21 @@ } print "${pref} NULL);\n$check"; } - elsif($type eq "SLISTPOINT") { + elsif($type eq "CURLOPTTYPE_SLISTPOINT") { print "${pref} slist);\n$check"; } - elsif($type eq "FUNCTIONPOINT") { + elsif($type eq "CURLOPTTYPE_FUNCTIONPOINT") { if($name =~ /([^ ]*)FUNCTION/) { - my $l=lc($1); - print "${pref}\n$i${l}cb);\n$check"; + my $l=lc($1); + $l =~ s/^curlopt_//; + print "${pref}\n$i${l}cb);\n$check"; } else { - print "${pref} &func);\n$check"; + print "${pref} &func);\n$check"; } print "${pref} NULL);\n$check"; } - elsif($type eq "OFF_T") { + elsif($type eq "CURLOPTTYPE_OFF_T") { # play conservative to work with 32bit curl_off_t print "${pref} OFF_NO);\n$check"; print "${pref} OFF_HI);\n$check"; @@ -249,7 +250,7 @@ ($_ =~ /^ CURLINFO_([^ ]*) *= *CURLINFO_([^ ]*)/)) { my ($info, $type)=($1, $2); my $c = " res = curl_easy_getinfo(curl, CURLINFO_$info,"; - my $check = " if(UNEX(res)) {\n geterr(\"$info\", res, __LINE__); goto test_cleanup; }\n"; + my $check = " if(UNEX(res)) {\n geterr(\"$info\", res, __LINE__);\n goto test_cleanup;\n }\n"; if($type eq "STRING") { print "$c &charp);\n$check"; } diff --git a/release/src/router/curl/tests/python_dependencies/impacket/smbserver.py b/release/src/router/curl/tests/python_dependencies/impacket/smbserver.py index 3473c9f0cf2..c481b27baad 100644 --- a/release/src/router/curl/tests/python_dependencies/impacket/smbserver.py +++ b/release/src/router/curl/tests/python_dependencies/impacket/smbserver.py @@ -26,7 +26,10 @@ import time import datetime import struct -import ConfigParser +try: # Python 3 + import configparser +except ImportError: # Python 2 + import ConfigParser as configparser import SocketServer import threading import logging @@ -4130,7 +4133,7 @@ def processConfigFile(self, configFile = None): if self.__serverConfig is None: if configFile is None: configFile = 'smb.conf' - self.__serverConfig = ConfigParser.ConfigParser() + self.__serverConfig = configparser.ConfigParser() self.__serverConfig.read(configFile) self.__serverName = self.__serverConfig.get('global','server_name') diff --git a/release/src/router/curl/tests/rtspserver.pl b/release/src/router/curl/tests/rtspserver.pl index 02d2f9f908c..026a8195064 100755 --- a/release/src/router/curl/tests/rtspserver.pl +++ b/release/src/router/curl/tests/rtspserver.pl @@ -34,6 +34,10 @@ BEGIN server_logfilename ); +use sshhelp qw( + exe_ext + ); + my $verbose = 0; # set to 1 for debugging my $port = 8990; # just a default my $ipvnum = 4; # default IP version of rtsp server @@ -106,4 +110,4 @@ BEGIN $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; $flags .= "--ipv$ipvnum --port $port --srcdir \"$srcdir\""; -exec("server/rtspd $flags"); +exec("server/rtspd".exe_ext('SRV')." $flags"); diff --git a/release/src/router/curl/tests/runtests.1 b/release/src/router/curl/tests/runtests.1 index 4fe875093be..00fee0005a3 100644 --- a/release/src/router/curl/tests/runtests.1 +++ b/release/src/router/curl/tests/runtests.1 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -20,29 +20,38 @@ .\" * .\" ************************************************************************** .\" -.TH runtests.pl 1 "December 13, 2019" "Curl 7.68.0" "runtests" +.TH runtests.pl 1 "March 03, 2020" "Curl 7.69.1" "runtests" .SH NAME runtests.pl \- run one or more test cases .SH SYNOPSIS -.B runtests.pl [options] [test number] [!test number] [key word] [!key word] +.B runtests.pl [options] [tests] .SH DESCRIPTION \fIruntests.pl\fP runs one, several or all the existing test cases in curl's test suite. It is often called from the root Makefile of the curl package with \&'make test'. -.SH "TEST NUMBER" -If no test case number is given, all existing tests that the script can find -will be considered for running. You can specify single test cases to run, -space-separated, like "1 3 5 7 11", and you can specify a range like "45 to -67". You can also specify only the tests you don't want to run by listing -the numbers with a leading exclamation point, like "!66". -.P -It is also possible to specify tests to skip based on a key word describing -the test. These are specified with a leading exclamation point and the -key word or phrase, like "!HTTP NTLM auth". Likewise, tests to run can -be specified simply by specifying the unadorned key words, like "FTPS". -Remember that the exclamation marks and spaces will need to be quoted somehow -when entered at many command shells. +.SH "TESTS" +Specify which test(s) to run by specifying test numbers or keywords. + +If no test number or keyword is given, all existing tests that the script can +find will be considered for running. You can specify single test cases to run +by specifying test numbers space-separated, like "1 3 5 7 11", and you can +specify a range of tests like "45 to 67". + +Specify tests to not run with a leading exclamation point, like "!66", which +runs all available tests except number 66. + +Prefix a test number with a tilde (~) to still run it, but ignore the results. + +It is also possible to specify tests based on a keyword describing the test(s) +to run, like "FTPS". The keywords are strings used in the indiviual tests. + +You can also specify keywords with a leading exclamation point and the keyword +or phrase, like "!HTTP NTLM auth" to run all tests \fBexcept\fP those using +this keyword. Remember that the exclamation marks and spaces will need to be +quoted somehow when entered at many command shells. + +Prefix a keyword with a tilde (~) to still run it, but ignore the results. .SH OPTIONS .IP "-a" Continue running the rest of the test cases even if one test fails. By @@ -79,6 +88,9 @@ people checking the failures and the reasons for them might not have physical access to the machine and logs. .IP "-R" Run the tests in a scrambled, or randomized, order instead of sequentially. + +The random seed initially set for this is fixed per month and can be set with +\fI--seed\fP. .IP "-r" Display run time statistics. (Requires Perl Time::HiRes module) .IP "-rf" @@ -92,11 +104,18 @@ If \fB-R\fP is also used, the scrambling is done after the repeats have extended the test sequence. .IP "-s" Shorter output. Speaks less than default. -.IP "--shallow=[num](,seed)" +.IP "--seed=[num]" +When using \fI--shallow\fP or \fI-R\rP that random certain aspects of the +behavior, this option can set the initial seed. If not set, the random seed +will be set based on the currently set local year and month and the first line +of the "curl -V" output. +.IP "--shallow=[num]" Used together with \fB-t\fP. This limits the number of tests to fail in torture mode to no more than 'num' per test case. If this reduces the amount, -the given 'seed' will be used to randomly discard entries to fail until the -amount is 'num'. +the script will randomly discard entries to fail until the amount is 'num'. + +The random seed initially set for this is fixed per month and can be set with +\fI--seed\fP. .IP "-t[num]" Selects a \fBtorture\fP test for the given tests. This makes runtests.pl first run the tests once and count the number of memory allocations made. It then diff --git a/release/src/router/curl/tests/runtests.pl b/release/src/router/curl/tests/runtests.pl index 27f62edd5a2..ec5462be5c5 100755 --- a/release/src/router/curl/tests/runtests.pl +++ b/release/src/router/curl/tests/runtests.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -69,6 +69,7 @@ BEGIN use strict; use warnings; use Cwd; +use Digest::MD5 qw(md5); # Subs imported from serverhelp module use serverhelp qw( @@ -110,6 +111,8 @@ BEGIN require "getpart.pm"; # array functions require "valgrind.pm"; # valgrind report parser require "ftp.pm"; +require "azure.pm"; +require "appveyor.pm"; my $HOSTIP="127.0.0.1"; # address on which the test server listens my $HOST6IP="[::1]"; # address on which the test server listens @@ -117,6 +120,8 @@ BEGIN my $CLIENT6IP="[::1]"; # address which curl uses for incoming connections my $base = 8990; # base port number +my $minport; # minimum used port number +my $maxport; # maximum used port number my $HTTPPORT; # HTTP server port my $HTTP6PORT; # HTTP IPv6 server port @@ -149,6 +154,8 @@ BEGIN my $SMBSPORT; # SMBS server port my $NEGTELNETPORT; # TELNET server port with negotiation +my $SSHSRVMD5; # MD5 of ssh server public key + my $srcdir = $ENV{'srcdir'} || '.'; my $CURL="../src/curl".exe_ext('TOOL'); # what curl executable to run on the tests my $VCURL=$CURL; # what curl binary to use to verify the servers with @@ -163,7 +170,7 @@ BEGIN my $SERVERIN="$LOGDIR/server.input"; # what curl sent the server my $SERVER2IN="$LOGDIR/server2.input"; # what curl sent the second server my $PROXYIN="$LOGDIR/proxy.input"; # what curl sent the proxy -my $CURLLOG="$LOGDIR/curl.log"; # all command lines run +my $CURLLOG="commands.log"; # all command lines run my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy ftp server instructions here my $SERVERLOGS_LOCK="$LOGDIR/serverlogs.lock"; # server logs advisor read lock my $CURLCONFIG="../curl-config"; # curl-config from current build @@ -241,6 +248,7 @@ BEGIN my $has_ldpreload; # set if curl is built for systems supporting LD_PRELOAD my $has_multissl; # set if curl is build with MultiSSL support my $has_manual; # set if curl is built with built-in manual +my $has_win32; # set if curl is built for Windows # this version is decided by the particular nghttp2 library that is being used my $h2cver = "h2c"; @@ -249,7 +257,6 @@ BEGIN my $has_gnutls; # built with GnuTLS my $has_nss; # built with NSS my $has_wolfssl; # built with wolfSSL -my $has_polarssl; # built with polarssl my $has_winssl; # built with WinSSL (Secure Channel aka Schannel) my $has_darwinssl; # built with DarwinSSL (Secure Transport) my $has_boringssl; # built with BoringSSL @@ -272,8 +279,10 @@ BEGIN my %skipped; # skipped{reason}=counter, reasons for skip my @teststat; # teststat[testnum]=reason, reasons for skip my %disabled_keywords; # key words of tests to skip +my %ignored_keywords; # key words of tests to ignore results my %enabled_keywords; # key words of tests to run my %disabled; # disabled test cases +my %ignored; # ignored results of test cases my $sshdid; # for socks server, ssh daemon version id my $sshdvernum; # for socks server, ssh daemon version number @@ -295,7 +304,8 @@ BEGIN my $testnumcheck; # test number, set in singletest sub. my %oldenv; -my %feature; # array of enabled features +my %feature; # array of enabled features +my %keywords; # array of keywords from the test spec ####################################################################### # variables that command line options may set @@ -323,7 +333,11 @@ BEGIN my $tortnum; my $tortalloc; my $shallow; -my $shallowseed; +my $randseed = 0; + +# Azure Pipelines specific variables +my $AZURE_RUN_ID = 0; +my $AZURE_RESULT_ID = 0; ####################################################################### # logmsg is our general message logging subroutine. @@ -471,7 +485,7 @@ sub startnew { logmsg "startnew: failed to write fake $pidfile with pid=$child\n"; } # could/should do a while connect fails sleep a bit and loop - sleep $timeout; + portable_sleep($timeout); if (checkdied($child)) { logmsg "startnew: child process has failed to start\n" if($verbose); return (-1,-1); @@ -2129,6 +2143,18 @@ sub runsshserver { return (0,0); } + my $hstpubmd5f = "curl_host_rsa_key.pub_md5"; + if(!open(PUBMD5FILE, "<", $hstpubmd5f) || + (read(PUBMD5FILE, $SSHSRVMD5, 32) != 32) || + !close(PUBMD5FILE) || + ($SSHSRVMD5 !~ /^[a-f0-9]{32}$/i)) + { + my $msg = "Fatal: $srvrname pubkey md5 missing : \"$hstpubmd5f\" : $!"; + logmsg "$msg\n"; + stopservers($verbose); + die $msg; + } + if($verbose) { logmsg "RUN: $srvrname server is now running PID $pid2\n"; } @@ -2172,7 +2198,7 @@ sub runsocksserver { $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); # start our socks server, get commands from the FTP cmd file - my $cmd="server/socksd". + my $cmd="server/socksd".exe_ext('SRV'). " --port $port ". " --pidfile $pidfile". " --backend $HOSTIP". @@ -2559,7 +2585,7 @@ sub cleardir { opendir(DIR, $dir) || return 0; # can't open dir while($file = readdir(DIR)) { - if($file !~ /^\./) { + if(($file !~ /^\./)) { unlink("$dir/$file"); $count++; } @@ -2632,6 +2658,7 @@ sub setupfeatures { $feature{"alt-svc"} = $has_altsvc; $feature{"manual"} = $has_manual; $feature{"unix-sockets"} = $has_unix; + $feature{"win32"} = $has_win32; # make each protocol an enabled "feature" for my $p (@protocols) { @@ -2685,7 +2712,7 @@ sub checksystem { @version = ; close(VERSOUT); - open(DISABLED, "server/disabled|"); + open(DISABLED, "server/disabled".exe_ext('TOOL')."|"); @disabled = ; close(DISABLED); @@ -2711,6 +2738,7 @@ sub checksystem { # Win32-style path. $pwd = pathhelp::sys_native_current_path(); $has_textaware = 1; + $has_win32 = 1; } if ($libcurl =~ /(winssl|schannel)/i) { $has_winssl=1; @@ -2732,10 +2760,6 @@ sub checksystem { $has_wolfssl=1; $has_sslpinning=1; } - elsif ($libcurl =~ /polarssl/i) { - $has_polarssl=1; - $has_sslpinning=1; - } elsif ($libcurl =~ /securetransport/i) { $has_darwinssl=1; $has_sslpinning=1; @@ -3008,6 +3032,8 @@ sub checksystem { logmsg sprintf("* Env: %s%s", $valgrind?"Valgrind ":"", $run_event_based?"event-based ":""); logmsg sprintf("%s\n", $libtool?"Libtool ":""); + logmsg ("* Seed: $randseed\n"); + logmsg ("* Port range: $minport-$maxport\n"); if($verbose) { logmsg "* Ports:\n"; @@ -3149,8 +3175,18 @@ sub subVariables { $$thing =~ s/%SRCDIR/$srcdir/g; $$thing =~ s/%USER/$USER/g; + if($$thing =~ /%SSHSRVMD5/) { + if(!$SSHSRVMD5) { + my $msg = "Fatal: Missing SSH server pubkey MD5. Is server running?"; + logmsg "$msg\n"; + stopservers($verbose); + die $msg; + } + $$thing =~ s/%SSHSRVMD5/$SSHSRVMD5/g; + } + # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be - # used for time-out tests and that whould work on most hosts as these + # used for time-out tests and that would work on most hosts as these # adjust for the startup/check time for this particular host. We needed # to do this to make the test suite run better on very slow hosts. @@ -3238,6 +3274,7 @@ sub singletest { my $why; my $cmd; my $disablevalgrind; + my $errorreturncode = 1; # 1 means normal error, 2 means ignored error # fist, remove all lingering log files cleardir($LOGDIR); @@ -3255,6 +3292,10 @@ sub singletest { if($disabled{$testnum}) { logmsg "Warning: test$testnum is explicitly disabled\n"; } + if($ignored{$testnum}) { + logmsg "Warning: test$testnum result is ignored\n"; + $errorreturncode = 2; + } # load the test case file definition if(loadtest("${TESTDIR}/test${testnum}")) { @@ -3304,21 +3345,30 @@ sub singletest { } if(!$why) { - my @keywords = getpart("info", "keywords"); + my @info_keywords = getpart("info", "keywords"); my $match; my $k; - if(!$keywords[0]) { + # Clear the list of keywords from the last test + %keywords = (); + + if(!$info_keywords[0]) { $why = "missing the section!"; } - for $k (@keywords) { + for $k (@info_keywords) { chomp $k; if ($disabled_keywords{lc($k)}) { $why = "disabled by keyword"; } elsif ($enabled_keywords{lc($k)}) { $match = 1; } + if ($ignored_keywords{lc($k)}) { + logmsg "Warning: test$testnum result is ignored due to $k\n"; + $errorreturncode = 2; + } + + $keywords{$k} = 1; } if(!$why && !$match && %enabled_keywords) { @@ -3341,6 +3391,19 @@ sub singletest { delete $oldenv{$var}; } + # get the name of the test early + my @testname= getpart("client", "name"); + my $testname = $testname[0]; + $testname =~ s/\n//g; + + # create test result in CI services + if(azure_check_environment() && $AZURE_RUN_ID) { + $AZURE_RESULT_ID = azure_create_test_result($AZURE_RUN_ID, $testnum, $testname); + } + elsif(appveyor_check_environment()) { + appveyor_create_test_result($testnum, $testname); + } + # remove test server commands file before servers are started/verified unlink($FTPDCMD) if(-f $FTPDCMD); @@ -3500,9 +3563,6 @@ sub singletest { my $CURLOUT="$LOGDIR/curl$testnum.out"; # curl output if not stdout # name of the test - my @testname= getpart("client", "name"); - my $testname = $testname[0]; - $testname =~ s/\n//g; logmsg "[$testname]\n" if(!$short); if($listonly) { @@ -3614,7 +3674,7 @@ sub singletest { $tool=$CMDLINE; $disablevalgrind=1; } - elsif(!$tool) { + elsif(!$tool && !$keywords{"unittest"}) { # run curl, add suitable command line options my $inc=""; if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-include/)) { @@ -3634,6 +3694,11 @@ sub singletest { $cmdargs = " $cmd"; # $cmd is the command line for the test file $CURLOUT = $STDOUT; # sends received data to stdout + # Default the tool to a unit test with the same name as the test spec + if($keywords{"unittest"} && !$tool) { + $tool="unit$testnum"; + } + if($tool =~ /^lib/) { $CMDLINE="$LIBDIR/$tool"; } @@ -3703,7 +3768,9 @@ sub singletest { logmsg "$CMDLINE\n"; } + open(CMDLOG, ">", "$LOGDIR/$CURLLOG"); print CMDLOG "$CMDLINE\n"; + close(CMDLOG); unlink("core"); @@ -3778,7 +3845,7 @@ sub singletest { if($serverlogslocktimeout) { my $lockretry = $serverlogslocktimeout * 20; while((-f $SERVERLOGS_LOCK) && $lockretry--) { - select(undef, undef, undef, 0.05); + portable_sleep(0.05); } if(($lockretry < 0) && ($serverlogslocktimeout >= $defserverlogslocktimeout)) { @@ -3795,7 +3862,7 @@ sub singletest { # based tests might need a small delay once that the client command has # run to avoid false test failures. - sleep($postcommanddelay) if($postcommanddelay); + portable_sleep($postcommanddelay) if($postcommanddelay); # timestamp removal of server logs advisor read lock $timesrvrlog{$testnum} = Time::HiRes::time(); @@ -3884,7 +3951,7 @@ sub singletest { logmsg " postcheck FAILED\n"; # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } } } @@ -3956,7 +4023,7 @@ sub singletest { $res = compare($testnum, $testname, "stdout", \@actual, \@validstdout); if($res) { - return 1; + return $errorreturncode; } $ok .= "s"; } @@ -4007,7 +4074,7 @@ sub singletest { $res = compare($testnum, $testname, "stderr", \@actual, \@validstderr); if($res) { - return 1; + return $errorreturncode; } $ok .= "r"; } @@ -4053,7 +4120,7 @@ sub singletest { $res = compare($testnum, $testname, "protocol", \@out, \@protstrip); if($res) { - return 1; + return $errorreturncode; } $ok .= "p"; @@ -4068,7 +4135,7 @@ sub singletest { my @out = loadarray($CURLOUT); $res = compare($testnum, $testname, "data", \@out, \@reply); if ($res) { - return 1; + return $errorreturncode; } $ok .= "d"; } @@ -4092,7 +4159,7 @@ sub singletest { $res = compare($testnum, $testname, "upload", \@out, \@upload); if ($res) { - return 1; + return $errorreturncode; } $ok .= "u"; } @@ -4138,7 +4205,7 @@ sub singletest { $res = compare($testnum, $testname, "proxy", \@out, \@protstrip); if($res) { - return 1; + return $errorreturncode; } $ok .= "P"; @@ -4196,7 +4263,7 @@ sub singletest { $res = compare($testnum, $testname, "output ($filename)", \@generated, \@outfile); if($res) { - return 1; + return $errorreturncode; } $outputok = 1; # output checked @@ -4226,7 +4293,7 @@ sub singletest { logmsg " exit FAILED\n"; # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } if($has_memory_tracking) { @@ -4249,7 +4316,7 @@ sub singletest { logmsg @memdata; # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } else { $ok .= "m"; @@ -4266,7 +4333,7 @@ sub singletest { logmsg "ERROR: unable to read $LOGDIR\n"; # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } my @files = readdir(DIR); closedir(DIR); @@ -4281,7 +4348,7 @@ sub singletest { logmsg "ERROR: valgrind log file missing for test $testnum\n"; # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } my @e = valgrindparse("$LOGDIR/$vgfile"); if(@e && $e[0]) { @@ -4294,7 +4361,7 @@ sub singletest { } # timestamp test result verification end $timevrfyend{$testnum} = Time::HiRes::time(); - return 1; + return $errorreturncode; } $ok .= "v"; } @@ -4333,6 +4400,9 @@ sub singletest { logmsg "PASS: $testnum - $testname\n"; } + if($errorreturncode==2) { + logmsg "Warning: test$testnum result is ignored, but passed!\n"; + } return 0; } @@ -5046,18 +5116,20 @@ sub runtimestats { $tortalloc = $1; } } - elsif($ARGV[0] =~ /--shallow=(\d+)(,|)(\d*)/) { + elsif($ARGV[0] =~ /--shallow=(\d+)/) { # Fail no more than this amount per tests when running # torture. - my ($num, $seed)=($1,$3); + my ($num)=($1); $shallow=$num; - $shallowseed=$seed?$seed:1234; # get a real seed later - srand($shallowseed); # make it predictable } elsif($ARGV[0] =~ /--repeat=(\d+)/) { # Repeat-run the given tests this many times $repeat = $1; } + elsif($ARGV[0] =~ /--seed=(\d+)/) { + # Set a fixed random seed (used for -R and --shallow) + $randseed = $1; + } elsif($ARGV[0] eq "-a") { # continue anyway, even if a test fail $anyway=1; @@ -5118,18 +5190,21 @@ sub runtimestats { -l list all test case names/descriptions -n no valgrind -p print log file contents when a test fails - -R scrambled order + -R scrambled order (uses the random seed, see --seed) -r run time statistics -rf full run time statistics -s short output - --shallow=[num](,seed) make the torture tests thinner + --seed=[num] set the random seed to a fixed number + --shallow=[num] randomly makes the torture tests "thinner" -t[N] torture (simulate function failures); N means fail Nth function -v verbose output -vc path use this curl only to verify the existing servers [num] like "5 6 9" or " 5 to 22 " to run those tests only [!num] like "!5 !6 !9" to disable those tests + [~num] like "~5 ~6 ~9" to ignore the result of those tests [keyword] like "IPv6" to select only tests containing the key word [!keyword] like "!cookies" to disable any tests containing the key word + [~keyword] like "~cookies" to ignore results of tests containing key word EOHELP ; exit; @@ -5162,9 +5237,16 @@ sub runtimestats { $fromnum = -1; $disabled{$1}=$1; } + elsif($ARGV[0] =~ /^~(\d+)/) { + $fromnum = -1; + $ignored{$1}=$1; + } elsif($ARGV[0] =~ /^!(.+)/) { $disabled_keywords{lc($1)}=$1; } + elsif($ARGV[0] =~ /^~(.+)/) { + $ignored_keywords{lc($1)}=$1; + } elsif($ARGV[0] =~ /^([-[{a-zA-Z].*)/) { $enabled_keywords{lc($1)}=$1; } @@ -5175,6 +5257,20 @@ sub runtimestats { shift @ARGV; } +if(!$randseed) { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = + localtime(time); + # seed of the month. December 2019 becomes 201912 + $randseed = ($year+1900)*100 + $mon+1; + open(C, "$CURL --version 2>/dev/null|"); + my @c = ; + close(C); + # use the first line of output and get the md5 out of it + my $str = md5($c[0]); + $randseed += unpack('S', $str); # unsigned 16 bit value +} +srand $randseed; + if(@testthis && ($testthis[0] ne "")) { $TESTCASES=join(" ", @testthis); } @@ -5231,6 +5327,8 @@ sub runtimestats { } } +$minport = $base; # original base port number + $HTTPPORT = $base++; # HTTP server port $HTTPSPORT = $base++; # HTTPS (stunnel) server port $FTPPORT = $base++; # FTP server port @@ -5262,6 +5360,8 @@ sub runtimestats { $NEGTELNETPORT = $base++; # TELNET port with negotiation $HTTPUNIXPATH = 'http.sock'; # HTTP server Unix domain socket path +$maxport = $base-1; # updated base port number + ####################################################################### # clear and create logging directory: # @@ -5372,14 +5472,6 @@ sub disabledtests { $TESTCASES = join(" ", @rand); } -####################################################################### -# Start the command line log -# -open(CMDLOG, ">$CURLLOG") || - logmsg "can't log command lines to $CURLLOG\n"; - -####################################################################### - # Display the contents of the given file. Line endings are canonicalized # and excessively long files are elided sub displaylogcontent { @@ -5474,6 +5566,15 @@ sub displaylogs { } } +####################################################################### +# Setup Azure Pipelines Test Run (if running in Azure DevOps) +# + +if(azure_check_environment()) { + $AZURE_RUN_ID = azure_create_test_run(); + logmsg "Azure Run ID: $AZURE_RUN_ID\n" if ($verbose); +} + ####################################################################### # The main test-loop # @@ -5481,6 +5582,7 @@ sub displaylogs { my $failed; my $testnum; my $ok=0; +my $ign=0; my $total=0; my $lasttest=0; my @at = split(" ", $TESTCASES); @@ -5494,6 +5596,16 @@ sub displaylogs { $count++; my $error = singletest($run_event_based, $testnum, $count, scalar(@at)); + + # update test result in CI services + if(azure_check_environment() && $AZURE_RUN_ID && $AZURE_RESULT_ID) { + $AZURE_RESULT_ID = azure_update_test_result($AZURE_RUN_ID, $AZURE_RESULT_ID, $testnum, $error, + $timeprepini{$testnum}, $timevrfyend{$testnum}); + } + elsif(appveyor_check_environment()) { + appveyor_update_test_result($testnum, $error, $timeprepini{$testnum}, $timevrfyend{$testnum}); + } + if($error < 0) { # not a test we can run next; @@ -5502,12 +5614,21 @@ sub displaylogs { $total++; # number of tests we've run if($error>0) { - $failed.= "$testnum "; + if($error==2) { + # ignored test failures are wrapped in () + $failed.= "($testnum) "; + } + else { + $failed.= "$testnum "; + } if($postmortem) { # display all files in log/ in a nice way displaylogs($testnum); } - if(!$anyway) { + if($error==2) { + $ign++; # ignored test result counter + } + elsif(!$anyway) { # a test failed, abort logmsg "\n - abort tests\n"; last; @@ -5523,9 +5644,12 @@ sub displaylogs { my $sofar = time() - $start; ####################################################################### -# Close command log +# Finish Azure Pipelines Test Run (if running in Azure DevOps) # -close(CMDLOG); + +if(azure_check_environment() && $AZURE_RUN_ID) { + $AZURE_RUN_ID = azure_update_test_run($AZURE_RUN_ID); +} # Tests done, stop the servers stopservers($verbose); @@ -5580,6 +5704,6 @@ sub displaylogs { } } -if($total && ($ok != $total)) { +if($total && (($ok+$ign) != $total)) { exit 1; } diff --git a/release/src/router/curl/tests/server/Makefile.in b/release/src/router/curl/tests/server/Makefile.in index 96105235dfb..d69522dd2fc 100644 --- a/release/src/router/curl/tests/server/Makefile.in +++ b/release/src/router/curl/tests/server/Makefile.in @@ -546,6 +546,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ diff --git a/release/src/router/curl/tests/server/sws.c b/release/src/router/curl/tests/server/sws.c index 10982b63a54..b397ed19bb9 100644 --- a/release/src/router/curl/tests/server/sws.c +++ b/release/src/router/curl/tests/server/sws.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -118,6 +118,8 @@ struct httprequest { int rcmd; /* doing a special command, see defines above */ int prot_version; /* HTTP version * 10 */ int callcount; /* times ProcessRequest() gets called */ + bool skipall; /* skip all incoming data */ + bool noexpect; /* refuse Expect: (don't read the body) */ bool connmon; /* monitor the state of the connection, log disconnects */ bool upgrade; /* test case allows upgrade to http2 */ bool upgrade_request; /* upgrade request found and allowed */ @@ -179,6 +181,9 @@ const char *serverlogfile = DEFAULT_LOGFILE; /* close connection */ #define CMD_SWSCLOSE "swsclose" +/* deny Expect: requests */ +#define CMD_NOEXPECT "no-expect" + #define END_OF_HEADERS "\r\n\r\n" enum { @@ -427,6 +432,10 @@ static int parse_servercmd(struct httprequest *req) logmsg("instructed to skip this number of bytes %d", num); req->skip = num; } + else if(!strncmp(CMD_NOEXPECT, cmd, strlen(CMD_NOEXPECT))) { + logmsg("instructed to reject Expect: 100-continue"); + req->noexpect = TRUE; + } else if(1 == sscanf(cmd, "writedelay: %d", &num)) { logmsg("instructed to delay %d secs between packets", num); req->writedelay = num; @@ -605,7 +614,7 @@ static int ProcessRequest(struct httprequest *req) } if(req->testno == DOCNUMBER_NOTHING) { - /* Still no test case number. Try to get the the number off the last dot + /* Still no test case number. Try to get the number off the last dot instead, IE we consider the TLD to be the test number. Test 123 can then be written as "example.com.123". */ @@ -735,19 +744,28 @@ static int ProcessRequest(struct httprequest *req) req->open = FALSE; /* closes connection */ return 1; /* done */ } - req->cl = clen - req->skip; + if(req->skipall) + req->cl = 0; + else + req->cl = clen - req->skip; logmsg("Found Content-Length: %lu in the request", clen); if(req->skip) logmsg("... but will abort after %zu bytes", req->cl); - break; } else if(strncasecompare("Transfer-Encoding: chunked", line, strlen("Transfer-Encoding: chunked"))) { /* chunked data coming in */ chunked = TRUE; } - + else if(req->noexpect && + strncasecompare("Expect: 100-continue", line, + strlen("Expect: 100-continue"))) { + if(req->cl) + req->cl = 0; + req->skipall = TRUE; + logmsg("Found Expect: 100-continue, ignore body"); + } if(chunked) { if(strstr(req->reqbuf, "\r\n0\r\n\r\n")) { @@ -939,6 +957,8 @@ static void init_httprequest(struct httprequest *req) req->digest = FALSE; req->ntlm = FALSE; req->skip = 0; + req->skipall = FALSE; + req->noexpect = FALSE; req->writedelay = 0; req->rcmd = RCMD_NORMALREQ; req->prot_version = 0; @@ -2143,7 +2163,7 @@ int main(int argc, char *argv[]) case AF_UNIX: memset(&me.sau, 0, sizeof(me.sau)); me.sau.sun_family = AF_UNIX; - strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path)); + strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path) - 1); rc = bind(sock, &me.sa, sizeof(me.sau)); if(0 != rc && errno == EADDRINUSE) { struct stat statbuf; diff --git a/release/src/router/curl/tests/server/util.h b/release/src/router/curl/tests/server/util.h index 7b4ec162677..236d4550e00 100644 --- a/release/src/router/curl/tests/server/util.h +++ b/release/src/router/curl/tests/server/util.h @@ -37,16 +37,16 @@ extern const char *path; /* global variable, log file name */ extern const char *serverlogfile; -#ifdef WIN32 +#if defined(WIN32) || defined(_WIN32) #include #include -#define sleep(sec) Sleep ((sec)*1000) +#define sleep(sec) Sleep ((sec)*1000) #undef perror #define perror(m) win32_perror(m) void win32_perror(const char *msg); -#endif /* WIN32 */ +#endif /* WIN32 or _WIN32 */ #ifdef USE_WINSOCK void win32_init(void); diff --git a/release/src/router/curl/tests/sshhelp.pm b/release/src/router/curl/tests/sshhelp.pm index 248be67a236..e43f8653279 100644 --- a/release/src/router/curl/tests/sshhelp.pm +++ b/release/src/router/curl/tests/sshhelp.pm @@ -50,6 +50,7 @@ use vars qw( $sftpcmds $hstprvkeyf $hstpubkeyf + $hstpubmd5f $cliprvkeyf $clipubkeyf @sftppath @@ -82,6 +83,7 @@ use vars qw( $sftpcmds $hstprvkeyf $hstpubkeyf + $hstpubmd5f $cliprvkeyf $clipubkeyf display_sshdconfig @@ -122,6 +124,7 @@ $sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file $knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file $hstprvkeyf = 'curl_host_rsa_key'; # host private key file $hstpubkeyf = 'curl_host_rsa_key.pub'; # host public key file +$hstpubmd5f = 'curl_host_rsa_key.pub_md5'; # md5 hash of host public key $cliprvkeyf = 'curl_client_key'; # client private key file $clipubkeyf = 'curl_client_key.pub'; # client public key file diff --git a/release/src/router/curl/tests/sshserver.pl b/release/src/router/curl/tests/sshserver.pl index 197e8b872ee..4414ca51bd9 100755 --- a/release/src/router/curl/tests/sshserver.pl +++ b/release/src/router/curl/tests/sshserver.pl @@ -28,6 +28,9 @@ use warnings; use Cwd; use Cwd 'abs_path'; +use Digest::MD5; +use Digest::MD5 'md5_hex'; +use MIME::Base64; #*************************************************************************** # Variables and subs imported from sshhelp module @@ -48,6 +51,7 @@ $sftpcmds $hstprvkeyf $hstpubkeyf + $hstpubmd5f $cliprvkeyf $clipubkeyf display_sshdconfig @@ -357,10 +361,11 @@ # if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) || (! -e $hstpubkeyf) || (! -s $hstpubkeyf) || + (! -e $hstpubmd5f) || (! -s $hstpubmd5f) || (! -e $cliprvkeyf) || (! -s $cliprvkeyf) || (! -e $clipubkeyf) || (! -s $clipubkeyf)) { # Make sure all files are gone so ssh-keygen doesn't complain - unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf); + unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $cliprvkeyf, $clipubkeyf); logmsg 'generating host keys...' if($verbose); if(system "\"$sshkeygen\" -q -t rsa -f $hstprvkeyf -C 'curl test server' -N ''") { logmsg 'Could not generate host key'; @@ -374,6 +379,21 @@ # Make sure that permissions are restricted so openssh doesn't complain system "chmod 600 $hstprvkeyf"; system "chmod 600 $cliprvkeyf"; + # Save md5 hash of public host key + open(RSAKEYFILE, "<$hstpubkeyf"); + my @rsahostkey = do { local $/ = ' '; }; + close(RSAKEYFILE); + if(!$rsahostkey[1]) { + logmsg 'Failed parsing base64 encoded RSA host key'; + exit 1; + } + open(PUBMD5FILE, ">$hstpubmd5f"); + print PUBMD5FILE md5_hex(decode_base64($rsahostkey[1])); + close(PUBMD5FILE); + if((! -e $hstpubmd5f) || (! -s $hstpubmd5f)) { + logmsg 'Failed writing md5 hash of RSA host key'; + exit 1; + } } @@ -1099,8 +1119,8 @@ sub sshd_supports_opt { #*************************************************************************** # Clean up once the server has stopped # -unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf, $knownhosts); -unlink($sshdconfig, $sshconfig, $sftpconfig); - +unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, + $cliprvkeyf, $clipubkeyf, $knownhosts, + $sshdconfig, $sshconfig, $sftpconfig); exit 0; diff --git a/release/src/router/curl/tests/testcurl.1 b/release/src/router/curl/tests/testcurl.1 index 7370ffccd46..863da041cef 100644 --- a/release/src/router/curl/tests/testcurl.1 +++ b/release/src/router/curl/tests/testcurl.1 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH testcurl.pl 1 "October 22, 2016" "Curl 7.68.0" "testcurl" +.TH testcurl.pl 1 "October 22, 2016" "Curl 7.69.1" "testcurl" .SH NAME testcurl.pl \- (automatically) test curl diff --git a/release/src/router/curl/tests/testcurl.pl b/release/src/router/curl/tests/testcurl.pl index 69722fb3603..fce53571ad7 100755 --- a/release/src/router/curl/tests/testcurl.pl +++ b/release/src/router/curl/tests/testcurl.pl @@ -173,7 +173,7 @@ } } -if (($^O eq 'MSWin32' || $^O eq 'msys') && +if (($^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys') && ($targetos =~ /vc/ || $targetos =~ /mingw32/ || $targetos =~ /borland/ || $targetos =~ /watcom/)) { diff --git a/release/src/router/curl/tests/tftpserver.pl b/release/src/router/curl/tests/tftpserver.pl index 8c84111bfb3..c16a9e14023 100755 --- a/release/src/router/curl/tests/tftpserver.pl +++ b/release/src/router/curl/tests/tftpserver.pl @@ -34,6 +34,10 @@ BEGIN server_logfilename ); +use sshhelp qw( + exe_ext + ); + my $verbose = 0; # set to 1 for debugging my $port = 8997; # just a default my $ipvnum = 4; # default IP version of tftp server @@ -107,4 +111,4 @@ BEGIN $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; $flags .= "--ipv$ipvnum --port $port --srcdir \"$srcdir\""; -exec("server/tftpd $flags"); +exec("server/tftpd".exe_ext('SRV')." $flags"); diff --git a/release/src/router/curl/tests/unit/Makefile.in b/release/src/router/curl/tests/unit/Makefile.in index b1731501631..bae6278b9b9 100644 --- a/release/src/router/curl/tests/unit/Makefile.in +++ b/release/src/router/curl/tests/unit/Makefile.in @@ -14,6 +14,28 @@ @SET_MAKE@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + # these files are used in every single unit test program VPATH = @srcdir@ @@ -127,6 +149,7 @@ am__EXEEXT_1 = unit1300$(EXEEXT) unit1301$(EXEEXT) unit1302$(EXEEXT) \ unit1601$(EXEEXT) unit1602$(EXEEXT) unit1603$(EXEEXT) \ unit1604$(EXEEXT) unit1605$(EXEEXT) unit1606$(EXEEXT) \ unit1607$(EXEEXT) unit1608$(EXEEXT) unit1609$(EXEEXT) \ + unit1610$(EXEEXT) unit1611$(EXEEXT) unit1612$(EXEEXT) \ unit1620$(EXEEXT) unit1621$(EXEEXT) unit1650$(EXEEXT) \ unit1651$(EXEEXT) unit1652$(EXEEXT) unit1653$(EXEEXT) \ unit1654$(EXEEXT) unit1655$(EXEEXT) @@ -299,49 +322,67 @@ unit1609_OBJECTS = $(am_unit1609_OBJECTS) unit1609_LDADD = $(LDADD) unit1609_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_28 = ../libtest/unit1620-first.$(OBJEXT) -am_unit1620_OBJECTS = unit1620-unit1620.$(OBJEXT) $(am__objects_28) +am__objects_28 = ../libtest/unit1610-first.$(OBJEXT) +am_unit1610_OBJECTS = unit1610-unit1610.$(OBJEXT) $(am__objects_28) +unit1610_OBJECTS = $(am_unit1610_OBJECTS) +unit1610_LDADD = $(LDADD) +unit1610_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ + $(top_builddir)/lib/libcurlu.la +am__objects_29 = ../libtest/unit1611-first.$(OBJEXT) +am_unit1611_OBJECTS = unit1611-unit1611.$(OBJEXT) $(am__objects_29) +unit1611_OBJECTS = $(am_unit1611_OBJECTS) +unit1611_LDADD = $(LDADD) +unit1611_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ + $(top_builddir)/lib/libcurlu.la +am__objects_30 = ../libtest/unit1612-first.$(OBJEXT) +am_unit1612_OBJECTS = unit1612-unit1612.$(OBJEXT) $(am__objects_30) +unit1612_OBJECTS = $(am_unit1612_OBJECTS) +unit1612_LDADD = $(LDADD) +unit1612_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ + $(top_builddir)/lib/libcurlu.la +am__objects_31 = ../libtest/unit1620-first.$(OBJEXT) +am_unit1620_OBJECTS = unit1620-unit1620.$(OBJEXT) $(am__objects_31) unit1620_OBJECTS = $(am_unit1620_OBJECTS) unit1620_LDADD = $(LDADD) unit1620_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_29 = ../libtest/unit1621-first.$(OBJEXT) -am_unit1621_OBJECTS = unit1621-unit1621.$(OBJEXT) $(am__objects_29) +am__objects_32 = ../libtest/unit1621-first.$(OBJEXT) +am_unit1621_OBJECTS = unit1621-unit1621.$(OBJEXT) $(am__objects_32) unit1621_OBJECTS = $(am_unit1621_OBJECTS) unit1621_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurl.la -am__objects_30 = ../libtest/unit1650-first.$(OBJEXT) -am_unit1650_OBJECTS = unit1650-unit1650.$(OBJEXT) $(am__objects_30) +am__objects_33 = ../libtest/unit1650-first.$(OBJEXT) +am_unit1650_OBJECTS = unit1650-unit1650.$(OBJEXT) $(am__objects_33) unit1650_OBJECTS = $(am_unit1650_OBJECTS) unit1650_LDADD = $(LDADD) unit1650_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_31 = ../libtest/unit1651-first.$(OBJEXT) -am_unit1651_OBJECTS = unit1651-unit1651.$(OBJEXT) $(am__objects_31) +am__objects_34 = ../libtest/unit1651-first.$(OBJEXT) +am_unit1651_OBJECTS = unit1651-unit1651.$(OBJEXT) $(am__objects_34) unit1651_OBJECTS = $(am_unit1651_OBJECTS) unit1651_LDADD = $(LDADD) unit1651_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_32 = ../libtest/unit1652-first.$(OBJEXT) -am_unit1652_OBJECTS = unit1652-unit1652.$(OBJEXT) $(am__objects_32) +am__objects_35 = ../libtest/unit1652-first.$(OBJEXT) +am_unit1652_OBJECTS = unit1652-unit1652.$(OBJEXT) $(am__objects_35) unit1652_OBJECTS = $(am_unit1652_OBJECTS) unit1652_LDADD = $(LDADD) unit1652_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_33 = ../libtest/unit1653-first.$(OBJEXT) -am_unit1653_OBJECTS = unit1653-unit1653.$(OBJEXT) $(am__objects_33) +am__objects_36 = ../libtest/unit1653-first.$(OBJEXT) +am_unit1653_OBJECTS = unit1653-unit1653.$(OBJEXT) $(am__objects_36) unit1653_OBJECTS = $(am_unit1653_OBJECTS) unit1653_LDADD = $(LDADD) unit1653_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_34 = ../libtest/unit1654-first.$(OBJEXT) -am_unit1654_OBJECTS = unit1654-unit1654.$(OBJEXT) $(am__objects_34) +am__objects_37 = ../libtest/unit1654-first.$(OBJEXT) +am_unit1654_OBJECTS = unit1654-unit1654.$(OBJEXT) $(am__objects_37) unit1654_OBJECTS = $(am_unit1654_OBJECTS) unit1654_LDADD = $(LDADD) unit1654_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ $(top_builddir)/lib/libcurlu.la -am__objects_35 = ../libtest/unit1655-first.$(OBJEXT) -am_unit1655_OBJECTS = unit1655-unit1655.$(OBJEXT) $(am__objects_35) +am__objects_38 = ../libtest/unit1655-first.$(OBJEXT) +am_unit1655_OBJECTS = unit1655-unit1655.$(OBJEXT) $(am__objects_38) unit1655_OBJECTS = $(am_unit1655_OBJECTS) unit1655_LDADD = $(LDADD) unit1655_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \ @@ -388,6 +429,9 @@ am__depfiles_remade = ../libtest/$(DEPDIR)/unit1300-first.Po \ ../libtest/$(DEPDIR)/unit1607-first.Po \ ../libtest/$(DEPDIR)/unit1608-first.Po \ ../libtest/$(DEPDIR)/unit1609-first.Po \ + ../libtest/$(DEPDIR)/unit1610-first.Po \ + ../libtest/$(DEPDIR)/unit1611-first.Po \ + ../libtest/$(DEPDIR)/unit1612-first.Po \ ../libtest/$(DEPDIR)/unit1620-first.Po \ ../libtest/$(DEPDIR)/unit1621-first.Po \ ../libtest/$(DEPDIR)/unit1650-first.Po \ @@ -423,6 +467,9 @@ am__depfiles_remade = ../libtest/$(DEPDIR)/unit1300-first.Po \ ./$(DEPDIR)/unit1607-unit1607.Po \ ./$(DEPDIR)/unit1608-unit1608.Po \ ./$(DEPDIR)/unit1609-unit1609.Po \ + ./$(DEPDIR)/unit1610-unit1610.Po \ + ./$(DEPDIR)/unit1611-unit1611.Po \ + ./$(DEPDIR)/unit1612-unit1612.Po \ ./$(DEPDIR)/unit1620-unit1620.Po \ ./$(DEPDIR)/unit1621-unit1621.Po \ ./$(DEPDIR)/unit1650-unit1650.Po \ @@ -459,6 +506,7 @@ SOURCES = $(unit1300_SOURCES) $(unit1301_SOURCES) $(unit1302_SOURCES) \ $(unit1601_SOURCES) $(unit1602_SOURCES) $(unit1603_SOURCES) \ $(unit1604_SOURCES) $(unit1605_SOURCES) $(unit1606_SOURCES) \ $(unit1607_SOURCES) $(unit1608_SOURCES) $(unit1609_SOURCES) \ + $(unit1610_SOURCES) $(unit1611_SOURCES) $(unit1612_SOURCES) \ $(unit1620_SOURCES) $(unit1621_SOURCES) $(unit1650_SOURCES) \ $(unit1651_SOURCES) $(unit1652_SOURCES) $(unit1653_SOURCES) \ $(unit1654_SOURCES) $(unit1655_SOURCES) @@ -471,7 +519,8 @@ DIST_SOURCES = $(unit1300_SOURCES) $(unit1301_SOURCES) \ $(unit1600_SOURCES) $(unit1601_SOURCES) $(unit1602_SOURCES) \ $(unit1603_SOURCES) $(unit1604_SOURCES) $(unit1605_SOURCES) \ $(unit1606_SOURCES) $(unit1607_SOURCES) $(unit1608_SOURCES) \ - $(unit1609_SOURCES) $(unit1620_SOURCES) $(unit1621_SOURCES) \ + $(unit1609_SOURCES) $(unit1610_SOURCES) $(unit1611_SOURCES) \ + $(unit1612_SOURCES) $(unit1620_SOURCES) $(unit1621_SOURCES) \ $(unit1650_SOURCES) $(unit1651_SOURCES) $(unit1652_SOURCES) \ $(unit1653_SOURCES) $(unit1654_SOURCES) $(unit1655_SOURCES) am__can_run_installinfo = \ @@ -647,6 +696,7 @@ USE_SCHANNEL = @USE_SCHANNEL@ USE_SECTRANSP = @USE_SECTRANSP@ USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ +USE_WOLFSSH = @USE_WOLFSSH@ USE_WOLFSSL = @USE_WOLFSSL@ VERSION = @VERSION@ VERSIONNUM = @VERSIONNUM@ @@ -771,7 +821,8 @@ UNITPROGS = unit1300 unit1301 unit1302 unit1303 unit1304 unit1305 unit1307 \ unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \ unit1399 \ unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \ - unit1608 unit1609 unit1620 unit1621 \ + unit1608 unit1609 unit1610 unit1611 unit1612 \ + unit1620 unit1621 \ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1300_SOURCES = unit1300.c $(UNITFILES) @@ -831,6 +882,12 @@ unit1608_SOURCES = unit1608.c $(UNITFILES) unit1608_CPPFLAGS = $(AM_CPPFLAGS) unit1609_SOURCES = unit1609.c $(UNITFILES) unit1609_CPPFLAGS = $(AM_CPPFLAGS) +unit1610_SOURCES = unit1610.c $(UNITFILES) +unit1610_CPPFLAGS = $(AM_CPPFLAGS) +unit1611_SOURCES = unit1611.c $(UNITFILES) +unit1611_CPPFLAGS = $(AM_CPPFLAGS) +unit1612_SOURCES = unit1612.c $(UNITFILES) +unit1612_CPPFLAGS = $(AM_CPPFLAGS) unit1620_SOURCES = unit1620.c $(UNITFILES) unit1620_CPPFLAGS = $(AM_CPPFLAGS) unit1621_SOURCES = unit1621.c $(UNITFILES) @@ -1065,6 +1122,24 @@ unit1608$(EXEEXT): $(unit1608_OBJECTS) $(unit1608_DEPENDENCIES) $(EXTRA_unit1608 unit1609$(EXEEXT): $(unit1609_OBJECTS) $(unit1609_DEPENDENCIES) $(EXTRA_unit1609_DEPENDENCIES) @rm -f unit1609$(EXEEXT) $(AM_V_CCLD)$(LINK) $(unit1609_OBJECTS) $(unit1609_LDADD) $(LIBS) +../libtest/unit1610-first.$(OBJEXT): ../libtest/$(am__dirstamp) \ + ../libtest/$(DEPDIR)/$(am__dirstamp) + +unit1610$(EXEEXT): $(unit1610_OBJECTS) $(unit1610_DEPENDENCIES) $(EXTRA_unit1610_DEPENDENCIES) + @rm -f unit1610$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit1610_OBJECTS) $(unit1610_LDADD) $(LIBS) +../libtest/unit1611-first.$(OBJEXT): ../libtest/$(am__dirstamp) \ + ../libtest/$(DEPDIR)/$(am__dirstamp) + +unit1611$(EXEEXT): $(unit1611_OBJECTS) $(unit1611_DEPENDENCIES) $(EXTRA_unit1611_DEPENDENCIES) + @rm -f unit1611$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit1611_OBJECTS) $(unit1611_LDADD) $(LIBS) +../libtest/unit1612-first.$(OBJEXT): ../libtest/$(am__dirstamp) \ + ../libtest/$(DEPDIR)/$(am__dirstamp) + +unit1612$(EXEEXT): $(unit1612_OBJECTS) $(unit1612_DEPENDENCIES) $(EXTRA_unit1612_DEPENDENCIES) + @rm -f unit1612$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit1612_OBJECTS) $(unit1612_LDADD) $(LIBS) ../libtest/unit1620-first.$(OBJEXT): ../libtest/$(am__dirstamp) \ ../libtest/$(DEPDIR)/$(am__dirstamp) @@ -1148,6 +1223,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1607-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1608-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1609-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1610-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1611-first.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1612-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1620-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1621-first.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../libtest/$(DEPDIR)/unit1650-first.Po@am__quote@ # am--include-marker @@ -1183,6 +1261,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1607-unit1607.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1608-unit1608.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1609-unit1609.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1610-unit1610.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1611-unit1611.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1612-unit1612.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1620-unit1620.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1621-unit1621.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1650-unit1650.Po@am__quote@ # am--include-marker @@ -1978,6 +2059,90 @@ unit1609-unit1609.obj: unit1609.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1609_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1609-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` +unit1610-unit1610.o: unit1610.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1610-unit1610.o -MD -MP -MF $(DEPDIR)/unit1610-unit1610.Tpo -c -o unit1610-unit1610.o `test -f 'unit1610.c' || echo '$(srcdir)/'`unit1610.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1610-unit1610.Tpo $(DEPDIR)/unit1610-unit1610.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1610.c' object='unit1610-unit1610.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1610-unit1610.o `test -f 'unit1610.c' || echo '$(srcdir)/'`unit1610.c + +unit1610-unit1610.obj: unit1610.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1610-unit1610.obj -MD -MP -MF $(DEPDIR)/unit1610-unit1610.Tpo -c -o unit1610-unit1610.obj `if test -f 'unit1610.c'; then $(CYGPATH_W) 'unit1610.c'; else $(CYGPATH_W) '$(srcdir)/unit1610.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1610-unit1610.Tpo $(DEPDIR)/unit1610-unit1610.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1610.c' object='unit1610-unit1610.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1610-unit1610.obj `if test -f 'unit1610.c'; then $(CYGPATH_W) 'unit1610.c'; else $(CYGPATH_W) '$(srcdir)/unit1610.c'; fi` + +../libtest/unit1610-first.o: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1610-first.o -MD -MP -MF ../libtest/$(DEPDIR)/unit1610-first.Tpo -c -o ../libtest/unit1610-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1610-first.Tpo ../libtest/$(DEPDIR)/unit1610-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1610-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1610-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c + +../libtest/unit1610-first.obj: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1610-first.obj -MD -MP -MF ../libtest/$(DEPDIR)/unit1610-first.Tpo -c -o ../libtest/unit1610-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1610-first.Tpo ../libtest/$(DEPDIR)/unit1610-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1610-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1610_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1610-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` + +unit1611-unit1611.o: unit1611.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1611-unit1611.o -MD -MP -MF $(DEPDIR)/unit1611-unit1611.Tpo -c -o unit1611-unit1611.o `test -f 'unit1611.c' || echo '$(srcdir)/'`unit1611.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1611-unit1611.Tpo $(DEPDIR)/unit1611-unit1611.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1611.c' object='unit1611-unit1611.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1611-unit1611.o `test -f 'unit1611.c' || echo '$(srcdir)/'`unit1611.c + +unit1611-unit1611.obj: unit1611.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1611-unit1611.obj -MD -MP -MF $(DEPDIR)/unit1611-unit1611.Tpo -c -o unit1611-unit1611.obj `if test -f 'unit1611.c'; then $(CYGPATH_W) 'unit1611.c'; else $(CYGPATH_W) '$(srcdir)/unit1611.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1611-unit1611.Tpo $(DEPDIR)/unit1611-unit1611.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1611.c' object='unit1611-unit1611.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1611-unit1611.obj `if test -f 'unit1611.c'; then $(CYGPATH_W) 'unit1611.c'; else $(CYGPATH_W) '$(srcdir)/unit1611.c'; fi` + +../libtest/unit1611-first.o: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1611-first.o -MD -MP -MF ../libtest/$(DEPDIR)/unit1611-first.Tpo -c -o ../libtest/unit1611-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1611-first.Tpo ../libtest/$(DEPDIR)/unit1611-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1611-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1611-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c + +../libtest/unit1611-first.obj: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1611-first.obj -MD -MP -MF ../libtest/$(DEPDIR)/unit1611-first.Tpo -c -o ../libtest/unit1611-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1611-first.Tpo ../libtest/$(DEPDIR)/unit1611-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1611-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1611_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1611-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` + +unit1612-unit1612.o: unit1612.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1612-unit1612.o -MD -MP -MF $(DEPDIR)/unit1612-unit1612.Tpo -c -o unit1612-unit1612.o `test -f 'unit1612.c' || echo '$(srcdir)/'`unit1612.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1612-unit1612.Tpo $(DEPDIR)/unit1612-unit1612.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1612.c' object='unit1612-unit1612.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1612-unit1612.o `test -f 'unit1612.c' || echo '$(srcdir)/'`unit1612.c + +unit1612-unit1612.obj: unit1612.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1612-unit1612.obj -MD -MP -MF $(DEPDIR)/unit1612-unit1612.Tpo -c -o unit1612-unit1612.obj `if test -f 'unit1612.c'; then $(CYGPATH_W) 'unit1612.c'; else $(CYGPATH_W) '$(srcdir)/unit1612.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1612-unit1612.Tpo $(DEPDIR)/unit1612-unit1612.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit1612.c' object='unit1612-unit1612.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit1612-unit1612.obj `if test -f 'unit1612.c'; then $(CYGPATH_W) 'unit1612.c'; else $(CYGPATH_W) '$(srcdir)/unit1612.c'; fi` + +../libtest/unit1612-first.o: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1612-first.o -MD -MP -MF ../libtest/$(DEPDIR)/unit1612-first.Tpo -c -o ../libtest/unit1612-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1612-first.Tpo ../libtest/$(DEPDIR)/unit1612-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1612-first.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1612-first.o `test -f '../libtest/first.c' || echo '$(srcdir)/'`../libtest/first.c + +../libtest/unit1612-first.obj: ../libtest/first.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../libtest/unit1612-first.obj -MD -MP -MF ../libtest/$(DEPDIR)/unit1612-first.Tpo -c -o ../libtest/unit1612-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../libtest/$(DEPDIR)/unit1612-first.Tpo ../libtest/$(DEPDIR)/unit1612-first.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../libtest/first.c' object='../libtest/unit1612-first.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1612_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../libtest/unit1612-first.obj `if test -f '../libtest/first.c'; then $(CYGPATH_W) '../libtest/first.c'; else $(CYGPATH_W) '$(srcdir)/../libtest/first.c'; fi` + unit1620-unit1620.o: unit1620.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit1620_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit1620-unit1620.o -MD -MP -MF $(DEPDIR)/unit1620-unit1620.Tpo -c -o unit1620-unit1620.o `test -f 'unit1620.c' || echo '$(srcdir)/'`unit1620.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/unit1620-unit1620.Tpo $(DEPDIR)/unit1620-unit1620.Po @@ -2362,6 +2527,9 @@ distclean: distclean-am -rm -f ../libtest/$(DEPDIR)/unit1607-first.Po -rm -f ../libtest/$(DEPDIR)/unit1608-first.Po -rm -f ../libtest/$(DEPDIR)/unit1609-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1610-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1611-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1612-first.Po -rm -f ../libtest/$(DEPDIR)/unit1620-first.Po -rm -f ../libtest/$(DEPDIR)/unit1621-first.Po -rm -f ../libtest/$(DEPDIR)/unit1650-first.Po @@ -2397,6 +2565,9 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/unit1607-unit1607.Po -rm -f ./$(DEPDIR)/unit1608-unit1608.Po -rm -f ./$(DEPDIR)/unit1609-unit1609.Po + -rm -f ./$(DEPDIR)/unit1610-unit1610.Po + -rm -f ./$(DEPDIR)/unit1611-unit1611.Po + -rm -f ./$(DEPDIR)/unit1612-unit1612.Po -rm -f ./$(DEPDIR)/unit1620-unit1620.Po -rm -f ./$(DEPDIR)/unit1621-unit1621.Po -rm -f ./$(DEPDIR)/unit1650-unit1650.Po @@ -2477,6 +2648,9 @@ maintainer-clean: maintainer-clean-am -rm -f ../libtest/$(DEPDIR)/unit1607-first.Po -rm -f ../libtest/$(DEPDIR)/unit1608-first.Po -rm -f ../libtest/$(DEPDIR)/unit1609-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1610-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1611-first.Po + -rm -f ../libtest/$(DEPDIR)/unit1612-first.Po -rm -f ../libtest/$(DEPDIR)/unit1620-first.Po -rm -f ../libtest/$(DEPDIR)/unit1621-first.Po -rm -f ../libtest/$(DEPDIR)/unit1650-first.Po @@ -2512,6 +2686,9 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/unit1607-unit1607.Po -rm -f ./$(DEPDIR)/unit1608-unit1608.Po -rm -f ./$(DEPDIR)/unit1609-unit1609.Po + -rm -f ./$(DEPDIR)/unit1610-unit1610.Po + -rm -f ./$(DEPDIR)/unit1611-unit1611.Po + -rm -f ./$(DEPDIR)/unit1612-unit1612.Po -rm -f ./$(DEPDIR)/unit1620-unit1620.Po -rm -f ./$(DEPDIR)/unit1621-unit1621.Po -rm -f ./$(DEPDIR)/unit1650-unit1650.Po diff --git a/release/src/router/curl/tests/unit/Makefile.inc b/release/src/router/curl/tests/unit/Makefile.inc index 45278ba8187..f63724f913c 100644 --- a/release/src/router/curl/tests/unit/Makefile.inc +++ b/release/src/router/curl/tests/unit/Makefile.inc @@ -1,3 +1,25 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + # these files are used in every single unit test program UNITFILES = curlcheck.h \ @@ -10,7 +32,8 @@ UNITPROGS = unit1300 unit1301 unit1302 unit1303 unit1304 unit1305 unit1307 \ unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \ unit1399 \ unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \ - unit1608 unit1609 unit1620 unit1621 \ + unit1608 unit1609 unit1610 unit1611 unit1612 \ + unit1620 unit1621 \ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1300_SOURCES = unit1300.c $(UNITFILES) @@ -97,6 +120,15 @@ unit1608_CPPFLAGS = $(AM_CPPFLAGS) unit1609_SOURCES = unit1609.c $(UNITFILES) unit1609_CPPFLAGS = $(AM_CPPFLAGS) +unit1610_SOURCES = unit1610.c $(UNITFILES) +unit1610_CPPFLAGS = $(AM_CPPFLAGS) + +unit1611_SOURCES = unit1611.c $(UNITFILES) +unit1611_CPPFLAGS = $(AM_CPPFLAGS) + +unit1612_SOURCES = unit1612.c $(UNITFILES) +unit1612_CPPFLAGS = $(AM_CPPFLAGS) + unit1620_SOURCES = unit1620.c $(UNITFILES) unit1620_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/release/src/router/curl/tests/unit/unit1300.c b/release/src/router/curl/tests/unit/unit1300.c index 5cfa6daf330..5d879977905 100644 --- a/release/src/router/curl/tests/unit/unit1300.c +++ b/release/src/router/curl/tests/unit/unit1300.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -54,7 +54,6 @@ UNITTEST_START struct curl_llist_element case2_list; struct curl_llist_element case3_list; struct curl_llist_element case4_list; - struct curl_llist_element case5_list; struct curl_llist_element *head; struct curl_llist_element *element_next; struct curl_llist_element *element_prev; @@ -216,55 +215,6 @@ UNITTEST_START fail_unless(llist.tail == NULL, "llist tail is not NULL while the llist is empty"); - /* @testing Curl_llist_move(struct curl_llist *, - * struct curl_llist_element *, struct curl_llist *, - * struct curl_llist_element *); - */ - - /** - * @case 1: - * moving head from an llist containing one element to an empty llist - * @assumptions: - * 1: llist size will be 0 - * 2: llist_destination size will be 1 - * 3: llist head will be NULL - * 4: llist_destination head == llist_destination tail != NULL - */ - - /* - * @setup - * add one element to the list - */ - - Curl_llist_insert_next(&llist, llist.head, &unusedData_case1, - &case5_list); - /* necessary assertions */ - - abort_unless(Curl_llist_count(&llist) == 1, - "Number of list elements is not as expected, Aborting"); - abort_unless(Curl_llist_count(&llist_destination) == 0, - "Number of list elements is not as expected, Aborting"); - - /*actual testing code*/ - Curl_llist_move(&llist, llist.head, &llist_destination, NULL); - fail_unless(Curl_llist_count(&llist) == 0, - "moving element from llist didn't decrement the size"); - - fail_unless(Curl_llist_count(&llist_destination) == 1, - "moving element to llist_destination didn't increment the size"); - - fail_unless(llist.head == NULL, - "llist head not set to null after moving the head"); - - fail_unless(llist_destination.head != NULL, - "llist_destination head set to null after moving an element"); - - fail_unless(llist_destination.tail != NULL, - "llist_destination tail set to null after moving an element"); - - fail_unless(llist_destination.tail == llist_destination.head, - "llist_destination tail doesn't equal llist_destination head"); - Curl_llist_destroy(&llist, NULL); Curl_llist_destroy(&llist_destination, NULL); } diff --git a/release/src/router/curl/tests/unit/unit1601.c b/release/src/router/curl/tests/unit/unit1601.c index a6120e1c269..bf00bc7e932 100644 --- a/release/src/router/curl/tests/unit/unit1601.c +++ b/release/src/router/curl/tests/unit/unit1601.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,18 +36,20 @@ static void unit_stop(void) UNITTEST_START #ifndef CURL_DISABLE_CRYPTO_AUTH - unsigned char output[16]; + const char string1[] = "1"; + const char string2[] = "hello-you-fool"; + unsigned char output[MD5_DIGEST_LEN]; unsigned char *testp = output; - Curl_md5it(output, (const unsigned char *)"1"); -/* !checksrc! disable LONGLINE 2 */ - verify_memory(testp, - "\xc4\xca\x42\x38\xa0\xb9\x23\x82\x0d\xcc\x50\x9a\x6f\x75\x84\x9b", 16); + Curl_md5it(output, (const unsigned char *) string1, strlen(string1)); - Curl_md5it(output, (const unsigned char *)"hello-you-fool"); + verify_memory(testp, "\xc4\xca\x42\x38\xa0\xb9\x23\x82\x0d\xcc\x50\x9a\x6f" + "\x75\x84\x9b", MD5_DIGEST_LEN); - verify_memory(testp, - "\x88\x67\x0b\x6d\x5d\x74\x2f\xad\xa5\xcd\xf9\xb6\x82\x87\x5f\x22", 16); + Curl_md5it(output, (const unsigned char *) string2, strlen(string2)); + + verify_memory(testp, "\x88\x67\x0b\x6d\x5d\x74\x2f\xad\xa5\xcd\xf9\xb6\x82" + "\x87\x5f\x22", MD5_DIGEST_LEN); #endif diff --git a/release/src/router/curl/tests/unit/unit1610.c b/release/src/router/curl/tests/unit/unit1610.c new file mode 100644 index 00000000000..bb9c937c926 --- /dev/null +++ b/release/src/router/curl/tests/unit/unit1610.c @@ -0,0 +1,60 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curlcheck.h" + +#include "curl_sha256.h" + +static CURLcode unit_setup(void) +{ + return CURLE_OK; +} + +static void unit_stop(void) +{ + +} + +UNITTEST_START + +#ifndef CURL_DISABLE_CRYPTO_AUTH + const char string1[] = "1"; + const char string2[] = "hello-you-fool"; + unsigned char output[SHA256_DIGEST_LENGTH]; + unsigned char *testp = output; + + Curl_sha256it(output, (const unsigned char *) string1, strlen(string1)); + + verify_memory(testp, + "\x6b\x86\xb2\x73\xff\x34\xfc\xe1\x9d\x6b\x80\x4e\xff\x5a\x3f" + "\x57\x47\xad\xa4\xea\xa2\x2f\x1d\x49\xc0\x1e\x52\xdd\xb7\x87" + "\x5b\x4b", SHA256_DIGEST_LENGTH); + + Curl_sha256it(output, (const unsigned char *) string2, strlen(string2)); + + verify_memory(testp, + "\xcb\xb1\x6a\x8a\xb9\xcb\xb9\x35\xa8\xcb\xa0\x2e\x28\xc0\x26" + "\x30\xd1\x19\x9c\x1f\x02\x17\xf4\x7c\x96\x20\xf3\xef\xe8\x27" + "\x15\xae", SHA256_DIGEST_LENGTH); +#endif + + +UNITTEST_STOP diff --git a/release/src/router/curl/tests/unit/unit1611.c b/release/src/router/curl/tests/unit/unit1611.c new file mode 100644 index 00000000000..bc19f8a5c0d --- /dev/null +++ b/release/src/router/curl/tests/unit/unit1611.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curlcheck.h" + +#include "curl_md4.h" + +static CURLcode unit_setup(void) +{ + return CURLE_OK; +} + +static void unit_stop(void) +{ + +} + +UNITTEST_START + +#ifndef CURL_DISABLE_CRYPTO_AUTH + const char string1[] = "1"; + const char string2[] = "hello-you-fool"; + unsigned char output[MD4_DIGEST_LENGTH]; + unsigned char *testp = output; + + Curl_md4it(output, (const unsigned char *) string1, strlen(string1)); + + verify_memory(testp, + "\x8b\xe1\xec\x69\x7b\x14\xad\x3a\x53\xb3\x71\x43\x61\x20\x64" + "\x1d", MD4_DIGEST_LENGTH); + + Curl_md4it(output, (const unsigned char *) string2, strlen(string2)); + + verify_memory(testp, + "\xa7\x16\x1c\xad\x7e\xbe\xdb\xbc\xf8\xc7\x23\x10\x2d\x2c\xe2" + "\x0b", MD4_DIGEST_LENGTH); +#endif + + +UNITTEST_STOP diff --git a/release/src/router/curl/tests/unit/unit1612.c b/release/src/router/curl/tests/unit/unit1612.c new file mode 100644 index 00000000000..3fb2de033ea --- /dev/null +++ b/release/src/router/curl/tests/unit/unit1612.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curlcheck.h" + +#include "curl_hmac.h" +#include "curl_md5.h" + +static CURLcode unit_setup(void) +{ + return CURLE_OK; +} + +static void unit_stop(void) +{ + +} + +UNITTEST_START + +#ifndef CURL_DISABLE_CRYPTO_AUTH + const char password[] = "Pa55worD"; + const char string1[] = "1"; + const char string2[] = "hello-you-fool"; + unsigned char output[HMAC_MD5_LENGTH]; + unsigned char *testp = output; + + Curl_hmacit(Curl_HMAC_MD5, + (const unsigned char *) password, strlen(password), + (const unsigned char *) string1, strlen(string1), + output); + + verify_memory(testp, + "\xd1\x29\x75\x43\x58\xdc\xab\x78\xdf\xcd\x7f\x2b\x29\x31\x13" + "\x37", HMAC_MD5_LENGTH); + + Curl_hmacit(Curl_HMAC_MD5, + (const unsigned char *) password, strlen(password), + (const unsigned char *) string2, strlen(string2), + output); + + verify_memory(testp, + "\x75\xf1\xa7\xb9\xf5\x40\xe5\xa4\x98\x83\x9f\x64\x5a\x27\x6d" + "\xd0", HMAC_MD5_LENGTH); +#endif + + +UNITTEST_STOP diff --git a/release/src/router/curl/tests/unit/unit1651.c b/release/src/router/curl/tests/unit/unit1651.c index 3652601f99a..44dbf4b51b6 100644 --- a/release/src/router/curl/tests/unit/unit1651.c +++ b/release/src/router/curl/tests/unit/unit1651.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. + * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -368,7 +368,7 @@ UNITTEST_START for(byte = 1 ; byte < 255; byte += 17) { for(i = 0; i < 45; i++) { char backup = cert[i]; - cert[i] = (unsigned char)byte&0xff; + cert[i] = (unsigned char) (byte & 0xff); (void) Curl_extract_certinfo(&conn, 0, beg, end); cert[i] = backup; } diff --git a/release/src/router/curl/tests/unit/unit1654.c b/release/src/router/curl/tests/unit/unit1654.c index a800d9c3a06..d05d0b214ce 100644 --- a/release/src/router/curl/tests/unit/unit1654.c +++ b/release/src/router/curl/tests/unit/unit1654.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019, Daniel Stenberg, , et al. + * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -124,7 +124,7 @@ UNITTEST_START } fail_unless(asi->num == 10, "wrong number of entries"); - Curl_altsvc_save(asi, outname); + Curl_altsvc_save(curl, asi, outname); curl_easy_cleanup(curl); fail: diff --git a/release/src/router/dnsmasq/CHANGELOG b/release/src/router/dnsmasq/CHANGELOG index 31b395c987f..60b08d015b2 100644 --- a/release/src/router/dnsmasq/CHANGELOG +++ b/release/src/router/dnsmasq/CHANGELOG @@ -1,12 +1,12 @@ version 2.81 - Impove cache behaviour for TCP connections. For ease of + Improve cache behaviour for TCP connections. For ease of implementaion, dnsmasq has always forked a new process to handle each incoming TCP connection. A side-effect of this is that any DNS queries answered from TCP connections are not cached: when TCP connections were rare, this was not a problem. - With the coming of DNSSEC, it's now the case that some + With the coming of DNSSEC, it is now the case that some DNSSEC queries have answers which spill to TCP, and if, - for instance, this applies to the keys for the root then + for instance, this applies to the keys for the root, then those never get cached, and performance is very bad. This fix passes cache entries back from the TCP child process to the main server process, and fixes the problem. @@ -35,7 +35,7 @@ version 2.81 configuration. Add --shared-network config. This enables allocation of addresses - the DHCP server in subnets where the server (or relay) doesn't + by the DHCP server in subnets where the server (or relay) does not have an interface on the network in that subnet. Many thanks to kamp.de for sponsoring this feature. @@ -66,7 +66,7 @@ version 2.81 Evgenii Seliavka for the suggestion and initial patch. In the router advert code, handle case where we have two - different interfaces on the same IPv6 net, and we're doing + different interfaces on the same IPv6 net, and we are doing RA/DHCP service on only one of them. Thanks to NIIBE Yutaka for spotting this case and making the initial patch. diff --git a/release/src/router/dnsmasq/VERSION b/release/src/router/dnsmasq/VERSION index 2dc8af4677d..4935fd3b4fd 100644 --- a/release/src/router/dnsmasq/VERSION +++ b/release/src/router/dnsmasq/VERSION @@ -1 +1 @@ -2.81rc4-33-g7558f2b +2.81-32-g93cb543 diff --git a/release/src/router/dnsmasq/man/dnsmasq.8 b/release/src/router/dnsmasq/man/dnsmasq.8 index 2032a374132..a2a60d5e2b3 100644 --- a/release/src/router/dnsmasq/man/dnsmasq.8 +++ b/release/src/router/dnsmasq/man/dnsmasq.8 @@ -1,4 +1,4 @@ -.TH DNSMASQ 8 +.TH DNSMASQ 8 2020-04-05 .SH NAME dnsmasq \- A lightweight DHCP and caching DNS server. .SH SYNOPSIS @@ -244,7 +244,7 @@ specified interface. The is the "glue record". It should resolve in the global DNS to an A and/or AAAA record which points to the address dnsmasq is listening on. When an interface is specified, it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6 -addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the glue record. +addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the primary external nameserver. .TP .B --local-service Accept DNS queries only from hosts whose address is on a local subnet, @@ -366,10 +366,13 @@ been built with DBus support. If the service name is given, dnsmasq provides service at that name, rather than the default which is .B uk.org.thekelleys.dnsmasq .TP -.B --enable-ubus +.B --enable-ubus[=] Enable dnsmasq UBus interface. It sends notifications via UBus on DHCPACK and DHCPRELEASE events. Furthermore it offers metrics. -Requires that dnsmasq has been built with UBus support. +Requires that dnsmasq has been built with UBus support. If the service +name is given, dnsmasq provides service at that namespace, rather than +the default which is +.B dnsmasq .TP .B \-o, --strict-order By default, dnsmasq will send queries to any of the upstream servers @@ -906,7 +909,7 @@ then the address can be simply :: The optional .B set: sets an alphanumeric label which marks this network so that -dhcp options may be specified on a per-network basis. +DHCP options may be specified on a per-network basis. When it is prefixed with 'tag:' instead, then its meaning changes from setting a tag to matching it. Only one tag may be set, but more than one tag may be matched. @@ -1014,7 +1017,7 @@ may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 address .B --dhcp-host=laptop,[1234::56] IPv6 addresses may contain only the host-identifier part: .B --dhcp-host=laptop,[::56] -in which case they act as wildcards in constructed dhcp ranges, with +in which case they act as wildcards in constructed DHCP ranges, with the appropriate network part inserted. For IPv6, an address may include a prefix length: .B --dhcp-host=laptop,[1234:50/126] which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability @@ -1351,7 +1354,7 @@ vendor-identifying vendor classes for the specified enterprise. Please see RFC 3925 for more details of these rare and interesting beasts. .TP .B --dhcp-name-match=set:,[*] -Set the tag if the given name is supplied by a dhcp client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client. +Set the tag if the given name is supplied by a DHCP client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client. .TP .B --tag-if=set:[,set:[,tag:[,tag:]]] Perform boolean operations on tags. Any tag appearing as set: is set if @@ -1748,7 +1751,7 @@ option also forces the leasechange script to be called on changes to the client-id and lease length and expiry time. .TP .B --script-on-renewal -Call the dhcp script when the lease expiry time changes, for instance when the +Call the DHCP script when the lease expiry time changes, for instance when the lease is renewed. .TP .B --bridge-interface=,[,] @@ -1764,25 +1767,34 @@ It is permissible to add more than one alias using more than one \fB--bridge-int \fB--bridge-interface=int1,alias1,alias2\fP is exactly equivalent to \fB--bridge-interface=int1,alias1 --bridge-interface=int1,alias2\fP .TP -.B --shared-network=|, -The DHCP server determines which dhcp ranges are useable for allocating and +.B --shared-network=, +.PD 0 +.TP +.B --shared-network=, +.PD 1v +The DHCP server determines which DHCP ranges are useable for allocating an address to a DHCP client based on the network from which the DHCP request arrives, and the IP configuration of the server's interface on that network. The shared-network -option extends the available subnets (and therefore dhcp ranges) beyond the -subnets configured on the arrival interface. The first argument is either the -name of an interface or an address which is configured on a local interface, and the +option extends the available subnets (and therefore DHCP ranges) beyond the +subnets configured on the arrival interface. + +The first argument is either the +name of an interface, or an address that is configured on a local interface, and the second argument is an address which defines another subnet on which addresses can be allocated. -To be useful, there must be suitable dhcp-range which allows address allocation on this subnet -and this dhcp-range MUST include the netmask. Use shared-network also needs extra -consideration of routing. Dnsmasq doesn't have the usual information which it uses to + +To be useful, there must be a suitable dhcp-range which allows address allocation on this subnet +and this dhcp-range MUST include the netmask. + +Using shared-network also needs extra +consideration of routing. Dnsmasq does not have the usual information that it uses to determine the default route, so the default route option (or other routing) MUST be -manually configured. The client must have a route to the server: if the two-address form -of shared-network is used, this will be to the first specified address. If the interface,address +configured manually. The client must have a route to the server: if the two-address form +of shared-network is used, this needs to be to the first specified address. If the interface,address form is used, there must be a route to all of the addresses configured on the interface. The two-address form of shared-network is also usable with a DHCP relay: the first address is the address of the relay and the second, as before, specifies an extra subnet which -may be allocated. +addresses may be allocated from. .TP .B \-s, --domain=[,
[,local]] @@ -1792,7 +1804,7 @@ firstly it causes the DHCP server to return the domain to any hosts which request it, and secondly it sets the domain which it is legal for DHCP-configured hosts to claim. The intention is to constrain hostnames so that an untrusted host on the LAN cannot advertise -its name via dhcp as e.g. "microsoft.com" and capture traffic not +its name via DHCP as e.g. "microsoft.com" and capture traffic not meant for it. If no domain suffix is specified, then any DHCP hostname with a domain part (ie with a period) will be disallowed and logged. If suffix is specified, then hostnames with a domain @@ -1883,7 +1895,7 @@ The mtu: parameter may be an arbitrary interface name, in which case the MTU val for (eg) advertising the MTU of a WAN interface on the other interfaces of a router. .TP .B --dhcp-reply-delay=[tag:,] -Delays sending DHCPOFFER and proxydhcp replies for at least the specified number of seconds. +Delays sending DHCPOFFER and PROXYDHCP replies for at least the specified number of seconds. This can be used as workaround for bugs in PXE boot firmware that does not function properly when receiving an instant reply. This option takes into account the time already spent waiting (e.g. performing ping check) if any. @@ -2019,7 +2031,7 @@ and .I /etc/ethers and any file given by \fB--dhcp-hostsfile\fP, \fB--dhcp-hostsdir\fP, \fB--dhcp-optsfile\fP, \fB--dhcp-optsdir\fP, \fB--addn-hosts\fP or \fB--hostsdir\fP. -The dhcp lease change script is called for all +The DHCP lease change script is called for all existing DHCP leases. If .B --no-poll @@ -2197,7 +2209,6 @@ as is the tag "bootp", allowing some control over the options returned to different classes of hosts. .SH AUTHORITATIVE CONFIGURATION -.PP Configuring dnsmasq to act as an authoritative DNS server is complicated by the fact that it involves configuration of external DNS servers to provide delegation. We will walk through three scenarios of @@ -2367,7 +2378,6 @@ used, and must match the zone's domain. .SH EXIT CODES -.PP 0 - Dnsmasq successfully forked into the background, or terminated normally if backgrounding is not enabled. .PP diff --git a/release/src/router/dnsmasq/src/auth.c b/release/src/router/dnsmasq/src/auth.c index 4daae30a760..b2fcd4b6fce 100644 --- a/release/src/router/dnsmasq/src/auth.c +++ b/release/src/router/dnsmasq/src/auth.c @@ -628,16 +628,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n { struct name_list *secondary; - newoffset = ansp - (unsigned char *)header; - if (add_resource_record(header, limit, &trunc, -offset, &ansp, - daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) + /* Only include the machine running dnsmasq if it's acting as an auth server */ + if (daemon->authinterface) { - if (offset == 0) - offset = newoffset; - if (ns) - anscount++; - else - authcount++; + newoffset = ansp - (unsigned char *)header; + if (add_resource_record(header, limit, &trunc, -offset, &ansp, + daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) + { + if (offset == 0) + offset = newoffset; + if (ns) + anscount++; + else + authcount++; + } } if (!subnet) diff --git a/release/src/router/dnsmasq/src/config.h b/release/src/router/dnsmasq/src/config.h index d4954427c57..bab99ed5eeb 100644 --- a/release/src/router/dnsmasq/src/config.h +++ b/release/src/router/dnsmasq/src/config.h @@ -19,7 +19,9 @@ #define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */ #define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */ #define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */ +#ifndef EDNS_PKTSZ #define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */ +#endif #define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */ #define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */ #define DNSSEC_WORK 50 /* Max number of queries to validate one question */ @@ -50,6 +52,7 @@ #define RANDFILE "/dev/urandom" #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */ #define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq" +#define DNSMASQ_UBUS_NAME "dnsmasq" /* Default - may be overridden by config */ #define AUTH_TTL 600 /* default TTL for auth DNS */ #define SOA_REFRESH 1200 /* SOA refresh default */ #define SOA_RETRY 180 /* SOA retry default */ diff --git a/release/src/router/dnsmasq/src/dnsmasq.c b/release/src/router/dnsmasq/src/dnsmasq.c index 5abbcb3eb49..9e35e42c97d 100644 --- a/release/src/router/dnsmasq/src/dnsmasq.c +++ b/release/src/router/dnsmasq/src/dnsmasq.c @@ -1693,7 +1693,7 @@ static int set_dns_listeners(time_t now) /* will we be able to get memory? */ if (daemon->port != 0) - get_new_frec(now, &wait, 0); + get_new_frec(now, &wait, NULL); for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) poll_listen(serverfdp->fd, POLLIN); @@ -2122,6 +2122,4 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id) return 0; } -#endif - - +#endif /* HAVE_DHCP */ diff --git a/release/src/router/dnsmasq/src/dnsmasq.h b/release/src/router/dnsmasq/src/dnsmasq.h index afc00cf6791..feaa1926886 100644 --- a/release/src/router/dnsmasq/src/dnsmasq.h +++ b/release/src/router/dnsmasq/src/dnsmasq.h @@ -1060,6 +1060,7 @@ extern struct daemon { unsigned int duid_enterprise, duid_config_len; unsigned char *duid_config; char *dbus_name; + char *ubus_name; char *dump_file; int dump_mask; unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry; @@ -1325,7 +1326,7 @@ void receive_query(struct listener *listen, time_t now); unsigned char *tcp_request(int confd, time_t now, union mysockaddr *local_addr, struct in_addr netmask, int auth_dns); void server_gone(struct server *server); -struct frec *get_new_frec(time_t now, int *wait, int force); +struct frec *get_new_frec(time_t now, int *wait, struct frec *force); int send_from(int fd, int nowild, char *packet, size_t len, union mysockaddr *to, union all_addr *source, unsigned int iface); diff --git a/release/src/router/dnsmasq/src/dnssec.c b/release/src/router/dnsmasq/src/dnssec.c index 0b1bbe1b464..a021efd9c6c 100644 --- a/release/src/router/dnsmasq/src/dnssec.c +++ b/release/src/router/dnsmasq/src/dnssec.c @@ -1002,7 +1002,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char cache_end_insert(); - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS"); + log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS"); } return STAT_OK; diff --git a/release/src/router/dnsmasq/src/forward.c b/release/src/router/dnsmasq/src/forward.c index c74aba167d9..641d6006424 100644 --- a/release/src/router/dnsmasq/src/forward.c +++ b/release/src/router/dnsmasq/src/forward.c @@ -348,7 +348,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, type &= ~SERV_DO_DNSSEC; if (daemon->servers && !flags) - forward = get_new_frec(now, NULL, 0); + forward = get_new_frec(now, NULL, NULL); /* table full - flags == 0, return REFUSED */ if (forward) @@ -1039,7 +1039,9 @@ void reply_query(int fd, int family, time_t now) /* Find the original query that started it all.... */ for (orig = forward; orig->dependent; orig = orig->dependent); - if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1))) + /* Make sure we don't expire and free the orig frec during the + allocation of a new one. */ + if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig))) status = STAT_ABANDONED; else { @@ -2251,9 +2253,10 @@ static void free_frec(struct frec *f) else return *wait zero if one available, or *wait is delay to when the oldest in-use record will expire. Impose an absolute limit of 4*TIMEOUT before we wipe things (for random sockets). - If force is set, always return a result, even if we have - to allocate above the limit. */ -struct frec *get_new_frec(time_t now, int *wait, int force) + If force is non-NULL, always return a result, even if we have + to allocate above the limit, and never free the record pointed + to by the force argument. */ +struct frec *get_new_frec(time_t now, int *wait, struct frec *force) { struct frec *f, *oldest, *target; int count; @@ -2270,7 +2273,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force) /* Don't free DNSSEC sub-queries here, as we may end up with dangling references to them. They'll go when their "real" query is freed. */ - if (!f->dependent) + if (!f->dependent && f != force) #endif { if (difftime(now, f->time) >= 4*TIMEOUT) diff --git a/release/src/router/dnsmasq/src/option.c b/release/src/router/dnsmasq/src/option.c index 7081a478773..8561df2d815 100644 --- a/release/src/router/dnsmasq/src/option.c +++ b/release/src/router/dnsmasq/src/option.c @@ -238,7 +238,7 @@ static const struct myoption opts[] = { "caa-record", 1, 0 , LOPT_CAA }, { "dns-rr", 1, 0, LOPT_RR }, { "enable-dbus", 2, 0, '1' }, - { "enable-ubus", 0, 0, LOPT_UBUS }, + { "enable-ubus", 2, 0, LOPT_UBUS }, { "bootp-dynamic", 2, 0, '3' }, { "dhcp-mac", 1, 0, '4' }, { "no-ping", 0, 0, '5' }, @@ -428,7 +428,7 @@ static struct { { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL }, { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE }, { '1', ARG_ONE, "[=]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL }, - { LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL }, + { LOPT_UBUS, ARG_ONE, "[=]", gettext_noop("Enable the UBus interface."), NULL }, { '2', ARG_DUP, "", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL }, { '3', ARG_DUP, "[=tag:]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL }, { '4', ARG_DUP, "set:,", gettext_noop("Map MAC address (with wildcards) to option set."), NULL }, @@ -1881,7 +1881,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma else daemon->dbus_name = DNSMASQ_SERVICE; break; - + + case LOPT_UBUS: /* --enable-ubus */ + set_option_bool(OPT_UBUS); + if (arg) + daemon->ubus_name = opt_string_alloc(arg); + else + daemon->ubus_name = DNSMASQ_UBUS_NAME; + break; + case '8': /* --log-facility */ /* may be a filename */ if (strchr(arg, '/') || strcmp (arg, "-") == 0) diff --git a/release/src/router/dnsmasq/src/ubus.c b/release/src/router/dnsmasq/src/ubus.c index c7f6b1995ec..5f812877927 100644 --- a/release/src/router/dnsmasq/src/ubus.c +++ b/release/src/router/dnsmasq/src/ubus.c @@ -38,7 +38,7 @@ static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods); static struct ubus_object ubus_object = { - .name = "dnsmasq", + .name = NULL, .type = &ubus_object_type, .methods = ubus_object_methods, .n_methods = ARRAY_SIZE(ubus_object_methods), @@ -94,6 +94,7 @@ void ubus_init() return; } + ubus_object.name = daemon->ubus_name; ret = ubus_add_object(ubus, &ubus_object); if (ret) { diff --git a/release/src/router/dnsmasq/src/util.c b/release/src/router/dnsmasq/src/util.c index debe708a333..2d44e48e4b2 100644 --- a/release/src/router/dnsmasq/src/util.c +++ b/release/src/router/dnsmasq/src/util.c @@ -210,6 +210,8 @@ int valid_hostname(char *name) "localhost", "ip6-localhost", "ip6-loopback", + "wpad", + "isatap", NULL }; const char **next; diff --git a/release/src/router/dropbear/.travis.yml b/release/src/router/dropbear/.travis.yml index 9bcbce48bc0..99499c84070 100644 --- a/release/src/router/dropbear/.travis.yml +++ b/release/src/router/dropbear/.travis.yml @@ -57,6 +57,7 @@ script: - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256 - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384 - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521 + - ~/inst/bin/dropbearkey -t ed25519 -f tested25519 - test -z $DO_FUZZ || ./fuzzers_test.sh branches: diff --git a/release/src/router/dropbear/FUZZER-NOTES.md b/release/src/router/dropbear/FUZZER-NOTES.md index 7b882389cb2..4967eba1170 100644 --- a/release/src/router/dropbear/FUZZER-NOTES.md +++ b/release/src/router/dropbear/FUZZER-NOTES.md @@ -72,3 +72,6 @@ Current fuzzers are - [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh. This is testing libtommath ECC routines. + +- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange + like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines. diff --git a/release/src/router/dropbear/Makefile.in b/release/src/router/dropbear/Makefile.in index 98e942b0215..dc5c55ff06a 100644 --- a/release/src/router/dropbear/Makefile.in +++ b/release/src/router/dropbear/Makefile.in @@ -53,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ tcp-accept.o listener.o process-packet.o dh_groups.o \ - common-runopts.o circbuffer.o list.o netio.o + common-runopts.o circbuffer.o list.o netio.o chachapoly.o KEYOBJS=dropbearkey.o @@ -256,7 +256,7 @@ tidy: ## Fuzzing targets # list of fuzz targets -FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh +FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS)) @@ -293,6 +293,9 @@ fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ +fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o + $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ + fuzzer-%.options: Makefile echo "[libfuzzer]" > $@ echo "max_len = 50000" >> $@ @@ -303,7 +306,9 @@ fuzz-hostkeys: dropbearkey -t rsa -f keyr dropbearkey -t dss -f keyd dropbearkey -t ecdsa -size 256 -f keye + dropbearkey -t ed25519 -f keyed25519 echo > hostkeys.c /usr/bin/xxd -i -a keyr >> hostkeys.c /usr/bin/xxd -i -a keye >> hostkeys.c /usr/bin/xxd -i -a keyd >> hostkeys.c + /usr/bin/xxd -i -a keyed25519 >> hostkeys.c diff --git a/release/src/router/dropbear/algo.h b/release/src/router/dropbear/algo.h index b12fb945594..efd0d735abe 100644 --- a/release/src/router/dropbear/algo.h +++ b/release/src/router/dropbear/algo.h @@ -72,6 +72,14 @@ struct dropbear_cipher_mode { unsigned long len, void *cipher_state); int (*decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long len, void *cipher_state); + int (*aead_crypt)(unsigned int seq, + const unsigned char *in, unsigned char *out, + unsigned long len, unsigned long taglen, + void *cipher_state, int direction); + int (*aead_getlength)(unsigned int seq, + const unsigned char *in, unsigned int *outlen, + unsigned long len, void *cipher_state); + const struct dropbear_hash *aead_mac; }; struct dropbear_hash { diff --git a/release/src/router/dropbear/chachapoly.c b/release/src/router/dropbear/chachapoly.c new file mode 100644 index 00000000000..0569ed49be1 --- /dev/null +++ b/release/src/router/dropbear/chachapoly.c @@ -0,0 +1,146 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2002,2003 Matt Johnston + * Copyright (c) 2020 by Vladislav Grishenko + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +#include "includes.h" +#include "algo.h" +#include "dbutil.h" +#include "chachapoly.h" + +#if DROPBEAR_CHACHA20POLY1305 + +#define CHACHA20_KEY_LEN 32 +#define CHACHA20_BLOCKSIZE 8 +#define POLY1305_KEY_LEN 32 +#define POLY1305_TAG_LEN 16 + +const struct dropbear_cipher dropbear_chachapoly = + {NULL, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE}; + +static const struct dropbear_hash dropbear_chachapoly_mac = + {NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN}; + +static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV), + const unsigned char *key, int keylen, + int UNUSED(num_rounds), dropbear_chachapoly_state *state) { + int err; + + TRACE2(("enter dropbear_chachapoly_start")) + + if (keylen != CHACHA20_KEY_LEN*2) { + return CRYPT_ERROR; + } + + if ((err = chacha_setup(&state->chacha, key, + CHACHA20_KEY_LEN, 20)) != CRYPT_OK) { + return err; + } + + if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN, + CHACHA20_KEY_LEN, 20) != CRYPT_OK)) { + return err; + } + + TRACE2(("leave dropbear_chachapoly_start")) + return CRYPT_OK; +} + +static int dropbear_chachapoly_crypt(unsigned int seq, + const unsigned char *in, unsigned char *out, + unsigned long len, unsigned long taglen, + dropbear_chachapoly_state *state, int direction) { + poly1305_state poly; + unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN]; + int err; + + TRACE2(("enter dropbear_chachapoly_crypt")) + + if (len < 4 || taglen != POLY1305_TAG_LEN) { + return CRYPT_ERROR; + } + + STORE64H(seq, seqbuf); + chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0); + if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) { + return err; + } + + poly1305_init(&poly, key, sizeof(key)); + if (direction == LTC_DECRYPT) { + poly1305_process(&poly, in, len); + poly1305_done(&poly, tag, &taglen); + if (constant_time_memcmp(in + len, tag, taglen) != 0) { + return CRYPT_ERROR; + } + } + + chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); + if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) { + return err; + } + + chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1); + if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) { + return err; + } + + if (direction == LTC_ENCRYPT) { + poly1305_process(&poly, out, len); + poly1305_done(&poly, out + len, &taglen); + } + + TRACE2(("leave dropbear_chachapoly_crypt")) + return CRYPT_OK; +} + +static int dropbear_chachapoly_getlength(unsigned int seq, + const unsigned char *in, unsigned int *outlen, + unsigned long len, dropbear_chachapoly_state *state) { + unsigned char seqbuf[8], buf[4]; + int err; + + TRACE2(("enter dropbear_chachapoly_parse")) + + if (len < sizeof(buf)) { + return CRYPT_ERROR; + } + + STORE64H(seq, seqbuf); + chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); + if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) { + return err; + } + + LOAD32H(*outlen, buf); + + TRACE2(("leave dropbear_chachapoly_parse")) + return CRYPT_OK; +} + +const struct dropbear_cipher_mode dropbear_mode_chachapoly = + {(void *)dropbear_chachapoly_start, NULL, NULL, + (void *)dropbear_chachapoly_crypt, + (void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac}; + +#endif /* DROPBEAR_CHACHA20POLY1305 */ diff --git a/release/src/router/dropbear/chachapoly.h b/release/src/router/dropbear/chachapoly.h new file mode 100644 index 00000000000..5a7c5b26b00 --- /dev/null +++ b/release/src/router/dropbear/chachapoly.h @@ -0,0 +1,44 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2002,2003 Matt Johnston + * Copyright (c) 2020 by Vladislav Grishenko + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_ +#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_ + +#include "includes.h" +#include "algo.h" + +#if DROPBEAR_CHACHA20POLY1305 + +typedef struct { + chacha_state chacha; + chacha_state header; +} dropbear_chachapoly_state; + +extern const struct dropbear_cipher dropbear_chachapoly; +extern const struct dropbear_cipher_mode dropbear_mode_chachapoly; + +#endif /* DROPBEAR_CHACHA20POLY1305 */ + +#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */ diff --git a/release/src/router/dropbear/common-algo.c b/release/src/router/dropbear/common-algo.c index 558aad25631..1436456b532 100644 --- a/release/src/router/dropbear/common-algo.c +++ b/release/src/router/dropbear/common-algo.c @@ -30,6 +30,7 @@ #include "dh_groups.h" #include "ltc_prng.h" #include "ecc.h" +#include "chachapoly.h" /* This file (algo.c) organises the ciphers which can be used, and is used to * decide which ciphers/hashes/compression/signing to use during key exchange*/ @@ -86,11 +87,11 @@ const struct dropbear_cipher dropbear_nocipher = * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */ #if DROPBEAR_ENABLE_CBC_MODE const struct dropbear_cipher_mode dropbear_mode_cbc = - {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt}; + {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL}; #endif /* DROPBEAR_ENABLE_CBC_MODE */ const struct dropbear_cipher_mode dropbear_mode_none = - {void_start, void_cipher, void_cipher}; + {void_start, void_cipher, void_cipher, NULL, NULL, NULL}; #if DROPBEAR_ENABLE_CTR_MODE /* a wrapper to make ctr_start and cbc_start look the same */ @@ -101,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher, return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr); } const struct dropbear_cipher_mode dropbear_mode_ctr = - {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt}; + {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL}; #endif /* DROPBEAR_ENABLE_CTR_MODE */ /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc. @@ -137,6 +138,10 @@ const struct dropbear_hash dropbear_nohash = * that is also supported by the server will get used. */ algo_type sshciphers[] = { +#if DROPBEAR_CHACHA20POLY1305 + {"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly}, +#endif + #if DROPBEAR_ENABLE_CTR_MODE #if DROPBEAR_AES128 {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr}, diff --git a/release/src/router/dropbear/common-kex.c b/release/src/router/dropbear/common-kex.c index 16b7e27f9cc..c87c0dc7db7 100644 --- a/release/src/router/dropbear/common-kex.c +++ b/release/src/router/dropbear/common-kex.c @@ -294,6 +294,7 @@ static void gen_new_keys() { hash_state hs; const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; char mactransletter, macrecvletter; /* Client or server specific */ + int recv_cipher, trans_cipher; TRACE(("enter gen_new_keys")) /* the dh_K and hash are the start of all hashes, we make use of that */ @@ -328,28 +329,30 @@ static void gen_new_keys() { hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C'); hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D'); + recv_cipher = -1; if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) { - int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); + recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); if (recv_cipher < 0) dropbear_exit("Crypto error"); - if (ses.newkeys->recv.crypt_mode->start(recv_cipher, - recv_IV, recv_key, - ses.newkeys->recv.algo_crypt->keysize, 0, - &ses.newkeys->recv.cipher_state) != CRYPT_OK) { - dropbear_exit("Crypto error"); - } + } + if (ses.newkeys->recv.crypt_mode->start(recv_cipher, + recv_IV, recv_key, + ses.newkeys->recv.algo_crypt->keysize, 0, + &ses.newkeys->recv.cipher_state) != CRYPT_OK) { + dropbear_exit("Crypto error"); } + trans_cipher = -1; if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) { - int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); + trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); if (trans_cipher < 0) dropbear_exit("Crypto error"); - if (ses.newkeys->trans.crypt_mode->start(trans_cipher, - trans_IV, trans_key, - ses.newkeys->trans.algo_crypt->keysize, 0, - &ses.newkeys->trans.cipher_state) != CRYPT_OK) { - dropbear_exit("Crypto error"); - } + } + if (ses.newkeys->trans.crypt_mode->start(trans_cipher, + trans_IV, trans_key, + ses.newkeys->trans.algo_crypt->keysize, 0, + &ses.newkeys->trans.cipher_state) != CRYPT_OK) { + dropbear_exit("Crypto error"); } if (ses.newkeys->trans.algo_mac->hash_desc != NULL) { @@ -868,19 +871,29 @@ static void read_kex_algos() { /* mac_algorithms_client_to_server */ c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); +#if DROPBEAR_AEAD_MODE + if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) { + c2s_hash_algo = NULL; + } else +#endif if (c2s_hash_algo == NULL) { erralgo = "mac c->s"; goto error; } - TRACE(("hash c2s is %s", c2s_hash_algo->name)) + TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "")) /* mac_algorithms_server_to_client */ s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); +#if DROPBEAR_AEAD_MODE + if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) { + s2c_hash_algo = NULL; + } else +#endif if (s2c_hash_algo == NULL) { erralgo = "mac s->c"; goto error; } - TRACE(("hash s2c is %s", s2c_hash_algo->name)) + TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "")) /* compression_algorithms_client_to_server */ c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); @@ -925,8 +938,14 @@ static void read_kex_algos() { ses.newkeys->trans.crypt_mode = (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; ses.newkeys->recv.algo_mac = +#if DROPBEAR_AEAD_MODE + s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : +#endif (struct dropbear_hash*)s2c_hash_algo->data; ses.newkeys->trans.algo_mac = +#if DROPBEAR_AEAD_MODE + c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : +#endif (struct dropbear_hash*)c2s_hash_algo->data; ses.newkeys->recv.algo_comp = s2c_comp_algo->val; ses.newkeys->trans.algo_comp = c2s_comp_algo->val; @@ -941,8 +960,14 @@ static void read_kex_algos() { ses.newkeys->trans.crypt_mode = (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; ses.newkeys->recv.algo_mac = +#if DROPBEAR_AEAD_MODE + c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : +#endif (struct dropbear_hash*)c2s_hash_algo->data; ses.newkeys->trans.algo_mac = +#if DROPBEAR_AEAD_MODE + s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : +#endif (struct dropbear_hash*)s2c_hash_algo->data; ses.newkeys->recv.algo_comp = c2s_comp_algo->val; ses.newkeys->trans.algo_comp = s2c_comp_algo->val; diff --git a/release/src/router/dropbear/default_options.h b/release/src/router/dropbear/default_options.h index f89636e1625..8843994b6b2 100644 --- a/release/src/router/dropbear/default_options.h +++ b/release/src/router/dropbear/default_options.h @@ -99,6 +99,12 @@ IMPORTANT: Some options will require "make clean" after changes */ * and forwards compatibility */ #define DROPBEAR_ENABLE_CTR_MODE 1 +/* Enable Chacha20-Poly1305 authenticated encryption mode. This is + * generally faster than AES256 on CPU w/o dedicated AES instructions, + * having the same key size. + * Compiling in will add ~5,5kB to binary size on x86-64 */ +#define DROPBEAR_CHACHA20POLY1305 1 + /* Message integrity. sha2-256 is recommended as a default, sha1 for compatibility */ #define DROPBEAR_SHA1_HMAC 1 @@ -125,6 +131,7 @@ IMPORTANT: Some options will require "make clean" after changes */ #define DROPBEAR_DEFAULT_RSA_SIZE 2048 /* DSS is always 1024 */ /* ECDSA defaults to largest size configured, usually 521 */ +/* Ed25519 is always 256 */ /* Add runtime flag "-R" to generate hostkeys as-needed when the first connection using that key type occurs. diff --git a/release/src/router/dropbear/fuzz-common.c b/release/src/router/dropbear/fuzz-common.c index 5c90c45c01a..b1b00f6e1a9 100644 --- a/release/src/router/dropbear/fuzz-common.c +++ b/release/src/router/dropbear/fuzz-common.c @@ -112,6 +112,14 @@ static void load_fixed_hostkeys(void) { dropbear_exit("failed fixed ecdsa hostkey"); } + buf_setlen(b, 0); + buf_putbytes(b, keyed25519, keyed25519_len); + buf_setpos(b, 0); + type = DROPBEAR_SIGNKEY_ED25519; + if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { + dropbear_exit("failed fixed ed25519 hostkey"); + } + buf_free(b); } diff --git a/release/src/router/dropbear/fuzz-hostkeys.c b/release/src/router/dropbear/fuzz-hostkeys.c index dc1615d1928..3fff5cbb704 100644 --- a/release/src/router/dropbear/fuzz-hostkeys.c +++ b/release/src/router/dropbear/fuzz-hostkeys.c @@ -127,3 +127,13 @@ unsigned char keyd[] = { 0xf9, 0x39 }; unsigned int keyd_len = 458; +unsigned char keyed25519[] = { + 0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, + 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5, + 0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66, + 0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2, + 0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19, + 0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69, + 0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9 +}; +unsigned int keyed25519_len = 83; diff --git a/release/src/router/dropbear/fuzzer-kexcurve25519.c b/release/src/router/dropbear/fuzzer-kexcurve25519.c new file mode 100644 index 00000000000..f2eab14aa1b --- /dev/null +++ b/release/src/router/dropbear/fuzzer-kexcurve25519.c @@ -0,0 +1,72 @@ +#include "fuzz.h" +#include "session.h" +#include "fuzz-wrapfd.h" +#include "debug.h" +#include "runopts.h" +#include "algo.h" +#include "bignum.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static int once = 0; + static struct key_context* keep_newkeys = NULL; + /* number of generated parameters is limited by the timeout for the first run. + TODO move this to the libfuzzer initialiser function instead if the timeout + doesn't apply there */ + #define NUM_PARAMS 20 + static struct kex_curve25519_param *curve25519_params[NUM_PARAMS]; + + if (!once) { + fuzz_common_setup(); + fuzz_svr_setup(); + + keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); + keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256"); + keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519; + ses.newkeys = keep_newkeys; + + /* Pre-generate parameters */ + int i; + for (i = 0; i < NUM_PARAMS; i++) { + curve25519_params[i] = gen_kexcurve25519_param(); + } + + once = 1; + } + + if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) { + return 0; + } + + m_malloc_set_epoch(1); + + if (setjmp(fuzz.jmp) == 0) { + /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() + with DROPBEAR_KEX_CURVE25519 */ + ses.newkeys = keep_newkeys; + + /* Choose from the collection of curve25519 params */ + unsigned int e = buf_getint(fuzz.input); + struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS]; + + buffer * ecdh_qs = buf_getstringbuf(fuzz.input); + + ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS); + kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey); + + mp_clear(ses.dh_K); + m_free(ses.dh_K); + buf_free(ecdh_qs); + + buf_free(ses.hash); + buf_free(ses.session_id); + /* kexhashbuf is freed in kexdh_comb_key */ + + m_malloc_free_epoch(1, 0); + } else { + m_malloc_free_epoch(1, 1); + TRACE(("dropbear_exit longjmped")) + /* dropbear_exit jumped here */ + } + + return 0; +} diff --git a/release/src/router/dropbear/keyimport.c b/release/src/router/dropbear/keyimport.c index 7304e58e2eb..ad0c5305df7 100644 --- a/release/src/router/dropbear/keyimport.c +++ b/release/src/router/dropbear/keyimport.c @@ -35,6 +35,15 @@ #include "buffer.h" #include "dbutil.h" #include "ecc.h" +#include "ssh.h" + +static const unsigned char OSSH_PKEY_BLOB[] = + "openssh-key-v1\0" /* AUTH_MAGIC */ + "\0\0\0\4none" /* cipher name*/ + "\0\0\0\4none" /* kdf name */ + "\0\0\0\0" /* kdf */ + "\0\0\0\1"; /* key num */ +#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1) #if DROPBEAR_ECDSA static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; @@ -352,7 +361,7 @@ struct mpint_pos { void *start; int bytes; }; * Code to read and write OpenSSH private keys. */ -enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; +enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY }; struct openssh_key { int type; int encrypted; @@ -364,11 +373,12 @@ struct openssh_key { static struct openssh_key *load_openssh_key(const char *filename) { struct openssh_key *ret; + buffer *buf = NULL; FILE *fp = NULL; char buffer[256]; char *errmsg = NULL, *p = NULL; int headers_done; - unsigned long len, outlen; + unsigned long len; ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); ret->keyblob = NULL; @@ -397,12 +407,15 @@ static struct openssh_key *load_openssh_key(const char *filename) ret->type = OSSH_DSA; else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) ret->type = OSSH_EC; + else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n")) + ret->type = OSSH_PKEY; else { errmsg = "Unrecognised key type"; goto error; } headers_done = 0; + buf = buf_new(0); while (1) { if (!fgets(buffer, sizeof(buffer), fp)) { errmsg = "Unexpected end of file"; @@ -448,20 +461,31 @@ static struct openssh_key *load_openssh_key(const char *filename) } else { headers_done = 1; len = strlen(buffer); - outlen = len*4/3; - if (ret->keyblob_len + outlen > ret->keyblob_size) { - ret->keyblob_size = ret->keyblob_len + outlen + 256; - ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, - ret->keyblob_size); - } - outlen = ret->keyblob_size - ret->keyblob_len; - if (base64_decode((const unsigned char *)buffer, len, - ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ - errmsg = "Error decoding base64"; - goto error; - } - ret->keyblob_len += outlen; + buf = buf_resize(buf, buf->size + len); + buf_putbytes(buf, buffer, len); + } + } + + if (buf && buf->len) { + ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256; + ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size); + len = ret->keyblob_size; + if (base64_decode((const unsigned char *)buf->data, buf->len, + ret->keyblob, &len) != CRYPT_OK){ + errmsg = "Error decoding base64"; + goto error; + } + ret->keyblob_len = len; + } + + if (ret->type == OSSH_PKEY) { + if (ret->keyblob_len < OSSH_PKEY_BLOBLEN || + memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) { + errmsg = "Error decoding OpenSSH key"; + goto error; } + ret->keyblob_len -= OSSH_PKEY_BLOBLEN; + memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len); } if (ret->keyblob_len == 0 || !ret->keyblob) { @@ -474,10 +498,18 @@ static struct openssh_key *load_openssh_key(const char *filename) goto error; } + if (buf) { + buf_burn(buf); + buf_free(buf); + } m_burn(buffer, sizeof(buffer)); return ret; error: + if (buf) { + buf_burn(buf); + buf_free(buf); + } m_burn(buffer, sizeof(buffer)); if (ret) { if (ret->keyblob) { @@ -569,6 +601,57 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra #endif } + /* + * Now we have a decrypted key blob, which contains OpenSSH + * encoded private key. We must now untangle the OpenSSH format. + */ + if (key->type == OSSH_PKEY) { + blobbuf = buf_new(key->keyblob_len); + buf_putbytes(blobbuf, key->keyblob, key->keyblob_len); + buf_setpos(blobbuf, 0); + + /* limit length of private key blob */ + len = buf_getint(blobbuf); + buf_setlen(blobbuf, blobbuf->pos + len); + + type = DROPBEAR_SIGNKEY_ANY; + if (buf_get_pub_key(blobbuf, retkey, &type) + != DROPBEAR_SUCCESS) { + errmsg = "Error parsing OpenSSH key"; + goto ossh_error; + } + + /* restore full length */ + buf_setlen(blobbuf, key->keyblob_len); + + if (type != DROPBEAR_SIGNKEY_NONE) { + retkey->type = type; + /* limit length of private key blob */ + len = buf_getint(blobbuf); + buf_setlen(blobbuf, blobbuf->pos + len); +#if DROPBEAR_ED25519 + if (type == DROPBEAR_SIGNKEY_ED25519) { + buf_incrpos(blobbuf, 8); + buf_eatstring(blobbuf); + buf_eatstring(blobbuf); + buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4); + if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key) + == DROPBEAR_SUCCESS) { + errmsg = NULL; + retval = retkey; + goto error; + } + } +#endif + } + + errmsg = "Unsupported OpenSSH key type"; + ossh_error: + sign_key_free(retkey); + retkey = NULL; + goto error; + } + /* * Now we have a decrypted key blob, which contains an ASN.1 * encoded private key. We must now untangle the ASN.1. @@ -1129,6 +1212,51 @@ static int openssh_write(const char *filename, sign_key *key, } #endif +#if DROPBEAR_ED25519 + if (key->type == DROPBEAR_SIGNKEY_ED25519) { + buffer *buf = buf_new(300); + keyblob = buf_new(100); + extrablob = buf_new(200); + + /* private key blob w/o header */ + buf_put_priv_key(keyblob, key, key->type); + buf_setpos(keyblob, 0); + buf_incrpos(keyblob, buf_getint(keyblob)); + len = buf_getint(keyblob); + + /* header */ + buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN); + + /* public key */ + buf_put_pub_key(buf, key, key->type); + + /* private key */ + buf_incrwritepos(extrablob, 4); + buf_put_pub_key(extrablob, key, key->type); + buf_putstring(extrablob, buf_getptr(keyblob, len), len); + /* comment */ + buf_putstring(extrablob, "", 0); + /* padding to cipher block length */ + len = (extrablob->len+8) & ~7; + for (i = 1; len - extrablob->len > 0; i++) + buf_putbyte(extrablob, i); + buf_setpos(extrablob, 0); + buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8); + buf_putbufstring(buf, extrablob); + + outlen = len = pos = buf->len; + outblob = (unsigned char*)m_malloc(outlen); + memcpy(outblob, buf->data, buf->len); + + buf_burn(buf); + buf_free(buf); + buf = NULL; + + header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"; + footer = "-----END OPENSSH PRIVATE KEY-----\n"; + } +#endif + /* * Padding on OpenSSH keys is deterministic. The number of * padding bytes is always more than zero, and always at most diff --git a/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_dropbear.h b/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_dropbear.h index b0ce45b1bc6..b4e27895b69 100644 --- a/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_dropbear.h +++ b/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_dropbear.h @@ -27,7 +27,7 @@ #define LTC_DES #endif -#if DROPBEAR_ENABLE_CTR_MODE +#if DROPBEAR_ENABLE_CBC_MODE #define LTC_CBC_MODE #endif @@ -35,6 +35,10 @@ #define LTC_CTR_MODE #endif +#if DROPBEAR_CHACHA20POLY1305 +#define LTC_CHACHA +#define LTC_POLY1305 +#endif #if DROPBEAR_SHA512 #define LTC_SHA512 diff --git a/release/src/router/dropbear/packet.c b/release/src/router/dropbear/packet.c index 9fda0d606e4..0454726e377 100644 --- a/release/src/router/dropbear/packet.c +++ b/release/src/router/dropbear/packet.c @@ -215,7 +215,7 @@ static int read_packet_init() { unsigned int maxlen; int slen; - unsigned int len; + unsigned int len, plen; unsigned int blocksize; unsigned int macsize; @@ -254,21 +254,35 @@ static int read_packet_init() { /* now we have the first block, need to get packet length, so we decrypt * the first block (only need first 4 bytes) */ buf_setpos(ses.readbuf, 0); - if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), - buf_getwriteptr(ses.readbuf, blocksize), - blocksize, - &ses.keys->recv.cipher_state) != CRYPT_OK) { - dropbear_exit("Error decrypting"); +#if DROPBEAR_AEAD_MODE + if (ses.keys->recv.crypt_mode->aead_crypt) { + if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq, + buf_getptr(ses.readbuf, blocksize), &plen, + blocksize, + &ses.keys->recv.cipher_state) != CRYPT_OK) { + dropbear_exit("Error decrypting"); + } + len = plen + 4 + macsize; + } else +#endif + { + if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), + buf_getwriteptr(ses.readbuf, blocksize), + blocksize, + &ses.keys->recv.cipher_state) != CRYPT_OK) { + dropbear_exit("Error decrypting"); + } + plen = buf_getint(ses.readbuf) + 4; + len = plen + macsize; } - len = buf_getint(ses.readbuf) + 4 + macsize; TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize)) /* check packet length */ if ((len > RECV_MAX_PACKET_LEN) || - (len < MIN_PACKET_LEN + macsize) || - ((len - macsize) % blocksize != 0)) { + (plen < blocksize) || + (plen % blocksize != 0)) { dropbear_exit("Integrity error (bad packet size %u)", len); } @@ -294,23 +308,42 @@ void decrypt_packet() { ses.kexstate.datarecv += ses.readbuf->len; - /* we've already decrypted the first blocksize in read_packet_init */ - buf_setpos(ses.readbuf, blocksize); - - /* decrypt it in-place */ - len = ses.readbuf->len - macsize - ses.readbuf->pos; - if (ses.keys->recv.crypt_mode->decrypt( - buf_getptr(ses.readbuf, len), - buf_getwriteptr(ses.readbuf, len), - len, - &ses.keys->recv.cipher_state) != CRYPT_OK) { - dropbear_exit("Error decrypting"); - } - buf_incrpos(ses.readbuf, len); +#if DROPBEAR_AEAD_MODE + if (ses.keys->recv.crypt_mode->aead_crypt) { + /* first blocksize is not decrypted yet */ + buf_setpos(ses.readbuf, 0); + + /* decrypt it in-place */ + len = ses.readbuf->len - macsize - ses.readbuf->pos; + if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq, + buf_getptr(ses.readbuf, len + macsize), + buf_getwriteptr(ses.readbuf, len), + len, macsize, + &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) { + dropbear_exit("Error decrypting"); + } + buf_incrpos(ses.readbuf, len); + } else +#endif + { + /* we've already decrypted the first blocksize in read_packet_init */ + buf_setpos(ses.readbuf, blocksize); + + /* decrypt it in-place */ + len = ses.readbuf->len - macsize - ses.readbuf->pos; + if (ses.keys->recv.crypt_mode->decrypt( + buf_getptr(ses.readbuf, len), + buf_getwriteptr(ses.readbuf, len), + len, + &ses.keys->recv.cipher_state) != CRYPT_OK) { + dropbear_exit("Error decrypting"); + } + buf_incrpos(ses.readbuf, len); - /* check the hmac */ - if (checkmac() != DROPBEAR_SUCCESS) { - dropbear_exit("Integrity error"); + /* check the hmac */ + if (checkmac() != DROPBEAR_SUCCESS) { + dropbear_exit("Integrity error"); + } } /* get padding length */ @@ -557,9 +590,16 @@ void encrypt_packet() { buf_setpos(ses.writepayload, 0); buf_setlen(ses.writepayload, 0); - /* length of padding - packet length must be a multiple of blocksize, - * with a minimum of 4 bytes of padding */ - padlen = blocksize - (writebuf->len) % blocksize; + /* length of padding - packet length excluding the packetlength uint32 + * field in aead mode must be a multiple of blocksize, with a minimum of + * 4 bytes of padding */ + len = writebuf->len; +#if DROPBEAR_AEAD_MODE + if (ses.keys->trans.crypt_mode->aead_crypt) { + len -= 4; + } +#endif + padlen = blocksize - len % blocksize; if (padlen < 4) { padlen += blocksize; } @@ -579,23 +619,42 @@ void encrypt_packet() { buf_incrlen(writebuf, padlen); genrandom(buf_getptr(writebuf, padlen), padlen); - make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); +#if DROPBEAR_AEAD_MODE + if (ses.keys->trans.crypt_mode->aead_crypt) { + /* do the actual encryption, in-place */ + buf_setpos(writebuf, 0); + /* encrypt it in-place*/ + len = writebuf->len; + buf_incrlen(writebuf, mac_size); + if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq, + buf_getptr(writebuf, len), + buf_getwriteptr(writebuf, len + mac_size), + len, mac_size, + &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) { + dropbear_exit("Error encrypting"); + } + buf_incrpos(writebuf, len + mac_size); + } else +#endif + { + make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); + + /* do the actual encryption, in-place */ + buf_setpos(writebuf, 0); + /* encrypt it in-place*/ + len = writebuf->len; + if (ses.keys->trans.crypt_mode->encrypt( + buf_getptr(writebuf, len), + buf_getwriteptr(writebuf, len), + len, + &ses.keys->trans.cipher_state) != CRYPT_OK) { + dropbear_exit("Error encrypting"); + } + buf_incrpos(writebuf, len); - /* do the actual encryption, in-place */ - buf_setpos(writebuf, 0); - /* encrypt it in-place*/ - len = writebuf->len; - if (ses.keys->trans.crypt_mode->encrypt( - buf_getptr(writebuf, len), - buf_getwriteptr(writebuf, len), - len, - &ses.keys->trans.cipher_state) != CRYPT_OK) { - dropbear_exit("Error encrypting"); + /* stick the MAC on it */ + buf_putbytes(writebuf, mac_bytes, mac_size); } - buf_incrpos(writebuf, len); - - /* stick the MAC on it */ - buf_putbytes(writebuf, mac_bytes, mac_size); /* Update counts */ ses.kexstate.datatrans += writebuf->len; diff --git a/release/src/router/dropbear/session.h b/release/src/router/dropbear/session.h index 0850d99ed3a..c9b0a2d8d8a 100644 --- a/release/src/router/dropbear/session.h +++ b/release/src/router/dropbear/session.h @@ -38,6 +38,7 @@ #include "chansession.h" #include "dbutil.h" #include "netio.h" +#include "chachapoly.h" void common_session_init(int sock_in, int sock_out); void session_loop(void(*loophandler)(void)) ATTRIB_NORETURN; @@ -74,9 +75,14 @@ struct key_context_directional { #endif /* actual keys */ union { +#if DROPBEAR_ENABLE_CBC_MODE symmetric_CBC cbc; +#endif #if DROPBEAR_ENABLE_CTR_MODE symmetric_CTR ctr; +#endif +#if DROPBEAR_CHACHA20POLY1305 + dropbear_chachapoly_state chachapoly; #endif } cipher_state; unsigned char mackey[MAX_MAC_LEN]; diff --git a/release/src/router/dropbear/sysoptions.h b/release/src/router/dropbear/sysoptions.h index 3a8e86eb78b..3f6717b15af 100644 --- a/release/src/router/dropbear/sysoptions.h +++ b/release/src/router/dropbear/sysoptions.h @@ -94,7 +94,11 @@ #define MD5_HASH_SIZE 16 #define MAX_HASH_SIZE 64 /* sha512 */ +#if DROPBEAR_CHACHA20POLY1305 +#define MAX_KEY_LEN 64 /* 2 x 256 bits for chacha20 */ +#else #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */ +#endif #define MAX_IV_LEN 20 /* must be same as max blocksize, */ #if DROPBEAR_SHA2_512_HMAC @@ -209,6 +213,8 @@ If you test it please contact the Dropbear author */ #define DROPBEAR_TWOFISH ((DROPBEAR_TWOFISH256) || (DROPBEAR_TWOFISH128)) +#define DROPBEAR_AEAD_MODE ((DROPBEAR_CHACHA20POLY1305)) + #define DROPBEAR_CLI_ANYTCPFWD ((DROPBEAR_CLI_REMOTETCPFWD) || (DROPBEAR_CLI_LOCALTCPFWD)) #define DROPBEAR_TCP_ACCEPT ((DROPBEAR_CLI_LOCALTCPFWD) || (DROPBEAR_SVR_REMOTETCPFWD)) @@ -248,7 +254,7 @@ If you test it please contact the Dropbear author */ #if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \ - || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128) + || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128 || DROPBEAR_CHACHA20POLY1305) #error "At least one encryption algorithm must be enabled. AES128 is recommended." #endif diff --git a/release/src/router/nano/ChangeLog b/release/src/router/nano/ChangeLog index fe15827ca2f..6923e73b88f 100644 --- a/release/src/router/nano/ChangeLog +++ b/release/src/router/nano/ChangeLog @@ -1,3 +1,247 @@ +Changes between v4.9.1 and v4.9.2: +---------------------------------- + +Benno Schulenberg (2): + bump version numbers and add a news item for the 4.9.2 release + undo: choose the proper x positions to place the cursor and rejoin lines + + +Changes between v4.9 and v4.9.1: +-------------------------------- + +Benno Schulenberg (9): + bump version numbers and add a news item for the 4.9.1 release + files: make filtering of the entire buffer into a new buffer work again + tweaks: delete a ChangeLog that is no longer updated and is incomplete + tweaks: delete another pointless ChangeLog + tweaks: fix twenty typos, in old Changelogs and in some comments + tweaks: for each version, mention the changes to the PO files last + tweaks: rename a symbol, to be more accurate, and reshuffle two lines + tweaks: uniformize some old translator credits + undo: when undoing a line cut, place the cursor back where it was + + +Changes between v4.8 and v4.9: +------------------------------ + +Benno Schulenberg (209): + bindings: remove the translation of ^H to Backspace on the BSDs + build: fix compilation for --enable-tiny --enable-justify + build: restore non-UTF8 fallbacks, to allow compiling with --disable-utf8 + build: update the conditional placement of the "Go To Line" menu item + bump version numbers and add a news item for the 4.9 release + chars: optimize a function for the most common blanks: space and tab + copyright: update to the current year for significantly changed files + cutting: let M-T cut a trailing empty line, but not nothing at all + cutting: with --cutfromcursor, allow ^K to cut the penultimate empty line + display: do not show a "[" double-width placeholder when softwrapping + display: keep the help items aligned, by not writing too many characters + docs: improve the descriptions of --softwrap and 'set softwrap' + docs: mark bracketed pasting as done in the TODO list + docs: mention that ^[ (Esc) is unbindable, and explain why + docs: remove the note saying that nanorc files must be in Unix format + docs: trim some TODO items, and condense several others + docs: update the form of an option, --suspendable / 'set suspendable' + docs: update the missed occurrences of --suspendable / 'set suspendable' + feedback: give a clearer message when trying to justify an empty region + feedback: make sure that a later message can overwrite a short warning + files: be consistent in which code means "New File" + files: don't check uninitialized memory when writing new file [valgrind] + files: when piping, always pipe whatever was cut to the external command + gnulib: update to its current upstream state + help: do not break a line inside the 17-column keystrokes area + help: increase the minimum help-text width from 32 to 40 columns + input: accommodate silly emulators that have LF instead of CR in a paste + input: after reallocating a string, do not write to its old address + input: allocate sufficient bytes for entering a Unicode codepoint + input: keep a multibyte character together during verbatim entry + justify: do not copy too many bytes when trimming leading whitespace + justify: do not crash when the user attempts to justify an empty region + justify: do not take an empty line as template for first-line indentation + justify: give the first line of a marked region its proper indentation + justify: never break a line in leading whitespace + justify: restore a region properly when it was marked backwards + justify: skip over blanks after the region, to not skew the indentation + justify: skip over in-line whitespace only, not over leading whitespace + justify: trim prefixed whitespace when justifying a marked region + justify: trim the leading blanks of a marked region at the right moment + justify: when appropriate, move end point of marked region forward + justify: when the cursor is at the left edge, keep it there + locking: do not open an empty buffer when respecting the first lock file + moving: do not put the cursor at end-of-line when in a help text + options: rename --suspend to --suspendable, to make more sense + prompt: insert a burst of bytes in one go instead of characterwise + rcfile: allow alternate line endings in nanorc files + rcfile: do not allow a regex for name, header, or magic to be empty + rcfile: don't store a coloring rule before it is complete + rcfile: rename bindable function 'suspendenable' to 'suspendable' + rcfile: when a start= is not matched with an end=, abandon the whole rule + rcfile: when finding a mistake, skip the rest of the line + shutdown: don't refer to an open file when there aren't any + softwrap: when typing goes beyond the bottom row, scroll just one row + syntax: nanorc: colorize 'rawsequences', not the obsolete 'rebindkeypad' + syntax: spec: add two missing % signs, and colorize also "%triggerprein" + syntax: spec: colorize the date and author of changelog items differently + syntax: spec: drop invalid parentheses after "Summary" + tweaks: abort in three situations that should never occur + tweaks: add a COUPLE_END undo item a bit later, instead of updating it + tweaks: add a different helping variable + tweaks: add a supporting variable, in order to condense some statements + tweaks: add calls of die() for five theoretical programming mistakes + tweaks: adjust some whitespace, reshuffle two ifs, and remove two braces + tweaks: adjust the indentation after the previous change + tweaks: always determine the second lead, to simplify the rewrap call + tweaks: avoid a complaint about uninitialized memory [valgrind] + tweaks: call add_undo() before the character is actually added + tweaks: change a function to return the name of the lock file on success + tweaks: change a function with two possible results to boolean + tweaks: change an integer to a short, and reshuffle it for better packing + tweaks: change another function with two possible results to boolean + tweaks: check for a starting quote in one place instead of three + tweaks: combine two ifs into one + tweaks: condense a comment, reshuffle conditions, and remove unwanted one + tweaks: condense a fragment of code + tweaks: condense two fragments of code + tweaks: convert integers to bytes in one place instead of two + tweaks: copy and store a deleted character in a conciser manner + tweaks: correct a typo, improve two indentations, and rewrap a line + tweaks: correct two typos in a changelog, and drop a doubled word + tweaks: create an undo item earlier, and discard it when needed + tweaks: don't bother reallocating the line data when undoing a line join + tweaks: do some text alignments properly: with spaces, not tabs + tweaks: drop a check for something that will not occur + tweaks: drop two comments that contain variable names + tweaks: elide a function call, by copying a byte directly + tweaks: elide an intermediate copy of a character during injection, twice + tweaks: elide an intermediate copy of an added character + tweaks: elide a parameter, and rename a variable + tweaks: elide a supporting variable, to make four loops slightly faster + tweaks: elide a variable and an unneeded iteration + tweaks: elide one variable and three gotos + tweaks: elide three unneeded #defines + tweaks: elide two variables and their two assignments + tweaks: exclude a function when compiled without spell-checking support + tweaks: extend the undo data for deleting and backspacing more directly + tweaks: factor out a three-line condition into a separate function + tweaks: frob a statement, rewrap two lines, and remove a pair of braces + tweaks: frob two statements, condense another, and add a comment + tweaks: highlight keystrokes in the documentation more consistently + tweaks: improve four comments, and condense two fragments of code + tweaks: improve three comments, and reshuffle two declarations + tweaks: improve two comments + tweaks: improve two comments, and remove an unneeded one + tweaks: inject the entire burst of bytes at once into the edit buffer + tweaks: instead of swapping the end points later, assign them correctly + tweaks: invert the logic of a symbol, to make more sense + tweaks: make prompt-bar input more similar to edit-buffer input + tweaks: make two conditions more direct, and thus elide two functions + tweaks: mesh two bits of code together + tweaks: move a function to after the one that it calls + tweaks: move a function to before the one that calls it + tweaks: move a function to before the one that calls it + tweaks: move a function to its proper place in the order of things + tweaks: move a function to where it is used + tweaks: move another function to where it is used + tweaks: move some definitions closer to where they are used + tweaks: move two functions to before the ones that call them + tweaks: normalize a translator hint, update one, and add another + tweaks: normalize the indentation after the previous change + tweaks: normalize the indentation after the previous change + tweaks: normalize the indentation after the previous two changes + tweaks: pull the NUL-terminating of a string into a function + tweaks: rearrange a case item, so that PASTE is always after CUT + tweaks: rearrange some conditions, for compactness + tweaks: relocate a function to before its callers + tweaks: relocate eleven functions to before they are called + tweaks: remove a now-unused helper function + tweaks: remove an unneeded indirection + tweaks: remove a redundant assignment + tweaks: remove a redundant statement, a spurious reference to 'cutbottom' + tweaks: remove a superfluous assignment, and reshuffle a call + tweaks: remove non-UTF-8 code from three more functions + tweaks: remove some redundant filtering, and thus elide a parameter + tweaks: remove some unneeded braces, not used elsewhere either + tweaks: remove two redundant case labels + tweaks: remove two superfluous checks + tweaks: remove two superfluous conditions + tweaks: rename a constant, and rename and relocate a function + tweaks: rename a function, and condense a few comments + tweaks: rename a function, and split a variable into two separate ones + tweaks: rename a function, to be more fitting, and improve some comments + tweaks: rename a function, to remove an obscuring abbreviation + tweaks: rename another function, to remove the obscuring abbreviation + tweaks: rename a parameter and a variable, and reword two comments + tweaks: rename a symbol, to match the corresponding renamed option + tweaks: rename a variable, and add a helping one + tweaks: rename a variable, and reshuffle a declaration + tweaks: rename a variable, away from a single letter + tweaks: rename a variable, away from a single letter + tweaks: rename a variable, for aptness + tweaks: rename a variable, reshuffle an assignment, and change a code + tweaks: rename a variable, to be a bit clearer + tweaks: rename a variable, to get out of the way of a later rename + tweaks: rename a variable, to not be a substring of a function name + tweaks: rename four more functions, to get rid of an abbreviation + tweaks: rename four parameters, to be more distinct and telling + tweaks: rename four variables, to be a bit more telling + tweaks: rename to the same name two variables that have the same role + tweaks: rename two elements of an undo record, to be more telling + tweaks: rename two functions, for shortness + tweaks: rename two functions, to match the style of others + tweaks: rename two more elements of an undo record, for symmetry + tweaks: rename two more functions, to match the style of others + tweaks: rename two more variables, to harmonize with two others + tweaks: rename two parameters, to not overlap with other names + tweaks: rename two symbols, to be more precise + tweaks: rename two variables, and frob four comments + tweaks: rename two variables, and reshuffle a few things + tweaks: rename two variables, for distinctiveness + tweaks: rename two variables, to be different or for more contrast + tweaks: rename two variables, to harmonize with two others + tweaks: rename two variables, to suit both the marked and unmarked case + tweaks: reorder a case item, to have SPLIT_BEGIN always before SPLIT_END + tweaks: reshuffle a condition, for compacter code + tweaks: reshuffle a condition, for compactness + tweaks: reshuffle a few declarations and assignments + tweaks: reshuffle an assignment and a free() + tweaks: reshuffle some code, in preparation for improving it + tweaks: reshuffle some stuff, to have related things together + tweaks: reshuffle the setting of the starting point of a cut + tweaks: reshuffle the trimming of leading whitespace, for compactness + tweaks: reshuffle two declarations plus a fragment of code + tweaks: simplify the undoing and redoing of an + tweaks: strip a parameter that is equivalent to 'openfile' for both calls + tweaks: strip a parameter that is TRUE for both calls + tweaks: swap the use of 'head' and 'tail' for CUT and PASTE undo items + tweaks: trim an unnecessary detail from an error message + tweaks: unabbreviate the name of a variable + tweaks: unwrap four lines, and use explicit codes where possible + tweaks: update several comments after the previous changes + tweaks: update some comments after the previous changes + tweaks: use a symbol instead of a number, and drop two unneeded casts + tweaks: use spaces when aligning things, not tabs + tweaks: use the variable that suits 'END' better + tweaks: weld two fragments together, twice, by eliding an unneeded 'if' + tweaks: when appropriate, move starting point of justified region back + tweaks: when extending the marked region, include also exotic blanks + tweaks: when undoing an addition or redoing a deletion, do not reallocate + undo: do not mark the buffer as modified when pasting back nothing + undo: do not try to copy a cutbuffer that is NULL + undo: do not try to paste back an empty cutbuffer + undo: for an automatic hard-wrap, store the correct previous buffer size + undo: store the cursor row, for redoing filtering & justification better + undo: treat a cut-until-end-of-buffer like a backward marked region + undo: use the correct original fusion point when unjoining two lines + undo: when undoing a paste or an insertion, remove an added magic line + usage: improve the description of --softwrap + +Neal Gompa (1): + syntax: spec: add some keywords that were added in RPM 4.15 and 4.13 + +Saagar Jha (1): + rcfile: fix an out-of-bounds read on empty lines + + Changes between v4.7 and v4.8: ------------------------------ @@ -28,7 +272,7 @@ Benno Schulenberg (166): docs: improve the description of which rc-files are read during startup docs: mention in the FAQ that auto-indentation is suppressed when pasting docs: mention that -D/--boldtext gets overridden by some nanorc options - docs: put the three new behaviors in a bulletted list, to catch the eye + docs: put the three new behaviors in a bulleted list, to catch the eye docs: stop saying that 'set fill' enables hard-wrapping -- it does not docs: use more generally available arrows in the cheatsheet feedback: ask a clearer question when a valid lock file is encountered @@ -415,7 +659,7 @@ Benno Schulenberg (60): tweaks: sort two keywords strictly alphabetically tweaks: speed up determining the width of plain ASCII characters tweaks: speed up the counting of the menu entries to be shown - tweaks: use a more effecient way to skip storing an empty file name + tweaks: use a more efficient way to skip storing an empty file name tweaks: use an early return when there is no tilde tweaks: use 'void' in prototypes of parameterless functions [coverity] usage: mark the -J/--guidestripe option plus argument as translatable @@ -1181,7 +1425,7 @@ Benno Schulenberg (87): tweaks: remove a check that was made redundant by the previous commit tweaks: remove a now-unused parameter from four functions tweaks: remove an unneeded check for NULL, and rename a parameter - tweaks: remove a stray file that was accidentally comitted + tweaks: remove a stray file that was accidentally committed tweaks: remove some old debugging code tweaks: rename a bunch of variables, to make it clearer what they contain tweaks: rename a flag, to match the name of the option @@ -1696,7 +1940,7 @@ Benno Schulenberg (65): undo: when redoing, don't try to find a line number that might not exist Brand Huntsman (1): - color: remove unneeded bright comparision to prevent duplicate pairs + color: remove unneeded bright comparison to prevent duplicate pairs David Lawrence Ramsey (3): docs: mention that errorcolor does have default colors @@ -1920,7 +2164,7 @@ Benno Schulenberg (103): docs: mention that macros work correctly only on terminal emulators docs: remove another remark about indenting lacking undo capability docs: update references to the nanorc files for the XDG changes - files: avoid an abortion when excuting a command in a new buffer + files: avoid an abortion when executing a command in a new buffer gnulib: update to its current upstream state help: don't fall back to other syntaxes if there is no nanohelp one history: after loading the lists, mark them as unchanged @@ -2016,7 +2260,7 @@ Brand Huntsman (3): David Lawrence Ramsey (18): build: add history.c to the list of files with translatable strings display: don't cut off zero-width characters at the end of a chunk - docs: decribe the bindable functions 'recordmacro' and 'runmacro' + docs: describe the bindable functions 'recordmacro' and 'runmacro' docs: document the more everyday names of three bindable functions docs: remove man page reference to indent/unindent lacking undo/redo files: don't change file format when inserting into an existing buffer diff --git a/release/src/router/nano/ChangeLog.1999-2006 b/release/src/router/nano/ChangeLog.1999-2006 index 0b0d58cb9ab..ff47b8cd72f 100644 --- a/release/src/router/nano/ChangeLog.1999-2006 +++ b/release/src/router/nano/ChangeLog.1999-2006 @@ -3007,7 +3007,7 @@ GNU nano 1.3.5 - 2004.11.22 - Don't change the file format when we insert another file into the current one. (DLR) do_insertfile() - - Simplify by reusing variables whereever possible, and add a + - Simplify by reusing variables wherever possible, and add a parameter execute to indicate whether or not to be in "Execute Command" mode. (DLR) - Rework so that goto is no longer needed, using do_writeout() @@ -5035,7 +5035,7 @@ GNU nano 1.1.99pre2 - 2003.02.03 - Fix the mouse code to work with lines longer than COLS and with the proper positioning, including special characters. (David Benbennick) - do_preserve_msg(): + do_preserve_msg() - Unsplit error message into a single fprintf call. (Jordi) main() - Call load_file with arg 0 for insert, as we aren't really @@ -5143,7 +5143,7 @@ GNU nano 1.1.99pre1 - 2003.01.17 - Added --enable-all option to compile in all the extra stuff we'd normally need extra flags for. - color.c: - update_color(): + update_color() - Remove an unneeded edit_refresh() call after do_colorinit(). (David Benbennick) - cut.c: @@ -5778,7 +5778,7 @@ GNU nano 1.1.10 - 2002.07.25 Also, pass current_x_find to strstrwrapper() so we know whether we're at the beginning of a string or not (see changes to strstrwrapper() below), and reset it between lines. (DLR) - do_gotoline(): + do_gotoline() - Make sure placewewant is zero after we go to a line. (David Benbennick) do_gotopos() @@ -6036,7 +6036,7 @@ GNU nano 1.1.8 - 2002.03.30 - Catalan and Spanish translation updates. (Jordi) - Typo. (DLR) - po/fr.po: - - French translation updates (Jean-Philippe Guérard). + - French translation updates. (Jean-Philippe Guérard) - po/gl.po: - Galician translation updates. (Jacobo Tarrio) - po/uk.po, po/ru.po: @@ -6156,10 +6156,9 @@ GNU nano 1.1.7 - 2002.03.05 - po/it.po: - Italian translation updates. (Marco Colombo) - po/cs.po: - - Partial Czech translation updates. (Vaclav Haisman) + - Partial Czech translation updates. (Václav Haisman) - po/hu.po: - - Hungarian translation updates, or to be precise, rewrite. - (Gergely Nagy) + - Hungarian translation updates, or to be precise, rewrite. (Gergely Nagy) - po/uk.po, po/ru.po: - Russian and Ukrainian translation updates. (Sergey A. Ribalchenko) - po/da.po: @@ -6268,7 +6267,7 @@ nano-1.1.6 - 2002.01.25 - po/nn.po: - Norwegian nynorsk translation updates. (Kjetil Torgrim Homme) - po/nb.po: - - New Norwegian bokmål translation. (Stig E Sandoe ) + - New Norwegian bokmål translation, by Stig E Sandoe . - po/da.po: - Danish translation update. (Keld Simonsen) @@ -6380,8 +6379,10 @@ nano-1.1.4 - 2001.12.11 do_wrap() - Many fixes. (David Lawrence Ramsey) do_spell() - - Dont prompt for replace if we don't change the word in + - Don't prompt for replace if we don't change the word in question. (Rocco Corsi) +- m4/gettext.m4: + - diff against mutt 1.2.5's gettext.m4. - po/de.po: - German translation updates. (Karl Eichwalder) - po/ru.po: @@ -6394,8 +6395,6 @@ nano-1.1.4 - 2001.12.11 - Spanish translation updates. (Jordi) - po/fr.po: - French translation updates. (Michel Robitaille) -- m4/gettext.m4: - - diff against mutt 1.2.5's gettext.m4. nano-1.1.3 - 2001.10.26 - General @@ -6770,7 +6769,7 @@ nano-1.1.0 - 2001.07.15 - po/es.po, po/ca.po: - Updated. (Jordi) - po/gl.po: - - Galician translation by Jacobo Tarrío. + - New Galician translation, by Jacobo Tarrío . - po/uk.po, po/ru.po: - New Ukrainian and Russian translations by Sergey A. Ribalchenko , thanks! @@ -6779,9 +6778,9 @@ nano-1.1.0 - 2001.07.15 - po/it.po - Updated Italian translation by Marco Colombo. - po/no.po: - - New Norwegian translation by Eivind Kjørstad . + - New Norwegian translation, by Eivind Kjørstad . - po/sv.po: - - New Swedish translation by Christian Rose . + - New Swedish translation, by Christian Rose . nano 1.0.1 - 2001.04.06 - General: @@ -6825,15 +6824,15 @@ nano-1.0.0 - 2001.03.22 the "new" C++ reserved word, even though there is likely no way nano will EVER be compilable with a C++ compiler. (suggested by Rocco Corsi). -- ca.po, es.po: - - Final tweaks for Nano 1.0. -- cs.po: - - Czech translation from Vaclav Haisman. - nano.info: - Added dir entry. (Albert Chin) - winio.c: statusq() - Added NANO_BACK_KEY and NANO_FORWARD_KEY cases for left and right. +- ca.po, es.po: + - Final tweaks for Nano 1.0. +- cs.po: + - New Czech translation, by Václav Haisman . 1.0-test prerelease - 2001.03.17 - nano.c: @@ -6847,7 +6846,7 @@ nano-1.0.0 - 2001.03.22 edit update. Fixes bug #57. - search.c: print_replaced() - - s/occurence/occurrence typos. (Jordi) + - Fix typos in "occurrence". (Jordi) search_init() - If using Pico mode and regex and same answer is entered, use last_search string instead of answer. Fixes bug #56. @@ -6888,13 +6887,13 @@ nano-0.9.99pre3 - 2001.02.19 - fi.po: - Translation updates by Pauli Virtanen. - hu.po: - - Hungarian translation by Horvath Szabolcs. + - New Hungarian translation, by Horvath Szabolcs . - id.po: - Translation updates by Tedi Heriyanto. - es.po: - Translation updates and grammatical/typo fixes. (Jordi) - ca.po: - - Catalan translation by Jordi Mallach :) + - Catalan translation by Jordi Mallach. :) - Miquel Vidal went over it and corrected many typos and completed bits that remained untranslated by error. @@ -6998,7 +6997,6 @@ General repeated string defs and globals. do_justify() - Small fix for totsize calculation. (Rob) - - fi.po: - Update by Pauli Virtanen. @@ -7395,7 +7393,7 @@ nano 0.9.18 - 2000.09.18 - es.po: - Translated new strings and minor updates. (Jordi) - de.po - - Revised translations by . + - Revised translations by Florian König. nano-0.9.17 - 2000.09.04 - General @@ -7426,7 +7424,7 @@ nano-0.9.17 - 2000.09.04 do_toggle() - Added checks for no help and no wrap mode, and print opposite enable/disable message. - do_suspend(), do_cont(): + do_suspend(), do_cont() - New functions, handle suspend signal in a Pico-like manner and work with Meta-Z. - winio.c: @@ -7447,7 +7445,7 @@ nano-0.9.17 - 2000.09.04 search_abort() - Now calls edit_refresh_clearok when MARK_ISSET to handle screen ugliness bug (reported by Ken Tyler). - findnextstr(): + findnextstr() - Added reset for placewewant. (Ben Roberts) - Fixed check for string that only occurs on the same line failing (bug discovered by Ken Tyler). @@ -7532,10 +7530,10 @@ nano-0.9.14 - 2000.07.27 - Changed check for filename to filename[0]. Added some code, overall fixes bug #30 =-) - nano.c: - do_justify() & do_wrap(): + do_justify(), do_wrap() - totsize-related fixes. (Rob) - de.po - - Revised translations by floki@bigfoot.com + - Revised translations by Florian König. nano-0.9.13 - 2000.07.23 - Implemented Pico's -k mode. New flag CUT_TO_END, option (-k, --cut), @@ -7548,32 +7546,32 @@ nano-0.9.13 - 2000.07.23 - Don't edit_refresh() if the bottom of the file is in the edit buffer. (Adam) - nano.c: - main(): + main() - TABSIZE now set before first call to edit_refresh. (Bill Soudan) - Different ^C kill code (patch by Christian Weisgerber). - die(): + die() - More intelligent emergency-save filename selection. (Rob) - do_spell(): + do_spell() - Changed exit semantics a bit so that aspell wouldn't get all screwy (bug discovered by Joshua Jensen). - files.c: - read_file(): + read_file() - Added init of buf variable, hopefully this will stop the "bleeding" of text seen with mutt and using i18n. - write_file(): + write_file() - Added code to check to see if using -l and the file is not in fact a link. This should fix the behavior where a file that does not have write permission but could be removed and rewritten is saved without error. Please test this feature and give feedback. - search.c: - search_init(): + search_init() - Added " (to replace)" statement to end of search string if we are doing a replace. Manually converted all the translations from '%s' to '%s%s' to ensure they still work with the new code. Also put in the translation for " (replace)" in the .po's. Hope I didn't step on your toes doing this Jordi. (Chris) - do_search(), do_replace(): + do_search(), do_replace() - Removed call to search_abort()/replace_abort() before call to the opposite function. - Fixed bug #28. @@ -7612,52 +7610,47 @@ nano-0.9.12 - 2000.07.07 - Corrected FIXME in do_enter with explanation. (Rob) - Fixed FIXME in do_justify, resulted in creation of fix_editbot [also fixed in do_enter] (winio.c). (Rob) - help_init(): + help_init() - Moved newline out of if statement. (Rocco Corsi) - do_char(): + do_char() - Magic Line related code in do_char. (Rob) - do_backspace(), do_delete(): + do_backspace(), do_delete() - Added magic line code here too. - -- de.po: - - Revised translations by floki@bigfoot.com. -- fi.po: - - Finnish translation by pauli.virtanen@saunalahti.fi. - utils.c: - Added new_magicline() - winio.c: - Added stdlib.h to includes, found by OpenBSD gcc. - lots of new commenting around display functions - do_yesno(), nanogetstr(): + do_yesno(), nanogetstr() - Removed now unnecessary raw/cbreak combos. - Removed gettext calls from "Y(es)", "N(o)", "A(ll)" and "^C", till we decide if those keybindings should be translated. (Jordi) - clear_bottomwin(): + clear_bottomwin() - Removed wrefresh(edit) call. - edit_update_top(): + edit_update_top() - Fixed a bug that caused nano to not update when current->next == NULL (e.g. paging down to the very bottom of ABOUT NLS wouldn't work). - fix_editbot: + fix_editbot() - Added (should rebuild editbot from a valid edittop). (Rob) - edit_add: + edit_add() - removal of redundant call to mvwaddnstr. +- de.po: + - Revised translations by Florian König. +- fi.po: + - New Finnish translation, by Pauli Virtanen . nano-0.9.11 - 2000.06.20 - New flag "-T" or "--tabsize" to specify how to display tab widths. Affects main() in nano.c, strlenpt(), xpt() and actual_x() (et al) in winio.c, and nano.h. Many hardcoded "8"s have been changed to the TABSIZE int. Added changes to nano.1 and nano.1.html. -- id.po: - - Indonesian translation by Tedi Heriyanto. -- es.po: - - Updated translation. (Jordi Mallach) - winio.c - Rewrite of display functions to correct the display problems we had been seeing. Affects: add_marked_sameline, edit_add, and many others. (Rob Siemborski) - totsize fixes. (Rob Siemborski) - total_refresh(): + total_refresh() - Cut display_main_list call, as this function is only supposed to refresh what's already on the screen, not go through the process of adding the text again. @@ -7669,12 +7662,12 @@ nano-0.9.11 - 2000.06.20 Changed all calls to editwinrows - 1 in nano.c and move.c. - Removed all functions that were split into other files. Affects LOTS of funcs. - do_enter(): + do_enter() - Added reset of placewewant to end. - do_insertfile(): + do_insertfile() - Fix display problem when using Ctrl-R to load a file into the buffer. (Rob Siemborski) - handle_sigwinch(): + handle_sigwinch() - Added titlebar(), edit_refresh() and display_main_list() calls because a resize wasn't picking up on possible different width correctly. @@ -7689,17 +7682,21 @@ nano-0.9.11 - 2000.06.20 - search.c: - Contains all our searching and related functions, (do_search(), findnextstr(), do_replace(), do_gotoline()). +- id.po: + - New Indonesian translation, by Tedi Heriyanto . +- es.po: + - Updated translation. (Jordi Mallach) nano-0.9.10 - 2000.06.04 -- es.po: - - Translation updates. (Jordi) - AUTHORS, nano.1.html, TODO, README: - Documentation and email address updates. (Jordi) - nano.c: - main(): + main() - Moved Adam's termio code down to after getopt() and before initscr() to stop people losing their SIGINT character when using args that exit nano before it runs (--version, --help, etc). +- es.po: + - Translation updates. (Jordi) nano-0.9.9 - 2000.05.31 - Makefile.am: @@ -7708,8 +7705,6 @@ nano-0.9.9 - 2000.05.31 - Spelling fixes. (Jordi Mallach) - Removed CFLAGS changes for gcc, reduces portability according to some, and it certainly doesn't seem to decrease exe size. -- es.po: - - Spanish translation updates. (Jordi Mallach) - POTFILES.in: - Added global.c file, was screwing up translations (i.e. they weren't getting done). @@ -7747,6 +7742,8 @@ nano-0.9.9 - 2000.05.31 - winio.c: total_refresh(): - Completely rewrote function, not quite so brain-damaged now. +- es.po: + - Spanish translation updates. (Jordi Mallach) nano-0.9.8 - 2000.05.18 - nano.c: @@ -7768,7 +7765,7 @@ nano-0.9.8 - 2000.05.18 should now only be called once, at the bottom of the main() loop. - global.c: - shortcut_init(): + shortcut_init(): - Removed suspend sc_init call and suspend message because suspend is no longer needed in the shortcut list to work properly. @@ -7787,7 +7784,6 @@ nano-0.9.7 - 2000.05.14 display update (bug discovered by Ken Tyler). nano-0.9.6 - 2000.05.08 -- New Italian translation (it.po), by Daniele Medri. - nano.c: page_up(), page_down(): - Added reset of placewewant to 0, as it should be. @@ -7806,6 +7802,12 @@ nano-0.9.6 - 2000.05.08 - Removed yucky code that didn't work, this function now just computes edittop and editbot and calls edit_refresh() to do the rest, which removes a lot of duplicate code... +- it.po: + - New Italian translation, by Daniele Medri . +- fr.po: + - New French translation, by Pierre Tane . +- de.po: + - New German translation, by Florian König . nano-0.9.5 - 2000.05.01 - Removed bytes from file struct because it was computationally wasteful. @@ -7831,25 +7833,23 @@ nano-0.9.5 - 2000.05.01 - Removed inefficient call to edit_refresh() after every keystroke. It is now up each function to leave the screen in a good state. - winio.c: - do_cursorpos() + do_cursorpos(): - Rewritten to not use bytes from filestruct by an incremental sum. update_line(), reset_cursor(): - Optimized calls to xplustabs() through a single variable. - update_line() now takes a new arg, an index into the string - for where to update the line from. Needed for new update - code. + for where to update the line from. Needed for new update code. - configure.in: - Better checks for slang, allows argument to --with-slang. (Albert Chin-A-Young) - Removed -Iintl from CFLAGS in gcc check. - Makefile.am: - - Addition of -Iintl for gettext (Albert Chin-A-Young) + - Addition of -Iintl for gettext. (Albert Chin-A-Young) nano-0.9.4 - 2000.04.25 - - Fixed calls to no_help and changed them to the more consistent - ISSET(NO_HELP). Fixed return val of no_help to be what it should (2, - not 1. Code to temporarily disable NO_HELP when in the - help system. (Adam Rogoyski) +- Fixed calls to no_help and changed them to the more consistent ISSET(NO_HELP). + Fixed return val of no_help to be what it should (2, not 1). Code to + temporarily disable NO_HELP when in the help system. (Adam Rogoyski) - cut.c: do_marked_cut(), do_cut(), do_uncut(): - Commented out unnecessary bits when NANO_SMALL is being used. @@ -7985,23 +7985,26 @@ nano-0.8.8 - 2000.03.12 support i18n. - nano.c: includes: Added sys/param.h and limits.h. (Adam Rogoyski). - statics: Changed some things that were not necessarily static - (Adam Rogoyski). - nrealloc(): New function, similar to nmalloc(). Changed calls from + statics: Changed some things that were not necessarily static. + (Adam Rogoyski) + nrealloc(): + New function, similar to nmalloc(). Changed calls from realloc() to nrealloc. (Adam Rogoyski) empty_line(), no_spaces(), justify_format(), do_justify(): New functions for justify function. (Adam Rogoyski) - winio.c: - blank_edit(): Added wrefresh call to edit so that screen updates (like - on ^L) actually work. - xplustabs(), xpt(), strlenpt(): Fixed off-by-one buglets. (Adam Rogoyski) + blank_edit(): + Added wrefresh call to edit so that screen updates (like on ^L) + actually work. + xplustabs(), xpt(), strlenpt(): + Fixed off-by-one buglets. (Adam Rogoyski) nano-0.8.7 - 2000.03.01 - main.c: - do_wrap(): Better fix for segfaults, and fix for lines being wrapped - to a single character on one line when no good place to - break the line exists, and for wrapping lines longer than - COLS. + do_wrap(): + Better fix for segfaults, and fix for lines being wrapped + to a single character on one line when no good place to break + the line exists, and for wrapping lines longer than COLS. - nano.1.html: Html version of man page, now included in dist. For the benefit of nano packages in Linux distributions. @@ -8024,7 +8027,8 @@ nano-0.8.6 - 2000.02.24 nano-0.8.5 - 2000.02.18 - nano.c: - main(): Finally fixed tilde being input on page up/down keys in + main(): + Finally fixed tilde being input on page up/down keys in certain terminal types. Fix was input 26->91->5[34] check for 126, if so make the kbinput PAGE UP/DOWN, else unget the keystroke and continue. Added #include for @@ -8038,7 +8042,7 @@ nano-0.8.5 - 2000.02.18 edit_refresh() is now unmanageably complex, and must be revamped. check_statblank(): - Added check for constupdate, makes things less choppy + Added check for constupdate, makes things less choppy. (Adam Rogoyski) nano-0.8.4 - 2000.02.11 @@ -8049,7 +8053,8 @@ nano-0.8.4 - 2000.02.11 Removed redundant NANO_CONTROL_H from backspace shortcut, added char 127 which should have been there. - nano.c: - main(): Fix for loops looping until MAIN_LEN, added -1 to stop + main(): + Fix for loops looping until MAIN_LEN, added -1 to stop segfaults. (Adam Rogoyski) - Makefile.am: Added all source filenames. (Adam Rogoyski) - nano.1: Fixed mail addressed and added mailing list address. @@ -8057,13 +8062,15 @@ nano-0.8.4 - 2000.02.11 nano-0.8.3 - 2000.02.08 - New Pico mode (-p, --pico), toggles (more) compatibility with the - Pico messages displayed in the shortcut list. Note that there are still - small differences in this mode. -- nano.h: New shortcut struct format, for the benefit of i18n and + Pico messages displayed in the shortcut list. Note that there are + still small differences in this mode. +- nano.h: + New shortcut struct format, for the benefit of i18n and our help menu. Removed shortcut message macros, they are now all in shortcut_init in global.c. - nano.c: - do_wrap(): Removed resetting of current_x when we are in fact + do_wrap(): + Removed resetting of current_x when we are in fact wrapping to the next line, fixes a bug in -i mode. do_enter(): Rewrote the autoindent mode code to be a lot less pretty, @@ -8116,7 +8123,8 @@ nano-0.8.1 - 2000.01.28 global variable fill, affects check_wrap(), do_wrap(), main(), usage(), global.c and proto.h. - nano.c: -write_file(): Added (incredibly) necessary check for EPERM when +write_file(): + Added (incredibly) necessary check for EPERM when link() fails. This allows us to actually save files via rename() on filesystems that don't support hard links (AIEEEEEE). @@ -8136,7 +8144,7 @@ nano-0.8.0 - 2000.01.25 - View flag (-v, --view) implemented. Global variable view_mode, affects main loop of nano.c and new_file(). (Chris) - nano.c: - split checks for TERMIOS_H and TERMIO_H up so we + Split checks for TERMIOS_H and TERMIO_H up so we can (theoretically) include them both, which is good. handle_sigwinch(): Added check for ncurses.h. (Andy Kahn) @@ -8254,7 +8262,6 @@ nano 0.7.6 - 2000.01.15 than one huge buffer, and replaced the strcat at the end with an index variable. Added call to read_bytes(). do_next_word(): New function, binding is Ctrl-Space (0). (Chris) - - winio.c: bottombars(): Fixed non-expanding shortcut keys at bottom of screen. (formula is extra space needed = COLS / 6 - 13). diff --git a/release/src/router/nano/ChangeLog.2007-2015 b/release/src/router/nano/ChangeLog.2007-2015 index 0595dc65961..08bf1778f0d 100644 --- a/release/src/router/nano/ChangeLog.2007-2015 +++ b/release/src/router/nano/ChangeLog.2007-2015 @@ -330,7 +330,7 @@ GNU nano 2.5.2 - 2016.02.12 2016-02-09 Benno Schulenberg * src/files.c (stat_with_alloc, open_buffer, write_file): Check the - result of a stat() to avoid referencing unitialized data. Original + result of a stat() to avoid referencing uninitialized data. Original patch was by Kamil Dudka. * doc/man/{nano.1,rnano.1,nanorc.5}: Adjust version for release. @@ -661,7 +661,7 @@ GNU nano 2.5.0 - 2015.12.05 This addresses Debian bug #805288. 2015-12-01 Benno Schulenberg - * src/files.c (do_insertfile): Mark the buffer as mofified only when + * src/files.c (do_insertfile): Mark the buffer as modified only when actually something was inserted. This fixes Savannah bug #45409. * src/files.c (do_insertfile): Rename two variables for clarity. * src/text.c (redo_cut): Delete two redundant assignments. @@ -1305,7 +1305,7 @@ GNU nano 2.4.2 - 2015.07.05 * src/text.c (do_alt_speller, do_linter, do_formatter): Distinguish a failure to launch the linter from receiving zero parsable lines; add a new function to glue together the invocation-error string. - * src/global.c (shortcut_init): In the Help Viewer and File Browswer, + * src/global.c (shortcut_init): In the Help Viewer and File Browser, bind the unbound Home and End keys to goto_top and goto_bottom, to mimic the behaviour of these keys in file viewers and web browsers. Also show ^Y and ^V in the WhereisFile menu instead of M-\ and M-/, @@ -2005,7 +2005,7 @@ GNU nano 2.3.4 - 2014.06.02 2014-06-02 Chris Allegretta * doc/syntax/default.nanorc: Can't do trailing spaces in the - default syntax or it will hilight the spaces as you type them + default syntax or it will highlight the spaces as you type them into a new file, which for non-programming is infuriating. 2014-05-29 Mark Majeres @@ -3448,14 +3448,14 @@ GNU nano 2.1.8 - 2009.02.07 2009-01-25 Chris Allegretta * files.c (open_file), nanorc.c (parse_include): Don't get_full_path on included rc files, due to it potentially impacting the ability to read files in nano's - cwd(). Fixes Savnanah bug #25297 reported by Mike Frysinger. + cwd(). Fixes Savannah bug #25297 reported by Mike Frysinger. 2009-01-24 Chris Allegretta - * First pass at some caching of caching color info. Right now it's only for + * First pass at some caching of color info. Right now it's only for multi-line regexes but this may not be enough to increase performance. * Add interruptability to search functions. New functions enable_nodelay and disable_nodelay and changes to the routines to handle checking for pending - searches. Fixes Savnnah bug #24946: Need interrrupt for search. + searches. Fixes Savannah bug #24946: Need interrupt for search. 2009-01-19 Chris Allegretta * Change function definitions to shorts instead of (void *)s. New mapping function @@ -3494,7 +3494,7 @@ GNU nano 2.1.6 - 2008.10.03 * ocaml.nanorc: Sample OCaml syntax highlighting file. 2008-09-30 Dave Geering - * objc.nanorc: Sample Objective-C syntax hightlighting file. + * objc.nanorc: Sample Objective-C syntax highlighting file. 2008-09-30 Chris Allegretta * configure.ac: Change extra, multibuffer, color and rcfile configure options @@ -3648,7 +3648,7 @@ GNU nano 2.1.1 - 2008.04.01 * gentoo.nanorc: Gentoo syntax highlighting config. 2008-03-17 Benno Schulenberg - * global.c: Fix incorrect first line jump messsage, fix + * global.c: Fix incorrect first line jump message, fix more comments to assist translators. * winio.c: Fix shortcut labels not being translated. diff --git a/release/src/router/nano/Makefile.in b/release/src/router/nano/Makefile.in index 077189973df..5c5c8b0d931 100644 --- a/release/src/router/nano/Makefile.in +++ b/release/src/router/nano/Makefile.in @@ -1245,6 +1245,7 @@ REPLACE_EXPM1F = @REPLACE_EXPM1F@ REPLACE_EXPM1L = @REPLACE_EXPM1L@ REPLACE_FABSL = @REPLACE_FABSL@ REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHMODAT = @REPLACE_FCHMODAT@ REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ REPLACE_FCLOSE = @REPLACE_FCLOSE@ REPLACE_FCNTL = @REPLACE_FCNTL@ diff --git a/release/src/router/nano/NEWS b/release/src/router/nano/NEWS index d59d3188887..c8cc864be35 100644 --- a/release/src/router/nano/NEWS +++ b/release/src/router/nano/NEWS @@ -1,3 +1,23 @@ +2020.04.07 - GNU nano 4.9.2 "Mali Lošinj" +• Another bug introduced in version 4.9 is fixed: a likely crash + after undoing an at the end of leading whitespace. + +2020.03.31 - GNU nano 4.9.1 "Sapperdeflap" +• Two bugs introduced in version 4.9 are fixed: the cursor + getting misplaced when undoing line cuts, and filtering + of the whole buffer to a new buffer not working. + +2020.03.24 - GNU nano 4.9 "die fetten Jahre sind vorbei" +• When justifying a selection, the new paragraph and the + succeeding one get the appropriate first-line indent. +• Trying to justify an empty selection does not crash. +• Redoing the insertion of an empty file does not crash. +• On the BSDs and macOS, ^H has become rebindable again + (in most terminal emulators, not on the console). +• DOS line endings in nanorc files are accepted. +• Option --suspend / 'set suspend' has been renamed to + the more logical --suspendable / 'set suspendable'. + 2020.02.07 - GNU nano 4.8 "Jaška" • When something is pasted into nano, auto-indentation is suppressed, and the paste can be undone as a whole with a single M-U. diff --git a/release/src/router/nano/TODO b/release/src/router/nano/TODO index 17d6d802a06..f17595ca3e5 100644 --- a/release/src/router/nano/TODO +++ b/release/src/router/nano/TODO @@ -1,20 +1,20 @@ A list of desired features -------------------------- -Somewhat urgent: -- Detect when text is being pasted, so that we can handle it faster. - See https://savannah.gnu.org/bugs/?40060. -- Allow color syntaxes to apply to more than just color, so that we can +* Allow color syntaxes to apply to more than just color, so that we can e.g. specify a different alternate spell checker depending on which file type we have open. -Vague musings: -- Add support for right-to-left text (RTL), through FriBidi? -- Allow setting marks (saved positions, not to be confused with the +* Add support for right-to-left text (RTL). + +* Allow setting bookmarks (saved positions, not to be confused with the mark set via Ctrl-^) at various lines and/or columns in the buffer, and allow movement between them with a single keystroke? -- Make matching bracket searches sophisticated enough to skip over - brackets inside comments? + See https://savannah.gnu.org/bugs/?57577. + + +For version 4.8: +- Detect when text is being pasted, so that we can handle it faster. [DONE] For version 4.0: - Make undo/redo work also for justifying. [DONE] @@ -31,8 +31,7 @@ For version 2.8: For version 2.4: - Handle window resizes better. After we've resized, we should stay wherever we were before we resized, as Pico does. [DONE] -- Allow even better file-type detection than we have currently, e.g. - through libmagic. [DONE] +- Allow even better file-type detection, e.g. through libmagic. [DONE] - Compatibility with vim status files to let other editors know we're in a file. [DONE] @@ -49,36 +48,31 @@ For version 2.0: - Support for paragraph searches. [DONE] - Support for justifying the entire file at once. [DONE] - Support for filename searches in the file browser. [DONE] -- Keystroke to implement "Add next sequence as raw" like vi's ^V. [DONE] +- A keystroke to implement "Add next sequence as raw", like vi's ^V. [DONE] - Spell check selected text only. [DONE] -- Make "To Line" (^W^T) and "Read from Command" (^R^X) reenter their - parent menu when their keystroke is entered a second time (^W^T^T and - (^R^X^X) (requires figuring out when to keep cursor position and when - not to). [DONE] -- Fix resetstatuspos global which we shouldn't have. [DONE] +- Make "To Line" (^W^T) and "Read from Command" (^R^X) return to their parent + menu when their keystroke is entered again (^W^T^T and ^R^X^X). [DONE] For version 1.2: - Single-line scroll up/down? [DONE] -- Color syntax highlighting? (There seems to be a demand for it.) [DONE] +- Color syntax highlighting? [DONE] - Support for a .nanorc file. [DONE] - Backup making (filename~)? [DONE] - Search/replace string history. [DONE] -- Implement Pico's -j and -g flags, as they are pretty easy to do. [DONE] -- Make mouse support work with clicking on the shortcuts (-m). [DONE] +- Implement Pico's -j and -g flags. [DONE] +- Make mouse support (-m) work with clicking on the shortcuts. [DONE] - Implement -o (--operatingdir, a chroot of sorts). [DONE] -- Allow -r to take a negative argument, meaning right margin instead of - left (allows resizing that way), formerly -W arg. [DONE] +- Allow -r to take a negative argument. [DONE] For version 1.0: - Implement Spelling. [DONE] - Implement Help. [DONE] - Internationalization [In progress, translators welcome!] - Allow nano to be resized in X. [DONE] -- On PageUp/Down, put the cursor on the first line (like Pico), not the - center line. [DONE] +- On PageUp/Down, put the cursor on the first screen line (like Pico). [DONE] - Implement justify function. [DONE] - Cut to end of line. [DONE] - Built-in speller command. [DONE] -- Better statusbar interaction (scrolling, tab completion). [DONE] +- Better status-bar interaction (scrolling, tab completion). [DONE] - Unjustify command (^U after ^J). [DONE] - Username completion (~user). [DONE] diff --git a/release/src/router/nano/config.h.in b/release/src/router/nano/config.h.in index d77b9ed68d6..e2b7c8850f6 100644 --- a/release/src/router/nano/config.h.in +++ b/release/src/router/nano/config.h.in @@ -148,6 +148,10 @@ whether the gnulib module fscanf shall be considered present. */ #undef GNULIB_FSCANF +/* Define to a C preprocessor expression that evaluates to 1 or 0, depending + whether the gnulib module isblank shall be considered present. */ +#undef GNULIB_ISBLANK + /* Define to a C preprocessor expression that evaluates to 1 or 0, depending whether the gnulib module lock shall be considered present. */ #undef GNULIB_LOCK @@ -1234,9 +1238,6 @@ # endif #endif -/* Enable large inode numbers on Mac OS X 10.5. */ -#undef _DARWIN_USE_64_BIT_INODE - /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS @@ -1267,7 +1268,10 @@ # define _Noreturn [[noreturn]] # elif ((!defined __cplusplus || defined __clang__) \ && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \ - || 4 < __GNUC__ + (7 <= __GNUC_MINOR__))) + || 4 < __GNUC__ + (7 <= __GNUC_MINOR__) \ + || (defined __apple_build_version__ \ + ? 6000000 <= __apple_build_version__ \ + : 3 < __clang_major__ + (5 <= __clang_minor__)))) /* _Noreturn works as-is. */ # elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C # define _Noreturn __attribute__ ((__noreturn__)) diff --git a/release/src/router/nano/configure b/release/src/router/nano/configure index 21d15823f21..c880c4072a2 100755 --- a/release/src/router/nano/configure +++ b/release/src/router/nano/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for GNU nano 4.8. +# Generated by GNU Autoconf 2.69 for GNU nano 4.9.2. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='GNU nano' PACKAGE_TARNAME='nano' -PACKAGE_VERSION='4.8' -PACKAGE_STRING='GNU nano 4.8' +PACKAGE_VERSION='4.9.2' +PACKAGE_STRING='GNU nano 4.9.2' PACKAGE_BUGREPORT='nano-devel@gnu.org' PACKAGE_URL='http://www.gnu.org/software/nano/' @@ -1215,6 +1215,7 @@ REPLACE_LSTAT REPLACE_FUTIMENS REPLACE_FSTATAT REPLACE_FSTAT +REPLACE_FCHMODAT HAVE_UTIMENSAT HAVE_MKNODAT HAVE_MKNOD @@ -2511,7 +2512,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures GNU nano 4.8 to adapt to many kinds of systems. +\`configure' configures GNU nano 4.9.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -2581,7 +2582,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of GNU nano 4.8:";; + short | recursive ) echo "Configuration of GNU nano 4.9.2:";; esac cat <<\_ACEOF @@ -2730,7 +2731,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -GNU nano configure 4.8 +GNU nano configure 4.9.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3444,7 +3445,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by GNU nano $as_me 4.8, which was +It was created by GNU nano $as_me 4.9.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4445,7 +4446,7 @@ fi # Define the identity of the package. PACKAGE='nano' - VERSION='4.8' + VERSION='4.9.2' cat >>confdefs.h <<_ACEOF @@ -7126,10 +7127,6 @@ _ACEOF esac rm -rf conftest* fi - - -$as_echo "#define _DARWIN_USE_64_BIT_INODE 1" >>confdefs.h - fi @@ -9385,6 +9382,7 @@ $as_echo "#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1" >>confdefs.h HAVE_MKNOD=1; HAVE_MKNODAT=1; HAVE_UTIMENSAT=1; + REPLACE_FCHMODAT=0; REPLACE_FSTAT=0; REPLACE_FSTATAT=0; REPLACE_FUTIMENS=0; @@ -9517,6 +9515,54 @@ $as_echo "$gl_cv_member_st_size_64" >&6; } ;; esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 +$as_echo_n "checking for C/C++ restrict keyword... " >&6; } +if ${ac_cv_c_restrict+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +typedef int *int_ptr; + int foo (int_ptr $ac_kw ip) { return ip[0]; } + int bar (int [$ac_kw]); /* Catch GCC bug 14050. */ + int bar (int ip[$ac_kw]) { return ip[0]; } + +int +main () +{ +int s[1]; + int *$ac_kw t = s; + t[0] = 0; + return foo (t) + bar (t); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_restrict=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_restrict" != no && break + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 +$as_echo "$ac_cv_c_restrict" >&6; } + + case $ac_cv_c_restrict in + restrict) ;; + no) $as_echo "#define restrict /**/" >>confdefs.h + ;; + *) cat >>confdefs.h <<_ACEOF +#define restrict $ac_cv_c_restrict +_ACEOF + ;; + esac + @@ -9632,6 +9678,8 @@ fi + + GNULIB_DPRINTF=0; GNULIB_FCLOSE=0; GNULIB_FDOPEN=0; @@ -10409,54 +10457,6 @@ $as_echo "$gl_cv_func_getopt_long_gnu" >&6; } REPLACE_GETTIMEOFDAY=0; REPLACE_STRUCT_TIMEVAL=0; -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 -$as_echo_n "checking for C/C++ restrict keyword... " >&6; } -if ${ac_cv_c_restrict+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_restrict=no - # The order here caters to the fact that C++ does not require restrict. - for ac_kw in __restrict __restrict__ _Restrict restrict; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -typedef int *int_ptr; - int foo (int_ptr $ac_kw ip) { return ip[0]; } - int bar (int [$ac_kw]); /* Catch GCC bug 14050. */ - int bar (int ip[$ac_kw]) { return ip[0]; } - -int -main () -{ -int s[1]; - int *$ac_kw t = s; - t[0] = 0; - return foo (t) + bar (t); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_restrict=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_restrict" != no && break - done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 -$as_echo "$ac_cv_c_restrict" >&6; } - - case $ac_cv_c_restrict in - restrict) ;; - no) $as_echo "#define restrict /**/" >>confdefs.h - ;; - *) cat >>confdefs.h <<_ACEOF -#define restrict $ac_cv_c_restrict -_ACEOF - ;; - esac - @@ -12575,6 +12575,8 @@ $as_echo "$gl_cv_next_inttypes_h" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'double'" >&5 $as_echo_n "checking where to find the exponent in a 'double'... " >&6; } if ${gl_cv_cc_double_expbit0+:} false; then : @@ -17013,6 +17015,21 @@ else if test "$cross_compiling" = yes; then : case "$host_os" in + # Guess no on glibc when _FORTIFY_SOURCE >= 2. + *-gnu* | gnu*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if _FORTIFY_SOURCE >= 2 + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_func_printf_directive_n="guessing yes" +else + gl_cv_func_printf_directive_n="guessing no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; # Guess no on Android. linux*-android*) gl_cv_func_printf_directive_n="guessing no";; # Guess no on native Windows. @@ -17836,7 +17853,6 @@ fi - if test $gl_cv_have_include_next = yes; then gl_cv_next_string_h='<'string.h'>' else @@ -17916,6 +17932,8 @@ $as_echo "$gl_cv_next_string_h" >&6; } + + @@ -18325,6 +18343,8 @@ $as_echo "$gl_cv_next_time_h" >&6; } + + gl_libunistring_sed_extract_major='/^[0-9]/{s/^\([0-9]*\).*/\1/p;q;} i\ 0 @@ -21284,6 +21304,13 @@ $as_echo "#define GNULIB_TEST_GLOB 1" >>confdefs.h fi +cat >>confdefs.h <<_ACEOF +#define GNULIB_ISBLANK 1 +_ACEOF + + + + @@ -26646,6 +26673,8 @@ fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for signbit macro" >&5 $as_echo_n "checking for signbit macro... " >&6; } if ${gl_cv_func_signbit+:} false; then : @@ -27898,8 +27927,21 @@ else if test "$cross_compiling" = yes; then : case "$host_os" in - # Guess yes on glibc systems. - *-gnu* | gnu*) gl_cv_func_snprintf_directive_n="guessing yes";; + # Guess no on glibc when _FORTIFY_SOURCE >= 2. + *-gnu* | gnu*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if _FORTIFY_SOURCE >= 2 + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_func_snprintf_directive_n="guessing yes" +else + gl_cv_func_snprintf_directive_n="guessing no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; # Guess yes on musl systems. *-musl*) gl_cv_func_snprintf_directive_n="guessing yes";; # Guess yes on FreeBSD >= 5. @@ -29294,6 +29336,8 @@ _ACEOF + + if test $gl_cv_have_include_next = yes; then gl_cv_next_stdlib_h='<'stdlib.h'>' else @@ -29365,6 +29409,8 @@ $as_echo "$gl_cv_next_stdlib_h" >&6; } + + for ac_func in strcasecmp do : ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" @@ -29807,6 +29853,8 @@ fi + + @@ -29990,6 +30038,8 @@ $as_echo "$gl_cv_next_unistd_h" >&6; } + + if { test "$HAVE_LIBUNISTRING" != yes \ || { @@ -30298,6 +30348,7 @@ $as_echo "#define FUTIMESAT_NULL_BUG 1" >>confdefs.h + if test $ac_cv_func_vasnprintf = no; then @@ -30696,8 +30747,21 @@ else if test "$cross_compiling" = yes; then : case "$host_os" in - # Guess yes on glibc systems. - *-gnu* | gnu*) gl_cv_func_snprintf_directive_n="guessing yes";; + # Guess no on glibc when _FORTIFY_SOURCE >= 2. + *-gnu* | gnu*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if _FORTIFY_SOURCE >= 2 + error fail + #endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_func_snprintf_directive_n="guessing yes" +else + gl_cv_func_snprintf_directive_n="guessing no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; # Guess yes on musl systems. *-musl*) gl_cv_func_snprintf_directive_n="guessing yes";; # Guess yes on FreeBSD >= 5. @@ -31361,6 +31425,8 @@ $as_echo "$gl_cv_next_wchar_h" >&6; } + + if case "$host_os" in mingw*) true ;; @@ -32641,10 +32707,6 @@ _ACEOF esac rm -rf conftest* fi - - -$as_echo "#define _DARWIN_USE_64_BIT_INODE 1" >>confdefs.h - fi @@ -37461,7 +37523,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by GNU nano $as_me 4.8, which was +This file was extended by GNU nano $as_me 4.9.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -37529,7 +37591,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -GNU nano config.status 4.8 +GNU nano config.status 4.9.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/release/src/router/nano/configure.ac b/release/src/router/nano/configure.ac index 3aaffd49d44..10e5fe60d47 100644 --- a/release/src/router/nano/configure.ac +++ b/release/src/router/nano/configure.ac @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see https://www.gnu.org/licenses/. -AC_INIT([GNU nano], [4.8], [nano-devel@gnu.org], [nano]) +AC_INIT([GNU nano], [4.9.2], [nano-devel@gnu.org], [nano]) AC_CONFIG_SRCDIR([src/nano.c]) AC_CANONICAL_HOST AM_INIT_AUTOMAKE([1.14]) diff --git a/release/src/router/nano/doc/Makefile.in b/release/src/router/nano/doc/Makefile.in index b7d8203a93b..1646469ef19 100644 --- a/release/src/router/nano/doc/Makefile.in +++ b/release/src/router/nano/doc/Makefile.in @@ -1300,6 +1300,7 @@ REPLACE_EXPM1F = @REPLACE_EXPM1F@ REPLACE_EXPM1L = @REPLACE_EXPM1L@ REPLACE_FABSL = @REPLACE_FABSL@ REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHMODAT = @REPLACE_FCHMODAT@ REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ REPLACE_FCLOSE = @REPLACE_FCLOSE@ REPLACE_FCNTL = @REPLACE_FCNTL@ diff --git a/release/src/router/nano/doc/faq.html b/release/src/router/nano/doc/faq.html index 9f7a4862a9a..de0c5dba5b8 100644 --- a/release/src/router/nano/doc/faq.html +++ b/release/src/router/nano/doc/faq.html @@ -89,7 +89,7 @@

1.2. What is the history behind nano?

1.3. Why the name change from TIP?

On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program "establishes a full duplex terminal connection to a remote host", and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).

1.4. What is the current version of nano?

-

The current version of nano should be 4.8. Of course, you should always check the nano homepage to see what the latest and greatest version is.

+

The current version of nano should be 4.9.2. Of course, you should always check the nano homepage to see what the latest and greatest version is.

1.5. I want to read the man page without having to download the program!

Jeez, demanding, aren't we? Okay, look here.


diff --git a/release/src/router/nano/doc/nano.1 b/release/src/router/nano/doc/nano.1 index 4e99458e2f3..e5623ac112b 100644 --- a/release/src/router/nano/doc/nano.1 +++ b/release/src/router/nano/doc/nano.1 @@ -16,7 +16,7 @@ .\" Documentation License along with this program. If not, see .\" . .\" -.TH NANO 1 "version 4.8" "February 2020" +.TH NANO 1 "version 4.9.2" "April 2020" .SH NAME nano \- Nano's ANOther editor, inspired by Pico @@ -281,8 +281,8 @@ Set the operating directory. This makes \fBnano\fP set up something similar to a chroot. .TP .BR \-p ", " \-\-preserve -Preserve the XON and XOFF sequences (^Q and ^S) so they will be caught -by the terminal. +Preserve the XON and XOFF sequences (\fB^Q\fR and \fB^S\fR) so they +will be caught by the terminal. .TP .BR \-r\ \fInumber ", " \-\-fill= \fInumber Set the target width for justifying and automatic hard-wrapping at this @@ -320,13 +320,14 @@ Don't show the two help lines at the bottom of the screen. .BR \-y ", " \-\-afterends Make Ctrl+Right stop at word ends instead of beginnings. .TP -.BR \-z ", " \-\-suspend -Enable the suspend ability. +.BR \-z ", " \-\-suspendable +Allow the user to suspend the editor (with \fB^Z\fR by default). .TP .BR \-$ ", " \-\-softwrap -Enable 'soft wrapping'. This will make \fBnano\fP attempt to display the -entire contents of any line, even if it is longer than the screen width, by -continuing it over multiple screen lines. Since +Display lines that exceed the screen's width over multiple screen lines. +(You can make this soft-wrapping occur at whitespace instead of rudely at +the screen's edge, by using also \fB\-\-atblanks\fR.) +Since \&'$' normally refers to a variable in the Unix shell, you should specify this option last when using other options (e.g.\& 'nano \-wS$') or pass it separately (e.g.\& 'nano \-wS \-$'). diff --git a/release/src/router/nano/doc/nano.1.html b/release/src/router/nano/doc/nano.1.html index d377979cfe3..5b3370263df 100644 --- a/release/src/router/nano/doc/nano.1.html +++ b/release/src/router/nano/doc/nano.1.html @@ -1,5 +1,5 @@ - + @@ -490,8 +490,8 @@

OPTIONS −−preserve

Preserve the XON and XOFF -sequences (^Q and ^S) so they will be caught by the -terminal.

+sequences (^Q and ^S) so they will be caught +by the terminal.

−r number, @@ -560,22 +560,23 @@

OPTIONS ends instead of beginnings.

−z, -−−suspend

+−−suspendable

-

Enable the suspend ability.

+

Allow the user to suspend the +editor (with ^Z by default).

−$, −−softwrap

-

Enable ’soft -wrapping’. This will make nano attempt to -display the entire contents of any line, even if it is -longer than the screen width, by continuing it over multiple -screen lines. Since ’$’ normally refers to a -variable in the Unix shell, you should specify this option -last when using other options (e.g. ’nano -−wS$’) or pass it separately (e.g. ’nano -−wS −$’).

+

Display lines that exceed the +screen’s width over multiple screen lines. (You can +make this soft-wrapping occur at whitespace instead of +rudely at the screen’s edge, by using also +−−atblanks.) Since ’$’ +normally refers to a variable in the Unix shell, you should +specify this option last when using other options (e.g. +’nano −wS$’) or pass it separately (e.g. +’nano −wS −$’).

TOGGLES diff --git a/release/src/router/nano/doc/nano.html b/release/src/router/nano/doc/nano.html index 9f170872a4f..082e3925398 100644 --- a/release/src/router/nano/doc/nano.html +++ b/release/src/router/nano/doc/nano.html @@ -45,7 +45,7 @@

nano

-

This manual documents the GNU nano editor, version 4.8. +

This manual documents the GNU nano editor, version 4.9.2.

- + + + + + + diff --git a/tools/build-all b/tools/build-all index fa50c1d30b2..094665fe670 100755 --- a/tools/build-all +++ b/tools/build-all @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh ####### ### Asuswrt-Merlin.ng build script @@ -12,10 +12,10 @@ ### Manual/hardcoded # Append git revision -export BUILDREV=1 +#export BUILDREV=1 # Enable update server support (don't use if you build a fork!) -# export MERLINUPDATE=y +#export MERLINUPDATE=y # rsync tree from central source tree before build RSYNC_TREE=y @@ -42,11 +42,11 @@ BAC86=y BAX88=y BAX58=y - +BAX56=y ### Paths # Store built images there -STAGE_LOC=~/images +STAGE_LOC="$HOME/images" # Copy built images there # Copy is done using scp, so it can be an ssh location @@ -55,36 +55,34 @@ STAGE_LOC=~/images FINAL_LOC=/media/sf_Share # Location of the original source code -SRC_LOC=~/amng +SRC_LOC="$HOME/amng" ### End config build_fw() { - BRANCH=$3 - FWMODEL=$2 - FWPATH=$1 + BRANCH="$3" + FWMODEL="$2" + FWPATH="$1" echo "*** $(date +%R) - Starting building $FWMODEL..." - cd ~/$FWPATH - make $FWMODEL &> output.txt - - if [ $? -eq 0 ]; then - cd image - if [ "$FWMODEL" == "rt-ac86u" -o "$FWMODEL" == "rt-ax88u" ]; then - FWNAME=$(ls -t *_cferom_ubi.w | head -n 1) - ZIPNAME="${FWNAME//_cferom_ubi.w/}".zip - else if [ "$FWMODEL" == "rt-ax58u" ] - FWNAME=$(ls -t *_cferom_pureubi.w | head -n 1) - ZIPNAME="${FWNAME//_cferom_pureubi.w/}".zip + cd "$HOME/$FWPATH" || exit 1 + if make "$FWMODEL" > "output.txt" 2>&1; then + cd image || exit 1 + if [ "$FWMODEL" = "rt-ac86u" ] || [ "$FWMODEL" = "rt-ax88u" ]; then + FWNAME="$(find -- *_cferom_ubi.w | head -n 1)" + ZIPNAME="$(echo "$FWNAME" | sed 's~_cferom_ubi.w~~g').zip" + elif [ "$FWMODEL" = "rt-ax58u" ] || [ "$FWMODEL" = "rt-ax56u" ]; then + FWNAME="$(find -- *_cferom_pureubi.w | head -n 1)" + ZIPNAME="$(echo "$FWNAME" | sed 's~_cferom_pureubi.w~~g').zip" else - FWNAME=$(ls -t *.trx | head -n 1) - ZIPNAME="${FWNAME%.*}".zip + FWNAME="$(find -- *.trx | head -n 1)" + ZIPNAME="$(echo "$FWNAME" | sed 's~.trx~~g').zip" fi - cp $FWNAME $STAGE_LOC/ + cp "$FWNAME" "$STAGE_LOC/" - sha256sum $FWNAME > sha256sum.sha256 - zip -j $STAGE_LOC/$ZIPNAME $FWNAME $STAGE_LOC/README-merlin.txt $STAGE_LOC/Changelog*.txt sha256sum.sha256 &>/dev/null + sha256sum "$FWNAME" > sha256sum.sha256 + zip -qj "$STAGE_LOC/$ZIPNAME" "$FWNAME" "$STAGE_LOC/README-merlin.txt" "$STAGE_LOC"/Changelog*.txt "sha256sum.sha256" 2>/dev/null echo "*** $(date +%R) - Done building $FWMODEL!" else echo "!!! $(date +%R) - $FWMODEL build failed!" @@ -93,134 +91,142 @@ build_fw() clean_tree() { - FWPATH=$1 - SDKPATH=$2 - FWMODEL=$3 - BRANCH=$4 + FWPATH="$1" + SDKPATH="$2" + FWMODEL="$3" + BRANCH="$4" echo "*** $(date +%R) - Cleaning up $FWMODEL..." - if [ "$RSYNC_TREE" == "y" ]; then + if [ "$RSYNC_TREE" = "y" ]; then echo "*** $(date +%R) - Updating $FWMODEL tree..." - rsync -a --del $SRC_LOC/ ~/$FWPATH + rsync -a --del "$SRC_LOC/" "$HOME/$FWPATH" fi - cd ~/$FWPATH + cd "$HOME/$FWPATH" || exit 1 - CURRENT=$(git branch | grep \* | cut -d ' ' -f2) + CURRENT=$(git branch | grep "\*" | cut -d ' ' -f2) if [ "$CURRENT" != "$BRANCH" ] ; then - git checkout $BRANCH + git checkout "$BRANCH" fi - if [ "$CLEANUP_TREE" == "y" ]; then - cd ~/$FWPATH/$SDKPATH - make cleankernel clean &>/dev/null 2>&1 - rm .config image/*.trx image/*.w &>/dev/null + if [ "$CLEANUP_TREE" = "y" ]; then + cd "$HOME/$FWPATH/$SDKPATH" || exit 1 + make cleankernel clean >/dev/null 2>&1 + rm .config image/*.trx image/*.w >/dev/null 2>&1 fi - echo -e "*** $(date +%R) - $FWMODEL code ready.\n" + echo "*** $(date +%R) - $FWMODEL code ready." } # Initial cleanup echo "--- $(date +%R) - Global cleanup..." -mkdir -p $STAGE_LOC/backup -mv $STAGE_LOC/* $STAGE_LOC/backup/ -cp $SRC_LOC/README-merlin.txt $STAGE_LOC/ -cp $SRC_LOC/Changelog*.txt $STAGE_LOC/ +mkdir -p "$STAGE_LOC/backup" +mv "$STAGE_LOC"/* "$STAGE_LOC/backup/" 2>/dev/null +cp "$SRC_LOC/README-merlin.txt" "$STAGE_LOC/" +cp "$SRC_LOC"/Changelog*.txt "$STAGE_LOC/" # Update all model trees echo "--- $(date +%R) - Preparing trees" -if [ "$BAC56" == "y" ]; then +if [ "$BAC56" = "y" ]; then clean_tree amng.ac56 release/src-rt-6.x.4708 rt-ac56u master fi -if [ "$BAC68" == "y" ]; then +if [ "$BAC68" = "y" ]; then clean_tree amng.ac68 release/src-rt-6.x.4708 rt-ac68u mainline fi -if [ "$BAC87" == "y" ]; then +if [ "$BAC87" = "y" ]; then clean_tree amng.ac87 release/src-rt-6.x.4708 rt-ac87u 384.13_x fi -if [ "$BAC3200" == "y" ]; then +if [ "$BAC3200" = "y" ]; then clean_tree amng.ac3200 release/src-rt-7.x.main/src rt-ac3200 384.13_x fi -if [ "$BAC3100" == "y" ]; then +if [ "$BAC3100" = "y" ]; then clean_tree amng.ac3100 release/src-rt-7.14.114.x/src rt-ac3100 mainline fi -if [ "$BAC88" == "y" ]; then +if [ "$BAC88" = "y" ]; then clean_tree amng.ac88 release/src-rt-7.14.114.x/src rt-ac88u mainline fi -if [ "$BAC5300" == "y" ]; then +if [ "$BAC5300" = "y" ]; then clean_tree amng.ac5300 release/src-rt-7.14.114.x/src rt-ac5300 mainline fi -if [ "$BAC86" == "y" ]; then +if [ "$BAC86" = "y" ]; then clean_tree amng.ac86 release/src-rt-5.02hnd rt-ac86u mainline fi -if [ "$BAX88" == "y" ]; then +if [ "$BAX88" = "y" ]; then clean_tree amng.ax88 release/src-rt-5.02axhnd rt-ax88u ax fi -if [ "$BAX58" == "y" ]; then +if [ "$BAX58" = "y" ]; then clean_tree amng.ax58 release/src-rt-5.02axhnd.675x rt-ax58u ax fi +if [ "$BAX56" = "y" ]; then + clean_tree amng.ax56 release/src-rt-5.02axhnd.675x rt-ax56u ax +fi -echo -e "--- $(date +%R) - All trees ready!\n" +echo "--- $(date +%R) - All trees ready!" # Launch parallel builds echo "--- $(date +%R) - Launching all builds" -if [ "$BAC56" == "y" ]; then +if [ "$BAC56" = "y" ]; then build_fw amng.ac56/release/src-rt-6.x.4708 rt-ac56u & sleep 20 fi -if [ "$BAC68" == "y" ]; then +if [ "$BAC68" = "y" ]; then build_fw amng.ac68/release/src-rt-6.x.4708 rt-ac68u & sleep 20 fi -if [ "$BAC87" == "y" ]; then +if [ "$BAC87" = "y" ]; then build_fw amng.ac87/release/src-rt-6.x.4708 rt-ac87u & sleep 20 fi -if [ "$BAC3200" == "y" ]; then +if [ "$BAC3200" = "y" ]; then build_fw amng.ac3200/release/src-rt-7.x.main/src rt-ac3200 & sleep 20 fi -if [ "$BAC3100" == "y" ]; then +if [ "$BAC3100" = "y" ]; then build_fw amng.ac3100/release/src-rt-7.14.114.x/src rt-ac3100 & sleep 20 fi -if [ "$BAC88" == "y" ]; then +if [ "$BAC88" = "y" ]; then build_fw amng.ac88/release/src-rt-7.14.114.x/src rt-ac88u & sleep 20 fi -if [ "$BAC5300" == "y" ]; then +if [ "$BAC5300" = "y" ]; then build_fw amng.ac5300/release/src-rt-7.14.114.x/src rt-ac5300 & sleep 10 fi -if [ "$BAC86" == "y" ]; then +if [ "$BAC86" = "y" ]; then build_fw amng.ac86/release/src-rt-5.02hnd rt-ac86u & sleep 10 fi -if [ "$BAX88" == "y" ]; then - build_fw amng.ax88/release/src-rt-5.02axhnd rt-ax88u & - sleep 10 +if [ "$BAX88" = "y" ]; then + build_fw amng.ax88/release/src-rt-5.02axhnd rt-ax88u & + sleep 10 fi -if [ "$BAX58" == "y" ]; then +if [ "$BAX58" = "y" ]; then build_fw amng.ax58/release/src-rt-5.02axhnd.675x rt-ax58u & sleep 10 fi +if [ "$BAX56" = "y" ]; then + build_fw amng.ax56/release/src-rt-5.02axhnd.675x rt-ax56u & + sleep 10 +fi + echo "--- $(date +%R) - All builds launched, please wait..." wait -echo "" -cd ~/images -sha256sum *.trx | unix2dos > sha256sums-ng.txt -sha256sum *.w | unix2dos >> sha256sums-ng.txt +echo +cd "$STAGE_LOC" || exit 1 +{ sha256sum -- *.trx +sha256sum -- *.w; } 2>/dev/null | unix2dos > sha256sums-ng.txt # Copy everything to the host if [ -z "$FINAL_LOC" ]; then - scp *.zip *.trx *.txt *.w $FINAL_LOC/ + scp -- *.zip *.trx *.txt *.w "$FINAL_LOC/" 2>/dev/null fi echo "=== $(date +%R) - All done!"